VirtualBox

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

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

*: scm --update-copyright-year

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

© 2023 Oracle
ContactPrivacy policyTerms of Use