VirtualBox

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

Last change on this file since 96391 was 94938, checked in by vboxsync, 3 years ago

Main/src-client/DisplayImplLegacy.cpp: Adjust to the new rules wrt. to rc -> hrc,vrc usage, ​bugref:10223

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