VirtualBox

source: vbox/trunk/src/VBox/Main/DisplayImpl.cpp@ 1

Last change on this file since 1 was 1, checked in by vboxsync, 55 years ago

import

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 57.4 KB
Line 
1/** @file
2 *
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2006 InnoTek Systemberatung GmbH
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22#include "DisplayImpl.h"
23#include "FramebufferImpl.h"
24#include "ConsoleImpl.h"
25#include "ConsoleVRDPServer.h"
26#include "VMMDev.h"
27
28#include "Logging.h"
29
30#include <iprt/semaphore.h>
31#include <iprt/thread.h>
32#include <iprt/asm.h>
33
34#include <VBox/pdm.h>
35#include <VBox/cfgm.h>
36#include <VBox/err.h>
37#include <VBox/vm.h>
38
39/**
40 * Display driver instance data.
41 */
42typedef struct DRVMAINDISPLAY
43{
44 /** Pointer to the display object. */
45 Display *pDisplay;
46 /** Pointer to the driver instance structure. */
47 PPDMDRVINS pDrvIns;
48 /** Pointer to the keyboard port interface of the driver/device above us. */
49 PPDMIDISPLAYPORT pUpPort;
50 /** Our display connector interface. */
51 PDMIDISPLAYCONNECTOR Connector;
52} DRVMAINDISPLAY, *PDRVMAINDISPLAY;
53
54/** Converts PDMIDISPLAYCONNECTOR pointer to a DRVMAINDISPLAY pointer. */
55#define PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface) ( (PDRVMAINDISPLAY) ((uintptr_t)pInterface - RT_OFFSETOF(DRVMAINDISPLAY, Connector)) )
56
57#ifdef DEBUG_sunlover
58static STAMPROFILE StatDisplayRefresh;
59static int stam = 0;
60#endif /* DEBUG_sunlover */
61
62// constructor / destructor
63/////////////////////////////////////////////////////////////////////////////
64
65HRESULT Display::FinalConstruct()
66{
67 mpVbvaMemory = NULL;
68 mfVideoAccelEnabled = false;
69 mfVideoAccelVRDP = false;
70 mfu32SupportedOrders = 0;
71 mcVideoAccelVRDPRefs = 0;
72
73 mpPendingVbvaMemory = NULL;
74 mfPendingVideoAccelEnable = false;
75
76 mfMachineRunning = false;
77
78 mpu8VbvaPartial = NULL;
79 mcbVbvaPartial = 0;
80
81 mParent = NULL;
82 mpDrv = NULL;
83 mpVMMDev = NULL;
84 mfVMMDevInited = false;
85 RTSemEventMultiCreate(&mResizeSem);
86 RTSemEventMultiCreate(&mUpdateSem);
87
88 mLastAddress = NULL;
89 mLastLineSize = 0;
90 mLastColorDepth = 0,
91 mLastWidth = 0;
92 mLastHeight = 0;
93
94 return S_OK;
95}
96
97void Display::FinalRelease()
98{
99 if (isReady())
100 uninit();
101}
102
103// public initializer/uninitializer for internal purposes only
104/////////////////////////////////////////////////////////////////////////////
105
106/**
107 * Initializes the display object.
108 *
109 * @returns COM result indicator
110 * @param parent handle of our parent object
111 * @param qemuConsoleData address of common console data structure
112 */
113HRESULT Display::init (Console *parent)
114{
115 LogFlowFunc (("isReady=%d", isReady()));
116
117 ComAssertRet (parent, E_INVALIDARG);
118
119 AutoLock alock (this);
120 ComAssertRet (!isReady(), E_UNEXPECTED);
121
122 mParent = parent;
123
124 /* reset the event sems */
125 RTSemEventMultiReset(mResizeSem);
126 RTSemEventMultiReset(mUpdateSem);
127
128 // by default, we have an internal framebuffer which is
129 // NULL, i.e. a black hole for no display output
130 mFramebuffer = 0;
131 mInternalFramebuffer = true;
132 mFramebufferOpened = false;
133 mSupportedAccelOps = 0;
134
135 mParent->RegisterCallback(this);
136
137 setReady (true);
138 return S_OK;
139}
140
141/**
142 * Uninitializes the instance and sets the ready flag to FALSE.
143 * Called either from FinalRelease() or by the parent when it gets destroyed.
144 */
145void Display::uninit()
146{
147 LogFlowFunc (("isReady=%d\n", isReady()));
148
149 AutoLock alock (this);
150 AssertReturn (isReady(), (void) 0);
151
152 mFramebuffer.setNull();
153 RTSemEventMultiDestroy(mResizeSem);
154 RTSemEventMultiDestroy(mUpdateSem);
155
156 if (mParent)
157 {
158 mParent->UnregisterCallback(this);
159 }
160
161 if (mpDrv)
162 mpDrv->pDisplay = NULL;
163 mpDrv = NULL;
164 mpVMMDev = NULL;
165 mfVMMDevInited = true;
166
167 setReady (false);
168}
169
170// IConsoleCallback method
171STDMETHODIMP Display::OnStateChange(MachineState_T machineState)
172{
173 if (machineState == MachineState_Running)
174 {
175 LogFlowFunc (("Machine running\n"));
176
177 mfMachineRunning = true;
178 }
179 else
180 {
181 mfMachineRunning = false;
182 }
183 return S_OK;
184}
185
186// public methods only for internal purposes
187/////////////////////////////////////////////////////////////////////////////
188
189void Display::callFramebufferResize (FramebufferPixelFormat_T pixelFormat, void *pvVRAM, uint32_t cbLine, int w, int h)
190{
191 Assert (!mFramebuffer.isNull());
192
193 /* Call the framebuffer to try and set required pixelFormat. */
194 BOOL finished = TRUE;
195
196 mFramebuffer->RequestResize (pixelFormat, (ULONG)pvVRAM, cbLine, w, h, &finished);
197
198 if (!finished)
199 {
200 LogFlowFunc (("External framebuffer wants us to wait!\n"));
201
202 /* The framebuffer needs more time to process
203 * the event so we have to halt the VM until it's done.
204 */
205 RTSemEventMultiReset(mResizeSem);
206 mFramebuffer->Unlock();
207 RTSemEventMultiWait(mResizeSem, RT_INDEFINITE_WAIT); /** @todo r=bird: this is a serious deadlock point, where EMT is stuck while the main thread is doing VMR3Req for some reason. */
208 mFramebuffer->Lock();
209 }
210}
211
212/**
213 * Handles display resize event.
214 *
215 * @param w New display width
216 * @param h New display height
217 *
218 * @thread EMT
219 */
220void Display::handleDisplayResize (uint32_t bpp, void *pvVRAM, uint32_t cbLine, int w, int h)
221{
222 LogRel (("Display::handleDisplayResize(): pvVRAM=%p w=%d h=%d bpp=%d cbLine=0x%X\n",
223 pvVRAM, w, h, bpp, cbLine));
224
225 /* If there is no framebuffer, this call is not interesting. */
226 if (mFramebuffer.isNull())
227 {
228 return;
229 }
230
231 mLastAddress = pvVRAM;
232 mLastLineSize = cbLine;
233 mLastColorDepth = bpp,
234 mLastWidth = w;
235 mLastHeight = h;
236
237 FramebufferPixelFormat_T pixelFormat;
238
239 switch (bpp)
240 {
241 case 32: pixelFormat = FramebufferPixelFormat_PixelFormatRGB32; break;
242 case 24: pixelFormat = FramebufferPixelFormat_PixelFormatRGB24; break;
243 case 16: pixelFormat = FramebufferPixelFormat_PixelFormatRGB16; break;
244 default: pixelFormat = FramebufferPixelFormat_PixelFormatDefault; cbLine = 0;
245 }
246
247 mFramebuffer->Lock();
248
249 callFramebufferResize (pixelFormat, pvVRAM, cbLine, w, h);
250
251 /* Indicated whether the FB should be set to a default format in case something went wrong. */
252 bool fResetFormat = false;
253
254 /* Check the framebuffer pixel format. */
255 FramebufferPixelFormat_T newPixelFormat;
256
257 mFramebuffer->COMGETTER(PixelFormat) (&newPixelFormat);
258
259 if (newPixelFormat == FramebufferPixelFormat_PixelFormatDefault)
260 {
261 mpDrv->pUpPort->pfnSetupVRAM (mpDrv->pUpPort, NULL, 0);
262 }
263 else
264 {
265 Assert(pixelFormat == newPixelFormat);
266
267 /* Framebuffer successfully set the requested format. */
268 ULONG address;
269 mFramebuffer->COMGETTER(Address) (&address);
270
271 ULONG lineSize;
272 mFramebuffer->COMGETTER(LineSize) (&lineSize);
273 Assert(lineSize == cbLine);
274
275 /* Trust Framebuffer implementation that it allocated a buffer,
276 * which size is a multiple of PAGE_SIZE.
277 */
278 uint32_t cbBuffer = cbLine * h;
279
280 int rc = mpDrv->pUpPort->pfnSetupVRAM (mpDrv->pUpPort, (void *)address, cbBuffer);
281
282 if (VBOX_FAILURE(rc))
283 {
284 LogFlowFunc (("pfnSetupVRAM returns %Vrc\n", rc));
285 fResetFormat = true;
286 }
287
288#ifdef DEBUG_sunlover
289 if (!stam)
290 {
291 /* protect mpVM */
292 Console::SafeVMPtr pVM (mParent);
293 AssertComRC (pVM.rc());
294
295 STAM_REG(pVM, &StatDisplayRefresh, STAMTYPE_PROFILE, "/PROF/Display/Refresh", STAMUNIT_TICKS_PER_CALL, "Time spent in EMT for display updates.");
296 stam = 1;
297 }
298#endif /* DEBUG_sunlover */
299 }
300
301 if (fResetFormat)
302 {
303 callFramebufferResize (FramebufferPixelFormat_PixelFormatDefault, NULL, 0, w, h);
304 }
305
306 updateDisplayData();
307
308 LogFlowFunc (("Calling VRDP\n"));
309
310 mParent->consoleVRDPServer()->SendResize();
311
312 mFramebuffer->Unlock();
313
314 return;
315}
316
317static void checkCoordBounds (int *px, int *py, int *pw, int *ph, int cx, int cy)
318{
319 /* Correct negative x and y coordinates. */
320 if (*px < 0)
321 {
322 *px += *pw; /* Compute xRight which is also the new width. */
323
324 *pw = (*px < 0)? 0: *px;
325
326 *px = 0;
327 }
328
329 if (*py < 0)
330 {
331 *py += *ph; /* Compute xBottom, which is also the new height. */
332
333 *ph = (*py < 0)? 0: *py;
334
335 *py = 0;
336 }
337
338 /* Also check if coords are greater than the display resolution. */
339 if (*px + *pw > cx)
340 {
341 *pw = cx > *px? cx - *px: 0;
342 }
343
344 if (*py + *ph > cy)
345 {
346 *ph = cy > *py? cy - *py: 0;
347 }
348}
349
350/**
351 * Handles display update event.
352 *
353 * @param x Update area x coordinate
354 * @param y Update area y coordinate
355 * @param w Update area width
356 * @param h Update area height
357 *
358 * @thread EMT
359 */
360void Display::handleDisplayUpdate (int x, int y, int w, int h)
361{
362 // if there is no framebuffer, this call is not interesting
363 if (mFramebuffer.isNull())
364 return;
365
366 mFramebuffer->Lock();
367
368#ifdef DEBUG_sunlover
369 LogFlowFunc (("%d,%d %dx%d (%d,%d)\n",
370 x, y, w, h, mpDrv->Connector.cx, mpDrv->Connector.cy));
371#endif /* DEBUG_sunlover */
372
373 checkCoordBounds (&x, &y, &w, &h, mpDrv->Connector.cx, mpDrv->Connector.cy);
374
375#ifdef DEBUG_sunlover
376 LogFlowFunc (("%d,%d %dx%d (checked)\n", x, y, w, h));
377#endif /* DEBUG_sunlover */
378
379 /* special processing for the internal framebuffer */
380 if (mInternalFramebuffer)
381 {
382 mFramebuffer->Unlock();
383 } else
384 {
385 /* callback into the framebuffer to notify it */
386 BOOL finished = FALSE;
387
388 mFramebuffer->NotifyUpdate(x, y, w, h, &finished);
389
390 if (!finished)
391 {
392 /*
393 * the framebuffer needs more time to process
394 * the event so we have to halt the VM until it's done
395 */
396 RTSemEventMultiReset(mUpdateSem);
397 mFramebuffer->Unlock();
398 RTSemEventMultiWait(mUpdateSem, RT_INDEFINITE_WAIT);
399 } else
400 {
401 mFramebuffer->Unlock();
402 }
403
404 if (!mfVideoAccelEnabled)
405 {
406 /* When VBVA is enabled, the VRDP server is informed in the VideoAccelFlush.
407 * Inform the server here only if VBVA is disabled.
408 */
409 mParent->consoleVRDPServer()->SendUpdateBitmap(x, y, w, h);
410 }
411 }
412 return;
413}
414
415typedef struct _VBVADIRTYREGION
416{
417 /* Copies of object's pointers used by vbvaRgn functions. */
418 IFramebuffer *pFramebuffer;
419 Display *pDisplay;
420 PPDMIDISPLAYPORT pPort;
421
422 /* Merged rectangles. */
423 int32_t xLeft;
424 int32_t xRight;
425 int32_t yTop;
426 int32_t yBottom;
427
428} VBVADIRTYREGION;
429
430static void vbvaRgnInit (VBVADIRTYREGION *prgn, IFramebuffer *pfb, Display *pd, PPDMIDISPLAYPORT pp)
431{
432 memset (prgn, 0, sizeof (VBVADIRTYREGION));
433
434 prgn->pFramebuffer = pfb;
435 prgn->pDisplay = pd;
436 prgn->pPort = pp;
437
438 return;
439}
440
441static void vbvaRgnDirtyRect (VBVADIRTYREGION *prgn, VBVACMDHDR *phdr)
442{
443 LogFlowFunc (("x = %d, y = %d, w = %d, h = %d\n",
444 phdr->x, phdr->y, phdr->w, phdr->h));
445
446 /*
447 * Here update rectangles are accumulated to form an update area.
448 * @todo
449 * Now the simpliest method is used which builds one rectangle that
450 * includes all update areas. A bit more advanced method can be
451 * employed here. The method should be fast however.
452 */
453 if (phdr->w == 0 || phdr->h == 0)
454 {
455 /* Empty rectangle. */
456 return;
457 }
458
459 int32_t xRight = phdr->x + phdr->w;
460 int32_t yBottom = phdr->y + phdr->h;
461
462 if (prgn->xRight == 0)
463 {
464 /* This is the first rectangle to be added. */
465 prgn->xLeft = phdr->x;
466 prgn->yTop = phdr->y;
467 prgn->xRight = xRight;
468 prgn->yBottom = yBottom;
469 }
470 else
471 {
472 /* Adjust region coordinates. */
473 if (prgn->xLeft > phdr->x)
474 {
475 prgn->xLeft = phdr->x;
476 }
477
478 if (prgn->yTop > phdr->y)
479 {
480 prgn->yTop = phdr->y;
481 }
482
483 if (prgn->xRight < xRight)
484 {
485 prgn->xRight = xRight;
486 }
487
488 if (prgn->yBottom < yBottom)
489 {
490 prgn->yBottom = yBottom;
491 }
492 }
493
494 return;
495}
496
497static void vbvaRgnUpdateFramebuffer (VBVADIRTYREGION *prgn)
498{
499 uint32_t w = prgn->xRight - prgn->xLeft;
500 uint32_t h = prgn->yBottom - prgn->yTop;
501
502 if (prgn->pFramebuffer && w != 0 && h != 0)
503 {
504 prgn->pPort->pfnUpdateDisplayRect (prgn->pPort, prgn->xLeft, prgn->yTop, w, h);
505 prgn->pDisplay->handleDisplayUpdate (prgn->xLeft, prgn->yTop, w, h);
506 }
507}
508
509static void vbvaSetMemoryFlags (VBVAMEMORY *pVbvaMemory,
510 bool fVideoAccelEnabled,
511 bool fVideoAccelVRDP,
512 uint32_t fu32SupportedOrders)
513{
514 if (pVbvaMemory)
515 {
516 /* This called only on changes in mode. So reset VRDP always. */
517 uint32_t fu32Flags = VBVA_F_MODE_VRDP_RESET;
518
519 if (fVideoAccelEnabled)
520 {
521 fu32Flags |= VBVA_F_MODE_ENABLED;
522
523 if (fVideoAccelVRDP)
524 {
525 fu32Flags |= VBVA_F_MODE_VRDP | VBVA_F_MODE_VRDP_ORDER_MASK;
526
527 pVbvaMemory->fu32SupportedOrders = fu32SupportedOrders;
528 }
529 }
530
531 pVbvaMemory->fu32ModeFlags = fu32Flags;
532 }
533}
534
535bool Display::VideoAccelAllowed (void)
536{
537 return true;
538}
539
540/**
541 * @thread EMT
542 */
543int Display::VideoAccelEnable (bool fEnable, VBVAMEMORY *pVbvaMemory)
544{
545 int rc = VINF_SUCCESS;
546
547 /* Called each time the guest wants to use acceleration,
548 * or when the VGA device disables acceleration,
549 * or when restoring the saved state with accel enabled.
550 *
551 * VGA device disables acceleration on each video mode change
552 * and on reset.
553 *
554 * Guest enabled acceleration at will. And it has to enable
555 * acceleration after a mode change.
556 */
557 LogFlowFunc (("mfVideoAccelEnabled = %d, fEnable = %d, pVbvaMemory = %p\n",
558 mfVideoAccelEnabled, fEnable, pVbvaMemory));
559
560 /* Strictly check parameters. Callers must not pass anything in the case. */
561 Assert((fEnable && pVbvaMemory) || (!fEnable && pVbvaMemory == NULL));
562
563 if (!VideoAccelAllowed ())
564 {
565 return VERR_NOT_SUPPORTED;
566 }
567
568 /*
569 * Verify that the VM is in running state. If it is not,
570 * then this must be postponed until it goes to running.
571 */
572 if (!mfMachineRunning)
573 {
574 Assert (!mfVideoAccelEnabled);
575
576 LogFlowFunc (("Machine is not yet running.\n"));
577
578 if (fEnable)
579 {
580 mfPendingVideoAccelEnable = fEnable;
581 mpPendingVbvaMemory = pVbvaMemory;
582 }
583
584 return rc;
585 }
586
587 /* Check that current status is not being changed */
588 if (mfVideoAccelEnabled == fEnable)
589 {
590 return rc;
591 }
592
593 if (mfVideoAccelEnabled)
594 {
595 /* Process any pending orders and empty the VBVA ring buffer. */
596 VideoAccelFlush ();
597 }
598
599 if (!fEnable && mpVbvaMemory)
600 {
601 mpVbvaMemory->fu32ModeFlags &= ~VBVA_F_MODE_ENABLED;
602 }
603
604 /* Safety precaution. There is no more VBVA until everything is setup! */
605 mpVbvaMemory = NULL;
606 mfVideoAccelEnabled = false;
607
608 /* Update entire display. */
609 mpDrv->pUpPort->pfnUpdateDisplayAll(mpDrv->pUpPort);
610
611 /* Everything OK. VBVA status can be changed. */
612
613 /* Notify the VMMDev, which saves VBVA status in the saved state,
614 * and needs to know current status.
615 */
616 PPDMIVMMDEVPORT pVMMDevPort = mParent->getVMMDev()->getVMMDevPort ();
617
618 if (pVMMDevPort)
619 {
620 pVMMDevPort->pfnVBVAChange (pVMMDevPort, fEnable);
621 }
622
623 if (fEnable)
624 {
625 mpVbvaMemory = pVbvaMemory;
626 mfVideoAccelEnabled = true;
627
628 /* Initialize the hardware memory. */
629 vbvaSetMemoryFlags (mpVbvaMemory, mfVideoAccelEnabled, mfVideoAccelVRDP, mfu32SupportedOrders);
630 mpVbvaMemory->off32Data = 0;
631 mpVbvaMemory->off32Free = 0;
632
633 memset (mpVbvaMemory->aRecords, 0, sizeof (mpVbvaMemory->aRecords));
634 mpVbvaMemory->indexRecordFirst = 0;
635 mpVbvaMemory->indexRecordFree = 0;
636
637 LogRel(("VBVA: Enabled.\n"));
638 }
639 else
640 {
641 LogRel(("VBVA: Disabled.\n"));
642 }
643
644 LogFlowFunc (("VideoAccelEnable: rc = %Vrc.\n", rc));
645
646 return rc;
647}
648
649#ifdef VBOX_VRDP
650#ifdef VRDP_MC
651/* Called always by one VRDP server thread. Can be thread-unsafe.
652 */
653void Display::VideoAccelVRDP (bool fEnable)
654{
655 /* Supporting all orders. */
656 uint32_t fu32SupportedOrders = ~0;
657
658 int c = fEnable?
659 ASMAtomicIncS32 (&mcVideoAccelVRDPRefs):
660 ASMAtomicDecS32 (&mcVideoAccelVRDPRefs);
661
662 Assert (c >= 0);
663
664 if (c == 0)
665 {
666 /* The last client has disconnected, and the accel can be
667 * disabled.
668 */
669 Assert (fEnable == false);
670
671 mfVideoAccelVRDP = false;
672 mfu32SupportedOrders = 0;
673
674 vbvaSetMemoryFlags (mpVbvaMemory, mfVideoAccelEnabled, mfVideoAccelVRDP, mfu32SupportedOrders);
675
676 LogRel(("VBVA: VRDP acceleration has been disabled.\n"));
677 }
678 else if ( c == 1
679 && !mfVideoAccelVRDP)
680 {
681 /* The first client has connected. Enable the accel.
682 */
683 Assert (fEnable == true);
684
685 mfVideoAccelVRDP = true;
686 /* Supporting all orders. */
687 mfu32SupportedOrders = ~0;
688
689 vbvaSetMemoryFlags (mpVbvaMemory, mfVideoAccelEnabled, mfVideoAccelVRDP, mfu32SupportedOrders);
690
691 LogRel(("VBVA: VRDP acceleration has been requested.\n"));
692 }
693 else
694 {
695 /* A client is connected or disconnected but there is no change in the
696 * accel state. It remains enabled.
697 */
698 Assert (mfVideoAccelVRDP == true);
699 }
700}
701#else
702void Display::VideoAccelVRDP (bool fEnable, uint32_t fu32SupportedOrders)
703{
704 Assert (mfVideoAccelVRDP != fEnable);
705
706 mfVideoAccelVRDP = fEnable;
707
708 if (fEnable)
709 {
710 mfu32SupportedOrders = fu32SupportedOrders;
711 }
712 else
713 {
714 mfu32SupportedOrders = 0;
715 }
716
717 vbvaSetMemoryFlags (mpVbvaMemory, mfVideoAccelEnabled, mfVideoAccelVRDP, mfu32SupportedOrders);
718
719 LogRel(("VBVA: VRDP acceleration has been %s.\n", fEnable? "requested": "disabled"));
720}
721#endif /* VRDP_MC */
722#endif /* VBOX_VRDP */
723
724static bool vbvaVerifyRingBuffer (VBVAMEMORY *pVbvaMemory)
725{
726 return true;
727}
728
729static void vbvaFetchBytes (VBVAMEMORY *pVbvaMemory, uint8_t *pu8Dst, uint32_t cbDst)
730{
731 if (cbDst >= VBVA_RING_BUFFER_SIZE)
732 {
733 AssertFailed ();
734 return;
735 }
736
737 uint32_t u32BytesTillBoundary = VBVA_RING_BUFFER_SIZE - pVbvaMemory->off32Data;
738 uint8_t *src = &pVbvaMemory->au8RingBuffer[pVbvaMemory->off32Data];
739 int32_t i32Diff = cbDst - u32BytesTillBoundary;
740
741 if (i32Diff <= 0)
742 {
743 /* Chunk will not cross buffer boundary. */
744 memcpy (pu8Dst, src, cbDst);
745 }
746 else
747 {
748 /* Chunk crosses buffer boundary. */
749 memcpy (pu8Dst, src, u32BytesTillBoundary);
750 memcpy (pu8Dst + u32BytesTillBoundary, &pVbvaMemory->au8RingBuffer[0], i32Diff);
751 }
752
753 /* Advance data offset. */
754 pVbvaMemory->off32Data = (pVbvaMemory->off32Data + cbDst) % VBVA_RING_BUFFER_SIZE;
755
756 return;
757}
758
759
760static bool vbvaPartialRead (uint8_t **ppu8, uint32_t *pcb, uint32_t cbRecord, VBVAMEMORY *pVbvaMemory)
761{
762 uint8_t *pu8New;
763
764 LogFlow(("MAIN::DisplayImpl::vbvaPartialRead: p = %p, cb = %d, cbRecord 0x%08X\n",
765 *ppu8, *pcb, cbRecord));
766
767 if (*ppu8)
768 {
769 Assert (*pcb);
770 pu8New = (uint8_t *)RTMemRealloc (*ppu8, cbRecord);
771 }
772 else
773 {
774 Assert (!*pcb);
775 pu8New = (uint8_t *)RTMemAlloc (cbRecord);
776 }
777
778 if (!pu8New)
779 {
780 /* Memory allocation failed, fail the function. */
781 Log(("MAIN::vbvaPartialRead: failed to (re)alocate memory for partial record!!! cbRecord 0x%08X\n",
782 cbRecord));
783
784 if (*ppu8)
785 {
786 RTMemFree (*ppu8);
787 }
788
789 *ppu8 = NULL;
790 *pcb = 0;
791
792 return false;
793 }
794
795 /* Fetch data from the ring buffer. */
796 vbvaFetchBytes (pVbvaMemory, pu8New + *pcb, cbRecord - *pcb);
797
798 *ppu8 = pu8New;
799 *pcb = cbRecord;
800
801 return true;
802}
803
804/* For contiguous chunks just return the address in the buffer.
805 * For crossing boundary - allocate a buffer from heap.
806 */
807bool Display::vbvaFetchCmd (VBVACMDHDR **ppHdr, uint32_t *pcbCmd)
808{
809 uint32_t indexRecordFirst = mpVbvaMemory->indexRecordFirst;
810 uint32_t indexRecordFree = mpVbvaMemory->indexRecordFree;
811
812#ifdef DEBUG_sunlover
813 LogFlowFunc (("first = %d, free = %d\n",
814 indexRecordFirst, indexRecordFree));
815#endif /* DEBUG_sunlover */
816
817 if (!vbvaVerifyRingBuffer (mpVbvaMemory))
818 {
819 return false;
820 }
821
822 if (indexRecordFirst == indexRecordFree)
823 {
824 /* No records to process. Return without assigning output variables. */
825 return true;
826 }
827
828 VBVARECORD *pRecord = &mpVbvaMemory->aRecords[indexRecordFirst];
829
830#ifdef DEBUG_sunlover
831 LogFlowFunc (("cbRecord = 0x%08X\n", pRecord->cbRecord));
832#endif /* DEBUG_sunlover */
833
834 uint32_t cbRecord = pRecord->cbRecord & ~VBVA_F_RECORD_PARTIAL;
835
836 if (mcbVbvaPartial)
837 {
838 /* There is a partial read in process. Continue with it. */
839
840 Assert (mpu8VbvaPartial);
841
842 LogFlowFunc (("continue partial record mcbVbvaPartial = %d cbRecord 0x%08X, first = %d, free = %d\n",
843 mcbVbvaPartial, pRecord->cbRecord, indexRecordFirst, indexRecordFree));
844
845 if (cbRecord > mcbVbvaPartial)
846 {
847 /* New data has been added to the record. */
848 if (!vbvaPartialRead (&mpu8VbvaPartial, &mcbVbvaPartial, cbRecord, mpVbvaMemory))
849 {
850 return false;
851 }
852 }
853
854 if (!(pRecord->cbRecord & VBVA_F_RECORD_PARTIAL))
855 {
856 /* The record is completed by guest. Return it to the caller. */
857 *ppHdr = (VBVACMDHDR *)mpu8VbvaPartial;
858 *pcbCmd = mcbVbvaPartial;
859
860 mpu8VbvaPartial = NULL;
861 mcbVbvaPartial = 0;
862
863 /* Advance the record index. */
864 mpVbvaMemory->indexRecordFirst = (indexRecordFirst + 1) % VBVA_MAX_RECORDS;
865
866#ifdef DEBUG_sunlover
867 LogFlowFunc (("partial done ok, data = %d, free = %d\n",
868 mpVbvaMemory->off32Data, mpVbvaMemory->off32Free));
869#endif /* DEBUG_sunlover */
870 }
871
872 return true;
873 }
874
875 /* A new record need to be processed. */
876 if (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL)
877 {
878 /* Current record is being written by guest. '=' is important here. */
879 if (cbRecord >= VBVA_RING_BUFFER_SIZE - VBVA_RING_BUFFER_THRESHOLD)
880 {
881 /* Partial read must be started. */
882 if (!vbvaPartialRead (&mpu8VbvaPartial, &mcbVbvaPartial, cbRecord, mpVbvaMemory))
883 {
884 return false;
885 }
886
887 LogFlowFunc (("started partial record mcbVbvaPartial = 0x%08X cbRecord 0x%08X, first = %d, free = %d\n",
888 mcbVbvaPartial, pRecord->cbRecord, indexRecordFirst, indexRecordFree));
889 }
890
891 return true;
892 }
893
894 /* Current record is complete. If it is not empty, process it. */
895 if (cbRecord)
896 {
897 /* The size of largest contiguos chunk in the ring biffer. */
898 uint32_t u32BytesTillBoundary = VBVA_RING_BUFFER_SIZE - mpVbvaMemory->off32Data;
899
900 /* The ring buffer pointer. */
901 uint8_t *au8RingBuffer = &mpVbvaMemory->au8RingBuffer[0];
902
903 /* The pointer to data in the ring buffer. */
904 uint8_t *src = &au8RingBuffer[mpVbvaMemory->off32Data];
905
906 /* Fetch or point the data. */
907 if (u32BytesTillBoundary >= cbRecord)
908 {
909 /* The command does not cross buffer boundary. Return address in the buffer. */
910 *ppHdr = (VBVACMDHDR *)src;
911
912 /* Advance data offset. */
913 mpVbvaMemory->off32Data = (mpVbvaMemory->off32Data + cbRecord) % VBVA_RING_BUFFER_SIZE;
914 }
915 else
916 {
917 /* The command crosses buffer boundary. Rare case, so not optimized. */
918 uint8_t *dst = (uint8_t *)RTMemAlloc (cbRecord);
919
920 if (!dst)
921 {
922 LogFlowFunc (("could not allocate %d bytes from heap!!!\n", cbRecord));
923 mpVbvaMemory->off32Data = (mpVbvaMemory->off32Data + cbRecord) % VBVA_RING_BUFFER_SIZE;
924 return false;
925 }
926
927 vbvaFetchBytes (mpVbvaMemory, dst, cbRecord);
928
929 *ppHdr = (VBVACMDHDR *)dst;
930
931#ifdef DEBUG_sunlover
932 LogFlowFunc (("Allocated from heap %p\n", dst));
933#endif /* DEBUG_sunlover */
934 }
935 }
936
937 *pcbCmd = cbRecord;
938
939 /* Advance the record index. */
940 mpVbvaMemory->indexRecordFirst = (indexRecordFirst + 1) % VBVA_MAX_RECORDS;
941
942#ifdef DEBUG_sunlover
943 LogFlowFunc (("done ok, data = %d, free = %d\n",
944 mpVbvaMemory->off32Data, mpVbvaMemory->off32Free));
945#endif /* DEBUG_sunlover */
946
947 return true;
948}
949
950void Display::vbvaReleaseCmd (VBVACMDHDR *pHdr, int32_t cbCmd)
951{
952 uint8_t *au8RingBuffer = mpVbvaMemory->au8RingBuffer;
953
954 if ( (uint8_t *)pHdr >= au8RingBuffer
955 && (uint8_t *)pHdr < &au8RingBuffer[VBVA_RING_BUFFER_SIZE])
956 {
957 /* The pointer is inside ring buffer. Must be continuous chunk. */
958 Assert (VBVA_RING_BUFFER_SIZE - ((uint8_t *)pHdr - au8RingBuffer) >= cbCmd);
959
960 /* Do nothing. */
961
962 Assert (!mpu8VbvaPartial && mcbVbvaPartial == 0);
963 }
964 else
965 {
966 /* The pointer is outside. It is then an allocated copy. */
967
968#ifdef DEBUG_sunlover
969 LogFlowFunc (("Free heap %p\n", pHdr));
970#endif /* DEBUG_sunlover */
971
972 if ((uint8_t *)pHdr == mpu8VbvaPartial)
973 {
974 mpu8VbvaPartial = NULL;
975 mcbVbvaPartial = 0;
976 }
977 else
978 {
979 Assert (!mpu8VbvaPartial && mcbVbvaPartial == 0);
980 }
981
982 RTMemFree (pHdr);
983 }
984
985 return;
986}
987
988
989/**
990 * Called regularly on the DisplayRefresh timer.
991 * Also on behalf of guest, when the ring buffer is full.
992 *
993 * @thread EMT
994 */
995void Display::VideoAccelFlush (void)
996{
997#ifdef DEBUG_sunlover
998 LogFlowFunc (("mfVideoAccelEnabled = %d\n", mfVideoAccelEnabled));
999#endif /* DEBUG_sunlover */
1000
1001 if (!mfVideoAccelEnabled)
1002 {
1003 Log(("Display::VideoAccelFlush: called with disabled VBVA!!! Ignoring.\n"));
1004 return;
1005 }
1006
1007 /* Here VBVA is enabled and we have the accelerator memory pointer. */
1008 Assert(mpVbvaMemory);
1009
1010#ifdef DEBUG_sunlover
1011 LogFlowFunc (("indexRecordFirst = %d, indexRecordFree = %d, off32Data = %d, off32Free = %d\n",
1012 mpVbvaMemory->indexRecordFirst, mpVbvaMemory->indexRecordFree, mpVbvaMemory->off32Data, mpVbvaMemory->off32Free));
1013#endif /* DEBUG_sunlover */
1014
1015 /* Quick check for "nothing to update" case. */
1016 if (mpVbvaMemory->indexRecordFirst == mpVbvaMemory->indexRecordFree)
1017 {
1018 return;
1019 }
1020
1021 /* Process the ring buffer */
1022
1023 bool fFramebufferIsNull = mFramebuffer.isNull();
1024
1025 if (!fFramebufferIsNull)
1026 {
1027 mFramebuffer->Lock();
1028 }
1029
1030 /* Initialize dirty rectangles accumulator. */
1031 VBVADIRTYREGION rgn;
1032 vbvaRgnInit (&rgn, mFramebuffer, this, mpDrv->pUpPort);
1033
1034 for (;;)
1035 {
1036 VBVACMDHDR *phdr = NULL;
1037 uint32_t cbCmd = ~0;
1038
1039 /* Fetch the command data. */
1040 if (!vbvaFetchCmd (&phdr, &cbCmd))
1041 {
1042 Log(("Display::VideoAccelFlush: unable to fetch command. off32Data = %d, off32Free = %d. Disabling VBVA!!!\n",
1043 mpVbvaMemory->off32Data, mpVbvaMemory->off32Free));
1044
1045 /* Disable VBVA on those processing errors. */
1046 VideoAccelEnable (false, NULL);
1047
1048 break;
1049 }
1050
1051 if (cbCmd == uint32_t(~0))
1052 {
1053 /* No more commands yet in the queue. */
1054 break;
1055 }
1056
1057 if (cbCmd != 0 && !fFramebufferIsNull)
1058 {
1059#ifdef DEBUG_sunlover
1060 LogFlowFunc (("hdr: cbCmd = %d, x=%d, y=%d, w=%d, h=%d\n",
1061 cbCmd, phdr->x, phdr->y, phdr->w, phdr->h));
1062#endif /* DEBUG_sunlover */
1063
1064 /* Handle the command.
1065 *
1066 * Guest is responsible for updating the guest video memory.
1067 * The Windows guest does all drawing using Eng*.
1068 *
1069 * For local output, only dirty rectangle information is used
1070 * to update changed areas.
1071 *
1072 * Dirty rectangles are accumulated to exclude overlapping updates and
1073 * group small updates to a larger one.
1074 */
1075
1076 /* Accumulate the update. */
1077 vbvaRgnDirtyRect (&rgn, phdr);
1078
1079 /* Forward the command to VRDP server. */
1080 mParent->consoleVRDPServer()->SendUpdate (phdr, cbCmd);
1081 }
1082
1083 vbvaReleaseCmd (phdr, cbCmd);
1084 }
1085
1086 if (!fFramebufferIsNull)
1087 {
1088 mFramebuffer->Unlock ();
1089 }
1090
1091 /* Draw the framebuffer. */
1092 vbvaRgnUpdateFramebuffer (&rgn);
1093}
1094
1095
1096// IDisplay properties
1097/////////////////////////////////////////////////////////////////////////////
1098
1099/**
1100 * Returns the current display width in pixel
1101 *
1102 * @returns COM status code
1103 * @param width Address of result variable.
1104 */
1105STDMETHODIMP Display::COMGETTER(Width) (ULONG *width)
1106{
1107 if (!width)
1108 return E_POINTER;
1109
1110 AutoLock alock (this);
1111 CHECK_READY();
1112
1113 CHECK_CONSOLE_DRV (mpDrv);
1114
1115 *width = mpDrv->Connector.cx;
1116 return S_OK;
1117}
1118
1119/**
1120 * Returns the current display height in pixel
1121 *
1122 * @returns COM status code
1123 * @param height Address of result variable.
1124 */
1125STDMETHODIMP Display::COMGETTER(Height) (ULONG *height)
1126{
1127 if (!height)
1128 return E_POINTER;
1129
1130 AutoLock alock (this);
1131 CHECK_READY();
1132
1133 CHECK_CONSOLE_DRV (mpDrv);
1134
1135 *height = mpDrv->Connector.cy;
1136 return S_OK;
1137}
1138
1139/**
1140 * Returns the current display color depth in bits
1141 *
1142 * @returns COM status code
1143 * @param colorDepth Address of result variable.
1144 */
1145STDMETHODIMP Display::COMGETTER(ColorDepth) (ULONG *colorDepth)
1146{
1147 if (!colorDepth)
1148 return E_INVALIDARG;
1149
1150 AutoLock alock (this);
1151 CHECK_READY();
1152
1153 CHECK_CONSOLE_DRV (mpDrv);
1154
1155 uint32_t cBits = 0;
1156 int rc = mpDrv->pUpPort->pfnQueryColorDepth(mpDrv->pUpPort, &cBits);
1157 AssertRC(rc);
1158 *colorDepth = cBits;
1159 return S_OK;
1160}
1161
1162
1163// IDisplay methods
1164/////////////////////////////////////////////////////////////////////////////
1165
1166STDMETHODIMP Display::SetupInternalFramebuffer (ULONG depth)
1167{
1168 LogFlowFunc (("\n"));
1169
1170 AutoLock lock (this);
1171 CHECK_READY();
1172
1173 /*
1174 * Create an internal framebuffer only if depth is not zero. Otherwise, we
1175 * reset back to the "black hole" state as it was at Display construction.
1176 */
1177 ComPtr <IFramebuffer> frameBuf;
1178 if (depth)
1179 {
1180 ComObjPtr <InternalFramebuffer> internal;
1181 internal.createObject();
1182 internal->init (640, 480, depth);
1183 frameBuf = internal; // query interface
1184 }
1185
1186 Console::SafeVMPtrQuiet pVM (mParent);
1187 if (pVM.isOk())
1188 {
1189 /* send request to the EMT thread */
1190 PVMREQ pReq = NULL;
1191 int vrc = VMR3ReqCall (pVM, &pReq, RT_INDEFINITE_WAIT,
1192 (PFNRT) changeFramebuffer, 3,
1193 this, static_cast <IFramebuffer *> (frameBuf),
1194 true /* aInternal */);
1195 if (VBOX_SUCCESS (vrc))
1196 vrc = pReq->iStatus;
1197 VMR3ReqFree (pReq);
1198
1199 ComAssertRCRet (vrc, E_FAIL);
1200 }
1201 else
1202 {
1203 /* No VM is created (VM is powered off), do a direct call */
1204 int vrc = changeFramebuffer (this, frameBuf, true /* aInternal */);
1205 ComAssertRCRet (vrc, E_FAIL);
1206 }
1207
1208 return S_OK;
1209}
1210
1211STDMETHODIMP Display::LockFramebuffer (ULONG *address)
1212{
1213 if (!address)
1214 return E_POINTER;
1215
1216 AutoLock lock(this);
1217 CHECK_READY();
1218
1219 /* only allowed for internal framebuffers */
1220 if (mInternalFramebuffer && !mFramebufferOpened && !mFramebuffer.isNull())
1221 {
1222 CHECK_CONSOLE_DRV (mpDrv);
1223
1224 mFramebuffer->Lock();
1225 mFramebufferOpened = true;
1226 *address = (ULONG)mpDrv->Connector.pu8Data;
1227 return S_OK;
1228 }
1229
1230 return setError (E_FAIL,
1231 tr ("Framebuffer locking is allowed only for the internal framebuffer"));
1232}
1233
1234STDMETHODIMP Display::UnlockFramebuffer()
1235{
1236 AutoLock lock(this);
1237 CHECK_READY();
1238
1239 if (mFramebufferOpened)
1240 {
1241 CHECK_CONSOLE_DRV (mpDrv);
1242
1243 mFramebuffer->Unlock();
1244 mFramebufferOpened = false;
1245 return S_OK;
1246 }
1247
1248 return setError (E_FAIL,
1249 tr ("Framebuffer locking is allowed only for the internal framebuffer"));
1250}
1251
1252STDMETHODIMP Display::RegisterExternalFramebuffer (IFramebuffer *frameBuf)
1253{
1254 LogFlowFunc (("\n"));
1255
1256 if (!frameBuf)
1257 return E_POINTER;
1258
1259 AutoLock lock (this);
1260 CHECK_READY();
1261
1262 Console::SafeVMPtrQuiet pVM (mParent);
1263 if (pVM.isOk())
1264 {
1265 /* send request to the EMT thread */
1266 PVMREQ pReq = NULL;
1267 int vrc = VMR3ReqCall (pVM, &pReq, RT_INDEFINITE_WAIT,
1268 (PFNRT) changeFramebuffer, 3,
1269 this, frameBuf, false /* aInternal */);
1270 if (VBOX_SUCCESS (vrc))
1271 vrc = pReq->iStatus;
1272 VMR3ReqFree (pReq);
1273
1274 ComAssertRCRet (vrc, E_FAIL);
1275 }
1276 else
1277 {
1278 /* No VM is created (VM is powered off), do a direct call */
1279 int vrc = changeFramebuffer (this, frameBuf, false /* aInternal */);
1280 ComAssertRCRet (vrc, E_FAIL);
1281 }
1282
1283 return S_OK;
1284}
1285
1286STDMETHODIMP Display::SetVideoModeHint(ULONG aWidth, ULONG aHeight, ULONG aColorDepth)
1287{
1288 AutoLock lock(this);
1289 CHECK_READY();
1290
1291 CHECK_CONSOLE_DRV (mpDrv);
1292
1293 /*
1294 * Do some rough checks for valid input
1295 */
1296 ULONG width = aWidth;
1297 if (!width)
1298 width = mpDrv->Connector.cx;
1299 ULONG height = aHeight;
1300 if (!height)
1301 height = mpDrv->Connector.cy;
1302 ULONG bpp = aColorDepth;
1303 if (!bpp)
1304 {
1305 uint32_t cBits = 0;
1306 int rc = mpDrv->pUpPort->pfnQueryColorDepth(mpDrv->pUpPort, &cBits);
1307 AssertRC(rc);
1308 bpp = cBits;
1309 }
1310 ULONG vramSize;
1311 mParent->machine()->COMGETTER(VRAMSize)(&vramSize);
1312 /* enough VRAM? */
1313 if ((width * height * (bpp / 8)) > (vramSize * 1024 * 1024))
1314 return setError(E_FAIL, tr("Not enough VRAM for the selected video mode"));
1315
1316 LogRel(("Display::SetVideoModeHint: got a video mode hint (%dx%dx%d)\n",
1317 aWidth, aHeight, bpp));
1318 if (mParent->getVMMDev())
1319 mParent->getVMMDev()->getVMMDevPort()->pfnRequestDisplayChange(mParent->getVMMDev()->getVMMDevPort(), aWidth, aHeight, aColorDepth);
1320 return S_OK;
1321}
1322
1323/**
1324 * Takes a screen shot of the requested size and copies it to the buffer
1325 * allocated by the caller. The screen shot is always a 32-bpp image, so the
1326 * size of the buffer must be at least (((width * 32 + 31) / 32) * 4) * height
1327 * (i.e. dword-aligned). If the requested screen shot dimentions differ from
1328 * the actual VM display size then the screen shot image is stretched and/or
1329 * shrunk accordingly.
1330 *
1331 * @returns COM status code
1332 * @param address the address of the buffer allocated by the caller
1333 * @param width the width of the screenshot to take
1334 * @param height the height of the screenshot to take
1335 */
1336STDMETHODIMP Display::TakeScreenShot (ULONG address, ULONG width, ULONG height)
1337{
1338 /// @todo (r=dmik) this function may take too long to complete if the VM
1339 // is doing something like saving state right now. Which, in case if it
1340 // is called on the GUI thread, will make it unresponsive. We should
1341 // check the machine state here (by enclosing the check and VMRequCall
1342 // within the Console lock to make it atomic).
1343
1344 LogFlowFuncEnter();
1345 LogFlowFunc (("address=%p, width=%d, height=%d\n",
1346 address, width, height));
1347
1348 if (!address)
1349 return E_POINTER;
1350 if (!width || !height)
1351 return E_INVALIDARG;
1352
1353 AutoLock lock(this);
1354 CHECK_READY();
1355
1356 CHECK_CONSOLE_DRV (mpDrv);
1357
1358 Console::SafeVMPtr pVM (mParent);
1359 CheckComRCReturnRC (pVM.rc());
1360
1361 HRESULT rc = S_OK;
1362
1363 LogFlowFunc (("Sending SCREENSHOT request\n"));
1364
1365 /*
1366 * First try use the graphics device features for making a snapshot.
1367 * This does not support streatching, is an optional feature (returns not supported).
1368 *
1369 * Note: It may cause a display resize. Watch out for deadlocks.
1370 */
1371 int rcVBox = VERR_NOT_SUPPORTED;
1372 if ( mpDrv->Connector.cx == width
1373 && mpDrv->Connector.cy == height)
1374 {
1375 PVMREQ pReq;
1376 size_t cbData = RT_ALIGN_Z(width, 4) * 4 * height;
1377 rcVBox = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT,
1378 (PFNRT)mpDrv->pUpPort->pfnSnapshot, 6, mpDrv->pUpPort,
1379 (void *)address, cbData, NULL, NULL, NULL);
1380 if (VBOX_SUCCESS(rcVBox))
1381 {
1382 rcVBox = pReq->iStatus;
1383 VMR3ReqFree(pReq);
1384 }
1385 }
1386
1387 /*
1388 * If the function returns not supported, or if streaching is requested,
1389 * we'll have to do all the work ourselves using the framebuffer data.
1390 */
1391 if (rcVBox == VERR_NOT_SUPPORTED || rcVBox == VERR_NOT_IMPLEMENTED)
1392 {
1393 /** @todo implement snapshot streching and generic snapshot fallback. */
1394 rc = setError (E_NOTIMPL, tr ("This feature is not implemented"));
1395 }
1396 else if (VBOX_FAILURE(rcVBox))
1397 rc = setError (E_FAIL,
1398 tr ("Could not take a screenshot (%Vrc)"), rcVBox);
1399
1400 LogFlowFunc (("rc=%08X\n", rc));
1401 LogFlowFuncLeave();
1402 return rc;
1403}
1404
1405/**
1406 * Draws an image of the specified size from the given buffer to the given
1407 * point on the VM display. The image is assumed to have a 32-bit depth, so the
1408 * size of one scanline must be ((width * 32 + 31) / 32) * 4), i.e.
1409 * dword-aligned. The total image size in the buffer is height * scanline size.
1410 *
1411 * @returns COM status code
1412 * @param address the address of the buffer containing the image
1413 * @param x the x coordinate on the VM display to place the image to
1414 * @param y the y coordinate on the VM display to place the image to
1415 * @param width the width of the image in the buffer
1416 * @param height the height of the image in the buffer
1417 */
1418STDMETHODIMP Display::DrawToScreen (ULONG address, ULONG x, ULONG y,
1419 ULONG width, ULONG height)
1420{
1421 /// @todo (r=dmik) this function may take too long to complete if the VM
1422 // is doing something like saving state right now. Which, in case if it
1423 // is called on the GUI thread, will make it unresponsive. We should
1424 // check the machine state here (by enclosing the check and VMRequCall
1425 // within the Console lock to make it atomic).
1426
1427 LogFlowFuncEnter();
1428 LogFlowFunc (("address=%p, x=%d, y=%d, width=%d, height=%d\n",
1429 address, x, y, width, height));
1430
1431 AutoLock lock(this);
1432 CHECK_READY();
1433
1434 CHECK_CONSOLE_DRV (mpDrv);
1435
1436 Console::SafeVMPtr pVM (mParent);
1437 CheckComRCReturnRC (pVM.rc());
1438
1439 /*
1440 * Again we're lazy and make the graphics device do all the
1441 * dirty convertion work.
1442 */
1443 PVMREQ pReq;
1444 int rcVBox = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT,
1445 (PFNRT)mpDrv->pUpPort->pfnDisplayBlt, 6, mpDrv->pUpPort,
1446 (void *)address, x, y, width, height);
1447 if (VBOX_SUCCESS(rcVBox))
1448 {
1449 rcVBox = pReq->iStatus;
1450 VMR3ReqFree(pReq);
1451 }
1452
1453 /*
1454 * If the function returns not supported, we'll have to do all the
1455 * work ourselves using the framebuffer.
1456 */
1457 HRESULT rc = S_OK;
1458 if (rcVBox == VERR_NOT_SUPPORTED || rcVBox == VERR_NOT_IMPLEMENTED)
1459 {
1460 /** @todo implement generic fallback for screen blitting. */
1461 rc = E_NOTIMPL;
1462 }
1463 else if (VBOX_FAILURE(rcVBox))
1464 rc = setError (E_FAIL,
1465 tr ("Could not draw to the screen (%Vrc)"), rcVBox);
1466//@todo
1467// else
1468// {
1469// /* All ok. Redraw the screen. */
1470// handleDisplayUpdate (x, y, width, height);
1471// }
1472
1473 LogFlowFunc (("rc=%08X\n", rc));
1474 LogFlowFuncLeave();
1475 return rc;
1476}
1477
1478/**
1479 * Does a full invalidation of the VM display and instructs the VM
1480 * to update it immediately.
1481 *
1482 * @returns COM status code
1483 */
1484STDMETHODIMP Display::InvalidateAndUpdate()
1485{
1486 LogFlowFuncEnter();
1487
1488 AutoLock lock(this);
1489 CHECK_READY();
1490
1491 CHECK_CONSOLE_DRV (mpDrv);
1492
1493 Console::SafeVMPtr pVM (mParent);
1494 CheckComRCReturnRC (pVM.rc());
1495
1496 HRESULT rc = S_OK;
1497
1498 LogFlowFunc (("Sending DPYUPDATE request\n"));
1499
1500 /* pdm.h says that this has to be called from the EMT thread */
1501 PVMREQ pReq;
1502 int rcVBox = VMR3ReqCallVoid(pVM, &pReq, RT_INDEFINITE_WAIT,
1503 (PFNRT)mpDrv->pUpPort->pfnUpdateDisplayAll, 1, mpDrv->pUpPort);
1504 if (VBOX_SUCCESS(rcVBox))
1505 VMR3ReqFree(pReq);
1506
1507 if (VBOX_FAILURE(rcVBox))
1508 rc = setError (E_FAIL,
1509 tr ("Could not invalidate and update the screen (%Vrc)"), rcVBox);
1510
1511 LogFlowFunc (("rc=%08X\n", rc));
1512 LogFlowFuncLeave();
1513 return rc;
1514}
1515
1516/**
1517 * Notification that the framebuffer has completed the
1518 * asynchronous resize processing
1519 *
1520 * @returns COM status code
1521 */
1522STDMETHODIMP Display::ResizeCompleted()
1523{
1524 LogFlowFunc (("\n"));
1525
1526 /// @todo (dmik) can we AutoLock alock (this); here?
1527 // do it when we switch this class to VirtualBoxBase_NEXT.
1528 // This will require general code review and may add some details.
1529 // In particular, we may want to check whether EMT is really waiting for
1530 // this notification, etc. It might be also good to obey the caller to make
1531 // sure this method is not called from more than one thread at a time
1532 // (and therefore don't use Display lock at all here to save some
1533 // milliseconds).
1534 CHECK_READY();
1535
1536 /* this is only valid for external framebuffers */
1537 if (mInternalFramebuffer)
1538 return setError (E_FAIL,
1539 tr ("Resize completed notification is valid only "
1540 "for external framebuffers"));
1541
1542 mFramebuffer->Lock();
1543 /* signal our semaphore */
1544 RTSemEventMultiSignal(mResizeSem);
1545 mFramebuffer->Unlock();
1546
1547 return S_OK;
1548}
1549
1550/**
1551 * Notification that the framebuffer has completed the
1552 * asynchronous update processing
1553 *
1554 * @returns COM status code
1555 */
1556STDMETHODIMP Display::UpdateCompleted()
1557{
1558 LogFlowFunc (("\n"));
1559
1560 /// @todo (dmik) can we AutoLock alock (this); here?
1561 // do it when we switch this class to VirtualBoxBase_NEXT.
1562 // Tthis will require general code review and may add some details.
1563 // In particular, we may want to check whether EMT is really waiting for
1564 // this notification, etc. It might be also good to obey the caller to make
1565 // sure this method is not called from more than one thread at a time
1566 // (and therefore don't use Display lock at all here to save some
1567 // milliseconds).
1568 CHECK_READY();
1569
1570 /* this is only valid for external framebuffers */
1571 if (mInternalFramebuffer)
1572 return setError (E_FAIL,
1573 tr ("Resize completed notification is valid only "
1574 "for external framebuffers"));
1575
1576 mFramebuffer->Lock();
1577 /* signal our semaphore */
1578 RTSemEventMultiSignal(mUpdateSem);
1579 mFramebuffer->Unlock();
1580
1581 return S_OK;
1582}
1583
1584// private methods
1585/////////////////////////////////////////////////////////////////////////////
1586
1587/**
1588 * Helper to update the display information from the framebuffer.
1589 *
1590 * @param aCheckParams true to compare the parameters of the current framebuffer
1591 * and the new one and issue handleDisplayResize()
1592 * if they differ.
1593 * @thread EMT
1594 */
1595void Display::updateDisplayData (bool aCheckParams /* = false */)
1596{
1597 /* the driver might not have been constructed yet */
1598 if (!mpDrv)
1599 return;
1600
1601#if DEBUG
1602 /*
1603 * Sanity check. Note that this method may be called on EMT after Console
1604 * has started the power down procedure (but before our #drvDestruct() is
1605 * called, in which case pVM will aleady be NULL but mpDrv will not). Since
1606 * we don't really need pVM to proceed, we avoid this check in the release
1607 * build to save some ms (necessary to construct SafeVMPtrQuiet) in this
1608 * time-critical method.
1609 */
1610 Console::SafeVMPtrQuiet pVM (mParent);
1611 if (pVM.isOk())
1612 VM_ASSERT_EMT (pVM.raw());
1613#endif
1614
1615 if (mFramebuffer)
1616 {
1617 HRESULT rc;
1618 ULONG address = 0;
1619 rc = mFramebuffer->COMGETTER(Address) (&address);
1620 AssertComRC (rc);
1621 ULONG lineSize = 0;
1622 rc = mFramebuffer->COMGETTER(LineSize) (&lineSize);
1623 AssertComRC (rc);
1624 ULONG colorDepth = 0;
1625 rc = mFramebuffer->COMGETTER(ColorDepth) (&colorDepth);
1626 AssertComRC (rc);
1627 ULONG width = 0;
1628 rc = mFramebuffer->COMGETTER(Width) (&width);
1629 AssertComRC (rc);
1630 ULONG height = 0;
1631 rc = mFramebuffer->COMGETTER(Height) (&height);
1632 AssertComRC (rc);
1633
1634 /*
1635 * Check current parameters with new ones and issue handleDisplayResize()
1636 * to let the new frame buffer adjust itself properly. Note that it will
1637 * result into a recursive updateDisplayData() call but with
1638 * aCheckOld = false.
1639 */
1640 if (aCheckParams &&
1641 (mLastAddress != (uint8_t *) address ||
1642 mLastLineSize != lineSize ||
1643 mLastColorDepth != colorDepth ||
1644 mLastWidth != (int) width ||
1645 mLastHeight != (int) height))
1646 {
1647 handleDisplayResize (mLastColorDepth,
1648 mLastAddress,
1649 mLastLineSize,
1650 mLastWidth,
1651 mLastHeight);
1652 return;
1653 }
1654
1655 mpDrv->Connector.pu8Data = (uint8_t *) address;
1656 mpDrv->Connector.cbScanline = lineSize;
1657 mpDrv->Connector.cBits = colorDepth;
1658 mpDrv->Connector.cx = width;
1659 mpDrv->Connector.cy = height;
1660 }
1661 else
1662 {
1663 /* black hole */
1664 mpDrv->Connector.pu8Data = NULL;
1665 mpDrv->Connector.cbScanline = 0;
1666 mpDrv->Connector.cBits = 0;
1667 mpDrv->Connector.cx = 0;
1668 mpDrv->Connector.cy = 0;
1669 }
1670}
1671
1672/**
1673 * Changes the current frame buffer. Called on EMT to avoid both
1674 * race conditions and excessive locking.
1675 *
1676 * @note locks this object for writing
1677 * @thread EMT
1678 */
1679/* static */
1680DECLCALLBACK(int) Display::changeFramebuffer (Display *that, IFramebuffer *aFB,
1681 bool aInternal)
1682{
1683 LogFlowFunc (("\n"));
1684
1685 AssertReturn (that, VERR_INVALID_PARAMETER);
1686 AssertReturn (aFB || aInternal, VERR_INVALID_PARAMETER);
1687
1688 /// @todo (r=dmik) AutoCaller
1689
1690 AutoLock alock (that);
1691
1692 that->mFramebuffer = aFB;
1693 that->mInternalFramebuffer = aInternal;
1694 that->mSupportedAccelOps = 0;
1695
1696 /* determine which acceleration functions are supported by this framebuffer */
1697 if (aFB && !aInternal)
1698 {
1699 HRESULT rc;
1700 BOOL accelSupported = FALSE;
1701 rc = aFB->OperationSupported (
1702 FramebufferAccelerationOperation_SolidFillAcceleration, &accelSupported);
1703 AssertComRC (rc);
1704 if (accelSupported)
1705 that->mSupportedAccelOps |=
1706 FramebufferAccelerationOperation_SolidFillAcceleration;
1707 accelSupported = FALSE;
1708 rc = aFB->OperationSupported (
1709 FramebufferAccelerationOperation_ScreenCopyAcceleration, &accelSupported);
1710 AssertComRC (rc);
1711 if (accelSupported)
1712 that->mSupportedAccelOps |=
1713 FramebufferAccelerationOperation_ScreenCopyAcceleration;
1714 }
1715
1716 that->mParent->consoleVRDPServer()->
1717 SetFramebuffer (aFB, aFB ? VRDP_EXTERNAL_FRAMEBUFFER :
1718 VRDP_INTERNAL_FRAMEBUFFER);
1719
1720 that->updateDisplayData (true /* aCheckParams */);
1721
1722 return VINF_SUCCESS;
1723}
1724
1725/**
1726 * Handle display resize event.
1727 *
1728 * @see PDMIDISPLAYCONNECTOR::pfnResize
1729 */
1730DECLCALLBACK(void) Display::displayResizeCallback(PPDMIDISPLAYCONNECTOR pInterface,
1731 uint32_t bpp, void *pvVRAM, uint32_t cbLine, uint32_t cx, uint32_t cy)
1732{
1733 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
1734
1735 LogFlowFunc (("bpp %d, pvVRAM %p, cbLine %d, cx %d, cy %d\n",
1736 bpp, pvVRAM, cbLine, cx, cy));
1737
1738 pDrv->pDisplay->handleDisplayResize(bpp, pvVRAM, cbLine, cx, cy);
1739}
1740
1741/**
1742 * Handle display update.
1743 *
1744 * @see PDMIDISPLAYCONNECTOR::pfnUpdateRect
1745 */
1746DECLCALLBACK(void) Display::displayUpdateCallback(PPDMIDISPLAYCONNECTOR pInterface,
1747 uint32_t x, uint32_t y, uint32_t cx, uint32_t cy)
1748{
1749 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
1750
1751#ifdef DEBUG_sunlover
1752 LogFlowFunc (("pDrv->pDisplay->mfVideoAccelEnabled = %d, %d,%d %dx%d\n",
1753 pDrv->pDisplay->mfVideoAccelEnabled, x, y, cx, cy));
1754#endif /* DEBUG_sunlover */
1755
1756 /* This call does update regardless of VBVA status.
1757 * But in VBVA mode this is called only as result of
1758 * pfnUpdateDisplayAll in the VGA device.
1759 */
1760
1761 pDrv->pDisplay->handleDisplayUpdate(x, y, cx, cy);
1762}
1763
1764/**
1765 * Periodic display refresh callback.
1766 *
1767 * @see PDMIDISPLAYCONNECTOR::pfnRefresh
1768 */
1769DECLCALLBACK(void) Display::displayRefreshCallback(PPDMIDISPLAYCONNECTOR pInterface)
1770{
1771 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
1772
1773#ifdef DEBUG_sunlover
1774 STAM_PROFILE_START(&StatDisplayRefresh, a);
1775#endif /* DEBUG_sunlover */
1776
1777#ifdef DEBUG_sunlover
1778 LogFlowFunc (("pDrv->pDisplay->mfVideoAccelEnabled = %d\n",
1779 pDrv->pDisplay->mfVideoAccelEnabled));
1780#endif /* DEBUG_sunlover */
1781
1782 Display *pDisplay = pDrv->pDisplay;
1783
1784 if (pDisplay->mFramebuffer.isNull())
1785 {
1786 /*
1787 * Do nothing in the "black hole" mode to avoid copying guest
1788 * video memory to the frame buffer
1789 */
1790 }
1791 else
1792 {
1793 if (pDisplay->mfPendingVideoAccelEnable)
1794 {
1795 /* Acceleration was enabled while machine was not yet running
1796 * due to restoring from saved state. Update entire display and
1797 * actually enable acceleration.
1798 */
1799 Assert(pDisplay->mpPendingVbvaMemory);
1800
1801 /* Acceleration can not be yet enabled.*/
1802 Assert(pDisplay->mpVbvaMemory == NULL);
1803 Assert(!pDisplay->mfVideoAccelEnabled);
1804
1805 if (pDisplay->mfMachineRunning)
1806 {
1807 pDisplay->VideoAccelEnable (pDisplay->mfPendingVideoAccelEnable,
1808 pDisplay->mpPendingVbvaMemory);
1809
1810 /* Reset the pending state. */
1811 pDisplay->mfPendingVideoAccelEnable = false;
1812 pDisplay->mpPendingVbvaMemory = NULL;
1813 }
1814 }
1815 else
1816 {
1817 Assert(pDisplay->mpPendingVbvaMemory == NULL);
1818
1819 if (pDisplay->mfVideoAccelEnabled)
1820 {
1821 Assert(pDisplay->mpVbvaMemory);
1822 pDisplay->VideoAccelFlush ();
1823 }
1824 else
1825 {
1826 Assert(pDrv->Connector.pu8Data);
1827 pDrv->pUpPort->pfnUpdateDisplay(pDrv->pUpPort);
1828 }
1829 }
1830#ifdef VRDP_MC
1831 /* Inform to VRDP server that the current display update sequence is
1832 * completed. At this moment the framebuffer memory contains a definite
1833 * image, that is synchronized with the orders already sent to VRDP client.
1834 * The server can now process redraw requests from clients or initial
1835 * fullscreen updates for new clients.
1836 */
1837 Assert (pDisplay->mParent && pDisplay->mParent->consoleVRDPServer());
1838 pDisplay->mParent->consoleVRDPServer()->SendUpdate (NULL, 0);
1839#endif /* VRDP_MC */
1840 }
1841
1842#ifdef DEBUG_sunlover
1843 STAM_PROFILE_STOP(&StatDisplayRefresh, a);
1844#endif /* DEBUG_sunlover */
1845}
1846
1847/**
1848 * Reset notification
1849 *
1850 * @see PDMIDISPLAYCONNECTOR::pfnReset
1851 */
1852DECLCALLBACK(void) Display::displayResetCallback(PPDMIDISPLAYCONNECTOR pInterface)
1853{
1854 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
1855
1856 LogFlowFunc (("\n"));
1857
1858 /* Disable VBVA mode. */
1859 pDrv->pDisplay->VideoAccelEnable (false, NULL);
1860}
1861
1862/**
1863 * LFBModeChange notification
1864 *
1865 * @see PDMIDISPLAYCONNECTOR::pfnLFBModeChange
1866 */
1867DECLCALLBACK(void) Display::displayLFBModeChangeCallback(PPDMIDISPLAYCONNECTOR pInterface, bool fEnabled)
1868{
1869 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
1870
1871 LogFlowFunc (("fEnabled=%d\n", fEnabled));
1872
1873 NOREF(fEnabled);
1874
1875 /* Disable VBVA mode in any case. The guest driver reenables VBVA mode if necessary. */
1876 pDrv->pDisplay->VideoAccelEnable (false, NULL);
1877}
1878
1879/**
1880 * Queries an interface to the driver.
1881 *
1882 * @returns Pointer to interface.
1883 * @returns NULL if the interface was not supported by the driver.
1884 * @param pInterface Pointer to this interface structure.
1885 * @param enmInterface The requested interface identification.
1886 */
1887DECLCALLBACK(void *) Display::drvQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
1888{
1889 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
1890 PDRVMAINDISPLAY pDrv = PDMINS2DATA(pDrvIns, PDRVMAINDISPLAY);
1891 switch (enmInterface)
1892 {
1893 case PDMINTERFACE_BASE:
1894 return &pDrvIns->IBase;
1895 case PDMINTERFACE_DISPLAY_CONNECTOR:
1896 return &pDrv->Connector;
1897 default:
1898 return NULL;
1899 }
1900}
1901
1902
1903/**
1904 * Destruct a display driver instance.
1905 *
1906 * @returns VBox status.
1907 * @param pDrvIns The driver instance data.
1908 */
1909DECLCALLBACK(void) Display::drvDestruct(PPDMDRVINS pDrvIns)
1910{
1911 PDRVMAINDISPLAY pData = PDMINS2DATA(pDrvIns, PDRVMAINDISPLAY);
1912 LogFlowFunc (("iInstance=%d\n", pDrvIns->iInstance));
1913 if (pData->pDisplay)
1914 {
1915 AutoLock displayLock (pData->pDisplay);
1916 pData->pDisplay->mpDrv = NULL;
1917 pData->pDisplay->mpVMMDev = NULL;
1918 pData->pDisplay->mLastAddress = NULL;
1919 pData->pDisplay->mLastLineSize = 0;
1920 pData->pDisplay->mLastColorDepth = 0,
1921 pData->pDisplay->mLastWidth = 0;
1922 pData->pDisplay->mLastHeight = 0;
1923 }
1924}
1925
1926
1927/**
1928 * Construct a display driver instance.
1929 *
1930 * @returns VBox status.
1931 * @param pDrvIns The driver instance data.
1932 * If the registration structure is needed, pDrvIns->pDrvReg points to it.
1933 * @param pCfgHandle Configuration node handle for the driver. Use this to obtain the configuration
1934 * of the driver instance. It's also found in pDrvIns->pCfgHandle, but like
1935 * iInstance it's expected to be used a bit in this function.
1936 */
1937DECLCALLBACK(int) Display::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
1938{
1939 PDRVMAINDISPLAY pData = PDMINS2DATA(pDrvIns, PDRVMAINDISPLAY);
1940 LogFlowFunc (("iInstance=%d\n", pDrvIns->iInstance));
1941
1942 /*
1943 * Validate configuration.
1944 */
1945 if (!CFGMR3AreValuesValid(pCfgHandle, "Object\0"))
1946 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
1947 PPDMIBASE pBaseIgnore;
1948 int rc = pDrvIns->pDrvHlp->pfnAttach(pDrvIns, &pBaseIgnore);
1949 if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
1950 {
1951 AssertMsgFailed(("Configuration error: Not possible to attach anything to this driver!\n"));
1952 return VERR_PDM_DRVINS_NO_ATTACH;
1953 }
1954
1955 /*
1956 * Init Interfaces.
1957 */
1958 pDrvIns->IBase.pfnQueryInterface = Display::drvQueryInterface;
1959
1960 pData->Connector.pfnResize = Display::displayResizeCallback;
1961 pData->Connector.pfnUpdateRect = Display::displayUpdateCallback;
1962 pData->Connector.pfnRefresh = Display::displayRefreshCallback;
1963 pData->Connector.pfnReset = Display::displayResetCallback;
1964 pData->Connector.pfnLFBModeChange = Display::displayLFBModeChangeCallback;
1965
1966 /*
1967 * Get the IDisplayPort interface of the above driver/device.
1968 */
1969 pData->pUpPort = (PPDMIDISPLAYPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_DISPLAY_PORT);
1970 if (!pData->pUpPort)
1971 {
1972 AssertMsgFailed(("Configuration error: No display port interface above!\n"));
1973 return VERR_PDM_MISSING_INTERFACE_ABOVE;
1974 }
1975
1976 /*
1977 * Get the Display object pointer and update the mpDrv member.
1978 */
1979 void *pv;
1980 rc = CFGMR3QueryPtr(pCfgHandle, "Object", &pv);
1981 if (VBOX_FAILURE(rc))
1982 {
1983 AssertMsgFailed(("Configuration error: No/bad \"Object\" value! rc=%Vrc\n", rc));
1984 return rc;
1985 }
1986 pData->pDisplay = (Display *)pv; /** @todo Check this cast! */
1987 pData->pDisplay->mpDrv = pData;
1988
1989 /*
1990 * Update our display information according to the framebuffer
1991 */
1992 pData->pDisplay->updateDisplayData();
1993
1994 /*
1995 * Start periodic screen refreshes
1996 */
1997 pData->pUpPort->pfnSetRefreshRate(pData->pUpPort, 20);
1998
1999 return VINF_SUCCESS;
2000}
2001
2002
2003/**
2004 * Display driver registration record.
2005 */
2006const PDMDRVREG Display::DrvReg =
2007{
2008 /* u32Version */
2009 PDM_DRVREG_VERSION,
2010 /* szDriverName */
2011 "MainDisplay",
2012 /* pszDescription */
2013 "Main display driver (Main as in the API).",
2014 /* fFlags */
2015 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
2016 /* fClass. */
2017 PDM_DRVREG_CLASS_DISPLAY,
2018 /* cMaxInstances */
2019 ~0,
2020 /* cbInstance */
2021 sizeof(DRVMAINDISPLAY),
2022 /* pfnConstruct */
2023 Display::drvConstruct,
2024 /* pfnDestruct */
2025 Display::drvDestruct,
2026 /* pfnIOCtl */
2027 NULL,
2028 /* pfnPowerOn */
2029 NULL,
2030 /* pfnReset */
2031 NULL,
2032 /* pfnSuspend */
2033 NULL,
2034 /* pfnResume */
2035 NULL,
2036 /* pfnDetach */
2037 NULL
2038};
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette