VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/DisplayImplLegacy.cpp@ 67531

Last change on this file since 67531 was 67531, checked in by vboxsync, 7 years ago

Main/Display: eliminate the old resize code, the new code is well tested and doing the right thing

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 30.9 KB
Line 
1/* $Id: DisplayImplLegacy.cpp 67531 2017-06-21 09:17:51Z vboxsync $ */
2/** @file
3 * VirtualBox IDisplay implementation
4 *
5 * Methods and helpers to support old guest additions 3.x or older.
6 * This is not used by the current guest additions.
7 */
8
9/*
10 * Copyright (C) 2006-2016 Oracle Corporation
11 *
12 * This file is part of VirtualBox Open Source Edition (OSE), as
13 * available from http://www.virtualbox.org. This file is free software;
14 * you can redistribute it and/or modify it under the terms of the GNU
15 * General Public License (GPL) as published by the Free Software
16 * Foundation, in version 2 as it comes in the "COPYING" file of the
17 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
18 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
19 */
20
21#include "DisplayImpl.h"
22#include "ConsoleImpl.h"
23#include "ConsoleVRDPServer.h"
24#include "VMMDev.h"
25
26#include "Logging.h"
27
28/* generated header */
29#include "VBoxEvents.h"
30
31
32int videoAccelConstruct(VIDEOACCEL *pVideoAccel)
33{
34 pVideoAccel->pVbvaMemory = NULL;
35 pVideoAccel->fVideoAccelEnabled = false;
36
37 pVideoAccel->pu8VbvaPartial = NULL;
38 pVideoAccel->cbVbvaPartial = 0;
39
40 pVideoAccel->hXRoadsVideoAccel = NIL_RTSEMXROADS;
41 int rc = RTSemXRoadsCreate(&pVideoAccel->hXRoadsVideoAccel);
42 AssertRC(rc);
43
44 return rc;
45}
46
47void videoAccelDestroy(VIDEOACCEL *pVideoAccel)
48{
49 RTSemXRoadsDestroy(pVideoAccel->hXRoadsVideoAccel);
50 RT_ZERO(*pVideoAccel);
51}
52
53static unsigned mapCoordsToScreen(DISPLAYFBINFO *pInfos, unsigned cInfos, int *px, int *py, int *pw, int *ph)
54{
55 RT_NOREF(pw, ph);
56
57 DISPLAYFBINFO *pInfo = pInfos;
58 unsigned uScreenId;
59 Log9(("mapCoordsToScreen: %d,%d %dx%d\n", *px, *py, *pw, *ph));
60 for (uScreenId = 0; uScreenId < cInfos; uScreenId++, pInfo++)
61 {
62 Log9((" [%d] %d,%d %dx%d\n", uScreenId, pInfo->xOrigin, pInfo->yOrigin, pInfo->w, pInfo->h));
63 if ( (pInfo->xOrigin <= *px && *px < pInfo->xOrigin + (int)pInfo->w)
64 && (pInfo->yOrigin <= *py && *py < pInfo->yOrigin + (int)pInfo->h))
65 {
66 /* The rectangle belongs to the screen. Correct coordinates. */
67 *px -= pInfo->xOrigin;
68 *py -= pInfo->yOrigin;
69 Log9((" -> %d,%d", *px, *py));
70 break;
71 }
72 }
73 if (uScreenId == cInfos)
74 {
75 /* Map to primary screen. */
76 uScreenId = 0;
77 }
78 Log9((" scr %d\n", uScreenId));
79 return uScreenId;
80}
81
82
83typedef struct _VBVADIRTYREGION
84{
85 /* Copies of object's pointers used by vbvaRgn functions. */
86 DISPLAYFBINFO *paFramebuffers;
87 unsigned cMonitors;
88 Display *pDisplay;
89 PPDMIDISPLAYPORT pPort;
90
91 /* The rectangle that includes all dirty rectangles. */
92 RTRECT aDirtyRects[SchemaDefs::MaxGuestMonitors];
93
94} VBVADIRTYREGION;
95
96static void vbvaRgnInit(VBVADIRTYREGION *prgn, DISPLAYFBINFO *paFramebuffers, unsigned cMonitors,
97 Display *pd, PPDMIDISPLAYPORT pp)
98{
99 prgn->paFramebuffers = paFramebuffers;
100 prgn->cMonitors = cMonitors;
101 prgn->pDisplay = pd;
102 prgn->pPort = pp;
103
104 RT_ZERO(prgn->aDirtyRects);
105}
106
107static void vbvaRgnDirtyRect(VBVADIRTYREGION *prgn, unsigned uScreenId, VBVACMDHDR *phdr)
108{
109 Log9(("x = %d, y = %d, w = %d, h = %d\n", phdr->x, phdr->y, phdr->w, phdr->h));
110
111 /*
112 * Here update rectangles are accumulated to form an update area.
113 */
114 /** @todo
115 * Now the simplest method is used which builds one rectangle that
116 * includes all update areas. A bit more advanced method can be
117 * employed here. The method should be fast however.
118 */
119 if (phdr->w == 0 || phdr->h == 0)
120 {
121 /* Empty rectangle. */
122 return;
123 }
124
125 int32_t xRight = phdr->x + phdr->w;
126 int32_t yBottom = phdr->y + phdr->h;
127
128 RTRECT *pDirtyRect = &prgn->aDirtyRects[uScreenId];
129 DISPLAYFBINFO *pFBInfo = &prgn->paFramebuffers[uScreenId];
130
131 if (pDirtyRect->xRight == 0)
132 {
133 /* This is the first rectangle to be added. */
134 pDirtyRect->xLeft = phdr->x;
135 pDirtyRect->yTop = phdr->y;
136 pDirtyRect->xRight = xRight;
137 pDirtyRect->yBottom = yBottom;
138 }
139 else
140 {
141 /* Adjust region coordinates. */
142 if (pDirtyRect->xLeft > phdr->x)
143 {
144 pDirtyRect->xLeft = phdr->x;
145 }
146
147 if (pDirtyRect->yTop > phdr->y)
148 {
149 pDirtyRect->yTop = phdr->y;
150 }
151
152 if (pDirtyRect->xRight < xRight)
153 {
154 pDirtyRect->xRight = xRight;
155 }
156
157 if (pDirtyRect->yBottom < yBottom)
158 {
159 pDirtyRect->yBottom = yBottom;
160 }
161 }
162
163 if (pFBInfo->fDefaultFormat)
164 {
165 /// @todo pfnUpdateDisplayRect must take the vram offset parameter for the framebuffer
166 prgn->pPort->pfnUpdateDisplayRect(prgn->pPort, phdr->x, phdr->y, phdr->w, phdr->h);
167 prgn->pDisplay->i_handleDisplayUpdate(uScreenId, phdr->x, phdr->y, phdr->w, phdr->h);
168 }
169
170 return;
171}
172
173static void vbvaRgnUpdateFramebuffer(VBVADIRTYREGION *prgn, unsigned uScreenId)
174{
175 RTRECT *pDirtyRect = &prgn->aDirtyRects[uScreenId];
176 DISPLAYFBINFO *pFBInfo = &prgn->paFramebuffers[uScreenId];
177
178 uint32_t w = pDirtyRect->xRight - pDirtyRect->xLeft;
179 uint32_t h = pDirtyRect->yBottom - pDirtyRect->yTop;
180
181 if (!pFBInfo->fDefaultFormat && w != 0 && h != 0)
182 {
183 /// @todo pfnUpdateDisplayRect must take the vram offset parameter for the framebuffer
184 prgn->pPort->pfnUpdateDisplayRect(prgn->pPort, pDirtyRect->xLeft, pDirtyRect->yTop, w, h);
185 prgn->pDisplay->i_handleDisplayUpdate(uScreenId, pDirtyRect->xLeft, pDirtyRect->yTop, w, h);
186 }
187}
188
189void i_vbvaSetMemoryFlags(VBVAMEMORY *pVbvaMemory,
190 bool fVideoAccelEnabled,
191 bool fVideoAccelVRDP,
192 uint32_t fu32SupportedOrders,
193 DISPLAYFBINFO *paFBInfos,
194 unsigned cFBInfos)
195{
196 if (pVbvaMemory)
197 {
198 /* This called only on changes in mode. So reset VRDP always. */
199 uint32_t fu32Flags = VBVA_F_MODE_VRDP_RESET;
200
201 if (fVideoAccelEnabled)
202 {
203 fu32Flags |= VBVA_F_MODE_ENABLED;
204
205 if (fVideoAccelVRDP)
206 {
207 fu32Flags |= VBVA_F_MODE_VRDP | VBVA_F_MODE_VRDP_ORDER_MASK;
208
209 pVbvaMemory->fu32SupportedOrders = fu32SupportedOrders;
210 }
211 }
212
213 pVbvaMemory->fu32ModeFlags = fu32Flags;
214 }
215
216 unsigned uScreenId;
217 for (uScreenId = 0; uScreenId < cFBInfos; uScreenId++)
218 {
219 if (paFBInfos[uScreenId].pHostEvents)
220 {
221 paFBInfos[uScreenId].pHostEvents->fu32Events |= VBOX_VIDEO_INFO_HOST_EVENTS_F_VRDP_RESET;
222 }
223 }
224}
225
226bool Display::i_VideoAccelAllowed(void)
227{
228 return true;
229}
230
231int videoAccelEnterVGA(VIDEOACCEL *pVideoAccel)
232{
233 return RTSemXRoadsNSEnter(pVideoAccel->hXRoadsVideoAccel);
234}
235
236void videoAccelLeaveVGA(VIDEOACCEL *pVideoAccel)
237{
238 RTSemXRoadsNSLeave(pVideoAccel->hXRoadsVideoAccel);
239}
240
241int videoAccelEnterVMMDev(VIDEOACCEL *pVideoAccel)
242{
243 return RTSemXRoadsEWEnter(pVideoAccel->hXRoadsVideoAccel);
244}
245
246void videoAccelLeaveVMMDev(VIDEOACCEL *pVideoAccel)
247{
248 RTSemXRoadsEWLeave(pVideoAccel->hXRoadsVideoAccel);
249}
250
251/**
252 * @thread EMT
253 */
254int Display::i_VideoAccelEnable(bool fEnable, VBVAMEMORY *pVbvaMemory, PPDMIDISPLAYPORT pUpPort)
255{
256 int rc;
257 LogRelFlowFunc(("fEnable = %d\n", fEnable));
258
259 rc = i_videoAccelEnable(fEnable, pVbvaMemory, pUpPort);
260
261 LogRelFlowFunc(("%Rrc.\n", rc));
262 return rc;
263}
264
265int Display::i_videoAccelEnable(bool fEnable, VBVAMEMORY *pVbvaMemory, PPDMIDISPLAYPORT pUpPort)
266{
267 int rc = VINF_SUCCESS;
268
269 VIDEOACCEL *pVideoAccel = &mVideoAccelLegacy;
270
271 /* Called each time the guest wants to use acceleration,
272 * or when the VGA device disables acceleration,
273 * or when restoring the saved state with accel enabled.
274 *
275 * VGA device disables acceleration on each video mode change
276 * and on reset.
277 *
278 * Guest enabled acceleration at will. And it has to enable
279 * acceleration after a mode change.
280 */
281 LogRelFlowFunc(("mfVideoAccelEnabled = %d, fEnable = %d, pVbvaMemory = %p\n",
282 pVideoAccel->fVideoAccelEnabled, fEnable, pVbvaMemory));
283
284 /* Strictly check parameters. Callers must not pass anything in the case. */
285 Assert((fEnable && pVbvaMemory) || (!fEnable && pVbvaMemory == NULL));
286
287 if (!i_VideoAccelAllowed ())
288 return VERR_NOT_SUPPORTED;
289
290 /* Check that current status is not being changed */
291 if (pVideoAccel->fVideoAccelEnabled == fEnable)
292 return rc;
293
294 if (pVideoAccel->fVideoAccelEnabled)
295 {
296 /* Process any pending orders and empty the VBVA ring buffer. */
297 i_videoAccelFlush (pUpPort);
298 }
299
300 if (!fEnable && pVideoAccel->pVbvaMemory)
301 pVideoAccel->pVbvaMemory->fu32ModeFlags &= ~VBVA_F_MODE_ENABLED;
302
303 if (fEnable)
304 {
305 /* Process any pending VGA device changes, resize. */
306 pUpPort->pfnUpdateDisplayAll(pUpPort, /* fFailOnResize = */ false);
307 }
308
309 /* Protect the videoaccel state transition. */
310 RTCritSectEnter(&mVideoAccelLock);
311
312 if (fEnable)
313 {
314 /* Initialize the hardware memory. */
315 i_vbvaSetMemoryFlags(pVbvaMemory, true, mfVideoAccelVRDP,
316 mfu32SupportedOrders, maFramebuffers, mcMonitors);
317 pVbvaMemory->off32Data = 0;
318 pVbvaMemory->off32Free = 0;
319
320 memset(pVbvaMemory->aRecords, 0, sizeof(pVbvaMemory->aRecords));
321 pVbvaMemory->indexRecordFirst = 0;
322 pVbvaMemory->indexRecordFree = 0;
323
324 pVideoAccel->pVbvaMemory = pVbvaMemory;
325 pVideoAccel->fVideoAccelEnabled = true;
326
327 LogRel(("VBVA: Enabled.\n"));
328 }
329 else
330 {
331 pVideoAccel->pVbvaMemory = NULL;
332 pVideoAccel->fVideoAccelEnabled = false;
333
334 LogRel(("VBVA: Disabled.\n"));
335 }
336
337 RTCritSectLeave(&mVideoAccelLock);
338
339 if (!fEnable)
340 {
341 pUpPort->pfnUpdateDisplayAll(pUpPort, /* fFailOnResize = */ false);
342 }
343
344 /* Notify the VMMDev, which saves VBVA status in the saved state,
345 * and needs to know current status.
346 */
347 VMMDev *pVMMDev = mParent->i_getVMMDev();
348 if (pVMMDev)
349 {
350 PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
351 if (pVMMDevPort)
352 pVMMDevPort->pfnVBVAChange(pVMMDevPort, fEnable);
353 }
354
355 LogRelFlowFunc(("%Rrc.\n", rc));
356 return rc;
357}
358
359static bool i_vbvaVerifyRingBuffer(VBVAMEMORY *pVbvaMemory)
360{
361 RT_NOREF(pVbvaMemory);
362 return true;
363}
364
365static void i_vbvaFetchBytes(VBVAMEMORY *pVbvaMemory, uint8_t *pu8Dst, uint32_t cbDst)
366{
367 if (cbDst >= VBVA_RING_BUFFER_SIZE)
368 {
369 AssertMsgFailed(("cbDst = 0x%08X, ring buffer size 0x%08X\n", cbDst, VBVA_RING_BUFFER_SIZE));
370 return;
371 }
372
373 uint32_t u32BytesTillBoundary = VBVA_RING_BUFFER_SIZE - pVbvaMemory->off32Data;
374 uint8_t *src = &pVbvaMemory->au8RingBuffer[pVbvaMemory->off32Data];
375 int32_t i32Diff = cbDst - u32BytesTillBoundary;
376
377 if (i32Diff <= 0)
378 {
379 /* Chunk will not cross buffer boundary. */
380 memcpy (pu8Dst, src, cbDst);
381 }
382 else
383 {
384 /* Chunk crosses buffer boundary. */
385 memcpy(pu8Dst, src, u32BytesTillBoundary);
386 memcpy(pu8Dst + u32BytesTillBoundary, &pVbvaMemory->au8RingBuffer[0], i32Diff);
387 }
388
389 /* Advance data offset. */
390 pVbvaMemory->off32Data = (pVbvaMemory->off32Data + cbDst) % VBVA_RING_BUFFER_SIZE;
391
392 return;
393}
394
395
396static bool i_vbvaPartialRead(uint8_t **ppu8, uint32_t *pcb, uint32_t cbRecord, VBVAMEMORY *pVbvaMemory)
397{
398 uint8_t *pu8New;
399
400 LogFlow(("MAIN::DisplayImpl::vbvaPartialRead: p = %p, cb = %d, cbRecord 0x%08X\n",
401 *ppu8, *pcb, cbRecord));
402
403 if (*ppu8)
404 {
405 Assert (*pcb);
406 pu8New = (uint8_t *)RTMemRealloc(*ppu8, cbRecord);
407 }
408 else
409 {
410 Assert (!*pcb);
411 pu8New = (uint8_t *)RTMemAlloc(cbRecord);
412 }
413
414 if (!pu8New)
415 {
416 /* Memory allocation failed, fail the function. */
417 Log(("MAIN::vbvaPartialRead: failed to (re)alocate memory for partial record!!! cbRecord 0x%08X\n",
418 cbRecord));
419
420 if (*ppu8)
421 {
422 RTMemFree(*ppu8);
423 }
424
425 *ppu8 = NULL;
426 *pcb = 0;
427
428 return false;
429 }
430
431 /* Fetch data from the ring buffer. */
432 i_vbvaFetchBytes(pVbvaMemory, pu8New + *pcb, cbRecord - *pcb);
433
434 *ppu8 = pu8New;
435 *pcb = cbRecord;
436
437 return true;
438}
439
440/* For contiguous chunks just return the address in the buffer.
441 * For crossing boundary - allocate a buffer from heap.
442 */
443static bool i_vbvaFetchCmd(VIDEOACCEL *pVideoAccel, VBVACMDHDR **ppHdr, uint32_t *pcbCmd)
444{
445 VBVAMEMORY *pVbvaMemory = pVideoAccel->pVbvaMemory;
446
447 uint32_t indexRecordFirst = pVbvaMemory->indexRecordFirst;
448 uint32_t indexRecordFree = pVbvaMemory->indexRecordFree;
449
450#ifdef DEBUG_sunlover
451 LogFlowFunc(("first = %d, free = %d\n",
452 indexRecordFirst, indexRecordFree));
453#endif /* DEBUG_sunlover */
454
455 if (!i_vbvaVerifyRingBuffer(pVbvaMemory))
456 {
457 return false;
458 }
459
460 if (indexRecordFirst == indexRecordFree)
461 {
462 /* No records to process. Return without assigning output variables. */
463 return true;
464 }
465
466 uint32_t cbRecordCurrent = ASMAtomicReadU32(&pVbvaMemory->aRecords[indexRecordFirst].cbRecord);
467
468#ifdef DEBUG_sunlover
469 LogFlowFunc(("cbRecord = 0x%08X\n", cbRecordCurrent));
470#endif /* DEBUG_sunlover */
471
472 uint32_t cbRecord = cbRecordCurrent & ~VBVA_F_RECORD_PARTIAL;
473
474 if (pVideoAccel->cbVbvaPartial)
475 {
476 /* There is a partial read in process. Continue with it. */
477
478 Assert(pVideoAccel->pu8VbvaPartial);
479
480 LogFlowFunc(("continue partial record cbVbvaPartial = %d cbRecord 0x%08X, first = %d, free = %d\n",
481 pVideoAccel->cbVbvaPartial, cbRecordCurrent, indexRecordFirst, indexRecordFree));
482
483 if (cbRecord > pVideoAccel->cbVbvaPartial)
484 {
485 /* New data has been added to the record. */
486 if (!i_vbvaPartialRead(&pVideoAccel->pu8VbvaPartial, &pVideoAccel->cbVbvaPartial, cbRecord, pVbvaMemory))
487 {
488 return false;
489 }
490 }
491
492 if (!(cbRecordCurrent & VBVA_F_RECORD_PARTIAL))
493 {
494 /* The record is completed by guest. Return it to the caller. */
495 *ppHdr = (VBVACMDHDR *)pVideoAccel->pu8VbvaPartial;
496 *pcbCmd = pVideoAccel->cbVbvaPartial;
497
498 pVideoAccel->pu8VbvaPartial = NULL;
499 pVideoAccel->cbVbvaPartial = 0;
500
501 /* Advance the record index. */
502 pVbvaMemory->indexRecordFirst = (indexRecordFirst + 1) % VBVA_MAX_RECORDS;
503
504#ifdef DEBUG_sunlover
505 LogFlowFunc(("partial done ok, data = %d, free = %d\n",
506 pVbvaMemory->off32Data, pVbvaMemory->off32Free));
507#endif /* DEBUG_sunlover */
508 }
509
510 return true;
511 }
512
513 /* A new record need to be processed. */
514 if (cbRecordCurrent & VBVA_F_RECORD_PARTIAL)
515 {
516 /* Current record is being written by guest. '=' is important here. */
517 if (cbRecord >= VBVA_RING_BUFFER_SIZE - VBVA_RING_BUFFER_THRESHOLD)
518 {
519 /* Partial read must be started. */
520 if (!i_vbvaPartialRead(&pVideoAccel->pu8VbvaPartial, &pVideoAccel->cbVbvaPartial, cbRecord, pVbvaMemory))
521 {
522 return false;
523 }
524
525 LogFlowFunc(("started partial record cbVbvaPartial = 0x%08X cbRecord 0x%08X, first = %d, free = %d\n",
526 pVideoAccel->cbVbvaPartial, cbRecordCurrent, indexRecordFirst, indexRecordFree));
527 }
528
529 return true;
530 }
531
532 /* Current record is complete. If it is not empty, process it. */
533 if (cbRecord)
534 {
535 /* The size of largest contiguous chunk in the ring biffer. */
536 uint32_t u32BytesTillBoundary = VBVA_RING_BUFFER_SIZE - pVbvaMemory->off32Data;
537
538 /* The ring buffer pointer. */
539 uint8_t *au8RingBuffer = &pVbvaMemory->au8RingBuffer[0];
540
541 /* The pointer to data in the ring buffer. */
542 uint8_t *src = &au8RingBuffer[pVbvaMemory->off32Data];
543
544 /* Fetch or point the data. */
545 if (u32BytesTillBoundary >= cbRecord)
546 {
547 /* The command does not cross buffer boundary. Return address in the buffer. */
548 *ppHdr = (VBVACMDHDR *)src;
549
550 /* Advance data offset. */
551 pVbvaMemory->off32Data = (pVbvaMemory->off32Data + cbRecord) % VBVA_RING_BUFFER_SIZE;
552 }
553 else
554 {
555 /* The command crosses buffer boundary. Rare case, so not optimized. */
556 uint8_t *dst = (uint8_t *)RTMemAlloc(cbRecord);
557
558 if (!dst)
559 {
560 LogRelFlowFunc(("could not allocate %d bytes from heap!!!\n", cbRecord));
561 pVbvaMemory->off32Data = (pVbvaMemory->off32Data + cbRecord) % VBVA_RING_BUFFER_SIZE;
562 return false;
563 }
564
565 i_vbvaFetchBytes(pVbvaMemory, dst, cbRecord);
566
567 *ppHdr = (VBVACMDHDR *)dst;
568
569#ifdef DEBUG_sunlover
570 LogFlowFunc(("Allocated from heap %p\n", dst));
571#endif /* DEBUG_sunlover */
572 }
573 }
574
575 *pcbCmd = cbRecord;
576
577 /* Advance the record index. */
578 pVbvaMemory->indexRecordFirst = (indexRecordFirst + 1) % VBVA_MAX_RECORDS;
579
580#ifdef DEBUG_sunlover
581 LogFlowFunc(("done ok, data = %d, free = %d\n",
582 pVbvaMemory->off32Data, pVbvaMemory->off32Free));
583#endif /* DEBUG_sunlover */
584
585 return true;
586}
587
588static void i_vbvaReleaseCmd(VIDEOACCEL *pVideoAccel, VBVACMDHDR *pHdr, int32_t cbCmd)
589{
590 RT_NOREF(cbCmd);
591 uint8_t *au8RingBuffer = pVideoAccel->pVbvaMemory->au8RingBuffer;
592
593 if ( (uint8_t *)pHdr >= au8RingBuffer
594 && (uint8_t *)pHdr < &au8RingBuffer[VBVA_RING_BUFFER_SIZE])
595 {
596 /* The pointer is inside ring buffer. Must be continuous chunk. */
597 Assert(VBVA_RING_BUFFER_SIZE - ((uint8_t *)pHdr - au8RingBuffer) >= cbCmd);
598
599 /* Do nothing. */
600
601 Assert(!pVideoAccel->pu8VbvaPartial && pVideoAccel->cbVbvaPartial == 0);
602 }
603 else
604 {
605 /* The pointer is outside. It is then an allocated copy. */
606
607#ifdef DEBUG_sunlover
608 LogFlowFunc(("Free heap %p\n", pHdr));
609#endif /* DEBUG_sunlover */
610
611 if ((uint8_t *)pHdr == pVideoAccel->pu8VbvaPartial)
612 {
613 pVideoAccel->pu8VbvaPartial = NULL;
614 pVideoAccel->cbVbvaPartial = 0;
615 }
616 else
617 {
618 Assert(!pVideoAccel->pu8VbvaPartial && pVideoAccel->cbVbvaPartial == 0);
619 }
620
621 RTMemFree(pHdr);
622 }
623
624 return;
625}
626
627
628/**
629 * Called regularly on the DisplayRefresh timer.
630 * Also on behalf of guest, when the ring buffer is full.
631 *
632 * @thread EMT
633 */
634void Display::i_VideoAccelFlush(PPDMIDISPLAYPORT pUpPort)
635{
636 int rc = i_videoAccelFlush(pUpPort);
637 if (RT_FAILURE(rc))
638 {
639 /* Disable on errors. */
640 i_videoAccelEnable(false, NULL, pUpPort);
641 }
642}
643
644int Display::i_videoAccelFlush(PPDMIDISPLAYPORT pUpPort)
645{
646 VIDEOACCEL *pVideoAccel = &mVideoAccelLegacy;
647 VBVAMEMORY *pVbvaMemory = pVideoAccel->pVbvaMemory;
648
649#ifdef DEBUG_sunlover_2
650 LogFlowFunc(("fVideoAccelEnabled = %d\n", pVideoAccel->fVideoAccelEnabled));
651#endif /* DEBUG_sunlover_2 */
652
653 if (!pVideoAccel->fVideoAccelEnabled)
654 {
655 Log(("Display::VideoAccelFlush: called with disabled VBVA!!! Ignoring.\n"));
656 return VINF_SUCCESS;
657 }
658
659 /* Here VBVA is enabled and we have the accelerator memory pointer. */
660 Assert(pVbvaMemory);
661
662#ifdef DEBUG_sunlover_2
663 LogFlowFunc(("indexRecordFirst = %d, indexRecordFree = %d, off32Data = %d, off32Free = %d\n",
664 pVbvaMemory->indexRecordFirst, pVbvaMemory->indexRecordFree,
665 pVbvaMemory->off32Data, pVbvaMemory->off32Free));
666#endif /* DEBUG_sunlover_2 */
667
668 /* Quick check for "nothing to update" case. */
669 if (pVbvaMemory->indexRecordFirst == pVbvaMemory->indexRecordFree)
670 {
671 return VINF_SUCCESS;
672 }
673
674 /* Process the ring buffer */
675 unsigned uScreenId;
676
677 /* Initialize dirty rectangles accumulator. */
678 VBVADIRTYREGION rgn;
679 vbvaRgnInit(&rgn, maFramebuffers, mcMonitors, this, pUpPort);
680
681 for (;;)
682 {
683 VBVACMDHDR *phdr = NULL;
684 uint32_t cbCmd = UINT32_MAX;
685
686 /* Fetch the command data. */
687 if (!i_vbvaFetchCmd(pVideoAccel, &phdr, &cbCmd))
688 {
689 Log(("Display::VideoAccelFlush: unable to fetch command. off32Data = %d, off32Free = %d. Disabling VBVA!!!\n",
690 pVbvaMemory->off32Data, pVbvaMemory->off32Free));
691 return VERR_INVALID_STATE;
692 }
693
694 if (cbCmd == uint32_t(~0))
695 {
696 /* No more commands yet in the queue. */
697#ifdef DEBUG_sunlover
698 LogFlowFunc(("no command\n"));
699#endif /* DEBUG_sunlover */
700 break;
701 }
702
703 if (cbCmd != 0)
704 {
705#ifdef DEBUG_sunlover
706 LogFlowFunc(("hdr: cbCmd = %d, x=%d, y=%d, w=%d, h=%d\n",
707 cbCmd, phdr->x, phdr->y, phdr->w, phdr->h));
708#endif /* DEBUG_sunlover */
709
710 VBVACMDHDR hdrSaved = *phdr;
711
712 int x = phdr->x;
713 int y = phdr->y;
714 int w = phdr->w;
715 int h = phdr->h;
716
717 uScreenId = mapCoordsToScreen(maFramebuffers, mcMonitors, &x, &y, &w, &h);
718
719 phdr->x = (int16_t)x;
720 phdr->y = (int16_t)y;
721 phdr->w = (uint16_t)w;
722 phdr->h = (uint16_t)h;
723
724 /* Handle the command.
725 *
726 * Guest is responsible for updating the guest video memory.
727 * The Windows guest does all drawing using Eng*.
728 *
729 * For local output, only dirty rectangle information is used
730 * to update changed areas.
731 *
732 * Dirty rectangles are accumulated to exclude overlapping updates and
733 * group small updates to a larger one.
734 */
735
736 /* Accumulate the update. */
737 vbvaRgnDirtyRect(&rgn, uScreenId, phdr);
738
739 /* Forward the command to VRDP server. */
740 mParent->i_consoleVRDPServer()->SendUpdate(uScreenId, phdr, cbCmd);
741
742 *phdr = hdrSaved;
743 }
744
745 i_vbvaReleaseCmd(pVideoAccel, phdr, cbCmd);
746 }
747
748 for (uScreenId = 0; uScreenId < mcMonitors; uScreenId++)
749 {
750 /* Draw the framebuffer. */
751 vbvaRgnUpdateFramebuffer(&rgn, uScreenId);
752 }
753 return VINF_SUCCESS;
754}
755
756int Display::i_videoAccelRefreshProcess(PPDMIDISPLAYPORT pUpPort)
757{
758 int rc = VWRN_INVALID_STATE; /* Default is to do a display update in VGA device. */
759
760 VIDEOACCEL *pVideoAccel = &mVideoAccelLegacy;
761
762 videoAccelEnterVGA(pVideoAccel);
763
764 if (pVideoAccel->fVideoAccelEnabled)
765 {
766 Assert(pVideoAccel->pVbvaMemory);
767 rc = i_videoAccelFlush(pUpPort);
768 if (RT_FAILURE(rc))
769 {
770 /* Disable on errors. */
771 i_videoAccelEnable(false, NULL, pUpPort);
772 rc = VWRN_INVALID_STATE; /* Do a display update in VGA device. */
773 }
774 else
775 {
776 rc = VINF_SUCCESS;
777 }
778 }
779
780 videoAccelLeaveVGA(pVideoAccel);
781
782 return rc;
783}
784
785void Display::processAdapterData(void *pvVRAM, uint32_t u32VRAMSize)
786{
787 RT_NOREF(u32VRAMSize);
788 if (pvVRAM == NULL)
789 {
790 unsigned i;
791 for (i = 0; i < mcMonitors; i++)
792 {
793 DISPLAYFBINFO *pFBInfo = &maFramebuffers[i];
794
795 pFBInfo->u32Offset = 0;
796 pFBInfo->u32MaxFramebufferSize = 0;
797 pFBInfo->u32InformationSize = 0;
798 }
799 }
800#ifndef VBOX_WITH_HGSMI
801 else
802 {
803 uint8_t *pu8 = (uint8_t *)pvVRAM;
804 pu8 += u32VRAMSize - VBOX_VIDEO_ADAPTER_INFORMATION_SIZE;
805
806 /// @todo
807 uint8_t *pu8End = pu8 + VBOX_VIDEO_ADAPTER_INFORMATION_SIZE;
808
809 VBOXVIDEOINFOHDR *pHdr;
810
811 for (;;)
812 {
813 pHdr = (VBOXVIDEOINFOHDR *)pu8;
814 pu8 += sizeof(VBOXVIDEOINFOHDR);
815
816 if (pu8 >= pu8End)
817 {
818 LogRel(("VBoxVideo: Guest adapter information overflow!!!\n"));
819 break;
820 }
821
822 if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_DISPLAY)
823 {
824 if (pHdr->u16Length != sizeof(VBOXVIDEOINFODISPLAY))
825 {
826 LogRel(("VBoxVideo: Guest adapter information %s invalid length %d!!!\n", "DISPLAY", pHdr->u16Length));
827 break;
828 }
829
830 VBOXVIDEOINFODISPLAY *pDisplay = (VBOXVIDEOINFODISPLAY *)pu8;
831
832 if (pDisplay->u32Index >= mcMonitors)
833 {
834 LogRel(("VBoxVideo: Guest adapter information invalid display index %d!!!\n", pDisplay->u32Index));
835 break;
836 }
837
838 DISPLAYFBINFO *pFBInfo = &maFramebuffers[pDisplay->u32Index];
839
840 pFBInfo->u32Offset = pDisplay->u32Offset;
841 pFBInfo->u32MaxFramebufferSize = pDisplay->u32FramebufferSize;
842 pFBInfo->u32InformationSize = pDisplay->u32InformationSize;
843
844 LogRelFlow(("VBOX_VIDEO_INFO_TYPE_DISPLAY: %d: at 0x%08X, size 0x%08X, info 0x%08X\n", pDisplay->u32Index,
845 pDisplay->u32Offset, pDisplay->u32FramebufferSize, pDisplay->u32InformationSize));
846 }
847 else if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_QUERY_CONF32)
848 {
849 if (pHdr->u16Length != sizeof(VBOXVIDEOINFOQUERYCONF32))
850 {
851 LogRel(("VBoxVideo: Guest adapter information %s invalid length %d!!!\n", "CONF32", pHdr->u16Length));
852 break;
853 }
854
855 VBOXVIDEOINFOQUERYCONF32 *pConf32 = (VBOXVIDEOINFOQUERYCONF32 *)pu8;
856
857 switch (pConf32->u32Index)
858 {
859 case VBOX_VIDEO_QCI32_MONITOR_COUNT:
860 {
861 pConf32->u32Value = mcMonitors;
862 } break;
863
864 case VBOX_VIDEO_QCI32_OFFSCREEN_HEAP_SIZE:
865 {
866 /** @todo make configurable. */
867 pConf32->u32Value = _1M;
868 } break;
869
870 default:
871 LogRel(("VBoxVideo: CONF32 %d not supported!!! Skipping.\n", pConf32->u32Index));
872 }
873 }
874 else if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_END)
875 {
876 if (pHdr->u16Length != 0)
877 {
878 LogRel(("VBoxVideo: Guest adapter information %s invalid length %d!!!\n", "END", pHdr->u16Length));
879 break;
880 }
881
882 break;
883 }
884 else if (pHdr->u8Type != VBOX_VIDEO_INFO_TYPE_NV_HEAP)
885 {
886 /** @todo why is Additions/WINNT/Graphics/Miniport/VBoxVideo. cpp pushing this to us? */
887 LogRel(("Guest adapter information contains unsupported type %d. The block has been skipped.\n", pHdr->u8Type));
888 }
889
890 pu8 += pHdr->u16Length;
891 }
892 }
893#endif /* !VBOX_WITH_HGSMI */
894}
895
896void Display::processDisplayData(void *pvVRAM, unsigned uScreenId)
897{
898 if (uScreenId >= mcMonitors)
899 {
900 LogRel(("VBoxVideo: Guest display information invalid display index %d!!!\n", uScreenId));
901 return;
902 }
903
904 /* Get the display information structure. */
905 DISPLAYFBINFO *pFBInfo = &maFramebuffers[uScreenId];
906
907 uint8_t *pu8 = (uint8_t *)pvVRAM;
908 pu8 += pFBInfo->u32Offset + pFBInfo->u32MaxFramebufferSize;
909
910 /// @todo
911 uint8_t *pu8End = pu8 + pFBInfo->u32InformationSize;
912
913 VBOXVIDEOINFOHDR *pHdr;
914
915 for (;;)
916 {
917 pHdr = (VBOXVIDEOINFOHDR *)pu8;
918 pu8 += sizeof(VBOXVIDEOINFOHDR);
919
920 if (pu8 >= pu8End)
921 {
922 LogRel(("VBoxVideo: Guest display information overflow!!!\n"));
923 break;
924 }
925
926 if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_SCREEN)
927 {
928 if (pHdr->u16Length != sizeof(VBOXVIDEOINFOSCREEN))
929 {
930 LogRel(("VBoxVideo: Guest display information %s invalid length %d!!!\n", "SCREEN", pHdr->u16Length));
931 break;
932 }
933
934 VBOXVIDEOINFOSCREEN *pScreen = (VBOXVIDEOINFOSCREEN *)pu8;
935
936 pFBInfo->xOrigin = pScreen->xOrigin;
937 pFBInfo->yOrigin = pScreen->yOrigin;
938
939 pFBInfo->w = pScreen->u16Width;
940 pFBInfo->h = pScreen->u16Height;
941
942 LogRelFlow(("VBOX_VIDEO_INFO_TYPE_SCREEN: (%p) %d: at %d,%d, linesize 0x%X, size %dx%d, bpp %d, flags 0x%02X\n",
943 pHdr, uScreenId, pScreen->xOrigin, pScreen->yOrigin, pScreen->u32LineSize, pScreen->u16Width,
944 pScreen->u16Height, pScreen->bitsPerPixel, pScreen->u8Flags));
945
946 if (uScreenId != VBOX_VIDEO_PRIMARY_SCREEN)
947 {
948 /* Primary screen resize is eeeeeeeee by the VGA device. */
949 if (pFBInfo->fDisabled)
950 {
951 pFBInfo->fDisabled = false;
952 fireGuestMonitorChangedEvent(mParent->i_getEventSource(),
953 GuestMonitorChangedEventType_Enabled,
954 uScreenId,
955 pFBInfo->xOrigin, pFBInfo->yOrigin,
956 pFBInfo->w, pFBInfo->h);
957 }
958
959 i_handleDisplayResize(uScreenId, pScreen->bitsPerPixel,
960 (uint8_t *)pvVRAM + pFBInfo->u32Offset,
961 pScreen->u32LineSize,
962 pScreen->u16Width, pScreen->u16Height,
963 VBVA_SCREEN_F_ACTIVE,
964 pScreen->xOrigin, pScreen->yOrigin, false);
965 }
966 }
967 else if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_END)
968 {
969 if (pHdr->u16Length != 0)
970 {
971 LogRel(("VBoxVideo: Guest adapter information %s invalid length %d!!!\n", "END", pHdr->u16Length));
972 break;
973 }
974
975 break;
976 }
977 else if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_HOST_EVENTS)
978 {
979 if (pHdr->u16Length != sizeof(VBOXVIDEOINFOHOSTEVENTS))
980 {
981 LogRel(("VBoxVideo: Guest display information %s invalid length %d!!!\n", "HOST_EVENTS", pHdr->u16Length));
982 break;
983 }
984
985 VBOXVIDEOINFOHOSTEVENTS *pHostEvents = (VBOXVIDEOINFOHOSTEVENTS *)pu8;
986
987 pFBInfo->pHostEvents = pHostEvents;
988
989 LogFlow(("VBOX_VIDEO_INFO_TYPE_HOSTEVENTS: (%p)\n",
990 pHostEvents));
991 }
992 else if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_LINK)
993 {
994 if (pHdr->u16Length != sizeof(VBOXVIDEOINFOLINK))
995 {
996 LogRel(("VBoxVideo: Guest adapter information %s invalid length %d!!!\n", "LINK", pHdr->u16Length));
997 break;
998 }
999
1000 VBOXVIDEOINFOLINK *pLink = (VBOXVIDEOINFOLINK *)pu8;
1001 pu8 += pLink->i32Offset;
1002 }
1003 else
1004 {
1005 LogRel(("Guest display information contains unsupported type %d\n", pHdr->u8Type));
1006 }
1007
1008 pu8 += pHdr->u16Length;
1009 }
1010}
1011
1012/* vi: set tabstop=4 shiftwidth=4 expandtab: */
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