Changeset 52769 in vbox for trunk/src/VBox
- Timestamp:
- Sep 17, 2014 6:50:20 AM (11 years ago)
- svn:sync-xref-src-repo-rev:
- 96141
- Location:
- trunk/src/VBox/Main
- Files:
-
- 3 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
TabularUnified trunk/src/VBox/Main/Makefile.kmk ¶
r52546 r52769 719 719 src-client/ConsoleVRDPServer.cpp \ 720 720 src-client/DisplayImpl.cpp \ 721 src-client/DisplayImplLegacy.cpp \ 721 722 src-client/DisplaySourceBitmapImpl.cpp \ 722 723 src-client/EmulatedUSBImpl.cpp \ -
TabularUnified trunk/src/VBox/Main/include/DisplayImpl.h ¶
r52667 r52769 39 39 typedef struct _DISPLAYFBINFO 40 40 { 41 /* The following 3 fields (u32Offset, u32MaxFramebufferSize and u32InformationSize) 42 * are not used by the current HGSMI. They are needed for backward compatibility with 43 * pre-HGSMI additions. 44 */ 41 45 uint32_t u32Offset; 42 46 uint32_t u32MaxFramebufferSize; … … 72 76 /** The framebuffer has default format and must be updates immediately. */ 73 77 bool fDefaultFormat; 74 75 struct76 {77 /* The rectangle that includes all dirty rectangles. */78 int32_t xLeft;79 int32_t xRight;80 int32_t yTop;81 int32_t yBottom;82 } dirtyRect;83 78 84 79 #ifdef VBOX_WITH_HGSMI … … 101 96 } DISPLAYFBINFO; 102 97 98 /* The legacy VBVA (VideoAccel) data. 99 * 100 * Backward compatibility with the guest additions 3.x or older. 101 */ 102 typedef struct VIDEOACCEL 103 { 104 VBVAMEMORY *pVbvaMemory; 105 bool fVideoAccelEnabled; 106 107 uint8_t *pu8VbvaPartial; 108 uint32_t cbVbvaPartial; 109 110 /* Old guest additions (3.x and older) use both VMMDev and DevVGA refresh timer 111 * to process the VBVABUFFER memory. Therefore the legacy VBVA (VideoAccel) host 112 * code can be executed concurrently by VGA refresh timer and the guest VMMDev 113 * request in SMP VMs. The semaphore serialized this. 114 */ 115 RTSEMXROADS hXRoadsVideoAccel; 116 117 } VIDEOACCEL; 118 103 119 class DisplayMouseInterface 104 120 { … … 131 147 int i_handleDisplayResize(unsigned uScreenId, uint32_t bpp, void *pvVRAM, uint32_t cbLine, 132 148 uint32_t w, uint32_t h, uint16_t flags); 133 void i_handleDisplayUpdateLegacy(int x, int y, int cx, int cy);134 149 void i_handleDisplayUpdate(unsigned uScreenId, int x, int y, int w, int h); 135 150 #ifdef VBOX_WITH_VIDEOHWACCEL … … 160 175 int i_handleQueryVisibleRegion(uint32_t *pcRect, PRTRECT pRect); 161 176 162 int i_VideoAccelEnable(bool fEnable, VBVAMEMORY *pVbvaMemory);163 void i_VideoAccelFlush(void);164 bool i_VideoAccelAllowed(void);165 177 void i_VideoAccelVRDP(bool fEnable); 166 178 … … 348 360 bool volatile fVGAResizing; 349 361 350 VBVAMEMORY *mpVbvaMemory;351 bool mfVideoAccelEnabled;352 362 bool mfVideoAccelVRDP; 353 363 uint32_t mfu32SupportedOrders; 354 355 364 int32_t volatile mcVideoAccelVRDPRefs; 356 365 … … 358 367 bool mfCrOglDataHidden; 359 368 #endif 360 361 uint8_t *mpu8VbvaPartial;362 uint32_t mcbVbvaPartial;363 369 364 370 #ifdef VBOX_WITH_CRHGSMI … … 374 380 #endif 375 381 376 bool i_vbvaFetchCmd(VBVACMDHDR **ppHdr, uint32_t *pcbCmd);377 void i_vbvaReleaseCmd(VBVACMDHDR *pHdr, int32_t cbCmd);378 379 382 void i_handleResizeCompletedEMT(unsigned uScreenId, BOOL fResizeContext); 380 383 381 /* Old guest additions (3.x and older) use both VMMDev and DevVGA refresh timer 382 * to process the VBVABUFFER memory. Therefore the legacy VBVA (VideoAccel) host 383 * code can be executed concurrently by VGA refresh timer and the guest VMMDev 384 * request in SMP VMs. The semaphore serialized this. 385 */ 386 RTSEMXROADS mhXRoadsVideoAccel; 387 int videoAccelEnterVGA(void); 388 void videoAccelLeaveVGA(void); 389 int videoAccelEnterVMMDev(void); 390 void videoAccelLeaveVMMDev(void); 391 392 /* Serializes access to mpVbvaMemory, etc between VRDP and Display. */ 384 /* The legacy VBVA data and methods. */ 385 VIDEOACCEL mVideoAccelLegacy; 386 387 int i_VideoAccelEnable(bool fEnable, VBVAMEMORY *pVbvaMemory, PPDMIDISPLAYPORT pUpPort); 388 void i_VideoAccelFlush(PPDMIDISPLAYPORT pUpPort); 389 bool i_VideoAccelAllowed(void); 390 391 int i_videoAccelRefreshProcess(PPDMIDISPLAYPORT pUpPort); 392 int i_videoAccelEnable(bool fEnable, VBVAMEMORY *pVbvaMemory, PPDMIDISPLAYPORT pUpPort); 393 int i_videoAccelFlush(PPDMIDISPLAYPORT pUpPort); 394 395 /* Legacy pre-HGSMI handlers. */ 396 void processAdapterData(void *pvVRAM, uint32_t u32VRAMSize); 397 void processDisplayData(void *pvVRAM, unsigned uScreenId); 398 399 /* Serializes access to mVideoAccelLegacy and mfVideoAccelVRDP, etc between VRDP and Display. */ 393 400 RTCRITSECT mVideoAccelLock; 394 401 … … 420 427 static int i_drawToScreenEMT(Display *pDisplay, ULONG aScreenId, BYTE *address, ULONG x, ULONG y, ULONG width, ULONG height); 421 428 422 int i_videoAccelRefreshProcess(void);423 424 /* Functions run under VBVA lock. */425 int i_videoAccelEnable(bool fEnable, VBVAMEMORY *pVbvaMemory);426 int i_videoAccelFlush(void);427 428 429 #if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) 429 430 int i_crOglWindowsShow(bool fShow); … … 439 440 #endif 440 441 }; 442 443 /* The legacy VBVA helpers. */ 444 int videoAccelConstruct(VIDEOACCEL *pVideoAccel); 445 void videoAccelDestroy(VIDEOACCEL *pVideoAccel); 446 void i_vbvaSetMemoryFlags(VBVAMEMORY *pVbvaMemory, 447 bool fVideoAccelEnabled, 448 bool fVideoAccelVRDP, 449 uint32_t fu32SupportedOrders, 450 DISPLAYFBINFO *paFBInfos, 451 unsigned cFBInfos); 452 int videoAccelEnterVGA(VIDEOACCEL *pVideoAccel); 453 void videoAccelLeaveVGA(VIDEOACCEL *pVideoAccel); 454 int videoAccelEnterVMMDev(VIDEOACCEL *pVideoAccel); 455 void videoAccelLeaveVMMDev(VIDEOACCEL *pVideoAccel); 456 441 457 442 458 /* helper function, code in DisplayResampleImage.cpp */ -
TabularUnified trunk/src/VBox/Main/src-client/DisplayImpl.cpp ¶
r52667 r52769 102 102 HRESULT Display::FinalConstruct() 103 103 { 104 mpVbvaMemory = NULL; 105 mfVideoAccelEnabled = false; 104 int rc = videoAccelConstruct(&mVideoAccelLegacy); 105 AssertRC(rc); 106 106 107 mfVideoAccelVRDP = false; 107 108 mfu32SupportedOrders = 0; … … 112 113 #endif 113 114 114 mpu8VbvaPartial = NULL;115 mcbVbvaPartial = 0;116 117 115 mpDrv = NULL; 118 116 mpVMMDev = NULL; 119 117 mfVMMDevInited = false; 120 118 121 int rc = RTCritSectInit(&mVideoAccelLock); 122 AssertRC(rc); 123 124 mhXRoadsVideoAccel = NIL_RTSEMXROADS; 125 rc = RTSemXRoadsCreate(&mhXRoadsVideoAccel); 119 rc = RTCritSectInit(&mVideoAccelLock); 126 120 AssertRC(rc); 127 121 … … 158 152 uninit(); 159 153 160 RTSemXRoadsDestroy(mhXRoadsVideoAccel);154 videoAccelDestroy(&mVideoAccelLegacy); 161 155 162 156 if (RTCritSectIsInitialized(&mVideoAccelLock)) … … 615 609 maFramebuffers[ul].fDefaultFormat = false; 616 610 617 RT_ZERO(maFramebuffers[ul].dirtyRect);618 611 #ifdef VBOX_WITH_HGSMI 619 612 maFramebuffers[ul].fVBVAEnabled = false; … … 1008 1001 } 1009 1002 1010 unsigned mapCoordsToScreen(DISPLAYFBINFO *pInfos, unsigned cInfos, int *px, int *py, int *pw, int *ph)1011 {1012 DISPLAYFBINFO *pInfo = pInfos;1013 unsigned uScreenId;1014 LogSunlover(("mapCoordsToScreen: %d,%d %dx%d\n", *px, *py, *pw, *ph));1015 for (uScreenId = 0; uScreenId < cInfos; uScreenId++, pInfo++)1016 {1017 LogSunlover((" [%d] %d,%d %dx%d\n", uScreenId, pInfo->xOrigin, pInfo->yOrigin, pInfo->w, pInfo->h));1018 if ( (pInfo->xOrigin <= *px && *px < pInfo->xOrigin + (int)pInfo->w)1019 && (pInfo->yOrigin <= *py && *py < pInfo->yOrigin + (int)pInfo->h))1020 {1021 /* The rectangle belongs to the screen. Correct coordinates. */1022 *px -= pInfo->xOrigin;1023 *py -= pInfo->yOrigin;1024 LogSunlover((" -> %d,%d", *px, *py));1025 break;1026 }1027 }1028 if (uScreenId == cInfos)1029 {1030 /* Map to primary screen. */1031 uScreenId = 0;1032 }1033 LogSunlover((" scr %d\n", uScreenId));1034 return uScreenId;1035 }1036 1037 1038 /**1039 * Handles display update event.1040 *1041 * @param x Update area x coordinate1042 * @param y Update area y coordinate1043 * @param w Update area width1044 * @param h Update area height1045 *1046 * @thread EMT1047 */1048 void Display::i_handleDisplayUpdateLegacy(int x, int y, int w, int h)1049 {1050 unsigned uScreenId = mapCoordsToScreen(maFramebuffers, mcMonitors, &x, &y, &w, &h);1051 1052 #ifdef DEBUG_sunlover1053 LogFlowFunc(("%d,%d %dx%d (checked)\n", x, y, w, h));1054 #endif /* DEBUG_sunlover */1055 1056 i_handleDisplayUpdate(uScreenId, x, y, w, h);1057 }1058 1059 1003 void Display::i_handleDisplayUpdate(unsigned uScreenId, int x, int y, int w, int h) 1060 1004 { … … 1120 1064 1121 1065 #ifndef VBOX_WITH_HGSMI 1122 if (!m fVideoAccelEnabled)1066 if (!mVideoAccelLegacy.fVideoAccelEnabled) 1123 1067 { 1124 1068 #else 1125 if (!m fVideoAccelEnabled && !maFramebuffers[uScreenId].fVBVAEnabled)1069 if (!mVideoAccelLegacy.fVideoAccelEnabled && !maFramebuffers[uScreenId].fVBVAEnabled) 1126 1070 { 1127 1071 #endif /* VBOX_WITH_HGSMI */ … … 1325 1269 } 1326 1270 1327 typedef struct _VBVADIRTYREGION1328 {1329 /* Copies of object's pointers used by vbvaRgn functions. */1330 DISPLAYFBINFO *paFramebuffers;1331 unsigned cMonitors;1332 Display *pDisplay;1333 PPDMIDISPLAYPORT pPort;1334 1335 } VBVADIRTYREGION;1336 1337 static void vbvaRgnInit(VBVADIRTYREGION *prgn, DISPLAYFBINFO *paFramebuffers, unsigned cMonitors,1338 Display *pd, PPDMIDISPLAYPORT pp)1339 {1340 prgn->paFramebuffers = paFramebuffers;1341 prgn->cMonitors = cMonitors;1342 prgn->pDisplay = pd;1343 prgn->pPort = pp;1344 1345 unsigned uScreenId;1346 for (uScreenId = 0; uScreenId < cMonitors; uScreenId++)1347 {1348 DISPLAYFBINFO *pFBInfo = &prgn->paFramebuffers[uScreenId];1349 1350 RT_ZERO(pFBInfo->dirtyRect);1351 }1352 }1353 1354 static void vbvaRgnDirtyRect(VBVADIRTYREGION *prgn, unsigned uScreenId, VBVACMDHDR *phdr)1355 {1356 LogSunlover(("x = %d, y = %d, w = %d, h = %d\n",1357 phdr->x, phdr->y, phdr->w, phdr->h));1358 1359 /*1360 * Here update rectangles are accumulated to form an update area.1361 * @todo1362 * Now the simplest method is used which builds one rectangle that1363 * includes all update areas. A bit more advanced method can be1364 * employed here. The method should be fast however.1365 */1366 if (phdr->w == 0 || phdr->h == 0)1367 {1368 /* Empty rectangle. */1369 return;1370 }1371 1372 int32_t xRight = phdr->x + phdr->w;1373 int32_t yBottom = phdr->y + phdr->h;1374 1375 DISPLAYFBINFO *pFBInfo = &prgn->paFramebuffers[uScreenId];1376 1377 if (pFBInfo->dirtyRect.xRight == 0)1378 {1379 /* This is the first rectangle to be added. */1380 pFBInfo->dirtyRect.xLeft = phdr->x;1381 pFBInfo->dirtyRect.yTop = phdr->y;1382 pFBInfo->dirtyRect.xRight = xRight;1383 pFBInfo->dirtyRect.yBottom = yBottom;1384 }1385 else1386 {1387 /* Adjust region coordinates. */1388 if (pFBInfo->dirtyRect.xLeft > phdr->x)1389 {1390 pFBInfo->dirtyRect.xLeft = phdr->x;1391 }1392 1393 if (pFBInfo->dirtyRect.yTop > phdr->y)1394 {1395 pFBInfo->dirtyRect.yTop = phdr->y;1396 }1397 1398 if (pFBInfo->dirtyRect.xRight < xRight)1399 {1400 pFBInfo->dirtyRect.xRight = xRight;1401 }1402 1403 if (pFBInfo->dirtyRect.yBottom < yBottom)1404 {1405 pFBInfo->dirtyRect.yBottom = yBottom;1406 }1407 }1408 1409 if (pFBInfo->fDefaultFormat)1410 {1411 //@todo pfnUpdateDisplayRect must take the vram offset parameter for the framebuffer1412 prgn->pPort->pfnUpdateDisplayRect(prgn->pPort, phdr->x, phdr->y, phdr->w, phdr->h);1413 prgn->pDisplay->i_handleDisplayUpdateLegacy(phdr->x + pFBInfo->xOrigin,1414 phdr->y + pFBInfo->yOrigin, phdr->w, phdr->h);1415 }1416 1417 return;1418 }1419 1420 static void vbvaRgnUpdateFramebuffer(VBVADIRTYREGION *prgn, unsigned uScreenId)1421 {1422 DISPLAYFBINFO *pFBInfo = &prgn->paFramebuffers[uScreenId];1423 1424 uint32_t w = pFBInfo->dirtyRect.xRight - pFBInfo->dirtyRect.xLeft;1425 uint32_t h = pFBInfo->dirtyRect.yBottom - pFBInfo->dirtyRect.yTop;1426 1427 if (!pFBInfo->fDefaultFormat && w != 0 && h != 0)1428 {1429 //@todo pfnUpdateDisplayRect must take the vram offset parameter for the framebuffer1430 prgn->pPort->pfnUpdateDisplayRect(prgn->pPort, pFBInfo->dirtyRect.xLeft, pFBInfo->dirtyRect.yTop, w, h);1431 prgn->pDisplay->i_handleDisplayUpdateLegacy(pFBInfo->dirtyRect.xLeft + pFBInfo->xOrigin,1432 pFBInfo->dirtyRect.yTop + pFBInfo->yOrigin, w, h);1433 }1434 }1435 1436 static void i_vbvaSetMemoryFlags(VBVAMEMORY *pVbvaMemory,1437 bool fVideoAccelEnabled,1438 bool fVideoAccelVRDP,1439 uint32_t fu32SupportedOrders,1440 DISPLAYFBINFO *paFBInfos,1441 unsigned cFBInfos)1442 {1443 if (pVbvaMemory)1444 {1445 /* This called only on changes in mode. So reset VRDP always. */1446 uint32_t fu32Flags = VBVA_F_MODE_VRDP_RESET;1447 1448 if (fVideoAccelEnabled)1449 {1450 fu32Flags |= VBVA_F_MODE_ENABLED;1451 1452 if (fVideoAccelVRDP)1453 {1454 fu32Flags |= VBVA_F_MODE_VRDP | VBVA_F_MODE_VRDP_ORDER_MASK;1455 1456 pVbvaMemory->fu32SupportedOrders = fu32SupportedOrders;1457 }1458 }1459 1460 pVbvaMemory->fu32ModeFlags = fu32Flags;1461 }1462 1463 unsigned uScreenId;1464 for (uScreenId = 0; uScreenId < cFBInfos; uScreenId++)1465 {1466 if (paFBInfos[uScreenId].pHostEvents)1467 {1468 paFBInfos[uScreenId].pHostEvents->fu32Events |= VBOX_VIDEO_INFO_HOST_EVENTS_F_VRDP_RESET;1469 }1470 }1471 }1472 1473 1271 #ifdef VBOX_WITH_HGSMI 1474 1272 static void vbvaSetMemoryFlagsHGSMI(unsigned uScreenId, … … 1514 1312 #endif /* VBOX_WITH_HGSMI */ 1515 1313 1516 bool Display::i_VideoAccelAllowed(void)1517 {1518 return true;1519 }1520 1521 int Display::videoAccelEnterVGA(void)1522 {1523 return RTSemXRoadsNSEnter(mhXRoadsVideoAccel);1524 }1525 1526 void Display::videoAccelLeaveVGA(void)1527 {1528 RTSemXRoadsNSLeave(mhXRoadsVideoAccel);1529 }1530 1531 int Display::videoAccelEnterVMMDev(void)1532 {1533 return RTSemXRoadsEWEnter(mhXRoadsVideoAccel);1534 }1535 1536 void Display::videoAccelLeaveVMMDev(void)1537 {1538 RTSemXRoadsEWLeave(mhXRoadsVideoAccel);1539 }1540 1541 1314 int Display::VideoAccelEnableVMMDev(bool fEnable, VBVAMEMORY *pVbvaMemory) 1542 1315 { 1543 1316 LogFlowFunc(("%d %p\n", fEnable, pVbvaMemory)); 1544 int rc = videoAccelEnterVMMDev( );1317 int rc = videoAccelEnterVMMDev(&mVideoAccelLegacy); 1545 1318 if (RT_SUCCESS(rc)) 1546 1319 { 1547 rc = i_VideoAccelEnable(fEnable, pVbvaMemory );1548 videoAccelLeaveVMMDev( );1320 rc = i_VideoAccelEnable(fEnable, pVbvaMemory, mpDrv->pUpPort); 1321 videoAccelLeaveVMMDev(&mVideoAccelLegacy); 1549 1322 } 1550 1323 LogFlowFunc(("leave %Rrc\n", rc)); … … 1555 1328 { 1556 1329 LogFlowFunc(("%d %p\n", fEnable, pVbvaMemory)); 1557 int rc = videoAccelEnterVGA( );1330 int rc = videoAccelEnterVGA(&mVideoAccelLegacy); 1558 1331 if (RT_SUCCESS(rc)) 1559 1332 { 1560 rc = i_VideoAccelEnable(fEnable, pVbvaMemory );1561 videoAccelLeaveVGA( );1333 rc = i_VideoAccelEnable(fEnable, pVbvaMemory, mpDrv->pUpPort); 1334 videoAccelLeaveVGA(&mVideoAccelLegacy); 1562 1335 } 1563 1336 LogFlowFunc(("leave %Rrc\n", rc)); … … 1568 1341 { 1569 1342 LogFlowFunc(("enter\n")); 1570 int rc = videoAccelEnterVMMDev( );1343 int rc = videoAccelEnterVMMDev(&mVideoAccelLegacy); 1571 1344 if (RT_SUCCESS(rc)) 1572 1345 { 1573 i_VideoAccelFlush( );1574 videoAccelLeaveVMMDev( );1346 i_VideoAccelFlush(mpDrv->pUpPort); 1347 videoAccelLeaveVMMDev(&mVideoAccelLegacy); 1575 1348 } 1576 1349 LogFlowFunc(("leave\n")); 1577 }1578 1579 /**1580 * @thread EMT1581 */1582 int Display::i_VideoAccelEnable(bool fEnable, VBVAMEMORY *pVbvaMemory)1583 {1584 int rc;1585 LogRelFlowFunc(("fEnable = %d\n", fEnable));1586 1587 rc = i_videoAccelEnable(fEnable, pVbvaMemory);1588 1589 LogRelFlowFunc(("%Rrc.\n", rc));1590 return rc;1591 }1592 1593 int Display::i_videoAccelEnable(bool fEnable, VBVAMEMORY *pVbvaMemory)1594 {1595 int rc = VINF_SUCCESS;1596 /* Called each time the guest wants to use acceleration,1597 * or when the VGA device disables acceleration,1598 * or when restoring the saved state with accel enabled.1599 *1600 * VGA device disables acceleration on each video mode change1601 * and on reset.1602 *1603 * Guest enabled acceleration at will. And it has to enable1604 * acceleration after a mode change.1605 */1606 LogRelFlowFunc(("mfVideoAccelEnabled = %d, fEnable = %d, pVbvaMemory = %p\n",1607 mfVideoAccelEnabled, fEnable, pVbvaMemory));1608 1609 /* Strictly check parameters. Callers must not pass anything in the case. */1610 Assert((fEnable && pVbvaMemory) || (!fEnable && pVbvaMemory == NULL));1611 1612 if (!i_VideoAccelAllowed ())1613 return VERR_NOT_SUPPORTED;1614 1615 /* Check that current status is not being changed */1616 if (mfVideoAccelEnabled == fEnable)1617 return rc;1618 1619 if (mfVideoAccelEnabled)1620 {1621 /* Process any pending orders and empty the VBVA ring buffer. */1622 i_videoAccelFlush ();1623 }1624 1625 if (!fEnable && mpVbvaMemory)1626 mpVbvaMemory->fu32ModeFlags &= ~VBVA_F_MODE_ENABLED;1627 1628 if (fEnable)1629 {1630 /* Process any pending VGA device changes, resize. */1631 mpDrv->pUpPort->pfnUpdateDisplayAll(mpDrv->pUpPort, /* fFailOnResize = */ false);1632 }1633 1634 /* Protect the videoaccel state transition. */1635 RTCritSectEnter(&mVideoAccelLock);1636 1637 if (fEnable)1638 {1639 mpVbvaMemory = pVbvaMemory;1640 mfVideoAccelEnabled = true;1641 1642 /* Initialize the hardware memory. */1643 i_vbvaSetMemoryFlags(mpVbvaMemory, mfVideoAccelEnabled, mfVideoAccelVRDP,1644 mfu32SupportedOrders, maFramebuffers, mcMonitors);1645 mpVbvaMemory->off32Data = 0;1646 mpVbvaMemory->off32Free = 0;1647 1648 memset(mpVbvaMemory->aRecords, 0, sizeof(mpVbvaMemory->aRecords));1649 mpVbvaMemory->indexRecordFirst = 0;1650 mpVbvaMemory->indexRecordFree = 0;1651 1652 LogRel(("VBVA: Enabled.\n"));1653 }1654 else1655 {1656 mpVbvaMemory = NULL;1657 mfVideoAccelEnabled = false;1658 1659 LogRel(("VBVA: Disabled.\n"));1660 }1661 1662 RTCritSectLeave(&mVideoAccelLock);1663 1664 if (!fEnable)1665 {1666 mpDrv->pUpPort->pfnUpdateDisplayAll(mpDrv->pUpPort, /* fFailOnResize = */ false);1667 }1668 1669 /* Notify the VMMDev, which saves VBVA status in the saved state,1670 * and needs to know current status.1671 */1672 VMMDev *pVMMDev = mParent->i_getVMMDev();1673 if (pVMMDev)1674 {1675 PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();1676 if (pVMMDevPort)1677 pVMMDevPort->pfnVBVAChange(pVMMDevPort, fEnable);1678 }1679 1680 LogRelFlowFunc(("%Rrc.\n", rc));1681 return rc;1682 1350 } 1683 1351 … … 1687 1355 { 1688 1356 LogRelFlowFunc(("fEnable = %d\n", fEnable)); 1357 1358 VIDEOACCEL *pVideoAccel = &mVideoAccelLegacy; 1689 1359 1690 1360 int c = fEnable? … … 1707 1377 mfu32SupportedOrders = 0; 1708 1378 1709 i_vbvaSetMemoryFlags( mpVbvaMemory, mfVideoAccelEnabled, mfVideoAccelVRDP, mfu32SupportedOrders,1379 i_vbvaSetMemoryFlags(pVideoAccel->pVbvaMemory, pVideoAccel->fVideoAccelEnabled, mfVideoAccelVRDP, mfu32SupportedOrders, 1710 1380 maFramebuffers, mcMonitors); 1711 1381 #ifdef VBOX_WITH_HGSMI … … 1727 1397 mfu32SupportedOrders = ~0; 1728 1398 1729 i_vbvaSetMemoryFlags( mpVbvaMemory, mfVideoAccelEnabled, mfVideoAccelVRDP, mfu32SupportedOrders,1399 i_vbvaSetMemoryFlags(pVideoAccel->pVbvaMemory, pVideoAccel->fVideoAccelEnabled, mfVideoAccelVRDP, mfu32SupportedOrders, 1730 1400 maFramebuffers, mcMonitors); 1731 1401 #ifdef VBOX_WITH_HGSMI … … 1745 1415 1746 1416 RTCritSectLeave(&mVideoAccelLock); 1747 }1748 1749 static bool i_vbvaVerifyRingBuffer(VBVAMEMORY *pVbvaMemory)1750 {1751 return true;1752 }1753 1754 static void i_vbvaFetchBytes(VBVAMEMORY *pVbvaMemory, uint8_t *pu8Dst, uint32_t cbDst)1755 {1756 if (cbDst >= VBVA_RING_BUFFER_SIZE)1757 {1758 AssertMsgFailed(("cbDst = 0x%08X, ring buffer size 0x%08X\n", cbDst, VBVA_RING_BUFFER_SIZE));1759 return;1760 }1761 1762 uint32_t u32BytesTillBoundary = VBVA_RING_BUFFER_SIZE - pVbvaMemory->off32Data;1763 uint8_t *src = &pVbvaMemory->au8RingBuffer[pVbvaMemory->off32Data];1764 int32_t i32Diff = cbDst - u32BytesTillBoundary;1765 1766 if (i32Diff <= 0)1767 {1768 /* Chunk will not cross buffer boundary. */1769 memcpy (pu8Dst, src, cbDst);1770 }1771 else1772 {1773 /* Chunk crosses buffer boundary. */1774 memcpy(pu8Dst, src, u32BytesTillBoundary);1775 memcpy(pu8Dst + u32BytesTillBoundary, &pVbvaMemory->au8RingBuffer[0], i32Diff);1776 }1777 1778 /* Advance data offset. */1779 pVbvaMemory->off32Data = (pVbvaMemory->off32Data + cbDst) % VBVA_RING_BUFFER_SIZE;1780 1781 return;1782 }1783 1784 1785 static bool i_vbvaPartialRead(uint8_t **ppu8, uint32_t *pcb, uint32_t cbRecord, VBVAMEMORY *pVbvaMemory)1786 {1787 uint8_t *pu8New;1788 1789 LogFlow(("MAIN::DisplayImpl::vbvaPartialRead: p = %p, cb = %d, cbRecord 0x%08X\n",1790 *ppu8, *pcb, cbRecord));1791 1792 if (*ppu8)1793 {1794 Assert (*pcb);1795 pu8New = (uint8_t *)RTMemRealloc(*ppu8, cbRecord);1796 }1797 else1798 {1799 Assert (!*pcb);1800 pu8New = (uint8_t *)RTMemAlloc(cbRecord);1801 }1802 1803 if (!pu8New)1804 {1805 /* Memory allocation failed, fail the function. */1806 Log(("MAIN::vbvaPartialRead: failed to (re)alocate memory for partial record!!! cbRecord 0x%08X\n",1807 cbRecord));1808 1809 if (*ppu8)1810 {1811 RTMemFree(*ppu8);1812 }1813 1814 *ppu8 = NULL;1815 *pcb = 0;1816 1817 return false;1818 }1819 1820 /* Fetch data from the ring buffer. */1821 i_vbvaFetchBytes(pVbvaMemory, pu8New + *pcb, cbRecord - *pcb);1822 1823 *ppu8 = pu8New;1824 *pcb = cbRecord;1825 1826 return true;1827 }1828 1829 /* For contiguous chunks just return the address in the buffer.1830 * For crossing boundary - allocate a buffer from heap.1831 */1832 bool Display::i_vbvaFetchCmd(VBVACMDHDR **ppHdr, uint32_t *pcbCmd)1833 {1834 uint32_t indexRecordFirst = mpVbvaMemory->indexRecordFirst;1835 uint32_t indexRecordFree = mpVbvaMemory->indexRecordFree;1836 1837 #ifdef DEBUG_sunlover1838 LogFlowFunc(("first = %d, free = %d\n",1839 indexRecordFirst, indexRecordFree));1840 #endif /* DEBUG_sunlover */1841 1842 if (!i_vbvaVerifyRingBuffer(mpVbvaMemory))1843 {1844 return false;1845 }1846 1847 if (indexRecordFirst == indexRecordFree)1848 {1849 /* No records to process. Return without assigning output variables. */1850 return true;1851 }1852 1853 VBVARECORD *pRecord = &mpVbvaMemory->aRecords[indexRecordFirst];1854 1855 #ifdef DEBUG_sunlover1856 LogFlowFunc(("cbRecord = 0x%08X\n", pRecord->cbRecord));1857 #endif /* DEBUG_sunlover */1858 1859 uint32_t cbRecord = pRecord->cbRecord & ~VBVA_F_RECORD_PARTIAL;1860 1861 if (mcbVbvaPartial)1862 {1863 /* There is a partial read in process. Continue with it. */1864 1865 Assert(mpu8VbvaPartial);1866 1867 LogFlowFunc(("continue partial record mcbVbvaPartial = %d cbRecord 0x%08X, first = %d, free = %d\n",1868 mcbVbvaPartial, pRecord->cbRecord, indexRecordFirst, indexRecordFree));1869 1870 if (cbRecord > mcbVbvaPartial)1871 {1872 /* New data has been added to the record. */1873 if (!i_vbvaPartialRead(&mpu8VbvaPartial, &mcbVbvaPartial, cbRecord, mpVbvaMemory))1874 {1875 return false;1876 }1877 }1878 1879 if (!(pRecord->cbRecord & VBVA_F_RECORD_PARTIAL))1880 {1881 /* The record is completed by guest. Return it to the caller. */1882 *ppHdr = (VBVACMDHDR *)mpu8VbvaPartial;1883 *pcbCmd = mcbVbvaPartial;1884 1885 mpu8VbvaPartial = NULL;1886 mcbVbvaPartial = 0;1887 1888 /* Advance the record index. */1889 mpVbvaMemory->indexRecordFirst = (indexRecordFirst + 1) % VBVA_MAX_RECORDS;1890 1891 #ifdef DEBUG_sunlover1892 LogFlowFunc(("partial done ok, data = %d, free = %d\n",1893 mpVbvaMemory->off32Data, mpVbvaMemory->off32Free));1894 #endif /* DEBUG_sunlover */1895 }1896 1897 return true;1898 }1899 1900 /* A new record need to be processed. */1901 if (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL)1902 {1903 /* Current record is being written by guest. '=' is important here. */1904 if (cbRecord >= VBVA_RING_BUFFER_SIZE - VBVA_RING_BUFFER_THRESHOLD)1905 {1906 /* Partial read must be started. */1907 if (!i_vbvaPartialRead(&mpu8VbvaPartial, &mcbVbvaPartial, cbRecord, mpVbvaMemory))1908 {1909 return false;1910 }1911 1912 LogFlowFunc(("started partial record mcbVbvaPartial = 0x%08X cbRecord 0x%08X, first = %d, free = %d\n",1913 mcbVbvaPartial, pRecord->cbRecord, indexRecordFirst, indexRecordFree));1914 }1915 1916 return true;1917 }1918 1919 /* Current record is complete. If it is not empty, process it. */1920 if (cbRecord)1921 {1922 /* The size of largest contiguous chunk in the ring biffer. */1923 uint32_t u32BytesTillBoundary = VBVA_RING_BUFFER_SIZE - mpVbvaMemory->off32Data;1924 1925 /* The ring buffer pointer. */1926 uint8_t *au8RingBuffer = &mpVbvaMemory->au8RingBuffer[0];1927 1928 /* The pointer to data in the ring buffer. */1929 uint8_t *src = &au8RingBuffer[mpVbvaMemory->off32Data];1930 1931 /* Fetch or point the data. */1932 if (u32BytesTillBoundary >= cbRecord)1933 {1934 /* The command does not cross buffer boundary. Return address in the buffer. */1935 *ppHdr = (VBVACMDHDR *)src;1936 1937 /* Advance data offset. */1938 mpVbvaMemory->off32Data = (mpVbvaMemory->off32Data + cbRecord) % VBVA_RING_BUFFER_SIZE;1939 }1940 else1941 {1942 /* The command crosses buffer boundary. Rare case, so not optimized. */1943 uint8_t *dst = (uint8_t *)RTMemAlloc(cbRecord);1944 1945 if (!dst)1946 {1947 LogRelFlowFunc(("could not allocate %d bytes from heap!!!\n", cbRecord));1948 mpVbvaMemory->off32Data = (mpVbvaMemory->off32Data + cbRecord) % VBVA_RING_BUFFER_SIZE;1949 return false;1950 }1951 1952 i_vbvaFetchBytes(mpVbvaMemory, dst, cbRecord);1953 1954 *ppHdr = (VBVACMDHDR *)dst;1955 1956 #ifdef DEBUG_sunlover1957 LogFlowFunc(("Allocated from heap %p\n", dst));1958 #endif /* DEBUG_sunlover */1959 }1960 }1961 1962 *pcbCmd = cbRecord;1963 1964 /* Advance the record index. */1965 mpVbvaMemory->indexRecordFirst = (indexRecordFirst + 1) % VBVA_MAX_RECORDS;1966 1967 #ifdef DEBUG_sunlover1968 LogFlowFunc(("done ok, data = %d, free = %d\n",1969 mpVbvaMemory->off32Data, mpVbvaMemory->off32Free));1970 #endif /* DEBUG_sunlover */1971 1972 return true;1973 }1974 1975 void Display::i_vbvaReleaseCmd(VBVACMDHDR *pHdr, int32_t cbCmd)1976 {1977 uint8_t *au8RingBuffer = mpVbvaMemory->au8RingBuffer;1978 1979 if ( (uint8_t *)pHdr >= au8RingBuffer1980 && (uint8_t *)pHdr < &au8RingBuffer[VBVA_RING_BUFFER_SIZE])1981 {1982 /* The pointer is inside ring buffer. Must be continuous chunk. */1983 Assert(VBVA_RING_BUFFER_SIZE - ((uint8_t *)pHdr - au8RingBuffer) >= cbCmd);1984 1985 /* Do nothing. */1986 1987 Assert(!mpu8VbvaPartial && mcbVbvaPartial == 0);1988 }1989 else1990 {1991 /* The pointer is outside. It is then an allocated copy. */1992 1993 #ifdef DEBUG_sunlover1994 LogFlowFunc(("Free heap %p\n", pHdr));1995 #endif /* DEBUG_sunlover */1996 1997 if ((uint8_t *)pHdr == mpu8VbvaPartial)1998 {1999 mpu8VbvaPartial = NULL;2000 mcbVbvaPartial = 0;2001 }2002 else2003 {2004 Assert(!mpu8VbvaPartial && mcbVbvaPartial == 0);2005 }2006 2007 RTMemFree(pHdr);2008 }2009 2010 return;2011 }2012 2013 2014 /**2015 * Called regularly on the DisplayRefresh timer.2016 * Also on behalf of guest, when the ring buffer is full.2017 *2018 * @thread EMT2019 */2020 void Display::i_VideoAccelFlush(void)2021 {2022 int rc = i_videoAccelFlush();2023 if (RT_FAILURE(rc))2024 {2025 /* Disable on errors. */2026 i_videoAccelEnable(false, NULL);2027 }2028 2029 if (RT_FAILURE(rc))2030 {2031 /* VideoAccel was disabled because of a failure, switching back to VGA updates. Redraw the screen. */2032 mpDrv->pUpPort->pfnUpdateDisplayAll(mpDrv->pUpPort, /* fFailOnResize = */ false);2033 }2034 }2035 2036 int Display::i_videoAccelFlush(void)2037 {2038 #ifdef DEBUG_sunlover_22039 LogFlowFunc(("mfVideoAccelEnabled = %d\n", mfVideoAccelEnabled));2040 #endif /* DEBUG_sunlover_2 */2041 2042 if (!mfVideoAccelEnabled)2043 {2044 Log(("Display::VideoAccelFlush: called with disabled VBVA!!! Ignoring.\n"));2045 return VINF_SUCCESS;2046 }2047 2048 /* Here VBVA is enabled and we have the accelerator memory pointer. */2049 Assert(mpVbvaMemory);2050 2051 #ifdef DEBUG_sunlover_22052 LogFlowFunc(("indexRecordFirst = %d, indexRecordFree = %d, off32Data = %d, off32Free = %d\n",2053 mpVbvaMemory->indexRecordFirst, mpVbvaMemory->indexRecordFree,2054 mpVbvaMemory->off32Data, mpVbvaMemory->off32Free));2055 #endif /* DEBUG_sunlover_2 */2056 2057 /* Quick check for "nothing to update" case. */2058 if (mpVbvaMemory->indexRecordFirst == mpVbvaMemory->indexRecordFree)2059 {2060 return VINF_SUCCESS;2061 }2062 2063 /* Process the ring buffer */2064 unsigned uScreenId;2065 2066 /* Initialize dirty rectangles accumulator. */2067 VBVADIRTYREGION rgn;2068 vbvaRgnInit(&rgn, maFramebuffers, mcMonitors, this, mpDrv->pUpPort);2069 2070 for (;;)2071 {2072 VBVACMDHDR *phdr = NULL;2073 uint32_t cbCmd = ~0;2074 2075 /* Fetch the command data. */2076 if (!i_vbvaFetchCmd(&phdr, &cbCmd))2077 {2078 Log(("Display::VideoAccelFlush: unable to fetch command. off32Data = %d, off32Free = %d. Disabling VBVA!!!\n",2079 mpVbvaMemory->off32Data, mpVbvaMemory->off32Free));2080 return VERR_INVALID_STATE;2081 }2082 2083 if (cbCmd == uint32_t(~0))2084 {2085 /* No more commands yet in the queue. */2086 break;2087 }2088 2089 if (cbCmd != 0)2090 {2091 #ifdef DEBUG_sunlover2092 LogFlowFunc(("hdr: cbCmd = %d, x=%d, y=%d, w=%d, h=%d\n",2093 cbCmd, phdr->x, phdr->y, phdr->w, phdr->h));2094 #endif /* DEBUG_sunlover */2095 2096 VBVACMDHDR hdrSaved = *phdr;2097 2098 int x = phdr->x;2099 int y = phdr->y;2100 int w = phdr->w;2101 int h = phdr->h;2102 2103 uScreenId = mapCoordsToScreen(maFramebuffers, mcMonitors, &x, &y, &w, &h);2104 2105 phdr->x = (int16_t)x;2106 phdr->y = (int16_t)y;2107 phdr->w = (uint16_t)w;2108 phdr->h = (uint16_t)h;2109 2110 DISPLAYFBINFO *pFBInfo = &maFramebuffers[uScreenId];2111 2112 /* Handle the command.2113 *2114 * Guest is responsible for updating the guest video memory.2115 * The Windows guest does all drawing using Eng*.2116 *2117 * For local output, only dirty rectangle information is used2118 * to update changed areas.2119 *2120 * Dirty rectangles are accumulated to exclude overlapping updates and2121 * group small updates to a larger one.2122 */2123 2124 /* Accumulate the update. */2125 vbvaRgnDirtyRect(&rgn, uScreenId, phdr);2126 2127 /* Forward the command to VRDP server. */2128 mParent->i_consoleVRDPServer()->SendUpdate(uScreenId, phdr, cbCmd);2129 2130 *phdr = hdrSaved;2131 }2132 2133 i_vbvaReleaseCmd(phdr, cbCmd);2134 }2135 2136 for (uScreenId = 0; uScreenId < mcMonitors; uScreenId++)2137 {2138 /* Draw the framebuffer. */2139 vbvaRgnUpdateFramebuffer(&rgn, uScreenId);2140 }2141 return VINF_SUCCESS;2142 }2143 2144 int Display::i_videoAccelRefreshProcess(void)2145 {2146 int rc = VWRN_INVALID_STATE; /* Default is to do a display update in VGA device. */2147 2148 videoAccelEnterVGA();2149 2150 if (mfVideoAccelEnabled)2151 {2152 Assert(mpVbvaMemory);2153 rc = i_videoAccelFlush();2154 if (RT_FAILURE(rc))2155 {2156 /* Disable on errors. */2157 i_videoAccelEnable(false, NULL);2158 rc = VWRN_INVALID_STATE; /* Do a display update in VGA device. */2159 }2160 else2161 {2162 rc = VINF_SUCCESS;2163 }2164 }2165 2166 videoAccelLeaveVGA();2167 2168 return rc;2169 1417 } 2170 1418 … … 3626 2874 3627 2875 #ifdef DEBUG_sunlover 3628 LogFlowFunc((" mfVideoAccelEnabled = %d, %d,%d %dx%d\n",3629 pDrv->pDisplay->m fVideoAccelEnabled, x, y, cx, cy));2876 LogFlowFunc(("fVideoAccelEnabled = %d, %d,%d %dx%d\n", 2877 pDrv->pDisplay->mVideoAccelLegacy.fVideoAccelEnabled, x, y, cx, cy)); 3630 2878 #endif /* DEBUG_sunlover */ 3631 2879 … … 3656 2904 unsigned uScreenId; 3657 2905 3658 int rc = pDisplay->i_videoAccelRefreshProcess( );2906 int rc = pDisplay->i_videoAccelRefreshProcess(pDrv->pUpPort); 3659 2907 if (rc != VINF_TRY_AGAIN) /* Means 'do nothing' here. */ 3660 2908 { … … 3812 3060 { 3813 3061 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface); 3814 3815 if (pvVRAM == NULL) 3816 { 3817 unsigned i; 3818 for (i = 0; i < pDrv->pDisplay->mcMonitors; i++) 3819 { 3820 DISPLAYFBINFO *pFBInfo = &pDrv->pDisplay->maFramebuffers[i]; 3821 3822 pFBInfo->u32Offset = 0; 3823 pFBInfo->u32MaxFramebufferSize = 0; 3824 pFBInfo->u32InformationSize = 0; 3825 } 3826 } 3827 #ifndef VBOX_WITH_HGSMI 3828 else 3829 { 3830 uint8_t *pu8 = (uint8_t *)pvVRAM; 3831 pu8 += u32VRAMSize - VBOX_VIDEO_ADAPTER_INFORMATION_SIZE; 3832 3833 // @todo 3834 uint8_t *pu8End = pu8 + VBOX_VIDEO_ADAPTER_INFORMATION_SIZE; 3835 3836 VBOXVIDEOINFOHDR *pHdr; 3837 3838 for (;;) 3839 { 3840 pHdr = (VBOXVIDEOINFOHDR *)pu8; 3841 pu8 += sizeof(VBOXVIDEOINFOHDR); 3842 3843 if (pu8 >= pu8End) 3844 { 3845 LogRel(("VBoxVideo: Guest adapter information overflow!!!\n")); 3846 break; 3847 } 3848 3849 if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_DISPLAY) 3850 { 3851 if (pHdr->u16Length != sizeof(VBOXVIDEOINFODISPLAY)) 3852 { 3853 LogRel(("VBoxVideo: Guest adapter information %s invalid length %d!!!\n", "DISPLAY", pHdr->u16Length)); 3854 break; 3855 } 3856 3857 VBOXVIDEOINFODISPLAY *pDisplay = (VBOXVIDEOINFODISPLAY *)pu8; 3858 3859 if (pDisplay->u32Index >= pDrv->pDisplay->mcMonitors) 3860 { 3861 LogRel(("VBoxVideo: Guest adapter information invalid display index %d!!!\n", pDisplay->u32Index)); 3862 break; 3863 } 3864 3865 DISPLAYFBINFO *pFBInfo = &pDrv->pDisplay->maFramebuffers[pDisplay->u32Index]; 3866 3867 pFBInfo->u32Offset = pDisplay->u32Offset; 3868 pFBInfo->u32MaxFramebufferSize = pDisplay->u32FramebufferSize; 3869 pFBInfo->u32InformationSize = pDisplay->u32InformationSize; 3870 3871 LogRelFlow(("VBOX_VIDEO_INFO_TYPE_DISPLAY: %d: at 0x%08X, size 0x%08X, info 0x%08X\n", pDisplay->u32Index, 3872 pDisplay->u32Offset, pDisplay->u32FramebufferSize, pDisplay->u32InformationSize)); 3873 } 3874 else if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_QUERY_CONF32) 3875 { 3876 if (pHdr->u16Length != sizeof(VBOXVIDEOINFOQUERYCONF32)) 3877 { 3878 LogRel(("VBoxVideo: Guest adapter information %s invalid length %d!!!\n", "CONF32", pHdr->u16Length)); 3879 break; 3880 } 3881 3882 VBOXVIDEOINFOQUERYCONF32 *pConf32 = (VBOXVIDEOINFOQUERYCONF32 *)pu8; 3883 3884 switch (pConf32->u32Index) 3885 { 3886 case VBOX_VIDEO_QCI32_MONITOR_COUNT: 3887 { 3888 pConf32->u32Value = pDrv->pDisplay->mcMonitors; 3889 } break; 3890 3891 case VBOX_VIDEO_QCI32_OFFSCREEN_HEAP_SIZE: 3892 { 3893 /* @todo make configurable. */ 3894 pConf32->u32Value = _1M; 3895 } break; 3896 3897 default: 3898 LogRel(("VBoxVideo: CONF32 %d not supported!!! Skipping.\n", pConf32->u32Index)); 3899 } 3900 } 3901 else if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_END) 3902 { 3903 if (pHdr->u16Length != 0) 3904 { 3905 LogRel(("VBoxVideo: Guest adapter information %s invalid length %d!!!\n", "END", pHdr->u16Length)); 3906 break; 3907 } 3908 3909 break; 3910 } 3911 else if (pHdr->u8Type != VBOX_VIDEO_INFO_TYPE_NV_HEAP) 3912 { 3913 /** @todo why is Additions/WINNT/Graphics/Miniport/VBoxVideo. cpp pushing this to us? */ 3914 LogRel(("Guest adapter information contains unsupported type %d. The block has been skipped.\n", pHdr->u8Type)); 3915 } 3916 3917 pu8 += pHdr->u16Length; 3918 } 3919 } 3920 #endif /* !VBOX_WITH_HGSMI */ 3062 pDrv->pDisplay->processAdapterData(pvVRAM, u32VRAMSize); 3921 3063 } 3922 3064 … … 3930 3072 { 3931 3073 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface); 3932 3933 if (uScreenId >= pDrv->pDisplay->mcMonitors) 3934 { 3935 LogRel(("VBoxVideo: Guest display information invalid display index %d!!!\n", uScreenId)); 3936 return; 3937 } 3938 3939 /* Get the display information structure. */ 3940 DISPLAYFBINFO *pFBInfo = &pDrv->pDisplay->maFramebuffers[uScreenId]; 3941 3942 uint8_t *pu8 = (uint8_t *)pvVRAM; 3943 pu8 += pFBInfo->u32Offset + pFBInfo->u32MaxFramebufferSize; 3944 3945 // @todo 3946 uint8_t *pu8End = pu8 + pFBInfo->u32InformationSize; 3947 3948 VBOXVIDEOINFOHDR *pHdr; 3949 3950 for (;;) 3951 { 3952 pHdr = (VBOXVIDEOINFOHDR *)pu8; 3953 pu8 += sizeof(VBOXVIDEOINFOHDR); 3954 3955 if (pu8 >= pu8End) 3956 { 3957 LogRel(("VBoxVideo: Guest display information overflow!!!\n")); 3958 break; 3959 } 3960 3961 if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_SCREEN) 3962 { 3963 if (pHdr->u16Length != sizeof(VBOXVIDEOINFOSCREEN)) 3964 { 3965 LogRel(("VBoxVideo: Guest display information %s invalid length %d!!!\n", "SCREEN", pHdr->u16Length)); 3966 break; 3967 } 3968 3969 VBOXVIDEOINFOSCREEN *pScreen = (VBOXVIDEOINFOSCREEN *)pu8; 3970 3971 pFBInfo->xOrigin = pScreen->xOrigin; 3972 pFBInfo->yOrigin = pScreen->yOrigin; 3973 3974 pFBInfo->w = pScreen->u16Width; 3975 pFBInfo->h = pScreen->u16Height; 3976 3977 LogRelFlow(("VBOX_VIDEO_INFO_TYPE_SCREEN: (%p) %d: at %d,%d, linesize 0x%X, size %dx%d, bpp %d, flags 0x%02X\n", 3978 pHdr, uScreenId, pScreen->xOrigin, pScreen->yOrigin, pScreen->u32LineSize, pScreen->u16Width, 3979 pScreen->u16Height, pScreen->bitsPerPixel, pScreen->u8Flags)); 3980 3981 if (uScreenId != VBOX_VIDEO_PRIMARY_SCREEN) 3982 { 3983 /* Primary screen resize is eeeeeeeee by the VGA device. */ 3984 if (pFBInfo->fDisabled) 3985 { 3986 pFBInfo->fDisabled = false; 3987 fireGuestMonitorChangedEvent(pDrv->pDisplay->mParent->i_getEventSource(), 3988 GuestMonitorChangedEventType_Enabled, 3989 uScreenId, 3990 pFBInfo->xOrigin, pFBInfo->yOrigin, 3991 pFBInfo->w, pFBInfo->h); 3992 } 3993 3994 pDrv->pDisplay->i_handleDisplayResize(uScreenId, pScreen->bitsPerPixel, 3995 (uint8_t *)pvVRAM + pFBInfo->u32Offset, 3996 pScreen->u32LineSize, 3997 pScreen->u16Width, pScreen->u16Height, 3998 VBVA_SCREEN_F_ACTIVE); 3999 } 4000 } 4001 else if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_END) 4002 { 4003 if (pHdr->u16Length != 0) 4004 { 4005 LogRel(("VBoxVideo: Guest adapter information %s invalid length %d!!!\n", "END", pHdr->u16Length)); 4006 break; 4007 } 4008 4009 break; 4010 } 4011 else if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_HOST_EVENTS) 4012 { 4013 if (pHdr->u16Length != sizeof(VBOXVIDEOINFOHOSTEVENTS)) 4014 { 4015 LogRel(("VBoxVideo: Guest display information %s invalid length %d!!!\n", "HOST_EVENTS", pHdr->u16Length)); 4016 break; 4017 } 4018 4019 VBOXVIDEOINFOHOSTEVENTS *pHostEvents = (VBOXVIDEOINFOHOSTEVENTS *)pu8; 4020 4021 pFBInfo->pHostEvents = pHostEvents; 4022 4023 LogFlow(("VBOX_VIDEO_INFO_TYPE_HOSTEVENTS: (%p)\n", 4024 pHostEvents)); 4025 } 4026 else if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_LINK) 4027 { 4028 if (pHdr->u16Length != sizeof(VBOXVIDEOINFOLINK)) 4029 { 4030 LogRel(("VBoxVideo: Guest adapter information %s invalid length %d!!!\n", "LINK", pHdr->u16Length)); 4031 break; 4032 } 4033 4034 VBOXVIDEOINFOLINK *pLink = (VBOXVIDEOINFOLINK *)pu8; 4035 pu8 += pLink->i32Offset; 4036 } 4037 else 4038 { 4039 LogRel(("Guest display information contains unsupported type %d\n", pHdr->u8Type)); 4040 } 4041 4042 pu8 += pHdr->u16Length; 4043 } 3074 pDrv->pDisplay->processDisplayData(pvVRAM, uScreenId); 4044 3075 } 4045 3076 … … 4604 3635 " pFBInfo->pHostEvents %p\n" 4605 3636 " pFBInfo->fDefaultFormat %d\n" 4606 " dirtyRect %d-%d %d-%d\n"4607 3637 " pFBInfo->fVBVAEnabled %d\n" 4608 3638 " pFBInfo->fVBVAForceResize %d\n" … … 4637 3667 pFBInfo->pHostEvents, 4638 3668 pFBInfo->fDefaultFormat, 4639 pFBInfo->dirtyRect.xLeft,4640 pFBInfo->dirtyRect.xRight,4641 pFBInfo->dirtyRect.yTop,4642 pFBInfo->dirtyRect.yBottom,4643 3669 pFBInfo->fVBVAEnabled, 4644 3670 pFBInfo->fVBVAForceResize, -
TabularUnified trunk/src/VBox/Main/src-client/DisplayImplLegacy.cpp ¶
r52667 r52769 1 1 /* $Id$ */ 2 2 /** @file 3 * VirtualBox COM class implementation 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. 4 7 */ 5 8 … … 17 20 18 21 #include "DisplayImpl.h" 19 #include "DisplayUtils.h"20 22 #include "ConsoleImpl.h" 21 23 #include "ConsoleVRDPServer.h" 22 24 #include "VMMDev.h" 23 25 24 #include "AutoCaller.h"25 26 #include "Logging.h" 26 27 … … 28 29 #include "VBoxEvents.h" 29 30 30 #include <iprt/semaphore.h> 31 #include <iprt/thread.h> 32 #include <iprt/asm.h> 33 #include <iprt/time.h> 34 #include <iprt/cpp/utils.h> 35 #include <iprt/alloca.h> 36 37 #include <VBox/vmm/pdmdrv.h> 38 #if defined(DEBUG) || defined(VBOX_STRICT) /* for VM_ASSERT_EMT(). */ 39 # include <VBox/vmm/vm.h> 40 #endif 41 42 #ifdef VBOX_WITH_VIDEOHWACCEL 43 # include <VBox/VBoxVideo.h> 44 #endif 45 46 #if defined(VBOX_WITH_CROGL) || defined(VBOX_WITH_CRHGSMI) 47 # include <VBox/HostServices/VBoxCrOpenGLSvc.h> 48 #endif 49 50 #include <VBox/com/array.h> 51 52 #ifdef VBOX_WITH_VPX 53 # include <iprt/path.h> 54 # include "VideoRec.h" 55 #endif 56 57 #ifdef VBOX_WITH_CROGL 58 typedef enum 59 { 60 CRVREC_STATE_IDLE, 61 CRVREC_STATE_SUBMITTED 62 } CRVREC_STATE; 63 #endif 64 65 /** 66 * Display driver instance data. 67 * 68 * @implements PDMIDISPLAYCONNECTOR 69 */ 70 typedef struct DRVMAINDISPLAY 71 { 72 /** Pointer to the display object. */ 73 Display *pDisplay; 74 /** Pointer to the driver instance structure. */ 75 PPDMDRVINS pDrvIns; 76 /** Pointer to the keyboard port interface of the driver/device above us. */ 77 PPDMIDISPLAYPORT pUpPort; 78 /** Our display connector interface. */ 79 PDMIDISPLAYCONNECTOR IConnector; 80 #if defined(VBOX_WITH_VIDEOHWACCEL) || defined(VBOX_WITH_CRHGSMI) 81 /** VBVA callbacks */ 82 PPDMIDISPLAYVBVACALLBACKS pVBVACallbacks; 83 #endif 84 } DRVMAINDISPLAY, *PDRVMAINDISPLAY; 85 86 /** Converts PDMIDISPLAYCONNECTOR pointer to a DRVMAINDISPLAY pointer. */ 87 #define PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface) RT_FROM_MEMBER(pInterface, DRVMAINDISPLAY, IConnector) 88 89 // constructor / destructor 90 ///////////////////////////////////////////////////////////////////////////// 91 92 Display::Display() 93 : mParent(NULL) 94 { 95 } 96 97 Display::~Display() 98 { 99 } 100 101 102 HRESULT Display::FinalConstruct() 103 { 104 mpVbvaMemory = NULL; 105 mfVideoAccelEnabled = false; 106 mfVideoAccelVRDP = false; 107 mfu32SupportedOrders = 0; 108 mcVideoAccelVRDPRefs = 0; 109 110 #ifdef VBOX_WITH_CROGL 111 mfCrOglDataHidden = false; 112 #endif 113 114 mpu8VbvaPartial = NULL; 115 mcbVbvaPartial = 0; 116 117 mpDrv = NULL; 118 mpVMMDev = NULL; 119 mfVMMDevInited = false; 120 121 int rc = RTCritSectInit(&mVideoAccelLock); 31 32 int 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); 122 42 AssertRC(rc); 123 43 124 mhXRoadsVideoAccel = NIL_RTSEMXROADS;125 rc = RTSemXRoadsCreate(&mhXRoadsVideoAccel);126 AssertRC(rc);127 128 #ifdef VBOX_WITH_HGSMI129 mu32UpdateVBVAFlags = 0;130 #endif131 #ifdef VBOX_WITH_VPX132 mpVideoRecCtx = NULL;133 for (unsigned i = 0; i < RT_ELEMENTS(maVideoRecEnabled); i++)134 maVideoRecEnabled[i] = true;135 #endif136 137 #ifdef VBOX_WITH_CRHGSMI138 mhCrOglSvc = NULL;139 rc = RTCritSectRwInit(&mCrOglLock);140 AssertRC(rc);141 #endif142 #ifdef VBOX_WITH_CROGL143 RT_ZERO(mCrOglCallbacks);144 RT_ZERO(mCrOglScreenshotData);145 mfCrOglVideoRecState = CRVREC_STATE_IDLE;146 mCrOglScreenshotData.u32Screen = CRSCREEN_ALL;147 mCrOglScreenshotData.pvContext = this;148 mCrOglScreenshotData.pfnScreenshotBegin = i_displayCrVRecScreenshotBegin;149 mCrOglScreenshotData.pfnScreenshotPerform = i_displayCrVRecScreenshotPerform;150 mCrOglScreenshotData.pfnScreenshotEnd = i_displayCrVRecScreenshotEnd;151 #endif152 153 return BaseFinalConstruct();154 }155 156 void Display::FinalRelease()157 {158 uninit();159 160 RTSemXRoadsDestroy(mhXRoadsVideoAccel);161 162 if (RTCritSectIsInitialized(&mVideoAccelLock))163 {164 RTCritSectDelete(&mVideoAccelLock);165 RT_ZERO(mVideoAccelLock);166 }167 168 #ifdef VBOX_WITH_CRHGSMI169 if (RTCritSectRwIsInitialized (&mCrOglLock))170 {171 RTCritSectRwDelete (&mCrOglLock);172 RT_ZERO(mCrOglLock);173 }174 #endif175 BaseFinalRelease();176 }177 178 // public initializer/uninitializer for internal purposes only179 /////////////////////////////////////////////////////////////////////////////180 181 #define kMaxSizeThumbnail 64182 183 /**184 * Save thumbnail and screenshot of the guest screen.185 */186 static int displayMakeThumbnail(uint8_t *pu8Data, uint32_t cx, uint32_t cy,187 uint8_t **ppu8Thumbnail, uint32_t *pcbThumbnail, uint32_t *pcxThumbnail, uint32_t *pcyThumbnail)188 {189 int rc = VINF_SUCCESS;190 191 uint8_t *pu8Thumbnail = NULL;192 uint32_t cbThumbnail = 0;193 uint32_t cxThumbnail = 0;194 uint32_t cyThumbnail = 0;195 196 if (cx > cy)197 {198 cxThumbnail = kMaxSizeThumbnail;199 cyThumbnail = (kMaxSizeThumbnail * cy) / cx;200 }201 else202 {203 cyThumbnail = kMaxSizeThumbnail;204 cxThumbnail = (kMaxSizeThumbnail * cx) / cy;205 }206 207 LogRelFlowFunc(("%dx%d -> %dx%d\n", cx, cy, cxThumbnail, cyThumbnail));208 209 cbThumbnail = cxThumbnail * 4 * cyThumbnail;210 pu8Thumbnail = (uint8_t *)RTMemAlloc(cbThumbnail);211 212 if (pu8Thumbnail)213 {214 uint8_t *dst = pu8Thumbnail;215 uint8_t *src = pu8Data;216 int dstW = cxThumbnail;217 int dstH = cyThumbnail;218 int srcW = cx;219 int srcH = cy;220 int iDeltaLine = cx * 4;221 222 BitmapScale32(dst,223 dstW, dstH,224 src,225 iDeltaLine,226 srcW, srcH);227 228 *ppu8Thumbnail = pu8Thumbnail;229 *pcbThumbnail = cbThumbnail;230 *pcxThumbnail = cxThumbnail;231 *pcyThumbnail = cyThumbnail;232 }233 else234 {235 rc = VERR_NO_MEMORY;236 }237 238 44 return rc; 239 45 } 240 46 241 #ifdef VBOX_WITH_CROGL 242 typedef struct 243 { 244 CRVBOXHGCMTAKESCREENSHOT Base; 245 246 /* 32bpp small RGB image. */ 247 uint8_t *pu8Thumbnail; 248 uint32_t cbThumbnail; 249 uint32_t cxThumbnail; 250 uint32_t cyThumbnail; 251 252 /* PNG screenshot. */ 253 uint8_t *pu8PNG; 254 uint32_t cbPNG; 255 uint32_t cxPNG; 256 uint32_t cyPNG; 257 } VBOX_DISPLAY_SAVESCREENSHOT_DATA; 258 259 static DECLCALLBACK(void) displaySaveScreenshotReport(void *pvCtx, uint32_t uScreen, 260 uint32_t x, uint32_t y, uint32_t uBitsPerPixel, 261 uint32_t uBytesPerLine, uint32_t uGuestWidth, uint32_t uGuestHeight, 262 uint8_t *pu8BufferAddress, uint64_t u64TimeStamp) 263 { 264 VBOX_DISPLAY_SAVESCREENSHOT_DATA *pData = (VBOX_DISPLAY_SAVESCREENSHOT_DATA*)pvCtx; 265 displayMakeThumbnail(pu8BufferAddress, uGuestWidth, uGuestHeight, &pData->pu8Thumbnail, 266 &pData->cbThumbnail, &pData->cxThumbnail, &pData->cyThumbnail); 267 int rc = DisplayMakePNG(pu8BufferAddress, uGuestWidth, uGuestHeight, &pData->pu8PNG, 268 &pData->cbPNG, &pData->cxPNG, &pData->cyPNG, 1); 269 if (RT_FAILURE(rc)) 270 { 271 AssertMsgFailed(("DisplayMakePNG failed %d\n", rc)); 272 if (pData->pu8PNG) 273 { 274 RTMemFree(pData->pu8PNG); 275 pData->pu8PNG = NULL; 276 } 277 pData->cbPNG = 0; 278 pData->cxPNG = 0; 279 pData->cyPNG = 0; 280 } 281 } 282 #endif 283 284 DECLCALLBACK(void) Display::i_displaySSMSaveScreenshot(PSSMHANDLE pSSM, void *pvUser) 285 { 286 Display *that = static_cast<Display*>(pvUser); 287 288 /* 32bpp small RGB image. */ 289 uint8_t *pu8Thumbnail = NULL; 290 uint32_t cbThumbnail = 0; 291 uint32_t cxThumbnail = 0; 292 uint32_t cyThumbnail = 0; 293 294 /* PNG screenshot. */ 295 uint8_t *pu8PNG = NULL; 296 uint32_t cbPNG = 0; 297 uint32_t cxPNG = 0; 298 uint32_t cyPNG = 0; 299 300 Console::SafeVMPtr ptrVM(that->mParent); 301 if (ptrVM.isOk()) 302 { 303 /* Query RGB bitmap. */ 304 uint8_t *pu8Data = NULL; 305 size_t cbData = 0; 306 uint32_t cx = 0; 307 uint32_t cy = 0; 308 309 #if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) 310 BOOL f3DSnapshot = FALSE; 311 BOOL is3denabled; 312 that->mParent->i_machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled); 313 if (is3denabled && that->mCrOglCallbacks.pfnHasData()) 314 { 315 VMMDev *pVMMDev = that->mParent->i_getVMMDev(); 316 if (pVMMDev) 317 { 318 VBOX_DISPLAY_SAVESCREENSHOT_DATA *pScreenshot = 319 (VBOX_DISPLAY_SAVESCREENSHOT_DATA*)RTMemAllocZ(sizeof(*pScreenshot)); 320 if (pScreenshot) 321 { 322 /* screen id or CRSCREEN_ALL to specify all enabled */ 323 pScreenshot->Base.u32Screen = 0; 324 pScreenshot->Base.u32Width = 0; 325 pScreenshot->Base.u32Height = 0; 326 pScreenshot->Base.u32Pitch = 0; 327 pScreenshot->Base.pvBuffer = NULL; 328 pScreenshot->Base.pvContext = pScreenshot; 329 pScreenshot->Base.pfnScreenshotBegin = NULL; 330 pScreenshot->Base.pfnScreenshotPerform = displaySaveScreenshotReport; 331 pScreenshot->Base.pfnScreenshotEnd = NULL; 332 333 VBOXCRCMDCTL_HGCM data; 334 data.Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM; 335 data.Hdr.u32Function = SHCRGL_HOST_FN_TAKE_SCREENSHOT; 336 337 data.aParms[0].type = VBOX_HGCM_SVC_PARM_PTR; 338 data.aParms[0].u.pointer.addr = &pScreenshot->Base; 339 data.aParms[0].u.pointer.size = sizeof(pScreenshot->Base); 340 341 int rc = that->i_crCtlSubmitSync(&data.Hdr, sizeof(data)); 342 if (RT_SUCCESS(rc)) 343 { 344 if (pScreenshot->pu8PNG) 345 { 346 pu8Thumbnail = pScreenshot->pu8Thumbnail; 347 cbThumbnail = pScreenshot->cbThumbnail; 348 cxThumbnail = pScreenshot->cxThumbnail; 349 cyThumbnail = pScreenshot->cyThumbnail; 350 351 /* PNG screenshot. */ 352 pu8PNG = pScreenshot->pu8PNG; 353 cbPNG = pScreenshot->cbPNG; 354 cxPNG = pScreenshot->cxPNG; 355 cyPNG = pScreenshot->cyPNG; 356 f3DSnapshot = TRUE; 357 } 358 else 359 AssertMsgFailed(("no png\n")); 360 } 361 else 362 AssertMsgFailed(("SHCRGL_HOST_FN_TAKE_SCREENSHOT failed %d\n", rc)); 363 364 365 RTMemFree(pScreenshot); 366 } 367 } 368 } 369 370 if (!f3DSnapshot) 371 #endif 372 { 373 /* SSM code is executed on EMT(0), therefore no need to use VMR3ReqCallWait. */ 374 int rc = Display::i_displayTakeScreenshotEMT(that, VBOX_VIDEO_PRIMARY_SCREEN, &pu8Data, &cbData, &cx, &cy); 375 376 /* 377 * It is possible that success is returned but everything is 0 or NULL. 378 * (no display attached if a VM is running with VBoxHeadless on OSE for example) 379 */ 380 if (RT_SUCCESS(rc) && pu8Data) 381 { 382 Assert(cx && cy); 383 384 /* Prepare a small thumbnail and a PNG screenshot. */ 385 displayMakeThumbnail(pu8Data, cx, cy, &pu8Thumbnail, &cbThumbnail, &cxThumbnail, &cyThumbnail); 386 rc = DisplayMakePNG(pu8Data, cx, cy, &pu8PNG, &cbPNG, &cxPNG, &cyPNG, 1); 387 if (RT_FAILURE(rc)) 388 { 389 if (pu8PNG) 390 { 391 RTMemFree(pu8PNG); 392 pu8PNG = NULL; 393 } 394 cbPNG = 0; 395 cxPNG = 0; 396 cyPNG = 0; 397 } 398 399 /* This can be called from any thread. */ 400 that->mpDrv->pUpPort->pfnFreeScreenshot(that->mpDrv->pUpPort, pu8Data); 401 } 402 } 403 } 404 else 405 { 406 LogFunc(("Failed to get VM pointer 0x%x\n", ptrVM.rc())); 407 } 408 409 /* Regardless of rc, save what is available: 410 * Data format: 411 * uint32_t cBlocks; 412 * [blocks] 413 * 414 * Each block is: 415 * uint32_t cbBlock; if 0 - no 'block data'. 416 * uint32_t typeOfBlock; 0 - 32bpp RGB bitmap, 1 - PNG, ignored if 'cbBlock' is 0. 417 * [block data] 418 * 419 * Block data for bitmap and PNG: 420 * uint32_t cx; 421 * uint32_t cy; 422 * [image data] 423 */ 424 SSMR3PutU32(pSSM, 2); /* Write thumbnail and PNG screenshot. */ 425 426 /* First block. */ 427 SSMR3PutU32(pSSM, cbThumbnail + 2 * sizeof(uint32_t)); 428 SSMR3PutU32(pSSM, 0); /* Block type: thumbnail. */ 429 430 if (cbThumbnail) 431 { 432 SSMR3PutU32(pSSM, cxThumbnail); 433 SSMR3PutU32(pSSM, cyThumbnail); 434 SSMR3PutMem(pSSM, pu8Thumbnail, cbThumbnail); 435 } 436 437 /* Second block. */ 438 SSMR3PutU32(pSSM, cbPNG + 2 * sizeof(uint32_t)); 439 SSMR3PutU32(pSSM, 1); /* Block type: png. */ 440 441 if (cbPNG) 442 { 443 SSMR3PutU32(pSSM, cxPNG); 444 SSMR3PutU32(pSSM, cyPNG); 445 SSMR3PutMem(pSSM, pu8PNG, cbPNG); 446 } 447 448 RTMemFree(pu8PNG); 449 RTMemFree(pu8Thumbnail); 450 } 451 452 DECLCALLBACK(int) 453 Display::i_displaySSMLoadScreenshot(PSSMHANDLE pSSM, void *pvUser, uint32_t uVersion, uint32_t uPass) 454 { 455 Display *that = static_cast<Display*>(pvUser); 456 457 if (uVersion != sSSMDisplayScreenshotVer) 458 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION; 459 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass); 460 461 /* Skip data. */ 462 uint32_t cBlocks; 463 int rc = SSMR3GetU32(pSSM, &cBlocks); 464 AssertRCReturn(rc, rc); 465 466 for (uint32_t i = 0; i < cBlocks; i++) 467 { 468 uint32_t cbBlock; 469 rc = SSMR3GetU32(pSSM, &cbBlock); 470 AssertRCBreak(rc); 471 472 uint32_t typeOfBlock; 473 rc = SSMR3GetU32(pSSM, &typeOfBlock); 474 AssertRCBreak(rc); 475 476 LogRelFlowFunc(("[%d] type %d, size %d bytes\n", i, typeOfBlock, cbBlock)); 477 478 /* Note: displaySSMSaveScreenshot writes size of a block = 8 and 479 * do not write any data if the image size was 0. 480 * @todo Fix and increase saved state version. 481 */ 482 if (cbBlock > 2 * sizeof(uint32_t)) 483 { 484 rc = SSMR3Skip(pSSM, cbBlock); 485 AssertRCBreak(rc); 486 } 487 } 488 489 return rc; 490 } 491 492 /** 493 * Save/Load some important guest state 494 */ 495 DECLCALLBACK(void) 496 Display::i_displaySSMSave(PSSMHANDLE pSSM, void *pvUser) 497 { 498 Display *that = static_cast<Display*>(pvUser); 499 500 SSMR3PutU32(pSSM, that->mcMonitors); 501 for (unsigned i = 0; i < that->mcMonitors; i++) 502 { 503 SSMR3PutU32(pSSM, that->maFramebuffers[i].u32Offset); 504 SSMR3PutU32(pSSM, that->maFramebuffers[i].u32MaxFramebufferSize); 505 SSMR3PutU32(pSSM, that->maFramebuffers[i].u32InformationSize); 506 SSMR3PutU32(pSSM, that->maFramebuffers[i].w); 507 SSMR3PutU32(pSSM, that->maFramebuffers[i].h); 508 SSMR3PutS32(pSSM, that->maFramebuffers[i].xOrigin); 509 SSMR3PutS32(pSSM, that->maFramebuffers[i].yOrigin); 510 SSMR3PutU32(pSSM, that->maFramebuffers[i].flags); 511 } 512 } 513 514 DECLCALLBACK(int) 515 Display::i_displaySSMLoad(PSSMHANDLE pSSM, void *pvUser, uint32_t uVersion, uint32_t uPass) 516 { 517 Display *that = static_cast<Display*>(pvUser); 518 519 if (!( uVersion == sSSMDisplayVer 520 || uVersion == sSSMDisplayVer2 521 || uVersion == sSSMDisplayVer3)) 522 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION; 523 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass); 524 525 uint32_t cMonitors; 526 int rc = SSMR3GetU32(pSSM, &cMonitors); 527 if (cMonitors != that->mcMonitors) 528 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Number of monitors changed (%d->%d)!"), cMonitors, that->mcMonitors); 529 530 for (uint32_t i = 0; i < cMonitors; i++) 531 { 532 SSMR3GetU32(pSSM, &that->maFramebuffers[i].u32Offset); 533 SSMR3GetU32(pSSM, &that->maFramebuffers[i].u32MaxFramebufferSize); 534 SSMR3GetU32(pSSM, &that->maFramebuffers[i].u32InformationSize); 535 if ( uVersion == sSSMDisplayVer2 536 || uVersion == sSSMDisplayVer3) 537 { 538 uint32_t w; 539 uint32_t h; 540 SSMR3GetU32(pSSM, &w); 541 SSMR3GetU32(pSSM, &h); 542 that->maFramebuffers[i].w = w; 543 that->maFramebuffers[i].h = h; 544 } 545 if (uVersion == sSSMDisplayVer3) 546 { 547 int32_t xOrigin; 548 int32_t yOrigin; 549 uint32_t flags; 550 SSMR3GetS32(pSSM, &xOrigin); 551 SSMR3GetS32(pSSM, &yOrigin); 552 SSMR3GetU32(pSSM, &flags); 553 that->maFramebuffers[i].xOrigin = xOrigin; 554 that->maFramebuffers[i].yOrigin = yOrigin; 555 that->maFramebuffers[i].flags = (uint16_t)flags; 556 that->maFramebuffers[i].fDisabled = (that->maFramebuffers[i].flags & VBVA_SCREEN_F_DISABLED) != 0; 557 } 558 } 559 560 return VINF_SUCCESS; 561 } 562 563 /** 564 * Initializes the display object. 565 * 566 * @returns COM result indicator 567 * @param parent handle of our parent object 568 * @param qemuConsoleData address of common console data structure 569 */ 570 HRESULT Display::init(Console *aParent) 571 { 572 ComAssertRet(aParent, E_INVALIDARG); 573 /* Enclose the state transition NotReady->InInit->Ready */ 574 AutoInitSpan autoInitSpan(this); 575 AssertReturn(autoInitSpan.isOk(), E_FAIL); 576 577 unconst(mParent) = aParent; 578 579 mfSourceBitmapEnabled = true; 580 fVGAResizing = false; 581 582 ULONG ul; 583 mParent->i_machine()->COMGETTER(MonitorCount)(&ul); 584 mcMonitors = ul; 585 586 for (ul = 0; ul < mcMonitors; ul++) 587 { 588 maFramebuffers[ul].u32Offset = 0; 589 maFramebuffers[ul].u32MaxFramebufferSize = 0; 590 maFramebuffers[ul].u32InformationSize = 0; 591 592 maFramebuffers[ul].pFramebuffer = NULL; 593 /* All secondary monitors are disabled at startup. */ 594 maFramebuffers[ul].fDisabled = ul > 0; 595 596 maFramebuffers[ul].u32Caps = 0; 597 598 maFramebuffers[ul].updateImage.pu8Address = NULL; 599 maFramebuffers[ul].updateImage.cbLine = 0; 600 601 maFramebuffers[ul].xOrigin = 0; 602 maFramebuffers[ul].yOrigin = 0; 603 604 maFramebuffers[ul].w = 0; 605 maFramebuffers[ul].h = 0; 606 607 maFramebuffers[ul].flags = maFramebuffers[ul].fDisabled? VBVA_SCREEN_F_DISABLED: 0; 608 609 maFramebuffers[ul].u16BitsPerPixel = 0; 610 maFramebuffers[ul].pu8FramebufferVRAM = NULL; 611 maFramebuffers[ul].u32LineSize = 0; 612 613 maFramebuffers[ul].pHostEvents = NULL; 614 615 maFramebuffers[ul].fDefaultFormat = false; 616 617 RT_ZERO(maFramebuffers[ul].dirtyRect); 618 #ifdef VBOX_WITH_HGSMI 619 maFramebuffers[ul].fVBVAEnabled = false; 620 maFramebuffers[ul].fVBVAForceResize = false; 621 maFramebuffers[ul].fRenderThreadMode = false; 622 maFramebuffers[ul].pVBVAHostFlags = NULL; 623 #endif /* VBOX_WITH_HGSMI */ 624 #ifdef VBOX_WITH_CROGL 625 RT_ZERO(maFramebuffers[ul].pendingViewportInfo); 626 #endif 627 } 628 629 { 630 // register listener for state change events 631 ComPtr<IEventSource> es; 632 mParent->COMGETTER(EventSource)(es.asOutParam()); 633 com::SafeArray<VBoxEventType_T> eventTypes; 634 eventTypes.push_back(VBoxEventType_OnStateChanged); 635 es->RegisterListener(this, ComSafeArrayAsInParam(eventTypes), true); 636 } 637 638 /* Confirm a successful initialization */ 639 autoInitSpan.setSucceeded(); 640 641 return S_OK; 642 } 643 644 /** 645 * Uninitializes the instance and sets the ready flag to FALSE. 646 * Called either from FinalRelease() or by the parent when it gets destroyed. 647 */ 648 void Display::uninit() 649 { 650 LogRelFlowFunc(("this=%p\n", this)); 651 652 /* Enclose the state transition Ready->InUninit->NotReady */ 653 AutoUninitSpan autoUninitSpan(this); 654 if (autoUninitSpan.uninitDone()) 655 return; 656 657 unsigned uScreenId; 658 for (uScreenId = 0; uScreenId < mcMonitors; uScreenId++) 659 { 660 maFramebuffers[uScreenId].pSourceBitmap.setNull(); 661 maFramebuffers[uScreenId].updateImage.pSourceBitmap.setNull(); 662 maFramebuffers[uScreenId].updateImage.pu8Address = NULL; 663 maFramebuffers[uScreenId].updateImage.cbLine = 0; 664 maFramebuffers[uScreenId].pFramebuffer.setNull(); 665 } 666 667 if (mParent) 668 { 669 ComPtr<IEventSource> es; 670 mParent->COMGETTER(EventSource)(es.asOutParam()); 671 es->UnregisterListener(this); 672 } 673 674 unconst(mParent) = NULL; 675 676 if (mpDrv) 677 mpDrv->pDisplay = NULL; 678 679 mpDrv = NULL; 680 mpVMMDev = NULL; 681 mfVMMDevInited = true; 682 } 683 684 /** 685 * Register the SSM methods. Called by the power up thread to be able to 686 * pass pVM 687 */ 688 int Display::i_registerSSM(PUVM pUVM) 689 { 690 /* Version 2 adds width and height of the framebuffer; version 3 adds 691 * the framebuffer offset in the virtual desktop and the framebuffer flags. 692 */ 693 int rc = SSMR3RegisterExternal(pUVM, "DisplayData", 0, sSSMDisplayVer3, 694 mcMonitors * sizeof(uint32_t) * 8 + sizeof(uint32_t), 695 NULL, NULL, NULL, 696 NULL, i_displaySSMSave, NULL, 697 NULL, i_displaySSMLoad, NULL, this); 698 AssertRCReturn(rc, rc); 699 700 /* 701 * Register loaders for old saved states where iInstance was 702 * 3 * sizeof(uint32_t *) due to a code mistake. 703 */ 704 rc = SSMR3RegisterExternal(pUVM, "DisplayData", 12 /*uInstance*/, sSSMDisplayVer, 0 /*cbGuess*/, 705 NULL, NULL, NULL, 706 NULL, NULL, NULL, 707 NULL, i_displaySSMLoad, NULL, this); 708 AssertRCReturn(rc, rc); 709 710 rc = SSMR3RegisterExternal(pUVM, "DisplayData", 24 /*uInstance*/, sSSMDisplayVer, 0 /*cbGuess*/, 711 NULL, NULL, NULL, 712 NULL, NULL, NULL, 713 NULL, i_displaySSMLoad, NULL, this); 714 AssertRCReturn(rc, rc); 715 716 /* uInstance is an arbitrary value greater than 1024. Such a value will ensure a quick seek in saved state file. */ 717 rc = SSMR3RegisterExternal(pUVM, "DisplayScreenshot", 1100 /*uInstance*/, sSSMDisplayScreenshotVer, 0 /*cbGuess*/, 718 NULL, NULL, NULL, 719 NULL, i_displaySSMSaveScreenshot, NULL, 720 NULL, i_displaySSMLoadScreenshot, NULL, this); 721 722 AssertRCReturn(rc, rc); 723 724 return VINF_SUCCESS; 725 } 726 727 DECLCALLBACK(void) Display::i_displayCrCmdFree(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd, int rc, void *pvCompletion) 728 { 729 Assert(pvCompletion); 730 RTMemFree(pvCompletion); 731 } 732 733 #if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) 734 int Display::i_crOglWindowsShow(bool fShow) 735 { 736 if (!mfCrOglDataHidden == !!fShow) 737 return VINF_SUCCESS; 738 739 if (!mhCrOglSvc) 740 { 741 /* no 3D */ 742 #ifdef DEBUG 743 BOOL is3denabled; 744 mParent->i_machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled); 745 Assert(!is3denabled); 746 #endif 747 return VERR_INVALID_STATE; 748 } 749 750 VMMDev *pVMMDev = mParent->i_getVMMDev(); 751 if (!pVMMDev) 752 { 753 AssertMsgFailed(("no vmmdev\n")); 754 return VERR_INVALID_STATE; 755 } 756 757 VBOXCRCMDCTL_HGCM *pData = (VBOXCRCMDCTL_HGCM*)RTMemAlloc(sizeof(VBOXCRCMDCTL_HGCM)); 758 if (!pData) 759 { 760 AssertMsgFailed(("RTMemAlloc failed\n")); 761 return VERR_NO_MEMORY; 762 } 763 764 pData->Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM; 765 pData->Hdr.u32Function = SHCRGL_HOST_FN_WINDOWS_SHOW; 766 767 pData->aParms[0].type = VBOX_HGCM_SVC_PARM_32BIT; 768 pData->aParms[0].u.uint32 = (uint32_t)fShow; 769 770 int rc = i_crCtlSubmit(&pData->Hdr, sizeof(*pData), i_displayCrCmdFree, pData); 771 if (RT_SUCCESS(rc)) 772 mfCrOglDataHidden = !fShow; 773 else 774 { 775 AssertMsgFailed(("crCtlSubmit failed rc %d\n", rc)); 776 RTMemFree(pData); 777 } 778 779 return rc; 780 } 781 #endif 782 783 784 // public methods only for internal purposes 785 ///////////////////////////////////////////////////////////////////////////// 786 787 int Display::i_notifyCroglResize(const PVBVAINFOVIEW pView, const PVBVAINFOSCREEN pScreen, void *pvVRAM) 788 { 789 #if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) 790 if (maFramebuffers[pScreen->u32ViewIndex].fRenderThreadMode) 791 return VINF_SUCCESS; /* nop it */ 792 793 BOOL is3denabled; 794 mParent->i_machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled); 795 796 if (is3denabled) 797 { 798 int rc = VERR_INVALID_STATE; 799 if (mhCrOglSvc) 800 { 801 VMMDev *pVMMDev = mParent->i_getVMMDev(); 802 if (pVMMDev) 803 { 804 VBOXCRCMDCTL_HGCM *pCtl = 805 (VBOXCRCMDCTL_HGCM*)RTMemAlloc(sizeof(CRVBOXHGCMDEVRESIZE) + sizeof(VBOXCRCMDCTL_HGCM)); 806 if (pCtl) 807 { 808 CRVBOXHGCMDEVRESIZE *pData = (CRVBOXHGCMDEVRESIZE*)(pCtl+1); 809 pData->Screen = *pScreen; 810 pData->pvVRAM = pvVRAM; 811 812 pCtl->Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM; 813 pCtl->Hdr.u32Function = SHCRGL_HOST_FN_DEV_RESIZE; 814 pCtl->aParms[0].type = VBOX_HGCM_SVC_PARM_PTR; 815 pCtl->aParms[0].u.pointer.addr = pData; 816 pCtl->aParms[0].u.pointer.size = sizeof(*pData); 817 818 rc = i_crCtlSubmit(&pCtl->Hdr, sizeof(*pCtl), i_displayCrCmdFree, pCtl); 819 if (!RT_SUCCESS(rc)) 820 { 821 AssertMsgFailed(("crCtlSubmit failed rc %d\n", rc)); 822 RTMemFree(pCtl); 823 } 824 } 825 else 826 rc = VERR_NO_MEMORY; 827 } 828 } 829 830 return rc; 831 } 832 #endif /* #if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) */ 833 return VINF_SUCCESS; 834 } 835 836 /** 837 * Handles display resize event. 838 * 839 * @param w New display width 840 * @param h New display height 841 * 842 * @thread EMT 843 */ 844 int Display::i_handleDisplayResize(unsigned uScreenId, uint32_t bpp, void *pvVRAM, 845 uint32_t cbLine, uint32_t w, uint32_t h, uint16_t flags) 846 { 847 LogRel(("Display::handleDisplayResize(): uScreenId = %d, pvVRAM=%p " 848 "w=%d h=%d bpp=%d cbLine=0x%X, flags=0x%X\n", 849 uScreenId, pvVRAM, w, h, bpp, cbLine, flags)); 850 851 if (uScreenId >= mcMonitors) 852 { 853 return VINF_SUCCESS; 854 } 855 856 DISPLAYFBINFO *pFBInfo = &maFramebuffers[uScreenId]; 857 858 /* Reset the update mode. */ 859 pFBInfo->updateImage.pSourceBitmap.setNull(); 860 pFBInfo->updateImage.pu8Address = NULL; 861 pFBInfo->updateImage.cbLine = 0; 862 863 if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN) 864 { 865 pFBInfo->w = w; 866 pFBInfo->h = h; 867 868 pFBInfo->u16BitsPerPixel = (uint16_t)bpp; 869 pFBInfo->pu8FramebufferVRAM = (uint8_t *)pvVRAM; 870 pFBInfo->u32LineSize = cbLine; 871 pFBInfo->flags = flags; 872 } 873 874 /* Guest screen image will be invalid during resize, make sure that it is not updated. */ 875 if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN) 876 { 877 mpDrv->pUpPort->pfnSetRenderVRAM(mpDrv->pUpPort, false); 878 879 mpDrv->IConnector.pu8Data = NULL; 880 mpDrv->IConnector.cbScanline = 0; 881 mpDrv->IConnector.cBits = 32; /* DevVGA does not work with cBits == 0. */ 882 mpDrv->IConnector.cx = 0; 883 mpDrv->IConnector.cy = 0; 884 } 885 886 maFramebuffers[uScreenId].pSourceBitmap.setNull(); 887 888 if (!maFramebuffers[uScreenId].pFramebuffer.isNull()) 889 { 890 HRESULT hr = maFramebuffers[uScreenId].pFramebuffer->NotifyChange(uScreenId, 0, 0, w, h); /* @todo origin */ 891 LogFunc(("NotifyChange hr %08X\n", hr)); 892 NOREF(hr); 893 } 894 895 i_handleResizeCompletedEMT(uScreenId, TRUE); 896 897 bool fUpdateImage = RT_BOOL(pFBInfo->u32Caps & FramebufferCapabilities_UpdateImage); 898 if (fUpdateImage && !pFBInfo->pFramebuffer.isNull()) 899 { 900 ComPtr<IDisplaySourceBitmap> pSourceBitmap; 901 HRESULT hr = QuerySourceBitmap(uScreenId, pSourceBitmap.asOutParam()); 902 if (SUCCEEDED(hr)) 903 { 904 BYTE *pAddress = NULL; 905 ULONG ulWidth = 0; 906 ULONG ulHeight = 0; 907 ULONG ulBitsPerPixel = 0; 908 ULONG ulBytesPerLine = 0; 909 ULONG ulPixelFormat = 0; 910 911 hr = pSourceBitmap->QueryBitmapInfo(&pAddress, 912 &ulWidth, 913 &ulHeight, 914 &ulBitsPerPixel, 915 &ulBytesPerLine, 916 &ulPixelFormat); 917 if (SUCCEEDED(hr)) 918 { 919 pFBInfo->updateImage.pSourceBitmap = pSourceBitmap; 920 pFBInfo->updateImage.pu8Address = pAddress; 921 pFBInfo->updateImage.cbLine = ulBytesPerLine; 922 } 923 } 924 } 925 926 return VINF_SUCCESS; 927 } 928 929 /** 930 * Framebuffer has been resized. 931 * Read the new display data and unlock the framebuffer. 932 * 933 * @thread EMT 934 */ 935 void Display::i_handleResizeCompletedEMT(unsigned uScreenId, BOOL fResizeContext) 936 { 937 LogRelFlowFunc(("\n")); 938 939 do /* to use 'break' */ 940 { 941 if (uScreenId >= mcMonitors) 942 { 943 break; 944 } 945 946 DISPLAYFBINFO *pFBInfo = &maFramebuffers[uScreenId]; 947 948 /* Inform VRDP server about the change of display parameters. 949 * Must be done before calling NotifyUpdate below. 950 */ 951 LogRelFlowFunc(("Calling VRDP\n")); 952 mParent->i_consoleVRDPServer()->SendResize(); 953 954 /* @todo Merge these two 'if's within one 'if (!pFBInfo->pFramebuffer.isNull())' */ 955 if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN && !pFBInfo->pFramebuffer.isNull()) 956 { 957 /* If the screen resize was because of disabling, tell framebuffer to repaint. 958 * The framebuffer if now in default format so it will not use guest VRAM 959 * and will show usually black image which is there after framebuffer resize. 960 */ 961 if (pFBInfo->fDisabled) 962 pFBInfo->pFramebuffer->NotifyUpdate(0, 0, mpDrv->IConnector.cx, mpDrv->IConnector.cy); 963 } 964 else if (!pFBInfo->pFramebuffer.isNull()) 965 { 966 /* If the screen resize was because of disabling, tell framebuffer to repaint. 967 * The framebuffer if now in default format so it will not use guest VRAM 968 * and will show usually black image which is there after framebuffer resize. 969 */ 970 if (pFBInfo->fDisabled) 971 pFBInfo->pFramebuffer->NotifyUpdate(0, 0, pFBInfo->w, pFBInfo->h); 972 } 973 LogRelFlow(("[%d]: default format %d\n", uScreenId, pFBInfo->fDefaultFormat)); 974 } while(0); 975 } 976 977 static void i_checkCoordBounds(int *px, int *py, int *pw, int *ph, int cx, int cy) 978 { 979 /* Correct negative x and y coordinates. */ 980 if (*px < 0) 981 { 982 *px += *pw; /* Compute xRight which is also the new width. */ 983 984 *pw = (*px < 0)? 0: *px; 985 986 *px = 0; 987 } 988 989 if (*py < 0) 990 { 991 *py += *ph; /* Compute xBottom, which is also the new height. */ 992 993 *ph = (*py < 0)? 0: *py; 994 995 *py = 0; 996 } 997 998 /* Also check if coords are greater than the display resolution. */ 999 if (*px + *pw > cx) 1000 { 1001 *pw = cx > *px? cx - *px: 0; 1002 } 1003 1004 if (*py + *ph > cy) 1005 { 1006 *ph = cy > *py? cy - *py: 0; 1007 } 1008 } 1009 1010 unsigned mapCoordsToScreen(DISPLAYFBINFO *pInfos, unsigned cInfos, int *px, int *py, int *pw, int *ph) 47 void videoAccelDestroy(VIDEOACCEL *pVideoAccel) 48 { 49 RTSemXRoadsDestroy(pVideoAccel->hXRoadsVideoAccel); 50 RT_ZERO(*pVideoAccel); 51 } 52 53 static unsigned mapCoordsToScreen(DISPLAYFBINFO *pInfos, unsigned cInfos, int *px, int *py, int *pw, int *ph) 1011 54 { 1012 55 DISPLAYFBINFO *pInfo = pInfos; … … 1036 79 1037 80 1038 /**1039 * Handles display update event.1040 *1041 * @param x Update area x coordinate1042 * @param y Update area y coordinate1043 * @param w Update area width1044 * @param h Update area height1045 *1046 * @thread EMT1047 */1048 void Display::i_handleDisplayUpdateLegacy(int x, int y, int w, int h)1049 {1050 unsigned uScreenId = mapCoordsToScreen(maFramebuffers, mcMonitors, &x, &y, &w, &h);1051 1052 #ifdef DEBUG_sunlover1053 LogFlowFunc(("%d,%d %dx%d (checked)\n", x, y, w, h));1054 #endif /* DEBUG_sunlover */1055 1056 i_handleDisplayUpdate(uScreenId, x, y, w, h);1057 }1058 1059 void Display::i_handleDisplayUpdate(unsigned uScreenId, int x, int y, int w, int h)1060 {1061 /*1062 * Always runs under either VBVA lock or, for HGSMI, DevVGA lock.1063 * Safe to use VBVA vars and take the framebuffer lock.1064 */1065 1066 #ifdef DEBUG_sunlover1067 LogFlowFunc(("[%d] %d,%d %dx%d (%d,%d)\n",1068 uScreenId, x, y, w, h, mpDrv->IConnector.cx, mpDrv->IConnector.cy));1069 #endif /* DEBUG_sunlover */1070 1071 /* No updates for a disabled guest screen. */1072 if (maFramebuffers[uScreenId].fDisabled)1073 return;1074 1075 if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN)1076 i_checkCoordBounds (&x, &y, &w, &h, mpDrv->IConnector.cx, mpDrv->IConnector.cy);1077 else1078 i_checkCoordBounds (&x, &y, &w, &h, maFramebuffers[uScreenId].w,1079 maFramebuffers[uScreenId].h);1080 1081 IFramebuffer *pFramebuffer = maFramebuffers[uScreenId].pFramebuffer;1082 if (pFramebuffer != NULL)1083 {1084 if (w != 0 && h != 0)1085 {1086 bool fUpdateImage = RT_BOOL(maFramebuffers[uScreenId].u32Caps & FramebufferCapabilities_UpdateImage);1087 if (RT_LIKELY(!fUpdateImage))1088 {1089 pFramebuffer->NotifyUpdate(x, y, w, h);1090 }1091 else1092 {1093 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);1094 1095 DISPLAYFBINFO *pFBInfo = &maFramebuffers[uScreenId];1096 1097 if (!pFBInfo->updateImage.pSourceBitmap.isNull())1098 {1099 Assert(pFBInfo->updateImage.pu8Address);1100 1101 size_t cbData = w * h * 4;1102 com::SafeArray<BYTE> image(cbData);1103 1104 uint8_t *pu8Dst = image.raw();1105 const uint8_t *pu8Src = pFBInfo->updateImage.pu8Address + pFBInfo->updateImage.cbLine * y + x * 4;1106 1107 int i;1108 for (i = y; i < y + h; ++i)1109 {1110 memcpy(pu8Dst, pu8Src, w * 4);1111 pu8Dst += w * 4;1112 pu8Src += pFBInfo->updateImage.cbLine;1113 }1114 1115 pFramebuffer->NotifyUpdateImage(x, y, w, h, ComSafeArrayAsInParam(image));1116 }1117 }1118 }1119 }1120 1121 #ifndef VBOX_WITH_HGSMI1122 if (!mfVideoAccelEnabled)1123 {1124 #else1125 if (!mfVideoAccelEnabled && !maFramebuffers[uScreenId].fVBVAEnabled)1126 {1127 #endif /* VBOX_WITH_HGSMI */1128 /* When VBVA is enabled, the VRDP server is informed1129 * either in VideoAccelFlush or displayVBVAUpdateProcess.1130 * Inform the server here only if VBVA is disabled.1131 */1132 mParent->i_consoleVRDPServer()->SendUpdateBitmap(uScreenId, x, y, w, h);1133 }1134 }1135 1136 /**1137 * Returns the upper left and lower right corners of the virtual framebuffer.1138 * The lower right is "exclusive" (i.e. first pixel beyond the framebuffer),1139 * and the origin is (0, 0), not (1, 1) like the GUI returns.1140 */1141 void Display::i_getFramebufferDimensions(int32_t *px1, int32_t *py1,1142 int32_t *px2, int32_t *py2)1143 {1144 int32_t x1 = 0, y1 = 0, x2 = 0, y2 = 0;1145 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);1146 1147 AssertPtrReturnVoid(px1);1148 AssertPtrReturnVoid(py1);1149 AssertPtrReturnVoid(px2);1150 AssertPtrReturnVoid(py2);1151 LogRelFlowFunc(("\n"));1152 1153 if (!mpDrv)1154 return;1155 /* If VBVA is not in use then this flag will not be set and this1156 * will still work as it should. */1157 if (!maFramebuffers[0].fDisabled)1158 {1159 x1 = (int32_t)maFramebuffers[0].xOrigin;1160 y1 = (int32_t)maFramebuffers[0].yOrigin;1161 x2 = mpDrv->IConnector.cx + (int32_t)maFramebuffers[0].xOrigin;1162 y2 = mpDrv->IConnector.cy + (int32_t)maFramebuffers[0].yOrigin;1163 }1164 for (unsigned i = 1; i < mcMonitors; ++i)1165 {1166 if (!maFramebuffers[i].fDisabled)1167 {1168 x1 = RT_MIN(x1, maFramebuffers[i].xOrigin);1169 y1 = RT_MIN(y1, maFramebuffers[i].yOrigin);1170 x2 = RT_MAX(x2, maFramebuffers[i].xOrigin1171 + (int32_t)maFramebuffers[i].w);1172 y2 = RT_MAX(y2, maFramebuffers[i].yOrigin1173 + (int32_t)maFramebuffers[i].h);1174 }1175 }1176 *px1 = x1;1177 *py1 = y1;1178 *px2 = x2;1179 *py2 = y2;1180 }1181 1182 static bool displayIntersectRect(RTRECT *prectResult,1183 const RTRECT *prect1,1184 const RTRECT *prect2)1185 {1186 /* Initialize result to an empty record. */1187 memset(prectResult, 0, sizeof(RTRECT));1188 1189 int xLeftResult = RT_MAX(prect1->xLeft, prect2->xLeft);1190 int xRightResult = RT_MIN(prect1->xRight, prect2->xRight);1191 1192 if (xLeftResult < xRightResult)1193 {1194 /* There is intersection by X. */1195 1196 int yTopResult = RT_MAX(prect1->yTop, prect2->yTop);1197 int yBottomResult = RT_MIN(prect1->yBottom, prect2->yBottom);1198 1199 if (yTopResult < yBottomResult)1200 {1201 /* There is intersection by Y. */1202 1203 prectResult->xLeft = xLeftResult;1204 prectResult->yTop = yTopResult;1205 prectResult->xRight = xRightResult;1206 prectResult->yBottom = yBottomResult;1207 1208 return true;1209 }1210 }1211 1212 return false;1213 }1214 1215 int Display::i_handleSetVisibleRegion(uint32_t cRect, PRTRECT pRect)1216 {1217 RTRECT *pVisibleRegion = (RTRECT *)RTMemTmpAlloc( RT_MAX(cRect, 1)1218 * sizeof(RTRECT));1219 if (!pVisibleRegion)1220 {1221 return VERR_NO_TMP_MEMORY;1222 }1223 1224 unsigned uScreenId;1225 for (uScreenId = 0; uScreenId < mcMonitors; uScreenId++)1226 {1227 DISPLAYFBINFO *pFBInfo = &maFramebuffers[uScreenId];1228 1229 if ( !pFBInfo->pFramebuffer.isNull()1230 & RT_BOOL(pFBInfo->u32Caps & FramebufferCapabilities_VisibleRegion))1231 {1232 /* Prepare a new array of rectangles which intersect with the framebuffer.1233 */1234 RTRECT rectFramebuffer;1235 if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN)1236 {1237 rectFramebuffer.xLeft = 0;1238 rectFramebuffer.yTop = 0;1239 if (mpDrv)1240 {1241 rectFramebuffer.xRight = mpDrv->IConnector.cx;1242 rectFramebuffer.yBottom = mpDrv->IConnector.cy;1243 }1244 else1245 {1246 rectFramebuffer.xRight = 0;1247 rectFramebuffer.yBottom = 0;1248 }1249 }1250 else1251 {1252 rectFramebuffer.xLeft = pFBInfo->xOrigin;1253 rectFramebuffer.yTop = pFBInfo->yOrigin;1254 rectFramebuffer.xRight = pFBInfo->xOrigin + pFBInfo->w;1255 rectFramebuffer.yBottom = pFBInfo->yOrigin + pFBInfo->h;1256 }1257 1258 uint32_t cRectVisibleRegion = 0;1259 1260 uint32_t i;1261 for (i = 0; i < cRect; i++)1262 {1263 if (displayIntersectRect(&pVisibleRegion[cRectVisibleRegion], &pRect[i], &rectFramebuffer))1264 {1265 pVisibleRegion[cRectVisibleRegion].xLeft -= pFBInfo->xOrigin;1266 pVisibleRegion[cRectVisibleRegion].yTop -= pFBInfo->yOrigin;1267 pVisibleRegion[cRectVisibleRegion].xRight -= pFBInfo->xOrigin;1268 pVisibleRegion[cRectVisibleRegion].yBottom -= pFBInfo->yOrigin;1269 1270 cRectVisibleRegion++;1271 }1272 }1273 pFBInfo->pFramebuffer->SetVisibleRegion((BYTE *)pVisibleRegion, cRectVisibleRegion);1274 }1275 }1276 1277 #if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)1278 BOOL is3denabled = FALSE;1279 1280 mParent->i_machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled);1281 1282 VMMDev *vmmDev = mParent->i_getVMMDev();1283 if (is3denabled && vmmDev)1284 {1285 if (mhCrOglSvc)1286 {1287 VBOXCRCMDCTL_HGCM *pCtl = (VBOXCRCMDCTL_HGCM*)RTMemAlloc(RT_MAX(cRect, 1) * sizeof(RTRECT)1288 + sizeof(VBOXCRCMDCTL_HGCM));1289 if (pCtl)1290 {1291 RTRECT *pRectsCopy = (RTRECT*)(pCtl+1);1292 memcpy(pRectsCopy, pRect, cRect * sizeof(RTRECT));1293 1294 pCtl->Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM;1295 pCtl->Hdr.u32Function = SHCRGL_HOST_FN_SET_VISIBLE_REGION;1296 1297 pCtl->aParms[0].type = VBOX_HGCM_SVC_PARM_PTR;1298 pCtl->aParms[0].u.pointer.addr = pRectsCopy;1299 pCtl->aParms[0].u.pointer.size = cRect * sizeof(RTRECT);1300 1301 int rc = i_crCtlSubmit(&pCtl->Hdr, sizeof(*pCtl), i_displayCrCmdFree, pCtl);1302 if (!RT_SUCCESS(rc))1303 {1304 AssertMsgFailed(("crCtlSubmit failed rc %d\n", rc));1305 RTMemFree(pCtl);1306 }1307 }1308 else1309 AssertMsgFailed(("failed to allocate rects memory\n"));1310 }1311 else1312 AssertMsgFailed(("mhCrOglSvc is NULL\n"));1313 }1314 #endif1315 1316 RTMemTmpFree(pVisibleRegion);1317 1318 return VINF_SUCCESS;1319 }1320 1321 int Display::i_handleQueryVisibleRegion(uint32_t *pcRect, PRTRECT pRect)1322 {1323 // @todo Currently not used by the guest and is not implemented in framebuffers. Remove?1324 return VERR_NOT_SUPPORTED;1325 }1326 1327 81 typedef struct _VBVADIRTYREGION 1328 82 { … … 1333 87 PPDMIDISPLAYPORT pPort; 1334 88 89 /* The rectangle that includes all dirty rectangles. */ 90 RTRECT aDirtyRects[SchemaDefs::MaxGuestMonitors]; 91 1335 92 } VBVADIRTYREGION; 1336 93 … … 1343 100 prgn->pPort = pp; 1344 101 1345 unsigned uScreenId; 1346 for (uScreenId = 0; uScreenId < cMonitors; uScreenId++) 1347 { 1348 DISPLAYFBINFO *pFBInfo = &prgn->paFramebuffers[uScreenId]; 1349 1350 RT_ZERO(pFBInfo->dirtyRect); 1351 } 102 RT_ZERO(prgn->aDirtyRects); 1352 103 } 1353 104 … … 1373 124 int32_t yBottom = phdr->y + phdr->h; 1374 125 126 RTRECT *pDirtyRect = &prgn->aDirtyRects[uScreenId]; 1375 127 DISPLAYFBINFO *pFBInfo = &prgn->paFramebuffers[uScreenId]; 1376 128 1377 if (p FBInfo->dirtyRect.xRight == 0)129 if (pDirtyRect->xRight == 0) 1378 130 { 1379 131 /* This is the first rectangle to be added. */ 1380 p FBInfo->dirtyRect.xLeft = phdr->x;1381 p FBInfo->dirtyRect.yTop = phdr->y;1382 p FBInfo->dirtyRect.xRight = xRight;1383 p FBInfo->dirtyRect.yBottom = yBottom;132 pDirtyRect->xLeft = phdr->x; 133 pDirtyRect->yTop = phdr->y; 134 pDirtyRect->xRight = xRight; 135 pDirtyRect->yBottom = yBottom; 1384 136 } 1385 137 else 1386 138 { 1387 139 /* Adjust region coordinates. */ 1388 if (p FBInfo->dirtyRect.xLeft > phdr->x)1389 { 1390 p FBInfo->dirtyRect.xLeft = phdr->x;1391 } 1392 1393 if (p FBInfo->dirtyRect.yTop > phdr->y)1394 { 1395 p FBInfo->dirtyRect.yTop = phdr->y;1396 } 1397 1398 if (p FBInfo->dirtyRect.xRight < xRight)1399 { 1400 p FBInfo->dirtyRect.xRight = xRight;1401 } 1402 1403 if (p FBInfo->dirtyRect.yBottom < yBottom)1404 { 1405 p FBInfo->dirtyRect.yBottom = yBottom;140 if (pDirtyRect->xLeft > phdr->x) 141 { 142 pDirtyRect->xLeft = phdr->x; 143 } 144 145 if (pDirtyRect->yTop > phdr->y) 146 { 147 pDirtyRect->yTop = phdr->y; 148 } 149 150 if (pDirtyRect->xRight < xRight) 151 { 152 pDirtyRect->xRight = xRight; 153 } 154 155 if (pDirtyRect->yBottom < yBottom) 156 { 157 pDirtyRect->yBottom = yBottom; 1406 158 } 1407 159 } … … 1411 163 //@todo pfnUpdateDisplayRect must take the vram offset parameter for the framebuffer 1412 164 prgn->pPort->pfnUpdateDisplayRect(prgn->pPort, phdr->x, phdr->y, phdr->w, phdr->h); 1413 prgn->pDisplay->i_handleDisplayUpdateLegacy(phdr->x + pFBInfo->xOrigin, 1414 phdr->y + pFBInfo->yOrigin, phdr->w, phdr->h); 165 prgn->pDisplay->i_handleDisplayUpdate(uScreenId, phdr->x, phdr->y, phdr->w, phdr->h); 1415 166 } 1416 167 … … 1420 171 static void vbvaRgnUpdateFramebuffer(VBVADIRTYREGION *prgn, unsigned uScreenId) 1421 172 { 173 RTRECT *pDirtyRect = &prgn->aDirtyRects[uScreenId]; 1422 174 DISPLAYFBINFO *pFBInfo = &prgn->paFramebuffers[uScreenId]; 1423 175 1424 uint32_t w = p FBInfo->dirtyRect.xRight - pFBInfo->dirtyRect.xLeft;1425 uint32_t h = p FBInfo->dirtyRect.yBottom - pFBInfo->dirtyRect.yTop;176 uint32_t w = pDirtyRect->xRight - pDirtyRect->xLeft; 177 uint32_t h = pDirtyRect->yBottom - pDirtyRect->yTop; 1426 178 1427 179 if (!pFBInfo->fDefaultFormat && w != 0 && h != 0) 1428 180 { 1429 181 //@todo pfnUpdateDisplayRect must take the vram offset parameter for the framebuffer 1430 prgn->pPort->pfnUpdateDisplayRect(prgn->pPort, pFBInfo->dirtyRect.xLeft, pFBInfo->dirtyRect.yTop, w, h); 1431 prgn->pDisplay->i_handleDisplayUpdateLegacy(pFBInfo->dirtyRect.xLeft + pFBInfo->xOrigin, 1432 pFBInfo->dirtyRect.yTop + pFBInfo->yOrigin, w, h); 1433 } 1434 } 1435 1436 static void i_vbvaSetMemoryFlags(VBVAMEMORY *pVbvaMemory, 1437 bool fVideoAccelEnabled, 1438 bool fVideoAccelVRDP, 1439 uint32_t fu32SupportedOrders, 1440 DISPLAYFBINFO *paFBInfos, 1441 unsigned cFBInfos) 182 prgn->pPort->pfnUpdateDisplayRect(prgn->pPort, pDirtyRect->xLeft, pDirtyRect->yTop, w, h); 183 prgn->pDisplay->i_handleDisplayUpdate(uScreenId, pDirtyRect->xLeft, pDirtyRect->yTop, w, h); 184 } 185 } 186 187 void i_vbvaSetMemoryFlags(VBVAMEMORY *pVbvaMemory, 188 bool fVideoAccelEnabled, 189 bool fVideoAccelVRDP, 190 uint32_t fu32SupportedOrders, 191 DISPLAYFBINFO *paFBInfos, 192 unsigned cFBInfos) 1442 193 { 1443 194 if (pVbvaMemory) … … 1471 222 } 1472 223 1473 #ifdef VBOX_WITH_HGSMI1474 static void vbvaSetMemoryFlagsHGSMI(unsigned uScreenId,1475 uint32_t fu32SupportedOrders,1476 bool fVideoAccelVRDP,1477 DISPLAYFBINFO *pFBInfo)1478 {1479 LogRelFlowFunc(("HGSMI[%d]: %p\n", uScreenId, pFBInfo->pVBVAHostFlags));1480 1481 if (pFBInfo->pVBVAHostFlags)1482 {1483 uint32_t fu32HostEvents = VBOX_VIDEO_INFO_HOST_EVENTS_F_VRDP_RESET;1484 1485 if (pFBInfo->fVBVAEnabled)1486 {1487 fu32HostEvents |= VBVA_F_MODE_ENABLED;1488 1489 if (fVideoAccelVRDP)1490 {1491 fu32HostEvents |= VBVA_F_MODE_VRDP;1492 }1493 }1494 1495 ASMAtomicWriteU32(&pFBInfo->pVBVAHostFlags->u32HostEvents, fu32HostEvents);1496 ASMAtomicWriteU32(&pFBInfo->pVBVAHostFlags->u32SupportedOrders, fu32SupportedOrders);1497 1498 LogRelFlowFunc((" fu32HostEvents = 0x%08X, fu32SupportedOrders = 0x%08X\n", fu32HostEvents, fu32SupportedOrders));1499 }1500 }1501 1502 static void vbvaSetMemoryFlagsAllHGSMI(uint32_t fu32SupportedOrders,1503 bool fVideoAccelVRDP,1504 DISPLAYFBINFO *paFBInfos,1505 unsigned cFBInfos)1506 {1507 unsigned uScreenId;1508 1509 for (uScreenId = 0; uScreenId < cFBInfos; uScreenId++)1510 {1511 vbvaSetMemoryFlagsHGSMI(uScreenId, fu32SupportedOrders, fVideoAccelVRDP, &paFBInfos[uScreenId]);1512 }1513 }1514 #endif /* VBOX_WITH_HGSMI */1515 1516 224 bool Display::i_VideoAccelAllowed(void) 1517 225 { … … 1519 227 } 1520 228 1521 int Display::videoAccelEnterVGA(void) 1522 { 1523 return RTSemXRoadsNSEnter(mhXRoadsVideoAccel); 1524 } 1525 1526 void Display::videoAccelLeaveVGA(void) 1527 { 1528 RTSemXRoadsNSLeave(mhXRoadsVideoAccel); 1529 } 1530 1531 int Display::videoAccelEnterVMMDev(void) 1532 { 1533 return RTSemXRoadsEWEnter(mhXRoadsVideoAccel); 1534 } 1535 1536 void Display::videoAccelLeaveVMMDev(void) 1537 { 1538 RTSemXRoadsEWLeave(mhXRoadsVideoAccel); 1539 } 1540 1541 int Display::VideoAccelEnableVMMDev(bool fEnable, VBVAMEMORY *pVbvaMemory) 1542 { 1543 LogFlowFunc(("%d %p\n", fEnable, pVbvaMemory)); 1544 int rc = videoAccelEnterVMMDev(); 1545 if (RT_SUCCESS(rc)) 1546 { 1547 rc = i_VideoAccelEnable(fEnable, pVbvaMemory); 1548 videoAccelLeaveVMMDev(); 1549 } 1550 LogFlowFunc(("leave %Rrc\n", rc)); 1551 return rc; 1552 } 1553 1554 int Display::VideoAccelEnableVGA(bool fEnable, VBVAMEMORY *pVbvaMemory) 1555 { 1556 LogFlowFunc(("%d %p\n", fEnable, pVbvaMemory)); 1557 int rc = videoAccelEnterVGA(); 1558 if (RT_SUCCESS(rc)) 1559 { 1560 rc = i_VideoAccelEnable(fEnable, pVbvaMemory); 1561 videoAccelLeaveVGA(); 1562 } 1563 LogFlowFunc(("leave %Rrc\n", rc)); 1564 return rc; 1565 } 1566 1567 void Display::VideoAccelFlushVMMDev(void) 1568 { 1569 LogFlowFunc(("enter\n")); 1570 int rc = videoAccelEnterVMMDev(); 1571 if (RT_SUCCESS(rc)) 1572 { 1573 i_VideoAccelFlush(); 1574 videoAccelLeaveVMMDev(); 1575 } 1576 LogFlowFunc(("leave\n")); 229 int videoAccelEnterVGA(VIDEOACCEL *pVideoAccel) 230 { 231 return RTSemXRoadsNSEnter(pVideoAccel->hXRoadsVideoAccel); 232 } 233 234 void videoAccelLeaveVGA(VIDEOACCEL *pVideoAccel) 235 { 236 RTSemXRoadsNSLeave(pVideoAccel->hXRoadsVideoAccel); 237 } 238 239 int videoAccelEnterVMMDev(VIDEOACCEL *pVideoAccel) 240 { 241 return RTSemXRoadsEWEnter(pVideoAccel->hXRoadsVideoAccel); 242 } 243 244 void videoAccelLeaveVMMDev(VIDEOACCEL *pVideoAccel) 245 { 246 RTSemXRoadsEWLeave(pVideoAccel->hXRoadsVideoAccel); 1577 247 } 1578 248 … … 1580 250 * @thread EMT 1581 251 */ 1582 int Display::i_VideoAccelEnable(bool fEnable, VBVAMEMORY *pVbvaMemory )252 int Display::i_VideoAccelEnable(bool fEnable, VBVAMEMORY *pVbvaMemory, PPDMIDISPLAYPORT pUpPort) 1583 253 { 1584 254 int rc; 1585 255 LogRelFlowFunc(("fEnable = %d\n", fEnable)); 1586 256 1587 rc = i_videoAccelEnable(fEnable, pVbvaMemory );257 rc = i_videoAccelEnable(fEnable, pVbvaMemory, pUpPort); 1588 258 1589 259 LogRelFlowFunc(("%Rrc.\n", rc)); … … 1591 261 } 1592 262 1593 int Display::i_videoAccelEnable(bool fEnable, VBVAMEMORY *pVbvaMemory )263 int Display::i_videoAccelEnable(bool fEnable, VBVAMEMORY *pVbvaMemory, PPDMIDISPLAYPORT pUpPort) 1594 264 { 1595 265 int rc = VINF_SUCCESS; 266 267 VIDEOACCEL *pVideoAccel = &mVideoAccelLegacy; 268 1596 269 /* Called each time the guest wants to use acceleration, 1597 270 * or when the VGA device disables acceleration, … … 1605 278 */ 1606 279 LogRelFlowFunc(("mfVideoAccelEnabled = %d, fEnable = %d, pVbvaMemory = %p\n", 1607 mfVideoAccelEnabled, fEnable, pVbvaMemory));280 pVideoAccel->fVideoAccelEnabled, fEnable, pVbvaMemory)); 1608 281 1609 282 /* Strictly check parameters. Callers must not pass anything in the case. */ … … 1614 287 1615 288 /* Check that current status is not being changed */ 1616 if ( mfVideoAccelEnabled == fEnable)289 if (pVideoAccel->fVideoAccelEnabled == fEnable) 1617 290 return rc; 1618 291 1619 if ( mfVideoAccelEnabled)292 if (pVideoAccel->fVideoAccelEnabled) 1620 293 { 1621 294 /* Process any pending orders and empty the VBVA ring buffer. */ 1622 i_videoAccelFlush ( );1623 } 1624 1625 if (!fEnable && mpVbvaMemory)1626 mpVbvaMemory->fu32ModeFlags &= ~VBVA_F_MODE_ENABLED;295 i_videoAccelFlush (pUpPort); 296 } 297 298 if (!fEnable && pVideoAccel->pVbvaMemory) 299 pVideoAccel->pVbvaMemory->fu32ModeFlags &= ~VBVA_F_MODE_ENABLED; 1627 300 1628 301 if (fEnable) 1629 302 { 1630 303 /* Process any pending VGA device changes, resize. */ 1631 mpDrv->pUpPort->pfnUpdateDisplayAll(mpDrv->pUpPort, /* fFailOnResize = */ false);304 pUpPort->pfnUpdateDisplayAll(pUpPort, /* fFailOnResize = */ false); 1632 305 } 1633 306 … … 1637 310 if (fEnable) 1638 311 { 1639 mpVbvaMemory = pVbvaMemory;1640 mfVideoAccelEnabled = true;1641 1642 312 /* Initialize the hardware memory. */ 1643 i_vbvaSetMemoryFlags( mpVbvaMemory, mfVideoAccelEnabled, mfVideoAccelVRDP,313 i_vbvaSetMemoryFlags(pVbvaMemory, true, mfVideoAccelVRDP, 1644 314 mfu32SupportedOrders, maFramebuffers, mcMonitors); 1645 mpVbvaMemory->off32Data = 0; 1646 mpVbvaMemory->off32Free = 0; 1647 1648 memset(mpVbvaMemory->aRecords, 0, sizeof(mpVbvaMemory->aRecords)); 1649 mpVbvaMemory->indexRecordFirst = 0; 1650 mpVbvaMemory->indexRecordFree = 0; 315 pVbvaMemory->off32Data = 0; 316 pVbvaMemory->off32Free = 0; 317 318 memset(pVbvaMemory->aRecords, 0, sizeof(pVbvaMemory->aRecords)); 319 pVbvaMemory->indexRecordFirst = 0; 320 pVbvaMemory->indexRecordFree = 0; 321 322 pVideoAccel->pVbvaMemory = pVbvaMemory; 323 pVideoAccel->fVideoAccelEnabled = true; 1651 324 1652 325 LogRel(("VBVA: Enabled.\n")); … … 1654 327 else 1655 328 { 1656 mpVbvaMemory = NULL;1657 mfVideoAccelEnabled = false;329 pVideoAccel->pVbvaMemory = NULL; 330 pVideoAccel->fVideoAccelEnabled = false; 1658 331 1659 332 LogRel(("VBVA: Disabled.\n")); … … 1664 337 if (!fEnable) 1665 338 { 1666 mpDrv->pUpPort->pfnUpdateDisplayAll(mpDrv->pUpPort, /* fFailOnResize = */ false);339 pUpPort->pfnUpdateDisplayAll(pUpPort, /* fFailOnResize = */ false); 1667 340 } 1668 341 … … 1682 355 } 1683 356 1684 /* Called always by one VRDP server thread. Can be thread-unsafe.1685 */1686 void Display::i_VideoAccelVRDP(bool fEnable)1687 {1688 LogRelFlowFunc(("fEnable = %d\n", fEnable));1689 1690 int c = fEnable?1691 ASMAtomicIncS32(&mcVideoAccelVRDPRefs):1692 ASMAtomicDecS32(&mcVideoAccelVRDPRefs);1693 1694 Assert (c >= 0);1695 1696 /* This can run concurrently with Display videoaccel state change. */1697 RTCritSectEnter(&mVideoAccelLock);1698 1699 if (c == 0)1700 {1701 /* The last client has disconnected, and the accel can be1702 * disabled.1703 */1704 Assert (fEnable == false);1705 1706 mfVideoAccelVRDP = false;1707 mfu32SupportedOrders = 0;1708 1709 i_vbvaSetMemoryFlags(mpVbvaMemory, mfVideoAccelEnabled, mfVideoAccelVRDP, mfu32SupportedOrders,1710 maFramebuffers, mcMonitors);1711 #ifdef VBOX_WITH_HGSMI1712 /* Here is VRDP-IN thread. Process the request in vbvaUpdateBegin under DevVGA lock on an EMT. */1713 ASMAtomicIncU32(&mu32UpdateVBVAFlags);1714 #endif /* VBOX_WITH_HGSMI */1715 1716 LogRel(("VBVA: VRDP acceleration has been disabled.\n"));1717 }1718 else if ( c == 11719 && !mfVideoAccelVRDP)1720 {1721 /* The first client has connected. Enable the accel.1722 */1723 Assert (fEnable == true);1724 1725 mfVideoAccelVRDP = true;1726 /* Supporting all orders. */1727 mfu32SupportedOrders = ~0;1728 1729 i_vbvaSetMemoryFlags(mpVbvaMemory, mfVideoAccelEnabled, mfVideoAccelVRDP, mfu32SupportedOrders,1730 maFramebuffers, mcMonitors);1731 #ifdef VBOX_WITH_HGSMI1732 /* Here is VRDP-IN thread. Process the request in vbvaUpdateBegin under DevVGA lock on an EMT. */1733 ASMAtomicIncU32(&mu32UpdateVBVAFlags);1734 #endif /* VBOX_WITH_HGSMI */1735 1736 LogRel(("VBVA: VRDP acceleration has been requested.\n"));1737 }1738 else1739 {1740 /* A client is connected or disconnected but there is no change in the1741 * accel state. It remains enabled.1742 */1743 Assert(mfVideoAccelVRDP == true);1744 }1745 1746 RTCritSectLeave(&mVideoAccelLock);1747 }1748 1749 357 static bool i_vbvaVerifyRingBuffer(VBVAMEMORY *pVbvaMemory) 1750 358 { … … 1830 438 * For crossing boundary - allocate a buffer from heap. 1831 439 */ 1832 bool Display::i_vbvaFetchCmd(VBVACMDHDR **ppHdr, uint32_t *pcbCmd) 1833 { 1834 uint32_t indexRecordFirst = mpVbvaMemory->indexRecordFirst; 1835 uint32_t indexRecordFree = mpVbvaMemory->indexRecordFree; 440 static bool i_vbvaFetchCmd(VIDEOACCEL *pVideoAccel, VBVACMDHDR **ppHdr, uint32_t *pcbCmd) 441 { 442 VBVAMEMORY *pVbvaMemory = pVideoAccel->pVbvaMemory; 443 444 uint32_t indexRecordFirst = pVbvaMemory->indexRecordFirst; 445 uint32_t indexRecordFree = pVbvaMemory->indexRecordFree; 1836 446 1837 447 #ifdef DEBUG_sunlover … … 1840 450 #endif /* DEBUG_sunlover */ 1841 451 1842 if (!i_vbvaVerifyRingBuffer( mpVbvaMemory))452 if (!i_vbvaVerifyRingBuffer(pVbvaMemory)) 1843 453 { 1844 454 return false; … … 1851 461 } 1852 462 1853 VBVARECORD *pRecord = &mpVbvaMemory->aRecords[indexRecordFirst];463 uint32_t cbRecordCurrent = ASMAtomicReadU32(&pVbvaMemory->aRecords[indexRecordFirst].cbRecord); 1854 464 1855 465 #ifdef DEBUG_sunlover 1856 LogFlowFunc(("cbRecord = 0x%08X\n", pRecord->cbRecord));466 LogFlowFunc(("cbRecord = 0x%08X\n", cbRecordCurrent)); 1857 467 #endif /* DEBUG_sunlover */ 1858 468 1859 uint32_t cbRecord = pRecord->cbRecord& ~VBVA_F_RECORD_PARTIAL;1860 1861 if ( mcbVbvaPartial)469 uint32_t cbRecord = cbRecordCurrent & ~VBVA_F_RECORD_PARTIAL; 470 471 if (pVideoAccel->cbVbvaPartial) 1862 472 { 1863 473 /* There is a partial read in process. Continue with it. */ 1864 474 1865 Assert( mpu8VbvaPartial);1866 1867 LogFlowFunc(("continue partial record mcbVbvaPartial = %d cbRecord 0x%08X, first = %d, free = %d\n",1868 mcbVbvaPartial, pRecord->cbRecord, indexRecordFirst, indexRecordFree));1869 1870 if (cbRecord > mcbVbvaPartial)475 Assert(pVideoAccel->pu8VbvaPartial); 476 477 LogFlowFunc(("continue partial record cbVbvaPartial = %d cbRecord 0x%08X, first = %d, free = %d\n", 478 pVideoAccel->cbVbvaPartial, cbRecordCurrent, indexRecordFirst, indexRecordFree)); 479 480 if (cbRecord > pVideoAccel->cbVbvaPartial) 1871 481 { 1872 482 /* New data has been added to the record. */ 1873 if (!i_vbvaPartialRead(& mpu8VbvaPartial, &mcbVbvaPartial, cbRecord, mpVbvaMemory))483 if (!i_vbvaPartialRead(&pVideoAccel->pu8VbvaPartial, &pVideoAccel->cbVbvaPartial, cbRecord, pVbvaMemory)) 1874 484 { 1875 485 return false; … … 1877 487 } 1878 488 1879 if (!( pRecord->cbRecord& VBVA_F_RECORD_PARTIAL))489 if (!(cbRecordCurrent & VBVA_F_RECORD_PARTIAL)) 1880 490 { 1881 491 /* The record is completed by guest. Return it to the caller. */ 1882 *ppHdr = (VBVACMDHDR *) mpu8VbvaPartial;1883 *pcbCmd = mcbVbvaPartial;1884 1885 mpu8VbvaPartial = NULL;1886 mcbVbvaPartial = 0;492 *ppHdr = (VBVACMDHDR *)pVideoAccel->pu8VbvaPartial; 493 *pcbCmd = pVideoAccel->cbVbvaPartial; 494 495 pVideoAccel->pu8VbvaPartial = NULL; 496 pVideoAccel->cbVbvaPartial = 0; 1887 497 1888 498 /* Advance the record index. */ 1889 mpVbvaMemory->indexRecordFirst = (indexRecordFirst + 1) % VBVA_MAX_RECORDS;499 pVbvaMemory->indexRecordFirst = (indexRecordFirst + 1) % VBVA_MAX_RECORDS; 1890 500 1891 501 #ifdef DEBUG_sunlover 1892 502 LogFlowFunc(("partial done ok, data = %d, free = %d\n", 1893 mpVbvaMemory->off32Data, mpVbvaMemory->off32Free));503 pVbvaMemory->off32Data, pVbvaMemory->off32Free)); 1894 504 #endif /* DEBUG_sunlover */ 1895 505 } … … 1899 509 1900 510 /* A new record need to be processed. */ 1901 if ( pRecord->cbRecord& VBVA_F_RECORD_PARTIAL)511 if (cbRecordCurrent & VBVA_F_RECORD_PARTIAL) 1902 512 { 1903 513 /* Current record is being written by guest. '=' is important here. */ … … 1905 515 { 1906 516 /* Partial read must be started. */ 1907 if (!i_vbvaPartialRead(& mpu8VbvaPartial, &mcbVbvaPartial, cbRecord, mpVbvaMemory))517 if (!i_vbvaPartialRead(&pVideoAccel->pu8VbvaPartial, &pVideoAccel->cbVbvaPartial, cbRecord, pVbvaMemory)) 1908 518 { 1909 519 return false; 1910 520 } 1911 521 1912 LogFlowFunc(("started partial record mcbVbvaPartial = 0x%08X cbRecord 0x%08X, first = %d, free = %d\n",1913 mcbVbvaPartial, pRecord->cbRecord, indexRecordFirst, indexRecordFree));522 LogFlowFunc(("started partial record cbVbvaPartial = 0x%08X cbRecord 0x%08X, first = %d, free = %d\n", 523 pVideoAccel->cbVbvaPartial, cbRecordCurrent, indexRecordFirst, indexRecordFree)); 1914 524 } 1915 525 … … 1921 531 { 1922 532 /* The size of largest contiguous chunk in the ring biffer. */ 1923 uint32_t u32BytesTillBoundary = VBVA_RING_BUFFER_SIZE - mpVbvaMemory->off32Data;533 uint32_t u32BytesTillBoundary = VBVA_RING_BUFFER_SIZE - pVbvaMemory->off32Data; 1924 534 1925 535 /* The ring buffer pointer. */ 1926 uint8_t *au8RingBuffer = & mpVbvaMemory->au8RingBuffer[0];536 uint8_t *au8RingBuffer = &pVbvaMemory->au8RingBuffer[0]; 1927 537 1928 538 /* The pointer to data in the ring buffer. */ 1929 uint8_t *src = &au8RingBuffer[ mpVbvaMemory->off32Data];539 uint8_t *src = &au8RingBuffer[pVbvaMemory->off32Data]; 1930 540 1931 541 /* Fetch or point the data. */ … … 1936 546 1937 547 /* Advance data offset. */ 1938 mpVbvaMemory->off32Data = (mpVbvaMemory->off32Data + cbRecord) % VBVA_RING_BUFFER_SIZE;548 pVbvaMemory->off32Data = (pVbvaMemory->off32Data + cbRecord) % VBVA_RING_BUFFER_SIZE; 1939 549 } 1940 550 else … … 1946 556 { 1947 557 LogRelFlowFunc(("could not allocate %d bytes from heap!!!\n", cbRecord)); 1948 mpVbvaMemory->off32Data = (mpVbvaMemory->off32Data + cbRecord) % VBVA_RING_BUFFER_SIZE;558 pVbvaMemory->off32Data = (pVbvaMemory->off32Data + cbRecord) % VBVA_RING_BUFFER_SIZE; 1949 559 return false; 1950 560 } 1951 561 1952 i_vbvaFetchBytes( mpVbvaMemory, dst, cbRecord);562 i_vbvaFetchBytes(pVbvaMemory, dst, cbRecord); 1953 563 1954 564 *ppHdr = (VBVACMDHDR *)dst; … … 1963 573 1964 574 /* Advance the record index. */ 1965 mpVbvaMemory->indexRecordFirst = (indexRecordFirst + 1) % VBVA_MAX_RECORDS;575 pVbvaMemory->indexRecordFirst = (indexRecordFirst + 1) % VBVA_MAX_RECORDS; 1966 576 1967 577 #ifdef DEBUG_sunlover 1968 578 LogFlowFunc(("done ok, data = %d, free = %d\n", 1969 mpVbvaMemory->off32Data, mpVbvaMemory->off32Free));579 pVbvaMemory->off32Data, pVbvaMemory->off32Free)); 1970 580 #endif /* DEBUG_sunlover */ 1971 581 … … 1973 583 } 1974 584 1975 void Display::i_vbvaReleaseCmd(VBVACMDHDR *pHdr, int32_t cbCmd)1976 { 1977 uint8_t *au8RingBuffer = mpVbvaMemory->au8RingBuffer;585 static void i_vbvaReleaseCmd(VIDEOACCEL *pVideoAccel, VBVACMDHDR *pHdr, int32_t cbCmd) 586 { 587 uint8_t *au8RingBuffer = pVideoAccel->pVbvaMemory->au8RingBuffer; 1978 588 1979 589 if ( (uint8_t *)pHdr >= au8RingBuffer … … 1985 595 /* Do nothing. */ 1986 596 1987 Assert(! mpu8VbvaPartial && mcbVbvaPartial == 0);597 Assert(!pVideoAccel->pu8VbvaPartial && pVideoAccel->cbVbvaPartial == 0); 1988 598 } 1989 599 else … … 1995 605 #endif /* DEBUG_sunlover */ 1996 606 1997 if ((uint8_t *)pHdr == mpu8VbvaPartial)1998 { 1999 mpu8VbvaPartial = NULL;2000 mcbVbvaPartial = 0;607 if ((uint8_t *)pHdr == pVideoAccel->pu8VbvaPartial) 608 { 609 pVideoAccel->pu8VbvaPartial = NULL; 610 pVideoAccel->cbVbvaPartial = 0; 2001 611 } 2002 612 else 2003 613 { 2004 Assert(! mpu8VbvaPartial && mcbVbvaPartial == 0);614 Assert(!pVideoAccel->pu8VbvaPartial && pVideoAccel->cbVbvaPartial == 0); 2005 615 } 2006 616 … … 2018 628 * @thread EMT 2019 629 */ 2020 void Display::i_VideoAccelFlush( void)2021 { 2022 int rc = i_videoAccelFlush( );630 void Display::i_VideoAccelFlush(PPDMIDISPLAYPORT pUpPort) 631 { 632 int rc = i_videoAccelFlush(pUpPort); 2023 633 if (RT_FAILURE(rc)) 2024 634 { 2025 635 /* Disable on errors. */ 2026 i_videoAccelEnable(false, NULL); 2027 } 2028 2029 if (RT_FAILURE(rc)) 2030 { 2031 /* VideoAccel was disabled because of a failure, switching back to VGA updates. Redraw the screen. */ 2032 mpDrv->pUpPort->pfnUpdateDisplayAll(mpDrv->pUpPort, /* fFailOnResize = */ false); 2033 } 2034 } 2035 2036 int Display::i_videoAccelFlush(void) 2037 { 636 i_videoAccelEnable(false, NULL, pUpPort); 637 } 638 } 639 640 int Display::i_videoAccelFlush(PPDMIDISPLAYPORT pUpPort) 641 { 642 VIDEOACCEL *pVideoAccel = &mVideoAccelLegacy; 643 VBVAMEMORY *pVbvaMemory = pVideoAccel->pVbvaMemory; 644 2038 645 #ifdef DEBUG_sunlover_2 2039 LogFlowFunc((" mfVideoAccelEnabled = %d\n", mfVideoAccelEnabled));646 LogFlowFunc(("fVideoAccelEnabled = %d\n", pVideoAccel->fVideoAccelEnabled)); 2040 647 #endif /* DEBUG_sunlover_2 */ 2041 648 2042 if (! mfVideoAccelEnabled)649 if (!pVideoAccel->fVideoAccelEnabled) 2043 650 { 2044 651 Log(("Display::VideoAccelFlush: called with disabled VBVA!!! Ignoring.\n")); … … 2047 654 2048 655 /* Here VBVA is enabled and we have the accelerator memory pointer. */ 2049 Assert( mpVbvaMemory);656 Assert(pVbvaMemory); 2050 657 2051 658 #ifdef DEBUG_sunlover_2 2052 659 LogFlowFunc(("indexRecordFirst = %d, indexRecordFree = %d, off32Data = %d, off32Free = %d\n", 2053 mpVbvaMemory->indexRecordFirst, mpVbvaMemory->indexRecordFree,2054 mpVbvaMemory->off32Data, mpVbvaMemory->off32Free));660 pVbvaMemory->indexRecordFirst, pVbvaMemory->indexRecordFree, 661 pVbvaMemory->off32Data, pVbvaMemory->off32Free)); 2055 662 #endif /* DEBUG_sunlover_2 */ 2056 663 2057 664 /* Quick check for "nothing to update" case. */ 2058 if ( mpVbvaMemory->indexRecordFirst == mpVbvaMemory->indexRecordFree)665 if (pVbvaMemory->indexRecordFirst == pVbvaMemory->indexRecordFree) 2059 666 { 2060 667 return VINF_SUCCESS; … … 2066 673 /* Initialize dirty rectangles accumulator. */ 2067 674 VBVADIRTYREGION rgn; 2068 vbvaRgnInit(&rgn, maFramebuffers, mcMonitors, this, mpDrv->pUpPort);675 vbvaRgnInit(&rgn, maFramebuffers, mcMonitors, this, pUpPort); 2069 676 2070 677 for (;;) … … 2074 681 2075 682 /* Fetch the command data. */ 2076 if (!i_vbvaFetchCmd( &phdr, &cbCmd))683 if (!i_vbvaFetchCmd(pVideoAccel, &phdr, &cbCmd)) 2077 684 { 2078 685 Log(("Display::VideoAccelFlush: unable to fetch command. off32Data = %d, off32Free = %d. Disabling VBVA!!!\n", 2079 mpVbvaMemory->off32Data, mpVbvaMemory->off32Free));686 pVbvaMemory->off32Data, pVbvaMemory->off32Free)); 2080 687 return VERR_INVALID_STATE; 2081 688 } … … 2084 691 { 2085 692 /* No more commands yet in the queue. */ 693 #ifdef DEBUG_sunlover 694 LogFlowFunc(("no command\n")); 695 #endif /* DEBUG_sunlover */ 2086 696 break; 2087 697 } … … 2131 741 } 2132 742 2133 i_vbvaReleaseCmd(p hdr, cbCmd);743 i_vbvaReleaseCmd(pVideoAccel, phdr, cbCmd); 2134 744 } 2135 745 … … 2142 752 } 2143 753 2144 int Display::i_videoAccelRefreshProcess( void)754 int Display::i_videoAccelRefreshProcess(PPDMIDISPLAYPORT pUpPort) 2145 755 { 2146 756 int rc = VWRN_INVALID_STATE; /* Default is to do a display update in VGA device. */ 2147 757 2148 videoAccelEnterVGA(); 2149 2150 if (mfVideoAccelEnabled) 2151 { 2152 Assert(mpVbvaMemory); 2153 rc = i_videoAccelFlush(); 758 VIDEOACCEL *pVideoAccel = &mVideoAccelLegacy; 759 760 videoAccelEnterVGA(pVideoAccel); 761 762 if (pVideoAccel->fVideoAccelEnabled) 763 { 764 Assert(pVideoAccel->pVbvaMemory); 765 rc = i_videoAccelFlush(pUpPort); 2154 766 if (RT_FAILURE(rc)) 2155 767 { 2156 768 /* Disable on errors. */ 2157 i_videoAccelEnable(false, NULL );769 i_videoAccelEnable(false, NULL, pUpPort); 2158 770 rc = VWRN_INVALID_STATE; /* Do a display update in VGA device. */ 2159 771 } … … 2164 776 } 2165 777 2166 videoAccelLeaveVGA( );778 videoAccelLeaveVGA(pVideoAccel); 2167 779 2168 780 return rc; 2169 781 } 2170 782 2171 void Display::i_notifyPowerDown(void) 2172 { 2173 LogRelFlowFunc(("\n")); 2174 2175 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 2176 2177 /* Source bitmaps are not available anymore. */ 2178 mfSourceBitmapEnabled = false; 2179 2180 /* Resize all displays to tell framebuffers to forget current source bitmap. */ 2181 unsigned uScreenId = mcMonitors; 2182 while (uScreenId > 0) 2183 { 2184 --uScreenId; 2185 2186 DISPLAYFBINFO *pFBInfo = &maFramebuffers[uScreenId]; 2187 if (!pFBInfo->fDisabled) 2188 { 2189 i_handleDisplayResize(uScreenId, 32, 2190 pFBInfo->pu8FramebufferVRAM, 2191 pFBInfo->u32LineSize, 2192 pFBInfo->w, 2193 pFBInfo->h, 2194 pFBInfo->flags); 2195 } 2196 } 2197 } 2198 2199 // Wrapped IDisplay methods 2200 ///////////////////////////////////////////////////////////////////////////// 2201 HRESULT Display::getScreenResolution(ULONG aScreenId, ULONG *aWidth, ULONG *aHeight, ULONG *aBitsPerPixel, 2202 LONG *aXOrigin, LONG *aYOrigin) 2203 { 2204 LogRelFlowFunc(("aScreenId=%RU32\n", aScreenId)); 2205 2206 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 2207 2208 uint32_t u32Width = 0; 2209 uint32_t u32Height = 0; 2210 uint32_t u32BitsPerPixel = 0; 2211 int32_t xOrigin = 0; 2212 int32_t yOrigin = 0; 2213 2214 if (aScreenId == VBOX_VIDEO_PRIMARY_SCREEN) 2215 { 2216 if (mpDrv) 2217 { 2218 u32Width = mpDrv->IConnector.cx; 2219 u32Height = mpDrv->IConnector.cy; 2220 2221 alock.release(); 2222 2223 int rc = mpDrv->pUpPort->pfnQueryColorDepth(mpDrv->pUpPort, &u32BitsPerPixel); 2224 AssertRC(rc); 2225 2226 alock.acquire(); 2227 } 2228 } 2229 else if (aScreenId < mcMonitors) 2230 { 2231 DISPLAYFBINFO *pFBInfo = &maFramebuffers[aScreenId]; 2232 u32Width = pFBInfo->w; 2233 u32Height = pFBInfo->h; 2234 u32BitsPerPixel = pFBInfo->u16BitsPerPixel; 2235 xOrigin = pFBInfo->xOrigin; 2236 yOrigin = pFBInfo->yOrigin; 2237 } 2238 else 2239 { 2240 return E_INVALIDARG; 2241 } 2242 2243 if (aWidth) 2244 *aWidth = u32Width; 2245 if (aHeight) 2246 *aHeight = u32Height; 2247 if (aBitsPerPixel) 2248 *aBitsPerPixel = u32BitsPerPixel; 2249 if (aXOrigin) 2250 *aXOrigin = xOrigin; 2251 if (aYOrigin) 2252 *aYOrigin = yOrigin; 2253 2254 return S_OK; 2255 } 2256 2257 2258 HRESULT Display::attachFramebuffer(ULONG aScreenId, const ComPtr<IFramebuffer> &aFramebuffer) 2259 { 2260 LogRelFlowFunc(("aScreenId = %d\n", aScreenId)); 2261 2262 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 2263 2264 if (aScreenId >= mcMonitors) 2265 return setError(E_INVALIDARG, tr("AttachFramebuffer: Invalid screen %d (total %d)"), 2266 aScreenId, mcMonitors); 2267 2268 DISPLAYFBINFO *pFBInfo = &maFramebuffers[aScreenId]; 2269 if (!pFBInfo->pFramebuffer.isNull()) 2270 return setError(E_FAIL, tr("AttachFramebuffer: Framebuffer already attached to %d"), 2271 aScreenId); 2272 2273 pFBInfo->pFramebuffer = aFramebuffer; 2274 2275 SafeArray<FramebufferCapabilities_T> caps; 2276 pFBInfo->pFramebuffer->COMGETTER(Capabilities)(ComSafeArrayAsOutParam(caps)); 2277 pFBInfo->u32Caps = 0; 2278 size_t i; 2279 for (i = 0; i < caps.size(); ++i) 2280 pFBInfo->u32Caps |= caps[i]; 2281 2282 alock.release(); 2283 2284 /* The driver might not have been constructed yet */ 2285 if (mpDrv) 2286 { 2287 /* Setup the new framebuffer. */ 2288 i_handleDisplayResize(aScreenId, pFBInfo->u16BitsPerPixel, 2289 pFBInfo->pu8FramebufferVRAM, 2290 pFBInfo->u32LineSize, 2291 pFBInfo->w, 2292 pFBInfo->h, 2293 pFBInfo->flags); 2294 } 2295 2296 Console::SafeVMPtrQuiet ptrVM(mParent); 2297 if (ptrVM.isOk()) 2298 { 2299 #if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) 2300 BOOL fIs3DEnabled = FALSE; 2301 mParent->i_machine()->COMGETTER(Accelerate3DEnabled)(&fIs3DEnabled); 2302 2303 if (fIs3DEnabled) 2304 { 2305 VBOXCRCMDCTL_HGCM data; 2306 RT_ZERO(data); 2307 data.Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM; 2308 data.Hdr.u32Function = SHCRGL_HOST_FN_SCREEN_CHANGED; 2309 2310 data.aParms[0].type = VBOX_HGCM_SVC_PARM_32BIT; 2311 data.aParms[0].u.uint32 = aScreenId; 2312 2313 int vrc = i_crCtlSubmitSync(&data.Hdr, sizeof(data)); 2314 AssertRC(vrc); 2315 } 2316 #endif /* defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) */ 2317 2318 VMR3ReqCallNoWaitU(ptrVM.rawUVM(), VMCPUID_ANY, (PFNRT)Display::i_InvalidateAndUpdateEMT, 2319 3, this, aScreenId, false); 2320 } 2321 2322 LogRelFlowFunc(("Attached to %d\n", aScreenId)); 2323 return S_OK; 2324 } 2325 2326 HRESULT Display::detachFramebuffer(ULONG aScreenId) 2327 { 2328 LogRelFlowFunc(("aScreenId = %d\n", aScreenId)); 2329 2330 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 2331 2332 if (aScreenId >= mcMonitors) 2333 return setError(E_INVALIDARG, tr("DetachFramebuffer: Invalid screen %d (total %d)"), 2334 aScreenId, mcMonitors); 2335 2336 DISPLAYFBINFO *pFBInfo = &maFramebuffers[aScreenId]; 2337 2338 pFBInfo->pFramebuffer.setNull(); 2339 2340 alock.release(); 2341 2342 #if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) 2343 Console::SafeVMPtrQuiet ptrVM(mParent); 2344 if (ptrVM.isOk()) 2345 { 2346 BOOL fIs3DEnabled = FALSE; 2347 mParent->i_machine()->COMGETTER(Accelerate3DEnabled)(&fIs3DEnabled); 2348 2349 if (fIs3DEnabled) 2350 { 2351 VBOXCRCMDCTL_HGCM data; 2352 RT_ZERO(data); 2353 data.Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM; 2354 data.Hdr.u32Function = SHCRGL_HOST_FN_SCREEN_CHANGED; 2355 2356 data.aParms[0].type = VBOX_HGCM_SVC_PARM_32BIT; 2357 data.aParms[0].u.uint32 = aScreenId; 2358 2359 int vrc = i_crCtlSubmitSync(&data.Hdr, sizeof(data)); 2360 AssertRC(vrc); 2361 } 2362 } 2363 #endif /* defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) */ 2364 2365 return S_OK; 2366 } 2367 2368 HRESULT Display::queryFramebuffer(ULONG aScreenId, ComPtr<IFramebuffer> &aFramebuffer) 2369 { 2370 LogRelFlowFunc(("aScreenId = %d\n", aScreenId)); 2371 2372 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 2373 2374 if (aScreenId >= mcMonitors) 2375 return setError(E_INVALIDARG, tr("QueryFramebuffer: Invalid screen %d (total %d)"), 2376 aScreenId, mcMonitors); 2377 2378 DISPLAYFBINFO *pFBInfo = &maFramebuffers[aScreenId]; 2379 2380 pFBInfo->pFramebuffer.queryInterfaceTo(aFramebuffer.asOutParam()); 2381 2382 return S_OK; 2383 } 2384 2385 HRESULT Display::setVideoModeHint(ULONG aDisplay, BOOL aEnabled, 2386 BOOL aChangeOrigin, LONG aOriginX, LONG aOriginY, 2387 ULONG aWidth, ULONG aHeight, ULONG aBitsPerPixel) 2388 { 2389 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 2390 2391 CHECK_CONSOLE_DRV(mpDrv); 2392 2393 /* 2394 * Do some rough checks for valid input. 2395 */ 2396 ULONG width = aWidth; 2397 if (!width) 2398 width = mpDrv->IConnector.cx; 2399 ULONG height = aHeight; 2400 if (!height) 2401 height = mpDrv->IConnector.cy; 2402 ULONG bpp = aBitsPerPixel; 2403 if (!bpp) 2404 { 2405 alock.release(); 2406 2407 uint32_t cBits = 0; 2408 int rc = mpDrv->pUpPort->pfnQueryColorDepth(mpDrv->pUpPort, &cBits); 2409 AssertRC(rc); 2410 bpp = cBits; 2411 2412 alock.acquire(); 2413 } 2414 ULONG cMonitors; 2415 mParent->i_machine()->COMGETTER(MonitorCount)(&cMonitors); 2416 if (cMonitors == 0 && aDisplay > 0) 2417 return E_INVALIDARG; 2418 if (aDisplay >= cMonitors) 2419 return E_INVALIDARG; 2420 2421 /* 2422 * sunlover 20070614: It is up to the guest to decide whether the hint is 2423 * valid. Therefore don't do any VRAM sanity checks here! 2424 */ 2425 2426 /* Have to release the lock because the pfnRequestDisplayChange 2427 * will call EMT. */ 2428 alock.release(); 2429 2430 VMMDev *pVMMDev = mParent->i_getVMMDev(); 2431 if (pVMMDev) 2432 { 2433 PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort(); 2434 if (pVMMDevPort) 2435 pVMMDevPort->pfnRequestDisplayChange(pVMMDevPort, aWidth, aHeight, aBitsPerPixel, 2436 aDisplay, aOriginX, aOriginY, 2437 RT_BOOL(aEnabled), RT_BOOL(aChangeOrigin)); 2438 } 2439 return S_OK; 2440 } 2441 2442 HRESULT Display::setSeamlessMode(BOOL enabled) 2443 { 2444 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 2445 2446 /* Have to release the lock because the pfnRequestSeamlessChange will call EMT. */ 2447 alock.release(); 2448 2449 VMMDev *pVMMDev = mParent->i_getVMMDev(); 2450 if (pVMMDev) 2451 { 2452 PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort(); 2453 if (pVMMDevPort) 2454 pVMMDevPort->pfnRequestSeamlessChange(pVMMDevPort, !!enabled); 2455 } 2456 2457 #if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) 2458 if (!enabled) 2459 { 2460 BOOL is3denabled = FALSE; 2461 2462 mParent->i_machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled); 2463 2464 VMMDev *vmmDev = mParent->i_getVMMDev(); 2465 if (is3denabled && vmmDev) 2466 { 2467 VBOXCRCMDCTL_HGCM *pData = (VBOXCRCMDCTL_HGCM*)RTMemAlloc(sizeof(VBOXCRCMDCTL_HGCM)); 2468 if (!pData) 2469 { 2470 AssertMsgFailed(("RTMemAlloc failed\n")); 2471 return VERR_NO_MEMORY; 2472 } 2473 2474 pData->Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM; 2475 pData->Hdr.u32Function = SHCRGL_HOST_FN_SET_VISIBLE_REGION; 2476 2477 pData->aParms[0].type = VBOX_HGCM_SVC_PARM_PTR; 2478 pData->aParms[0].u.pointer.addr = NULL; 2479 pData->aParms[0].u.pointer.size = 0; /* <- means null rects, NULL pRects address and 0 rects means "disable" */ 2480 2481 int rc = i_crCtlSubmit(&pData->Hdr, sizeof(*pData), i_displayCrCmdFree, pData); 2482 if (!RT_SUCCESS(rc)) 2483 { 2484 AssertMsgFailed(("crCtlSubmit failed rc %d\n", rc)); 2485 RTMemFree(pData); 2486 } 2487 } 2488 } 2489 #endif 2490 return S_OK; 2491 } 2492 2493 #if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) 2494 BOOL Display::i_displayCheckTakeScreenshotCrOgl(Display *pDisplay, ULONG aScreenId, uint8_t *pu8Data, 2495 uint32_t u32Width, uint32_t u32Height) 2496 { 2497 BOOL is3denabled; 2498 pDisplay->mParent->i_machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled); 2499 if (is3denabled && pDisplay->mCrOglCallbacks.pfnHasData()) 2500 { 2501 VMMDev *pVMMDev = pDisplay->mParent->i_getVMMDev(); 2502 if (pVMMDev) 2503 { 2504 CRVBOXHGCMTAKESCREENSHOT *pScreenshot = (CRVBOXHGCMTAKESCREENSHOT*)RTMemAlloc(sizeof(*pScreenshot)); 2505 if (pScreenshot) 2506 { 2507 /* screen id or CRSCREEN_ALL to specify all enabled */ 2508 pScreenshot->u32Screen = aScreenId; 2509 pScreenshot->u32Width = u32Width; 2510 pScreenshot->u32Height = u32Height; 2511 pScreenshot->u32Pitch = u32Width * 4; 2512 pScreenshot->pvBuffer = pu8Data; 2513 pScreenshot->pvContext = NULL; 2514 pScreenshot->pfnScreenshotBegin = NULL; 2515 pScreenshot->pfnScreenshotPerform = NULL; 2516 pScreenshot->pfnScreenshotEnd = NULL; 2517 2518 VBOXCRCMDCTL_HGCM data; 2519 data.Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM; 2520 data.Hdr.u32Function = SHCRGL_HOST_FN_TAKE_SCREENSHOT; 2521 2522 data.aParms[0].type = VBOX_HGCM_SVC_PARM_PTR; 2523 data.aParms[0].u.pointer.addr = pScreenshot; 2524 data.aParms[0].u.pointer.size = sizeof(*pScreenshot); 2525 2526 int rc = pDisplay->i_crCtlSubmitSync(&data.Hdr, sizeof(data)); 2527 2528 RTMemFree(pScreenshot); 2529 2530 if (RT_SUCCESS(rc)) 2531 return TRUE; 2532 else 2533 { 2534 AssertMsgFailed(("failed to get screenshot data from crOgl %d\n", rc)); 2535 /* fall back to the non-3d mechanism */ 2536 } 2537 } 2538 } 2539 } 2540 return FALSE; 2541 } 2542 #endif 2543 2544 int Display::i_displayTakeScreenshotEMT(Display *pDisplay, ULONG aScreenId, uint8_t **ppu8Data, size_t *pcbData, 2545 uint32_t *pu32Width, uint32_t *pu32Height) 2546 { 2547 int rc; 2548 2549 if ( aScreenId == VBOX_VIDEO_PRIMARY_SCREEN 2550 && pDisplay->maFramebuffers[aScreenId].fVBVAEnabled == false) /* A non-VBVA mode. */ 2551 { 2552 rc = pDisplay->mpDrv->pUpPort->pfnTakeScreenshot(pDisplay->mpDrv->pUpPort, ppu8Data, pcbData, pu32Width, pu32Height); 2553 } 2554 else if (aScreenId < pDisplay->mcMonitors) 2555 { 2556 DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[aScreenId]; 2557 2558 uint32_t width = pFBInfo->w; 2559 uint32_t height = pFBInfo->h; 2560 2561 /* Allocate 32 bit per pixel bitmap. */ 2562 size_t cbRequired = width * 4 * height; 2563 2564 if (cbRequired) 2565 { 2566 uint8_t *pu8Data = (uint8_t *)RTMemAlloc(cbRequired); 2567 2568 if (pu8Data == NULL) 2569 { 2570 rc = VERR_NO_MEMORY; 2571 } 2572 else 2573 { 2574 /* Copy guest VRAM to the allocated 32bpp buffer. */ 2575 const uint8_t *pu8Src = pFBInfo->pu8FramebufferVRAM; 2576 int32_t xSrc = 0; 2577 int32_t ySrc = 0; 2578 uint32_t u32SrcWidth = width; 2579 uint32_t u32SrcHeight = height; 2580 uint32_t u32SrcLineSize = pFBInfo->u32LineSize; 2581 uint32_t u32SrcBitsPerPixel = pFBInfo->u16BitsPerPixel; 2582 2583 uint8_t *pu8Dst = pu8Data; 2584 int32_t xDst = 0; 2585 int32_t yDst = 0; 2586 uint32_t u32DstWidth = u32SrcWidth; 2587 uint32_t u32DstHeight = u32SrcHeight; 2588 uint32_t u32DstLineSize = u32DstWidth * 4; 2589 uint32_t u32DstBitsPerPixel = 32; 2590 2591 rc = pDisplay->mpDrv->pUpPort->pfnCopyRect(pDisplay->mpDrv->pUpPort, 2592 width, height, 2593 pu8Src, 2594 xSrc, ySrc, 2595 u32SrcWidth, u32SrcHeight, 2596 u32SrcLineSize, u32SrcBitsPerPixel, 2597 pu8Dst, 2598 xDst, yDst, 2599 u32DstWidth, u32DstHeight, 2600 u32DstLineSize, u32DstBitsPerPixel); 2601 if (RT_SUCCESS(rc)) 2602 { 2603 *ppu8Data = pu8Data; 2604 *pcbData = cbRequired; 2605 *pu32Width = width; 2606 *pu32Height = height; 2607 } 2608 else 2609 { 2610 RTMemFree(pu8Data); 2611 2612 /* CopyRect can fail if VBVA was paused in VGA device, retry using the generic method. */ 2613 if ( rc == VERR_INVALID_STATE 2614 && aScreenId == VBOX_VIDEO_PRIMARY_SCREEN) 2615 { 2616 rc = pDisplay->mpDrv->pUpPort->pfnTakeScreenshot(pDisplay->mpDrv->pUpPort, 2617 ppu8Data, pcbData, pu32Width, pu32Height); 2618 } 2619 } 2620 } 2621 } 2622 else 2623 { 2624 /* No image. */ 2625 *ppu8Data = NULL; 2626 *pcbData = 0; 2627 *pu32Width = 0; 2628 *pu32Height = 0; 2629 rc = VINF_SUCCESS; 2630 } 2631 } 2632 else 2633 { 2634 rc = VERR_INVALID_PARAMETER; 2635 } 2636 2637 return rc; 2638 } 2639 2640 static int i_displayTakeScreenshot(PUVM pUVM, Display *pDisplay, struct DRVMAINDISPLAY *pDrv, ULONG aScreenId, 2641 BYTE *address, ULONG width, ULONG height) 2642 { 2643 uint8_t *pu8Data = NULL; 2644 size_t cbData = 0; 2645 uint32_t cx = 0; 2646 uint32_t cy = 0; 2647 int vrc = VINF_SUCCESS; 2648 2649 # if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) 2650 if (Display::i_displayCheckTakeScreenshotCrOgl(pDisplay, aScreenId, (uint8_t*)address, width, height)) 2651 return VINF_SUCCESS; 2652 #endif 2653 2654 int cRetries = 5; 2655 2656 while (cRetries-- > 0) 2657 { 2658 /* Note! Not sure if the priority call is such a good idea here, but 2659 it would be nice to have an accurate screenshot for the bug 2660 report if the VM deadlocks. */ 2661 vrc = VMR3ReqPriorityCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)Display::i_displayTakeScreenshotEMT, 6, 2662 pDisplay, aScreenId, &pu8Data, &cbData, &cx, &cy); 2663 if (vrc != VERR_TRY_AGAIN) 2664 { 2665 break; 2666 } 2667 2668 RTThreadSleep(10); 2669 } 2670 2671 if (RT_SUCCESS(vrc) && pu8Data) 2672 { 2673 if (cx == width && cy == height) 2674 { 2675 /* No scaling required. */ 2676 memcpy(address, pu8Data, cbData); 2677 } 2678 else 2679 { 2680 /* Scale. */ 2681 LogRelFlowFunc(("SCALE: %dx%d -> %dx%d\n", cx, cy, width, height)); 2682 2683 uint8_t *dst = address; 2684 uint8_t *src = pu8Data; 2685 int dstW = width; 2686 int dstH = height; 2687 int srcW = cx; 2688 int srcH = cy; 2689 int iDeltaLine = cx * 4; 2690 2691 BitmapScale32(dst, 2692 dstW, dstH, 2693 src, 2694 iDeltaLine, 2695 srcW, srcH); 2696 } 2697 2698 if (aScreenId == VBOX_VIDEO_PRIMARY_SCREEN) 2699 { 2700 /* This can be called from any thread. */ 2701 pDrv->pUpPort->pfnFreeScreenshot(pDrv->pUpPort, pu8Data); 2702 } 2703 else 2704 { 2705 RTMemFree(pu8Data); 2706 } 2707 } 2708 2709 return vrc; 2710 } 2711 2712 HRESULT Display::takeScreenShotWorker(ULONG aScreenId, 2713 BYTE *aAddress, 2714 ULONG aWidth, 2715 ULONG aHeight, 2716 BitmapFormat_T aBitmapFormat, 2717 ULONG *pcbOut) 2718 { 2719 HRESULT rc = S_OK; 2720 2721 /* Do not allow too small and too large screenshots. This also filters out negative 2722 * values passed as either 'aWidth' or 'aHeight'. 2723 */ 2724 CheckComArgExpr(aWidth, aWidth != 0 && aWidth <= 32767); 2725 CheckComArgExpr(aHeight, aHeight != 0 && aHeight <= 32767); 2726 2727 if ( aBitmapFormat != BitmapFormat_BGR0 2728 && aBitmapFormat != BitmapFormat_BGRA 2729 && aBitmapFormat != BitmapFormat_RGBA 2730 && aBitmapFormat != BitmapFormat_PNG) 2731 { 2732 return setError(E_NOTIMPL, 2733 tr("Unsupported screenshot format 0x%08X"), aBitmapFormat); 2734 } 2735 2736 Console::SafeVMPtr ptrVM(mParent); 2737 if (!ptrVM.isOk()) 2738 return ptrVM.rc(); 2739 2740 int vrc = i_displayTakeScreenshot(ptrVM.rawUVM(), this, mpDrv, aScreenId, aAddress, aWidth, aHeight); 2741 2742 if (RT_SUCCESS(vrc)) 2743 { 2744 const size_t cbData = aWidth * 4 * aHeight; 2745 2746 /* Most of uncompressed formats. */ 2747 *pcbOut = (ULONG)cbData; 2748 2749 if (aBitmapFormat == BitmapFormat_BGR0) 2750 { 2751 /* Do nothing. */ 2752 } 2753 else if (aBitmapFormat == BitmapFormat_BGRA) 2754 { 2755 uint32_t *pu32 = (uint32_t *)aAddress; 2756 size_t cPixels = aWidth * aHeight; 2757 while (cPixels--) 2758 { 2759 *pu32++ |= UINT32_C(0xFF000000); 2760 } 2761 } 2762 else if (aBitmapFormat == BitmapFormat_RGBA) 2763 { 2764 uint8_t *pu8 = aAddress; 2765 size_t cPixels = aWidth * aHeight; 2766 while (cPixels--) 2767 { 2768 uint8_t u8 = pu8[0]; 2769 pu8[0] = pu8[2]; 2770 pu8[2] = u8; 2771 pu8[3] = 0xFF; 2772 2773 pu8 += 4; 2774 } 2775 } 2776 else if (aBitmapFormat == BitmapFormat_PNG) 2777 { 2778 uint8_t *pu8PNG = NULL; 2779 uint32_t cbPNG = 0; 2780 uint32_t cxPNG = 0; 2781 uint32_t cyPNG = 0; 2782 2783 vrc = DisplayMakePNG(aAddress, aWidth, aHeight, &pu8PNG, &cbPNG, &cxPNG, &cyPNG, 0); 2784 if (RT_SUCCESS(vrc)) 2785 { 2786 if (cbPNG <= cbData) 2787 { 2788 memcpy(aAddress, pu8PNG, cbPNG); 2789 *pcbOut = cbPNG; 2790 } 2791 else 2792 { 2793 rc = setError(E_FAIL, 2794 tr("PNG is larger than 32bpp bitmap")); 2795 } 2796 } 2797 else 2798 { 2799 rc = setError(VBOX_E_IPRT_ERROR, 2800 tr("Could not convert screenshot to PNG (%Rrc)"), vrc); 2801 } 2802 RTMemFree(pu8PNG); 2803 } 2804 } 2805 else if (vrc == VERR_TRY_AGAIN) 2806 rc = setError(E_UNEXPECTED, 2807 tr("Screenshot is not available at this time")); 2808 else if (RT_FAILURE(vrc)) 2809 rc = setError(VBOX_E_IPRT_ERROR, 2810 tr("Could not take a screenshot (%Rrc)"), vrc); 2811 2812 return rc; 2813 } 2814 2815 HRESULT Display::takeScreenShot(ULONG aScreenId, 2816 BYTE *aAddress, 2817 ULONG aWidth, 2818 ULONG aHeight, 2819 BitmapFormat_T aBitmapFormat) 2820 { 2821 HRESULT rc = S_OK; 2822 2823 LogRelFlowFunc(("[%d] address=%p, width=%d, height=%d, format 0x%08X\n", 2824 aScreenId, aAddress, aWidth, aHeight, aBitmapFormat)); 2825 2826 ULONG cbOut = 0; 2827 rc = takeScreenShotWorker(aScreenId, aAddress, aWidth, aHeight, aBitmapFormat, &cbOut); 2828 NOREF(cbOut); 2829 2830 LogRelFlowFunc(("%Rhrc\n", rc)); 2831 return rc; 2832 } 2833 2834 HRESULT Display::takeScreenShotToArray(ULONG aScreenId, 2835 ULONG aWidth, 2836 ULONG aHeight, 2837 BitmapFormat_T aBitmapFormat, 2838 std::vector<BYTE> &aScreenData) 2839 { 2840 HRESULT rc = S_OK; 2841 2842 LogRelFlowFunc(("[%d] width=%d, height=%d, format 0x%08X\n", 2843 aScreenId, aWidth, aHeight, aBitmapFormat)); 2844 2845 /* Do not allow too small and too large screenshots. This also filters out negative 2846 * values passed as either 'aWidth' or 'aHeight'. 2847 */ 2848 CheckComArgExpr(aWidth, aWidth != 0 && aWidth <= 32767); 2849 CheckComArgExpr(aHeight, aHeight != 0 && aHeight <= 32767); 2850 2851 const size_t cbData = aWidth * 4 * aHeight; 2852 aScreenData.resize(cbData); 2853 2854 ULONG cbOut = 0; 2855 rc = takeScreenShotWorker(aScreenId, &aScreenData.front(), aWidth, aHeight, aBitmapFormat, &cbOut); 2856 if (FAILED(rc)) 2857 cbOut = 0; 2858 2859 aScreenData.resize(cbOut); 2860 2861 LogRelFlowFunc(("%Rhrc\n", rc)); 2862 return rc; 2863 } 2864 2865 2866 int Display::i_VideoCaptureEnableScreens(ComSafeArrayIn(BOOL, aScreens)) 2867 { 2868 #ifdef VBOX_WITH_VPX 2869 com::SafeArray<BOOL> Screens(ComSafeArrayInArg(aScreens)); 2870 for (unsigned i = 0; i < Screens.size(); i++) 2871 maVideoRecEnabled[i] = RT_BOOL(Screens[i]); 2872 return VINF_SUCCESS; 2873 #else 2874 return VERR_NOT_IMPLEMENTED; 2875 #endif 2876 } 2877 2878 /** 2879 * Start video capturing. Does nothing if capturing is already active. 2880 */ 2881 int Display::i_VideoCaptureStart() 2882 { 2883 #ifdef VBOX_WITH_VPX 2884 if (VideoRecIsEnabled(mpVideoRecCtx)) 2885 return VINF_SUCCESS; 2886 2887 int rc = VideoRecContextCreate(&mpVideoRecCtx, mcMonitors); 2888 if (RT_FAILURE(rc)) 2889 { 2890 LogFlow(("Failed to create video recording context (%Rrc)!\n", rc)); 2891 return rc; 2892 } 2893 ComPtr<IMachine> pMachine = mParent->i_machine(); 2894 com::SafeArray<BOOL> screens; 2895 HRESULT hrc = pMachine->COMGETTER(VideoCaptureScreens)(ComSafeArrayAsOutParam(screens)); 2896 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED); 2897 for (unsigned i = 0; i < RT_ELEMENTS(maVideoRecEnabled); i++) 2898 maVideoRecEnabled[i] = i < screens.size() && screens[i]; 2899 ULONG ulWidth; 2900 hrc = pMachine->COMGETTER(VideoCaptureWidth)(&ulWidth); 2901 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED); 2902 ULONG ulHeight; 2903 hrc = pMachine->COMGETTER(VideoCaptureHeight)(&ulHeight); 2904 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED); 2905 ULONG ulRate; 2906 hrc = pMachine->COMGETTER(VideoCaptureRate)(&ulRate); 2907 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED); 2908 ULONG ulFPS; 2909 hrc = pMachine->COMGETTER(VideoCaptureFPS)(&ulFPS); 2910 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED); 2911 BSTR strFile; 2912 hrc = pMachine->COMGETTER(VideoCaptureFile)(&strFile); 2913 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED); 2914 ULONG ulMaxTime; 2915 hrc = pMachine->COMGETTER(VideoCaptureMaxTime)(&ulMaxTime); 2916 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED); 2917 ULONG ulMaxSize; 2918 hrc = pMachine->COMGETTER(VideoCaptureMaxFileSize)(&ulMaxSize); 2919 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED); 2920 BSTR strOptions; 2921 hrc = pMachine->COMGETTER(VideoCaptureOptions)(&strOptions); 2922 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED); 2923 2924 RTTIMESPEC ts; 2925 RTTimeNow(&ts); 2926 RTTIME time; 2927 RTTimeExplode(&time, &ts); 2928 for (unsigned uScreen = 0; uScreen < mcMonitors; uScreen++) 2929 { 2930 char *pszAbsPath = RTPathAbsDup(com::Utf8Str(strFile).c_str()); 2931 char *pszSuff = RTPathSuffix(pszAbsPath); 2932 if (pszSuff) 2933 pszSuff = RTStrDup(pszSuff); 2934 RTPathStripSuffix(pszAbsPath); 2935 if (!pszAbsPath) 2936 rc = VERR_INVALID_PARAMETER; 2937 if (!pszSuff) 2938 pszSuff = RTStrDup(".webm"); 2939 char *pszName = NULL; 2940 if (RT_SUCCESS(rc)) 2941 { 2942 if (mcMonitors > 1) 2943 rc = RTStrAPrintf(&pszName, "%s-%u%s", pszAbsPath, uScreen+1, pszSuff); 2944 else 2945 rc = RTStrAPrintf(&pszName, "%s%s", pszAbsPath, pszSuff); 2946 } 2947 if (RT_SUCCESS(rc)) 2948 { 2949 rc = VideoRecStrmInit(mpVideoRecCtx, uScreen, 2950 pszName, ulWidth, ulHeight, 2951 ulRate, ulFPS, ulMaxTime, 2952 ulMaxSize, com::Utf8Str(strOptions).c_str()); 2953 if (rc == VERR_ALREADY_EXISTS) 2954 { 2955 RTStrFree(pszName); 2956 pszName = NULL; 2957 2958 if (mcMonitors > 1) 2959 rc = RTStrAPrintf(&pszName, "%s-%04d-%02u-%02uT%02u-%02u-%02u-%09uZ-%u%s", 2960 pszAbsPath, time.i32Year, time.u8Month, time.u8MonthDay, 2961 time.u8Hour, time.u8Minute, time.u8Second, time.u32Nanosecond, 2962 uScreen+1, pszSuff); 2963 else 2964 rc = RTStrAPrintf(&pszName, "%s-%04d-%02u-%02uT%02u-%02u-%02u-%09uZ%s", 2965 pszAbsPath, time.i32Year, time.u8Month, time.u8MonthDay, 2966 time.u8Hour, time.u8Minute, time.u8Second, time.u32Nanosecond, 2967 pszSuff); 2968 if (RT_SUCCESS(rc)) 2969 rc = VideoRecStrmInit(mpVideoRecCtx, uScreen, 2970 pszName, ulWidth, ulHeight, ulRate, 2971 ulFPS, ulMaxTime, 2972 ulMaxSize, com::Utf8Str(strOptions).c_str()); 2973 } 2974 } 2975 2976 if (RT_SUCCESS(rc)) 2977 LogRel(("WebM/VP8 video recording screen #%u with %ux%u @ %u kbps, %u fps to '%s' enabled.\n", 2978 uScreen, ulWidth, ulHeight, ulRate, ulFPS, pszName)); 2979 else 2980 LogRel(("Failed to initialize video recording context #%u (%Rrc)!\n", uScreen, rc)); 2981 RTStrFree(pszName); 2982 RTStrFree(pszSuff); 2983 RTStrFree(pszAbsPath); 2984 } 2985 return rc; 2986 #else 2987 return VERR_NOT_IMPLEMENTED; 2988 #endif 2989 } 2990 2991 /** 2992 * Stop video capturing. Does nothing if video capturing is not active. 2993 */ 2994 void Display::i_VideoCaptureStop() 2995 { 2996 #ifdef VBOX_WITH_VPX 2997 if (VideoRecIsEnabled(mpVideoRecCtx)) 2998 LogRel(("WebM/VP8 video recording stopped.\n")); 2999 VideoRecContextClose(mpVideoRecCtx); 3000 mpVideoRecCtx = NULL; 3001 #endif 3002 } 3003 3004 int Display::i_drawToScreenEMT(Display *pDisplay, ULONG aScreenId, BYTE *address, 3005 ULONG x, ULONG y, ULONG width, ULONG height) 3006 { 3007 int rc = VINF_SUCCESS; 3008 3009 DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[aScreenId]; 3010 3011 if (aScreenId == VBOX_VIDEO_PRIMARY_SCREEN) 3012 { 3013 rc = pDisplay->mpDrv->pUpPort->pfnDisplayBlt(pDisplay->mpDrv->pUpPort, address, x, y, width, height); 3014 } 3015 else if (aScreenId < pDisplay->mcMonitors) 3016 { 3017 /* Copy the bitmap to the guest VRAM. */ 3018 const uint8_t *pu8Src = address; 3019 int32_t xSrc = 0; 3020 int32_t ySrc = 0; 3021 uint32_t u32SrcWidth = width; 3022 uint32_t u32SrcHeight = height; 3023 uint32_t u32SrcLineSize = width * 4; 3024 uint32_t u32SrcBitsPerPixel = 32; 3025 3026 uint8_t *pu8Dst = pFBInfo->pu8FramebufferVRAM; 3027 int32_t xDst = x; 3028 int32_t yDst = y; 3029 uint32_t u32DstWidth = pFBInfo->w; 3030 uint32_t u32DstHeight = pFBInfo->h; 3031 uint32_t u32DstLineSize = pFBInfo->u32LineSize; 3032 uint32_t u32DstBitsPerPixel = pFBInfo->u16BitsPerPixel; 3033 3034 rc = pDisplay->mpDrv->pUpPort->pfnCopyRect(pDisplay->mpDrv->pUpPort, 3035 width, height, 3036 pu8Src, 3037 xSrc, ySrc, 3038 u32SrcWidth, u32SrcHeight, 3039 u32SrcLineSize, u32SrcBitsPerPixel, 3040 pu8Dst, 3041 xDst, yDst, 3042 u32DstWidth, u32DstHeight, 3043 u32DstLineSize, u32DstBitsPerPixel); 3044 if (RT_SUCCESS(rc)) 3045 { 3046 if (!pFBInfo->pSourceBitmap.isNull()) 3047 { 3048 /* Update the changed screen area. When source bitmap uses VRAM directly, just notify 3049 * frontend to update. And for default format, render the guest VRAM to the source bitmap. 3050 */ 3051 if ( pFBInfo->fDefaultFormat 3052 && !pFBInfo->fDisabled) 3053 { 3054 BYTE *pAddress = NULL; 3055 ULONG ulWidth = 0; 3056 ULONG ulHeight = 0; 3057 ULONG ulBitsPerPixel = 0; 3058 ULONG ulBytesPerLine = 0; 3059 ULONG ulPixelFormat = 0; 3060 3061 HRESULT hrc = pFBInfo->pSourceBitmap->QueryBitmapInfo(&pAddress, 3062 &ulWidth, 3063 &ulHeight, 3064 &ulBitsPerPixel, 3065 &ulBytesPerLine, 3066 &ulPixelFormat); 3067 if (SUCCEEDED(hrc)) 3068 { 3069 pu8Src = pFBInfo->pu8FramebufferVRAM; 3070 xSrc = x; 3071 ySrc = y; 3072 u32SrcWidth = pFBInfo->w; 3073 u32SrcHeight = pFBInfo->h; 3074 u32SrcLineSize = pFBInfo->u32LineSize; 3075 u32SrcBitsPerPixel = pFBInfo->u16BitsPerPixel; 3076 3077 /* Default format is 32 bpp. */ 3078 pu8Dst = pAddress; 3079 xDst = xSrc; 3080 yDst = ySrc; 3081 u32DstWidth = u32SrcWidth; 3082 u32DstHeight = u32SrcHeight; 3083 u32DstLineSize = u32DstWidth * 4; 3084 u32DstBitsPerPixel = 32; 3085 3086 pDisplay->mpDrv->pUpPort->pfnCopyRect(pDisplay->mpDrv->pUpPort, 3087 width, height, 3088 pu8Src, 3089 xSrc, ySrc, 3090 u32SrcWidth, u32SrcHeight, 3091 u32SrcLineSize, u32SrcBitsPerPixel, 3092 pu8Dst, 3093 xDst, yDst, 3094 u32DstWidth, u32DstHeight, 3095 u32DstLineSize, u32DstBitsPerPixel); 3096 } 3097 } 3098 } 3099 3100 pDisplay->i_handleDisplayUpdate(aScreenId, x, y, width, height); 3101 } 3102 } 3103 else 3104 { 3105 rc = VERR_INVALID_PARAMETER; 3106 } 3107 3108 if (RT_SUCCESS(rc)) 3109 pDisplay->mParent->i_consoleVRDPServer()->SendUpdateBitmap(aScreenId, x, y, width, height); 3110 3111 return rc; 3112 } 3113 3114 HRESULT Display::drawToScreen(ULONG aScreenId, BYTE *aAddress, ULONG aX, ULONG aY, ULONG aWidth, ULONG aHeight) 3115 { 3116 /// @todo (r=dmik) this function may take too long to complete if the VM 3117 // is doing something like saving state right now. Which, in case if it 3118 // is called on the GUI thread, will make it unresponsive. We should 3119 // check the machine state here (by enclosing the check and VMRequCall 3120 // within the Console lock to make it atomic). 3121 3122 LogRelFlowFunc(("aAddress=%p, x=%d, y=%d, width=%d, height=%d\n", 3123 (void *)aAddress, aX, aY, aWidth, aHeight)); 3124 3125 CheckComArgExpr(aWidth, aWidth != 0); 3126 CheckComArgExpr(aHeight, aHeight != 0); 3127 3128 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 3129 3130 CHECK_CONSOLE_DRV(mpDrv); 3131 3132 Console::SafeVMPtr ptrVM(mParent); 3133 if (!ptrVM.isOk()) 3134 return ptrVM.rc(); 3135 3136 /* Release lock because the call scheduled on EMT may also try to take it. */ 3137 alock.release(); 3138 3139 /* 3140 * Again we're lazy and make the graphics device do all the 3141 * dirty conversion work. 3142 */ 3143 int rcVBox = VMR3ReqCallWaitU(ptrVM.rawUVM(), VMCPUID_ANY, (PFNRT)Display::i_drawToScreenEMT, 7, 3144 this, aScreenId, aAddress, aX, aY, aWidth, aHeight); 3145 3146 /* 3147 * If the function returns not supported, we'll have to do all the 3148 * work ourselves using the framebuffer. 3149 */ 3150 HRESULT rc = S_OK; 3151 if (rcVBox == VERR_NOT_SUPPORTED || rcVBox == VERR_NOT_IMPLEMENTED) 3152 { 3153 /** @todo implement generic fallback for screen blitting. */ 3154 rc = E_NOTIMPL; 3155 } 3156 else if (RT_FAILURE(rcVBox)) 3157 rc = setError(VBOX_E_IPRT_ERROR, 3158 tr("Could not draw to the screen (%Rrc)"), rcVBox); 3159 //@todo 3160 // else 3161 // { 3162 // /* All ok. Redraw the screen. */ 3163 // handleDisplayUpdate (x, y, width, height); 3164 // } 3165 3166 LogRelFlowFunc(("rc=%Rhrc\n", rc)); 3167 return rc; 3168 } 3169 3170 int Display::i_InvalidateAndUpdateEMT(Display *pDisplay, unsigned uId, bool fUpdateAll) 3171 { 3172 LogRelFlowFunc(("uId=%d, fUpdateAll %d\n", uId, fUpdateAll)); 3173 3174 unsigned uScreenId; 3175 for (uScreenId = (fUpdateAll ? 0 : uId); uScreenId < pDisplay->mcMonitors; uScreenId++) 3176 { 3177 DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[uScreenId]; 3178 3179 if ( !pFBInfo->fVBVAEnabled 3180 && uScreenId == VBOX_VIDEO_PRIMARY_SCREEN) 3181 { 3182 pDisplay->mpDrv->pUpPort->pfnUpdateDisplayAll(pDisplay->mpDrv->pUpPort, /* fFailOnResize = */ true); 3183 } 3184 else 3185 { 3186 if (!pFBInfo->fDisabled) 3187 { 3188 /* Render complete VRAM screen to the framebuffer. 3189 * When framebuffer uses VRAM directly, just notify it to update. 3190 */ 3191 if (pFBInfo->fDefaultFormat && !pFBInfo->pSourceBitmap.isNull()) 3192 { 3193 BYTE *pAddress = NULL; 3194 ULONG ulWidth = 0; 3195 ULONG ulHeight = 0; 3196 ULONG ulBitsPerPixel = 0; 3197 ULONG ulBytesPerLine = 0; 3198 ULONG ulPixelFormat = 0; 3199 3200 HRESULT hrc = pFBInfo->pSourceBitmap->QueryBitmapInfo(&pAddress, 3201 &ulWidth, 3202 &ulHeight, 3203 &ulBitsPerPixel, 3204 &ulBytesPerLine, 3205 &ulPixelFormat); 3206 if (SUCCEEDED(hrc)) 3207 { 3208 uint32_t width = pFBInfo->w; 3209 uint32_t height = pFBInfo->h; 3210 3211 const uint8_t *pu8Src = pFBInfo->pu8FramebufferVRAM; 3212 int32_t xSrc = 0; 3213 int32_t ySrc = 0; 3214 uint32_t u32SrcWidth = pFBInfo->w; 3215 uint32_t u32SrcHeight = pFBInfo->h; 3216 uint32_t u32SrcLineSize = pFBInfo->u32LineSize; 3217 uint32_t u32SrcBitsPerPixel = pFBInfo->u16BitsPerPixel; 3218 3219 /* Default format is 32 bpp. */ 3220 uint8_t *pu8Dst = pAddress; 3221 int32_t xDst = xSrc; 3222 int32_t yDst = ySrc; 3223 uint32_t u32DstWidth = u32SrcWidth; 3224 uint32_t u32DstHeight = u32SrcHeight; 3225 uint32_t u32DstLineSize = u32DstWidth * 4; 3226 uint32_t u32DstBitsPerPixel = 32; 3227 3228 /* if uWidth != pFBInfo->w and uHeight != pFBInfo->h 3229 * implies resize of Framebuffer is in progress and 3230 * copyrect should not be called. 3231 */ 3232 if (ulWidth == pFBInfo->w && ulHeight == pFBInfo->h) 3233 { 3234 pDisplay->mpDrv->pUpPort->pfnCopyRect(pDisplay->mpDrv->pUpPort, 3235 width, height, 3236 pu8Src, 3237 xSrc, ySrc, 3238 u32SrcWidth, u32SrcHeight, 3239 u32SrcLineSize, u32SrcBitsPerPixel, 3240 pu8Dst, 3241 xDst, yDst, 3242 u32DstWidth, u32DstHeight, 3243 u32DstLineSize, u32DstBitsPerPixel); 3244 } 3245 } 3246 } 3247 3248 pDisplay->i_handleDisplayUpdate(uScreenId, 0, 0, pFBInfo->w, pFBInfo->h); 3249 } 3250 } 3251 if (!fUpdateAll) 3252 break; 3253 } 3254 LogRelFlowFunc(("done\n")); 3255 return VINF_SUCCESS; 3256 } 3257 3258 /** 3259 * Does a full invalidation of the VM display and instructs the VM 3260 * to update it immediately. 3261 * 3262 * @returns COM status code 3263 */ 3264 3265 HRESULT Display::invalidateAndUpdate() 3266 { 3267 LogRelFlowFunc(("\n")); 3268 3269 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 3270 3271 CHECK_CONSOLE_DRV(mpDrv); 3272 3273 Console::SafeVMPtr ptrVM(mParent); 3274 if (!ptrVM.isOk()) 3275 return ptrVM.rc(); 3276 3277 HRESULT rc = S_OK; 3278 3279 LogRelFlowFunc(("Sending DPYUPDATE request\n")); 3280 3281 /* Have to release the lock when calling EMT. */ 3282 alock.release(); 3283 3284 int rcVBox = VMR3ReqCallNoWaitU(ptrVM.rawUVM(), VMCPUID_ANY, (PFNRT)Display::i_InvalidateAndUpdateEMT, 3285 3, this, 0, true); 3286 alock.acquire(); 3287 3288 if (RT_FAILURE(rcVBox)) 3289 rc = setError(VBOX_E_IPRT_ERROR, 3290 tr("Could not invalidate and update the screen (%Rrc)"), rcVBox); 3291 3292 LogRelFlowFunc(("rc=%Rhrc\n", rc)); 3293 return rc; 3294 } 3295 3296 HRESULT Display::invalidateAndUpdateScreen(ULONG aScreenId) 3297 { 3298 LogRelFlowFunc(("\n")); 3299 3300 HRESULT rc = S_OK; 3301 3302 Console::SafeVMPtr ptrVM(mParent); 3303 if (!ptrVM.isOk()) 3304 return ptrVM.rc(); 3305 3306 int rcVBox = VMR3ReqCallNoWaitU(ptrVM.rawUVM(), VMCPUID_ANY, (PFNRT)Display::i_InvalidateAndUpdateEMT, 3307 3, this, aScreenId, false); 3308 if (RT_FAILURE(rcVBox)) 3309 rc = setError(VBOX_E_IPRT_ERROR, 3310 tr("Could not invalidate and update the screen %d (%Rrc)"), aScreenId, rcVBox); 3311 3312 LogRelFlowFunc(("rc=%Rhrc\n", rc)); 3313 return rc; 3314 } 3315 3316 HRESULT Display::completeVHWACommand(BYTE *aCommand) 3317 { 3318 #ifdef VBOX_WITH_VIDEOHWACCEL 3319 mpDrv->pVBVACallbacks->pfnVHWACommandCompleteAsync(mpDrv->pVBVACallbacks, (PVBOXVHWACMD)aCommand); 3320 return S_OK; 3321 #else 3322 return E_NOTIMPL; 3323 #endif 3324 } 3325 3326 HRESULT Display::viewportChanged(ULONG aScreenId, ULONG aX, ULONG aY, ULONG aWidth, ULONG aHeight) 3327 { 3328 #if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) 3329 3330 if (mcMonitors <= aScreenId) 3331 { 3332 AssertMsgFailed(("invalid screen id\n")); 3333 return E_INVALIDARG; 3334 } 3335 3336 BOOL is3denabled; 3337 mParent->i_machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled); 3338 3339 if (is3denabled) 3340 { 3341 int rc = i_crViewportNotify(aScreenId, aX, aY, aWidth, aHeight); 3342 if (RT_FAILURE(rc)) 3343 { 3344 DISPLAYFBINFO *pFb = &maFramebuffers[aScreenId]; 3345 pFb->pendingViewportInfo.fPending = true; 3346 pFb->pendingViewportInfo.x = aX; 3347 pFb->pendingViewportInfo.y = aY; 3348 pFb->pendingViewportInfo.width = aWidth; 3349 pFb->pendingViewportInfo.height = aHeight; 3350 } 3351 } 3352 #endif /* VBOX_WITH_CROGL && VBOX_WITH_HGCM */ 3353 return S_OK; 3354 } 3355 3356 HRESULT Display::querySourceBitmap(ULONG aScreenId, 3357 ComPtr<IDisplaySourceBitmap> &aDisplaySourceBitmap) 3358 { 3359 LogRelFlowFunc(("aScreenId = %d\n", aScreenId)); 3360 3361 Console::SafeVMPtr ptrVM(mParent); 3362 if (!ptrVM.isOk()) 3363 return ptrVM.rc(); 3364 3365 bool fSetRenderVRAM = false; 3366 bool fInvalidate = false; 3367 3368 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 3369 3370 if (aScreenId >= mcMonitors) 3371 return setError(E_INVALIDARG, tr("QuerySourceBitmap: Invalid screen %d (total %d)"), 3372 aScreenId, mcMonitors); 3373 3374 if (!mfSourceBitmapEnabled) 3375 { 3376 aDisplaySourceBitmap = NULL; 3377 return E_FAIL; 3378 } 3379 3380 HRESULT hr = S_OK; 3381 3382 DISPLAYFBINFO *pFBInfo = &maFramebuffers[aScreenId]; 3383 if (pFBInfo->pSourceBitmap.isNull()) 3384 { 3385 /* Create a new object. */ 3386 ComObjPtr<DisplaySourceBitmap> obj; 3387 hr = obj.createObject(); 3388 if (SUCCEEDED(hr)) 3389 hr = obj->init(this, aScreenId, pFBInfo); 3390 3391 if (SUCCEEDED(hr)) 3392 { 3393 bool fDefaultFormat = !obj->i_usesVRAM(); 3394 3395 if (aScreenId == VBOX_VIDEO_PRIMARY_SCREEN) 3396 { 3397 /* Start buffer updates. */ 3398 BYTE *pAddress = NULL; 3399 ULONG ulWidth = 0; 3400 ULONG ulHeight = 0; 3401 ULONG ulBitsPerPixel = 0; 3402 ULONG ulBytesPerLine = 0; 3403 ULONG ulPixelFormat = 0; 3404 3405 obj->QueryBitmapInfo(&pAddress, 3406 &ulWidth, 3407 &ulHeight, 3408 &ulBitsPerPixel, 3409 &ulBytesPerLine, 3410 &ulPixelFormat); 3411 3412 mpDrv->IConnector.pu8Data = pAddress; 3413 mpDrv->IConnector.cbScanline = ulBytesPerLine; 3414 mpDrv->IConnector.cBits = ulBitsPerPixel; 3415 mpDrv->IConnector.cx = ulWidth; 3416 mpDrv->IConnector.cy = ulHeight; 3417 3418 fSetRenderVRAM = fDefaultFormat; 3419 } 3420 3421 /* Make sure that the bitmap contains the latest image. */ 3422 fInvalidate = fDefaultFormat; 3423 3424 pFBInfo->pSourceBitmap = obj; 3425 pFBInfo->fDefaultFormat = fDefaultFormat; 3426 } 3427 } 3428 3429 if (SUCCEEDED(hr)) 3430 { 3431 pFBInfo->pSourceBitmap.queryInterfaceTo(aDisplaySourceBitmap.asOutParam()); 3432 } 3433 3434 /* Leave the IDisplay lock because the VGA device must not be called under it. */ 3435 alock.release(); 3436 3437 if (SUCCEEDED(hr)) 3438 { 3439 if (fSetRenderVRAM) 3440 { 3441 mpDrv->pUpPort->pfnSetRenderVRAM(mpDrv->pUpPort, true); 3442 } 3443 3444 if (fInvalidate) 3445 VMR3ReqCallWaitU(ptrVM.rawUVM(), VMCPUID_ANY, (PFNRT)Display::i_InvalidateAndUpdateEMT, 3446 3, this, aScreenId, false); 3447 } 3448 3449 LogRelFlowFunc(("%Rhrc\n", hr)); 3450 return hr; 3451 } 3452 3453 // wrapped IEventListener method 3454 HRESULT Display::handleEvent(const ComPtr<IEvent> &aEvent) 3455 { 3456 VBoxEventType_T aType = VBoxEventType_Invalid; 3457 3458 aEvent->COMGETTER(Type)(&aType); 3459 switch (aType) 3460 { 3461 case VBoxEventType_OnStateChanged: 3462 { 3463 ComPtr<IStateChangedEvent> scev = aEvent; 3464 Assert(scev); 3465 MachineState_T machineState; 3466 scev->COMGETTER(State)(&machineState); 3467 if ( machineState == MachineState_Running 3468 || machineState == MachineState_Teleporting 3469 || machineState == MachineState_LiveSnapshotting 3470 || machineState == MachineState_DeletingSnapshotOnline 3471 ) 3472 { 3473 LogRelFlowFunc(("Machine is running.\n")); 3474 3475 #ifdef VBOX_WITH_CROGL 3476 i_crOglWindowsShow(true); 3477 #endif 3478 } 3479 else 3480 { 3481 #ifdef VBOX_WITH_CROGL 3482 if (machineState == MachineState_Paused) 3483 i_crOglWindowsShow(false); 3484 #endif 3485 } 3486 break; 3487 } 3488 default: 3489 AssertFailed(); 3490 } 3491 3492 return S_OK; 3493 } 3494 3495 3496 // private methods 3497 ///////////////////////////////////////////////////////////////////////////// 3498 3499 #if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) 3500 int Display::i_crViewportNotify(ULONG aScreenId, ULONG x, ULONG y, ULONG width, ULONG height) 3501 { 3502 VMMDev *pVMMDev = mParent->i_getVMMDev(); 3503 if (!pVMMDev) 3504 return VERR_INVALID_STATE; 3505 3506 size_t cbData = RT_UOFFSETOF(VBOXCRCMDCTL_HGCM, aParms[5]); 3507 VBOXCRCMDCTL_HGCM *pData = (VBOXCRCMDCTL_HGCM*)alloca(cbData); 3508 3509 pData->Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM; 3510 pData->Hdr.u32Function = SHCRGL_HOST_FN_VIEWPORT_CHANGED; 3511 3512 pData->aParms[0].type = VBOX_HGCM_SVC_PARM_32BIT; 3513 pData->aParms[0].u.uint32 = aScreenId; 3514 3515 pData->aParms[1].type = VBOX_HGCM_SVC_PARM_32BIT; 3516 pData->aParms[1].u.uint32 = x; 3517 3518 pData->aParms[2].type = VBOX_HGCM_SVC_PARM_32BIT; 3519 pData->aParms[2].u.uint32 = y; 3520 3521 pData->aParms[3].type = VBOX_HGCM_SVC_PARM_32BIT; 3522 pData->aParms[3].u.uint32 = width; 3523 3524 pData->aParms[4].type = VBOX_HGCM_SVC_PARM_32BIT; 3525 pData->aParms[4].u.uint32 = height; 3526 3527 return i_crCtlSubmitSyncIfHasDataForScreen(aScreenId, &pData->Hdr, (uint32_t)cbData); 3528 } 3529 #endif 3530 3531 #ifdef VBOX_WITH_CRHGSMI 3532 void Display::i_setupCrHgsmiData(void) 3533 { 3534 VMMDev *pVMMDev = mParent->i_getVMMDev(); 3535 Assert(pVMMDev); 3536 int rc = RTCritSectRwEnterExcl(&mCrOglLock); 3537 AssertRC(rc); 3538 3539 if (pVMMDev) 3540 rc = pVMMDev->hgcmHostSvcHandleCreate("VBoxSharedCrOpenGL", &mhCrOglSvc); 3541 else 3542 rc = VERR_GENERAL_FAILURE; 3543 3544 if (RT_SUCCESS(rc)) 3545 { 3546 Assert(mhCrOglSvc); 3547 /* setup command completion callback */ 3548 VBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_MAINCB Completion; 3549 Completion.Hdr.enmType = VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_MAINCB; 3550 Completion.Hdr.cbCmd = sizeof(Completion); 3551 Completion.hCompletion = mpDrv->pVBVACallbacks; 3552 Completion.pfnCompletion = mpDrv->pVBVACallbacks->pfnCrHgsmiCommandCompleteAsync; 3553 3554 VBOXHGCMSVCPARM parm; 3555 parm.type = VBOX_HGCM_SVC_PARM_PTR; 3556 parm.u.pointer.addr = &Completion; 3557 parm.u.pointer.size = 0; 3558 3559 rc = pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_CRHGSMI_CTL, 1, &parm); 3560 if (RT_SUCCESS(rc)) 3561 mCrOglCallbacks = Completion.MainInterface; 3562 else 3563 AssertMsgFailed(("VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_COMPLETION failed rc %d", rc)); 3564 } 3565 3566 if (RT_FAILURE(rc)) 3567 mhCrOglSvc = NULL; 3568 3569 RTCritSectRwLeaveExcl(&mCrOglLock); 3570 } 3571 3572 void Display::i_destructCrHgsmiData(void) 3573 { 3574 int rc = RTCritSectRwEnterExcl(&mCrOglLock); 3575 AssertRC(rc); 3576 mhCrOglSvc = NULL; 3577 RTCritSectRwLeaveExcl(&mCrOglLock); 3578 } 3579 #endif 3580 3581 /** 3582 * Handle display resize event issued by the VGA device for the primary screen. 3583 * 3584 * @see PDMIDISPLAYCONNECTOR::pfnResize 3585 */ 3586 DECLCALLBACK(int) Display::i_displayResizeCallback(PPDMIDISPLAYCONNECTOR pInterface, 3587 uint32_t bpp, void *pvVRAM, uint32_t cbLine, uint32_t cx, uint32_t cy) 3588 { 3589 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface); 3590 Display *pThis = pDrv->pDisplay; 3591 3592 LogRelFlowFunc(("bpp %d, pvVRAM %p, cbLine %d, cx %d, cy %d\n", 3593 bpp, pvVRAM, cbLine, cx, cy)); 3594 3595 bool f = ASMAtomicCmpXchgBool(&pThis->fVGAResizing, true, false); 3596 if (!f) 3597 { 3598 /* This is a result of recursive call when the source bitmap is being updated 3599 * during a VGA resize. Tell the VGA device to ignore the call. 3600 * 3601 * @todo It is a workaround, actually pfnUpdateDisplayAll must 3602 * fail on resize. 3603 */ 3604 LogRel(("displayResizeCallback: already processing\n")); 3605 return VINF_VGA_RESIZE_IN_PROGRESS; 3606 } 3607 3608 int rc = pThis->i_handleDisplayResize(VBOX_VIDEO_PRIMARY_SCREEN, bpp, pvVRAM, cbLine, cx, cy, VBVA_SCREEN_F_ACTIVE); 3609 3610 /* Restore the flag. */ 3611 f = ASMAtomicCmpXchgBool(&pThis->fVGAResizing, false, true); 3612 AssertRelease(f); 3613 3614 return rc; 3615 } 3616 3617 /** 3618 * Handle display update. 3619 * 3620 * @see PDMIDISPLAYCONNECTOR::pfnUpdateRect 3621 */ 3622 DECLCALLBACK(void) Display::i_displayUpdateCallback(PPDMIDISPLAYCONNECTOR pInterface, 3623 uint32_t x, uint32_t y, uint32_t cx, uint32_t cy) 3624 { 3625 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface); 3626 3627 #ifdef DEBUG_sunlover 3628 LogFlowFunc(("mfVideoAccelEnabled = %d, %d,%d %dx%d\n", 3629 pDrv->pDisplay->mfVideoAccelEnabled, x, y, cx, cy)); 3630 #endif /* DEBUG_sunlover */ 3631 3632 /* This call does update regardless of VBVA status. 3633 * But in VBVA mode this is called only as result of 3634 * pfnUpdateDisplayAll in the VGA device. 3635 */ 3636 3637 pDrv->pDisplay->i_handleDisplayUpdate(VBOX_VIDEO_PRIMARY_SCREEN, x, y, cx, cy); 3638 } 3639 3640 /** 3641 * Periodic display refresh callback. 3642 * 3643 * @see PDMIDISPLAYCONNECTOR::pfnRefresh 3644 * @thread EMT 3645 */ 3646 DECLCALLBACK(void) Display::i_displayRefreshCallback(PPDMIDISPLAYCONNECTOR pInterface) 3647 { 3648 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface); 3649 3650 #ifdef DEBUG_sunlover_2 3651 LogFlowFunc(("pDrv->pDisplay->mfVideoAccelEnabled = %d\n", 3652 pDrv->pDisplay->mfVideoAccelEnabled)); 3653 #endif /* DEBUG_sunlover_2 */ 3654 3655 Display *pDisplay = pDrv->pDisplay; 3656 unsigned uScreenId; 3657 3658 int rc = pDisplay->i_videoAccelRefreshProcess(); 3659 if (rc != VINF_TRY_AGAIN) /* Means 'do nothing' here. */ 3660 { 3661 if (rc == VWRN_INVALID_STATE) 3662 { 3663 /* No VBVA do a display update. */ 3664 DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[VBOX_VIDEO_PRIMARY_SCREEN]; 3665 pDrv->pUpPort->pfnUpdateDisplay(pDrv->pUpPort); 3666 } 3667 3668 /* Inform the VRDP server that the current display update sequence is 3669 * completed. At this moment the framebuffer memory contains a definite 3670 * image, that is synchronized with the orders already sent to VRDP client. 3671 * The server can now process redraw requests from clients or initial 3672 * fullscreen updates for new clients. 3673 */ 3674 for (uScreenId = 0; uScreenId < pDisplay->mcMonitors; uScreenId++) 3675 { 3676 DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[uScreenId]; 3677 3678 Assert(pDisplay->mParent && pDisplay->mParent->i_consoleVRDPServer()); 3679 pDisplay->mParent->i_consoleVRDPServer()->SendUpdate(uScreenId, NULL, 0); 3680 } 3681 } 3682 3683 #ifdef VBOX_WITH_VPX 3684 if (VideoRecIsEnabled(pDisplay->mpVideoRecCtx)) 3685 { 3686 do { 3687 # if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) 3688 BOOL is3denabled; 3689 pDisplay->mParent->i_machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled); 3690 if (is3denabled) 3691 { 3692 if (ASMAtomicCmpXchgU32(&pDisplay->mfCrOglVideoRecState, CRVREC_STATE_SUBMITTED, CRVREC_STATE_IDLE)) 3693 { 3694 if (pDisplay->mCrOglCallbacks.pfnHasData()) 3695 { 3696 /* submit */ 3697 VBOXCRCMDCTL_HGCM *pData = &pDisplay->mCrOglScreenshotCtl; 3698 3699 pData->Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM; 3700 pData->Hdr.u32Function = SHCRGL_HOST_FN_TAKE_SCREENSHOT; 3701 3702 pData->aParms[0].type = VBOX_HGCM_SVC_PARM_PTR; 3703 pData->aParms[0].u.pointer.addr = &pDisplay->mCrOglScreenshotData; 3704 pData->aParms[0].u.pointer.size = sizeof(pDisplay->mCrOglScreenshotData); 3705 rc = pDisplay->i_crCtlSubmit(&pData->Hdr, sizeof(*pData), Display::i_displayVRecCompletion, pDisplay); 3706 if (RT_SUCCESS(rc)) 3707 break; 3708 else 3709 AssertMsgFailed(("crCtlSubmit failed rc %d\n", rc)); 3710 } 3711 3712 /* no 3D data available, or error has occured, 3713 * go the straight way */ 3714 ASMAtomicWriteU32(&pDisplay->mfCrOglVideoRecState, CRVREC_STATE_IDLE); 3715 } 3716 else 3717 { 3718 /* record request is still in progress, don't do anything */ 3719 break; 3720 } 3721 } 3722 # endif /* VBOX_WITH_HGCM && VBOX_WITH_CROGL */ 3723 3724 uint64_t u64Now = RTTimeProgramMilliTS(); 3725 for (uScreenId = 0; uScreenId < pDisplay->mcMonitors; uScreenId++) 3726 { 3727 if (!pDisplay->maVideoRecEnabled[uScreenId]) 3728 continue; 3729 3730 if (VideoRecIsFull(pDisplay->mpVideoRecCtx, uScreenId, u64Now)) 3731 { 3732 pDisplay->i_VideoCaptureStop(); 3733 pDisplay->mParent->i_machine()->COMSETTER(VideoCaptureEnabled)(false); 3734 break; 3735 } 3736 3737 DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[uScreenId]; 3738 3739 if ( !pFBInfo->pFramebuffer.isNull() 3740 && !pFBInfo->fDisabled) 3741 { 3742 rc = VERR_NOT_SUPPORTED; 3743 if ( pFBInfo->fVBVAEnabled 3744 && pFBInfo->pu8FramebufferVRAM) 3745 { 3746 rc = VideoRecCopyToIntBuf(pDisplay->mpVideoRecCtx, uScreenId, 0, 0, 3747 BitmapFormat_BGR, 3748 pFBInfo->u16BitsPerPixel, 3749 pFBInfo->u32LineSize, pFBInfo->w, pFBInfo->h, 3750 pFBInfo->pu8FramebufferVRAM, u64Now); 3751 } 3752 else if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN && pDrv->IConnector.pu8Data) 3753 { 3754 rc = VideoRecCopyToIntBuf(pDisplay->mpVideoRecCtx, uScreenId, 0, 0, 3755 BitmapFormat_BGR, 3756 pDrv->IConnector.cBits, 3757 pDrv->IConnector.cbScanline, pDrv->IConnector.cx, 3758 pDrv->IConnector.cy, pDrv->IConnector.pu8Data, u64Now); 3759 } 3760 if (rc == VINF_TRY_AGAIN) 3761 break; 3762 } 3763 } 3764 } while (0); 3765 } 3766 #endif /* VBOX_WITH_VPX */ 3767 3768 #ifdef DEBUG_sunlover_2 3769 LogFlowFunc(("leave\n")); 3770 #endif /* DEBUG_sunlover_2 */ 3771 } 3772 3773 /** 3774 * Reset notification 3775 * 3776 * @see PDMIDISPLAYCONNECTOR::pfnReset 3777 */ 3778 DECLCALLBACK(void) Display::i_displayResetCallback(PPDMIDISPLAYCONNECTOR pInterface) 3779 { 3780 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface); 3781 3782 LogRelFlowFunc(("\n")); 3783 3784 /* Disable VBVA mode. */ 3785 pDrv->pDisplay->VideoAccelEnableVGA(false, NULL); 3786 } 3787 3788 /** 3789 * LFBModeChange notification 3790 * 3791 * @see PDMIDISPLAYCONNECTOR::pfnLFBModeChange 3792 */ 3793 DECLCALLBACK(void) Display::i_displayLFBModeChangeCallback(PPDMIDISPLAYCONNECTOR pInterface, bool fEnabled) 3794 { 3795 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface); 3796 3797 LogRelFlowFunc(("fEnabled=%d\n", fEnabled)); 3798 3799 NOREF(fEnabled); 3800 3801 /* Disable VBVA mode in any case. The guest driver reenables VBVA mode if necessary. */ 3802 pDrv->pDisplay->VideoAccelEnableVGA(false, NULL); 3803 } 3804 3805 /** 3806 * Adapter information change notification. 3807 * 3808 * @see PDMIDISPLAYCONNECTOR::pfnProcessAdapterData 3809 */ 3810 DECLCALLBACK(void) Display::i_displayProcessAdapterDataCallback(PPDMIDISPLAYCONNECTOR pInterface, void *pvVRAM, 3811 uint32_t u32VRAMSize) 3812 { 3813 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface); 3814 783 void Display::processAdapterData(void *pvVRAM, uint32_t u32VRAMSize) 784 { 3815 785 if (pvVRAM == NULL) 3816 786 { 3817 787 unsigned i; 3818 for (i = 0; i < pDrv->pDisplay->mcMonitors; i++)3819 { 3820 DISPLAYFBINFO *pFBInfo = & pDrv->pDisplay->maFramebuffers[i];788 for (i = 0; i < mcMonitors; i++) 789 { 790 DISPLAYFBINFO *pFBInfo = &maFramebuffers[i]; 3821 791 3822 792 pFBInfo->u32Offset = 0; … … 3857 827 VBOXVIDEOINFODISPLAY *pDisplay = (VBOXVIDEOINFODISPLAY *)pu8; 3858 828 3859 if (pDisplay->u32Index >= pDrv->pDisplay->mcMonitors)829 if (pDisplay->u32Index >= mcMonitors) 3860 830 { 3861 831 LogRel(("VBoxVideo: Guest adapter information invalid display index %d!!!\n", pDisplay->u32Index)); … … 3863 833 } 3864 834 3865 DISPLAYFBINFO *pFBInfo = & pDrv->pDisplay->maFramebuffers[pDisplay->u32Index];835 DISPLAYFBINFO *pFBInfo = &maFramebuffers[pDisplay->u32Index]; 3866 836 3867 837 pFBInfo->u32Offset = pDisplay->u32Offset; … … 3886 856 case VBOX_VIDEO_QCI32_MONITOR_COUNT: 3887 857 { 3888 pConf32->u32Value = pDrv->pDisplay->mcMonitors;858 pConf32->u32Value = mcMonitors; 3889 859 } break; 3890 860 … … 3921 891 } 3922 892 3923 /** 3924 * Display information change notification. 3925 * 3926 * @see PDMIDISPLAYCONNECTOR::pfnProcessDisplayData 3927 */ 3928 DECLCALLBACK(void) Display::i_displayProcessDisplayDataCallback(PPDMIDISPLAYCONNECTOR pInterface, 3929 void *pvVRAM, unsigned uScreenId) 3930 { 3931 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface); 3932 3933 if (uScreenId >= pDrv->pDisplay->mcMonitors) 893 void Display::processDisplayData(void *pvVRAM, unsigned uScreenId) 894 { 895 if (uScreenId >= mcMonitors) 3934 896 { 3935 897 LogRel(("VBoxVideo: Guest display information invalid display index %d!!!\n", uScreenId)); … … 3938 900 3939 901 /* Get the display information structure. */ 3940 DISPLAYFBINFO *pFBInfo = & pDrv->pDisplay->maFramebuffers[uScreenId];902 DISPLAYFBINFO *pFBInfo = &maFramebuffers[uScreenId]; 3941 903 3942 904 uint8_t *pu8 = (uint8_t *)pvVRAM; … … 3985 947 { 3986 948 pFBInfo->fDisabled = false; 3987 fireGuestMonitorChangedEvent( pDrv->pDisplay->mParent->i_getEventSource(),949 fireGuestMonitorChangedEvent(mParent->i_getEventSource(), 3988 950 GuestMonitorChangedEventType_Enabled, 3989 951 uScreenId, … … 3992 954 } 3993 955 3994 pDrv->pDisplay->i_handleDisplayResize(uScreenId, pScreen->bitsPerPixel,956 i_handleDisplayResize(uScreenId, pScreen->bitsPerPixel, 3995 957 (uint8_t *)pvVRAM + pFBInfo->u32Offset, 3996 958 pScreen->u32LineSize, … … 4044 1006 } 4045 1007 4046 #ifdef VBOX_WITH_VIDEOHWACCEL4047 4048 #ifndef S_FALSE4049 # define S_FALSE ((HRESULT)1L)4050 #endif4051 4052 int Display::i_handleVHWACommandProcess(PVBOXVHWACMD pCommand)4053 {4054 unsigned id = (unsigned)pCommand->iDisplay;4055 int rc = VINF_SUCCESS;4056 if (id >= mcMonitors)4057 return VERR_INVALID_PARAMETER;4058 4059 ComPtr<IFramebuffer> pFramebuffer;4060 AutoReadLock arlock(this COMMA_LOCKVAL_SRC_POS);4061 pFramebuffer = maFramebuffers[id].pFramebuffer;4062 bool fVHWASupported = RT_BOOL(maFramebuffers[id].u32Caps & FramebufferCapabilities_VHWA);4063 arlock.release();4064 4065 if (pFramebuffer == NULL || !fVHWASupported)4066 return VERR_NOT_IMPLEMENTED; /* Implementation is not available. */4067 4068 HRESULT hr = pFramebuffer->ProcessVHWACommand((BYTE*)pCommand);4069 if (hr == S_FALSE)4070 return VINF_SUCCESS;4071 else if (SUCCEEDED(hr))4072 return VINF_CALLBACK_RETURN;4073 else if (hr == E_ACCESSDENIED)4074 return VERR_INVALID_STATE; /* notify we can not handle request atm */4075 else if (hr == E_NOTIMPL)4076 return VERR_NOT_IMPLEMENTED;4077 return VERR_GENERAL_FAILURE;4078 }4079 4080 DECLCALLBACK(int) Display::i_displayVHWACommandProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVHWACMD pCommand)4081 {4082 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);4083 4084 return pDrv->pDisplay->i_handleVHWACommandProcess(pCommand);4085 }4086 #endif4087 4088 #ifdef VBOX_WITH_CRHGSMI4089 void Display::i_handleCrHgsmiCommandCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam)4090 {4091 mpDrv->pVBVACallbacks->pfnCrHgsmiCommandCompleteAsync(mpDrv->pVBVACallbacks,4092 (PVBOXVDMACMD_CHROMIUM_CMD)pParam->u.pointer.addr, result);4093 }4094 4095 void Display::i_handleCrHgsmiControlCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam)4096 {4097 PVBOXVDMACMD_CHROMIUM_CTL pCtl = (PVBOXVDMACMD_CHROMIUM_CTL)pParam->u.pointer.addr;4098 mpDrv->pVBVACallbacks->pfnCrHgsmiControlCompleteAsync(mpDrv->pVBVACallbacks, pCtl, result);4099 }4100 4101 void Display::i_handleCrHgsmiCommandProcess(PVBOXVDMACMD_CHROMIUM_CMD pCmd, uint32_t cbCmd)4102 {4103 int rc = VERR_NOT_SUPPORTED;4104 VBOXHGCMSVCPARM parm;4105 parm.type = VBOX_HGCM_SVC_PARM_PTR;4106 parm.u.pointer.addr = pCmd;4107 parm.u.pointer.size = cbCmd;4108 4109 if (mhCrOglSvc)4110 {4111 VMMDev *pVMMDev = mParent->i_getVMMDev();4112 if (pVMMDev)4113 {4114 /* no completion callback is specified with this call,4115 * the CrOgl code will complete the CrHgsmi command once it processes it */4116 rc = pVMMDev->hgcmHostFastCallAsync(mhCrOglSvc, SHCRGL_HOST_FN_CRHGSMI_CMD, &parm, NULL, NULL);4117 AssertRC(rc);4118 if (RT_SUCCESS(rc))4119 return;4120 }4121 else4122 rc = VERR_INVALID_STATE;4123 }4124 4125 /* we are here because something went wrong with command processing, complete it */4126 i_handleCrHgsmiCommandCompletion(rc, SHCRGL_HOST_FN_CRHGSMI_CMD, &parm);4127 }4128 4129 void Display::i_handleCrHgsmiControlProcess(PVBOXVDMACMD_CHROMIUM_CTL pCtl, uint32_t cbCtl)4130 {4131 int rc = VERR_NOT_SUPPORTED;4132 VBOXHGCMSVCPARM parm;4133 parm.type = VBOX_HGCM_SVC_PARM_PTR;4134 parm.u.pointer.addr = pCtl;4135 parm.u.pointer.size = cbCtl;4136 4137 if (mhCrOglSvc)4138 {4139 VMMDev *pVMMDev = mParent->i_getVMMDev();4140 if (pVMMDev)4141 {4142 bool fCheckPendingViewport = (pCtl->enmType == VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP);4143 rc = pVMMDev->hgcmHostFastCallAsync(mhCrOglSvc, SHCRGL_HOST_FN_CRHGSMI_CTL, &parm,4144 Display::i_displayCrHgsmiControlCompletion, this);4145 AssertRC(rc);4146 if (RT_SUCCESS(rc))4147 {4148 if (fCheckPendingViewport)4149 {4150 ULONG ul;4151 for (ul = 0; ul < mcMonitors; ul++)4152 {4153 DISPLAYFBINFO *pFb = &maFramebuffers[ul];4154 if (!pFb->pendingViewportInfo.fPending)4155 continue;4156 4157 rc = i_crViewportNotify(ul, pFb->pendingViewportInfo.x, pFb->pendingViewportInfo.y,4158 pFb->pendingViewportInfo.width, pFb->pendingViewportInfo.height);4159 if (RT_SUCCESS(rc))4160 pFb->pendingViewportInfo.fPending = false;4161 else4162 {4163 AssertMsgFailed(("crViewportNotify failed %d\n", rc));4164 rc = VINF_SUCCESS;4165 }4166 }4167 }4168 return;4169 }4170 }4171 else4172 rc = VERR_INVALID_STATE;4173 }4174 4175 /* we are here because something went wrong with command processing, complete it */4176 i_handleCrHgsmiControlCompletion(rc, SHCRGL_HOST_FN_CRHGSMI_CTL, &parm);4177 }4178 4179 DECLCALLBACK(void) Display::i_displayCrHgsmiCommandProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVDMACMD_CHROMIUM_CMD pCmd,4180 uint32_t cbCmd)4181 {4182 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);4183 4184 pDrv->pDisplay->i_handleCrHgsmiCommandProcess(pCmd, cbCmd);4185 }4186 4187 DECLCALLBACK(void) Display::i_displayCrHgsmiControlProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVDMACMD_CHROMIUM_CTL pCmd,4188 uint32_t cbCmd)4189 {4190 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);4191 4192 pDrv->pDisplay->i_handleCrHgsmiControlProcess(pCmd, cbCmd);4193 }4194 4195 DECLCALLBACK(void) Display::i_displayCrHgsmiCommandCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam,4196 void *pvContext)4197 {4198 AssertMsgFailed(("not expected!"));4199 Display *pDisplay = (Display *)pvContext;4200 pDisplay->i_handleCrHgsmiCommandCompletion(result, u32Function, pParam);4201 }4202 4203 DECLCALLBACK(void) Display::i_displayCrHgsmiControlCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam,4204 void *pvContext)4205 {4206 Display *pDisplay = (Display *)pvContext;4207 pDisplay->i_handleCrHgsmiControlCompletion(result, u32Function, pParam);4208 4209 }4210 #endif4211 4212 #if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)4213 DECLCALLBACK(void) Display::i_displayCrHgcmCtlSubmitCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam,4214 void *pvContext)4215 {4216 VBOXCRCMDCTL *pCmd = (VBOXCRCMDCTL*)pParam->u.pointer.addr;4217 if (pCmd->u.pfnInternal)4218 ((PFNCRCTLCOMPLETION)pCmd->u.pfnInternal)(pCmd, pParam->u.pointer.size, result, pvContext);4219 }4220 4221 int Display::i_handleCrHgcmCtlSubmit(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd,4222 PFNCRCTLCOMPLETION pfnCompletion,4223 void *pvCompletion)4224 {4225 VMMDev *pVMMDev = mParent ? mParent->i_getVMMDev() : NULL;4226 if (!pVMMDev)4227 {4228 AssertMsgFailed(("no vmmdev\n"));4229 return VERR_INVALID_STATE;4230 }4231 4232 Assert(mhCrOglSvc);4233 VBOXHGCMSVCPARM parm;4234 parm.type = VBOX_HGCM_SVC_PARM_PTR;4235 parm.u.pointer.addr = pCmd;4236 parm.u.pointer.size = cbCmd;4237 4238 pCmd->u.pfnInternal = (void(*)())pfnCompletion;4239 int rc = pVMMDev->hgcmHostFastCallAsync(mhCrOglSvc, SHCRGL_HOST_FN_CTL, &parm, i_displayCrHgcmCtlSubmitCompletion,4240 pvCompletion);4241 if (!RT_SUCCESS(rc))4242 AssertMsgFailed(("hgcmHostFastCallAsync failed rc %d\n", rc));4243 4244 return rc;4245 }4246 4247 DECLCALLBACK(int) Display::i_displayCrHgcmCtlSubmit(PPDMIDISPLAYCONNECTOR pInterface,4248 struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd,4249 PFNCRCTLCOMPLETION pfnCompletion,4250 void *pvCompletion)4251 {4252 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);4253 Display *pThis = pDrv->pDisplay;4254 return pThis->i_handleCrHgcmCtlSubmit(pCmd, cbCmd, pfnCompletion, pvCompletion);4255 }4256 4257 int Display::i_crCtlSubmit(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd, PFNCRCTLCOMPLETION pfnCompletion, void *pvCompletion)4258 {4259 int rc = RTCritSectRwEnterShared(&mCrOglLock);4260 if (RT_SUCCESS(rc))4261 {4262 if (mhCrOglSvc)4263 rc = mpDrv->pVBVACallbacks->pfnCrCtlSubmit(mpDrv->pVBVACallbacks, pCmd, cbCmd, pfnCompletion, pvCompletion);4264 else4265 rc = VERR_NOT_SUPPORTED;4266 4267 RTCritSectRwLeaveShared(&mCrOglLock);4268 }4269 return rc;4270 }4271 4272 int Display::i_crCtlSubmitSync(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd)4273 {4274 int rc = RTCritSectRwEnterShared(&mCrOglLock);4275 if (RT_SUCCESS(rc))4276 {4277 if (mhCrOglSvc)4278 rc = mpDrv->pVBVACallbacks->pfnCrCtlSubmitSync(mpDrv->pVBVACallbacks, pCmd, cbCmd);4279 else4280 rc = VERR_NOT_SUPPORTED;4281 4282 RTCritSectRwLeaveShared(&mCrOglLock);4283 }4284 return rc;4285 }4286 4287 int Display::i_crCtlSubmitAsyncCmdCopy(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd)4288 {4289 VBOXCRCMDCTL* pCmdCopy = (VBOXCRCMDCTL*)RTMemAlloc(cbCmd);4290 if (!pCmdCopy)4291 {4292 LogRel(("RTMemAlloc failed\n"));4293 return VERR_NO_MEMORY;4294 }4295 4296 memcpy(pCmdCopy, pCmd, cbCmd);4297 4298 int rc = i_crCtlSubmit(pCmdCopy, cbCmd, i_displayCrCmdFree, pCmdCopy);4299 if (RT_FAILURE(rc))4300 {4301 LogRel(("crCtlSubmit failed %d\n", rc));4302 RTMemFree(pCmdCopy);4303 return rc;4304 }4305 4306 return VINF_SUCCESS;4307 }4308 4309 int Display::i_crCtlSubmitSyncIfHasDataForScreen(uint32_t u32ScreenID, struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd)4310 {4311 int rc = RTCritSectRwEnterShared(&mCrOglLock);4312 AssertRCReturn(rc, rc);4313 4314 if (mCrOglCallbacks.pfnHasDataForScreen && mCrOglCallbacks.pfnHasDataForScreen(u32ScreenID))4315 rc = i_crCtlSubmitSync(pCmd, cbCmd);4316 else4317 rc = i_crCtlSubmitAsyncCmdCopy(pCmd, cbCmd);4318 4319 RTCritSectRwLeaveShared(&mCrOglLock);4320 4321 return rc;4322 }4323 4324 bool Display::i_handleCrVRecScreenshotBegin(uint32_t uScreen, uint64_t u64TimeStamp)4325 {4326 # if VBOX_WITH_VPX4327 return VideoRecIsReady(mpVideoRecCtx, uScreen, u64TimeStamp);4328 # else4329 return false;4330 # endif4331 }4332 4333 void Display::i_handleCrVRecScreenshotEnd(uint32_t uScreen, uint64_t u64TimeStamp)4334 {4335 }4336 4337 void Display::i_handleCrVRecScreenshotPerform(uint32_t uScreen,4338 uint32_t x, uint32_t y, uint32_t uPixelFormat,4339 uint32_t uBitsPerPixel, uint32_t uBytesPerLine,4340 uint32_t uGuestWidth, uint32_t uGuestHeight,4341 uint8_t *pu8BufferAddress, uint64_t u64TimeStamp)4342 {4343 Assert(mfCrOglVideoRecState == CRVREC_STATE_SUBMITTED);4344 # if VBOX_WITH_VPX4345 int rc = VideoRecCopyToIntBuf(mpVideoRecCtx, uScreen, x, y,4346 uPixelFormat,4347 uBitsPerPixel, uBytesPerLine,4348 uGuestWidth, uGuestHeight,4349 pu8BufferAddress, u64TimeStamp);4350 Assert(rc == VINF_SUCCESS /* || rc == VERR_TRY_AGAIN || rc == VINF_TRY_AGAIN*/);4351 # endif4352 }4353 4354 void Display::i_handleVRecCompletion()4355 {4356 Assert(mfCrOglVideoRecState == CRVREC_STATE_SUBMITTED);4357 ASMAtomicWriteU32(&mfCrOglVideoRecState, CRVREC_STATE_IDLE);4358 }4359 4360 DECLCALLBACK(void) Display::i_displayCrVRecScreenshotPerform(void *pvCtx, uint32_t uScreen,4361 uint32_t x, uint32_t y,4362 uint32_t uBitsPerPixel, uint32_t uBytesPerLine,4363 uint32_t uGuestWidth, uint32_t uGuestHeight,4364 uint8_t *pu8BufferAddress, uint64_t u64TimeStamp)4365 {4366 Display *pDisplay = (Display *)pvCtx;4367 pDisplay->i_handleCrVRecScreenshotPerform(uScreen,4368 x, y, BitmapFormat_BGR, uBitsPerPixel,4369 uBytesPerLine, uGuestWidth, uGuestHeight,4370 pu8BufferAddress, u64TimeStamp);4371 }4372 4373 DECLCALLBACK(bool) Display::i_displayCrVRecScreenshotBegin(void *pvCtx, uint32_t uScreen, uint64_t u64TimeStamp)4374 {4375 Display *pDisplay = (Display *)pvCtx;4376 return pDisplay->i_handleCrVRecScreenshotBegin(uScreen, u64TimeStamp);4377 }4378 4379 DECLCALLBACK(void) Display::i_displayCrVRecScreenshotEnd(void *pvCtx, uint32_t uScreen, uint64_t u64TimeStamp)4380 {4381 Display *pDisplay = (Display *)pvCtx;4382 pDisplay->i_handleCrVRecScreenshotEnd(uScreen, u64TimeStamp);4383 }4384 4385 DECLCALLBACK(void) Display::i_displayVRecCompletion(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd, int rc, void *pvCompletion)4386 {4387 Display *pDisplay = (Display *)pvCompletion;4388 pDisplay->i_handleVRecCompletion();4389 }4390 4391 #endif4392 4393 4394 #ifdef VBOX_WITH_HGSMI4395 DECLCALLBACK(int) Display::i_displayVBVAEnable(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId, PVBVAHOSTFLAGS pHostFlags,4396 bool fRenderThreadMode)4397 {4398 LogRelFlowFunc(("uScreenId %d\n", uScreenId));4399 4400 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);4401 Display *pThis = pDrv->pDisplay;4402 4403 if (pThis->maFramebuffers[uScreenId].fVBVAEnabled && pThis->maFramebuffers[uScreenId].fRenderThreadMode != fRenderThreadMode)4404 {4405 LogRel(("enabling different vbva mode"));4406 #ifdef DEBUG_misha4407 AssertMsgFailed(("enabling different vbva mode"));4408 #endif4409 return VERR_INVALID_STATE;4410 }4411 4412 pThis->maFramebuffers[uScreenId].fVBVAEnabled = true;4413 pThis->maFramebuffers[uScreenId].pVBVAHostFlags = pHostFlags;4414 pThis->maFramebuffers[uScreenId].fRenderThreadMode = fRenderThreadMode;4415 pThis->maFramebuffers[uScreenId].fVBVAForceResize = true;4416 4417 vbvaSetMemoryFlagsHGSMI(uScreenId, pThis->mfu32SupportedOrders, pThis->mfVideoAccelVRDP, &pThis->maFramebuffers[uScreenId]);4418 4419 return VINF_SUCCESS;4420 }4421 4422 DECLCALLBACK(void) Display::i_displayVBVADisable(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId)4423 {4424 LogRelFlowFunc(("uScreenId %d\n", uScreenId));4425 4426 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);4427 Display *pThis = pDrv->pDisplay;4428 4429 DISPLAYFBINFO *pFBInfo = &pThis->maFramebuffers[uScreenId];4430 4431 bool fRenderThreadMode = pFBInfo->fRenderThreadMode;4432 4433 if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN)4434 {4435 /* Make sure that the primary screen is visible now.4436 * The guest can't use VBVA anymore, so only only the VGA device output works.4437 */4438 if (pFBInfo->fDisabled)4439 {4440 pFBInfo->fDisabled = false;4441 fireGuestMonitorChangedEvent(pThis->mParent->i_getEventSource(),4442 GuestMonitorChangedEventType_Enabled,4443 uScreenId,4444 pFBInfo->xOrigin, pFBInfo->yOrigin,4445 pFBInfo->w, pFBInfo->h);4446 }4447 }4448 4449 pFBInfo->fVBVAEnabled = false;4450 pFBInfo->fVBVAForceResize = false;4451 pFBInfo->fRenderThreadMode = false;4452 4453 vbvaSetMemoryFlagsHGSMI(uScreenId, 0, false, pFBInfo);4454 4455 pFBInfo->pVBVAHostFlags = NULL;4456 4457 if (!fRenderThreadMode && uScreenId == VBOX_VIDEO_PRIMARY_SCREEN)4458 {4459 /* Force full screen update, because VGA device must take control, do resize, etc. */4460 pThis->mpDrv->pUpPort->pfnUpdateDisplayAll(pThis->mpDrv->pUpPort, /* fFailOnResize = */ false);4461 }4462 }4463 4464 DECLCALLBACK(void) Display::i_displayVBVAUpdateBegin(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId)4465 {4466 LogFlowFunc(("uScreenId %d\n", uScreenId));4467 4468 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);4469 Display *pThis = pDrv->pDisplay;4470 DISPLAYFBINFO *pFBInfo = &pThis->maFramebuffers[uScreenId];4471 4472 if (ASMAtomicReadU32(&pThis->mu32UpdateVBVAFlags) > 0)4473 {4474 vbvaSetMemoryFlagsAllHGSMI(pThis->mfu32SupportedOrders, pThis->mfVideoAccelVRDP, pThis->maFramebuffers,4475 pThis->mcMonitors);4476 ASMAtomicDecU32(&pThis->mu32UpdateVBVAFlags);4477 }4478 }4479 4480 DECLCALLBACK(void) Display::i_displayVBVAUpdateProcess(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId,4481 const PVBVACMDHDR pCmd, size_t cbCmd)4482 {4483 LogFlowFunc(("uScreenId %d pCmd %p cbCmd %d, @%d,%d %dx%d\n", uScreenId, pCmd, cbCmd, pCmd->x, pCmd->y, pCmd->w, pCmd->h));4484 4485 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);4486 Display *pThis = pDrv->pDisplay;4487 DISPLAYFBINFO *pFBInfo = &pThis->maFramebuffers[uScreenId];4488 4489 if (pFBInfo->fDefaultFormat)4490 {4491 /* Make sure that framebuffer contains the same image as the guest VRAM. */4492 if ( uScreenId == VBOX_VIDEO_PRIMARY_SCREEN4493 && !pFBInfo->fDisabled)4494 {4495 pDrv->pUpPort->pfnUpdateDisplayRect(pDrv->pUpPort, pCmd->x, pCmd->y, pCmd->w, pCmd->h);4496 }4497 else if ( !pFBInfo->pSourceBitmap.isNull()4498 && !pFBInfo->fDisabled)4499 {4500 /* Render VRAM content to the framebuffer. */4501 BYTE *pAddress = NULL;4502 ULONG ulWidth = 0;4503 ULONG ulHeight = 0;4504 ULONG ulBitsPerPixel = 0;4505 ULONG ulBytesPerLine = 0;4506 ULONG ulPixelFormat = 0;4507 4508 HRESULT hrc = pFBInfo->pSourceBitmap->QueryBitmapInfo(&pAddress,4509 &ulWidth,4510 &ulHeight,4511 &ulBitsPerPixel,4512 &ulBytesPerLine,4513 &ulPixelFormat);4514 if (SUCCEEDED(hrc))4515 {4516 uint32_t width = pCmd->w;4517 uint32_t height = pCmd->h;4518 4519 const uint8_t *pu8Src = pFBInfo->pu8FramebufferVRAM;4520 int32_t xSrc = pCmd->x - pFBInfo->xOrigin;4521 int32_t ySrc = pCmd->y - pFBInfo->yOrigin;4522 uint32_t u32SrcWidth = pFBInfo->w;4523 uint32_t u32SrcHeight = pFBInfo->h;4524 uint32_t u32SrcLineSize = pFBInfo->u32LineSize;4525 uint32_t u32SrcBitsPerPixel = pFBInfo->u16BitsPerPixel;4526 4527 uint8_t *pu8Dst = pAddress;4528 int32_t xDst = xSrc;4529 int32_t yDst = ySrc;4530 uint32_t u32DstWidth = u32SrcWidth;4531 uint32_t u32DstHeight = u32SrcHeight;4532 uint32_t u32DstLineSize = u32DstWidth * 4;4533 uint32_t u32DstBitsPerPixel = 32;4534 4535 pDrv->pUpPort->pfnCopyRect(pDrv->pUpPort,4536 width, height,4537 pu8Src,4538 xSrc, ySrc,4539 u32SrcWidth, u32SrcHeight,4540 u32SrcLineSize, u32SrcBitsPerPixel,4541 pu8Dst,4542 xDst, yDst,4543 u32DstWidth, u32DstHeight,4544 u32DstLineSize, u32DstBitsPerPixel);4545 }4546 }4547 }4548 4549 VBVACMDHDR hdrSaved = *pCmd;4550 4551 VBVACMDHDR *pHdrUnconst = (VBVACMDHDR *)pCmd;4552 4553 pHdrUnconst->x -= (int16_t)pFBInfo->xOrigin;4554 pHdrUnconst->y -= (int16_t)pFBInfo->yOrigin;4555 4556 /* @todo new SendUpdate entry which can get a separate cmd header or coords. */4557 pThis->mParent->i_consoleVRDPServer()->SendUpdate(uScreenId, pCmd, (uint32_t)cbCmd);4558 4559 *pHdrUnconst = hdrSaved;4560 }4561 4562 DECLCALLBACK(void) Display::i_displayVBVAUpdateEnd(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId, int32_t x, int32_t y,4563 uint32_t cx, uint32_t cy)4564 {4565 LogFlowFunc(("uScreenId %d %d,%d %dx%d\n", uScreenId, x, y, cx, cy));4566 4567 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);4568 Display *pThis = pDrv->pDisplay;4569 DISPLAYFBINFO *pFBInfo = &pThis->maFramebuffers[uScreenId];4570 4571 /* @todo handleFramebufferUpdate (uScreenId,4572 * x - pThis->maFramebuffers[uScreenId].xOrigin,4573 * y - pThis->maFramebuffers[uScreenId].yOrigin,4574 * cx, cy);4575 */4576 pThis->i_handleDisplayUpdate(uScreenId, x - pFBInfo->xOrigin, y - pFBInfo->yOrigin, cx, cy);4577 }4578 4579 #ifdef DEBUG_sunlover4580 static void logVBVAResize(const PVBVAINFOVIEW pView, const PVBVAINFOSCREEN pScreen, const DISPLAYFBINFO *pFBInfo)4581 {4582 LogRel(("displayVBVAResize: [%d] %s\n"4583 " pView->u32ViewIndex %d\n"4584 " pView->u32ViewOffset 0x%08X\n"4585 " pView->u32ViewSize 0x%08X\n"4586 " pView->u32MaxScreenSize 0x%08X\n"4587 " pScreen->i32OriginX %d\n"4588 " pScreen->i32OriginY %d\n"4589 " pScreen->u32StartOffset 0x%08X\n"4590 " pScreen->u32LineSize 0x%08X\n"4591 " pScreen->u32Width %d\n"4592 " pScreen->u32Height %d\n"4593 " pScreen->u16BitsPerPixel %d\n"4594 " pScreen->u16Flags 0x%04X\n"4595 " pFBInfo->u32Offset 0x%08X\n"4596 " pFBInfo->u32MaxFramebufferSize 0x%08X\n"4597 " pFBInfo->u32InformationSize 0x%08X\n"4598 " pFBInfo->fDisabled %d\n"4599 " xOrigin, yOrigin, w, h: %d,%d %dx%d\n"4600 " pFBInfo->u16BitsPerPixel %d\n"4601 " pFBInfo->pu8FramebufferVRAM %p\n"4602 " pFBInfo->u32LineSize 0x%08X\n"4603 " pFBInfo->flags 0x%04X\n"4604 " pFBInfo->pHostEvents %p\n"4605 " pFBInfo->fDefaultFormat %d\n"4606 " dirtyRect %d-%d %d-%d\n"4607 " pFBInfo->fVBVAEnabled %d\n"4608 " pFBInfo->fVBVAForceResize %d\n"4609 " pFBInfo->pVBVAHostFlags %p\n"4610 "",4611 pScreen->u32ViewIndex,4612 (pScreen->u16Flags & VBVA_SCREEN_F_DISABLED)? "DISABLED": "ENABLED",4613 pView->u32ViewIndex,4614 pView->u32ViewOffset,4615 pView->u32ViewSize,4616 pView->u32MaxScreenSize,4617 pScreen->i32OriginX,4618 pScreen->i32OriginY,4619 pScreen->u32StartOffset,4620 pScreen->u32LineSize,4621 pScreen->u32Width,4622 pScreen->u32Height,4623 pScreen->u16BitsPerPixel,4624 pScreen->u16Flags,4625 pFBInfo->u32Offset,4626 pFBInfo->u32MaxFramebufferSize,4627 pFBInfo->u32InformationSize,4628 pFBInfo->fDisabled,4629 pFBInfo->xOrigin,4630 pFBInfo->yOrigin,4631 pFBInfo->w,4632 pFBInfo->h,4633 pFBInfo->u16BitsPerPixel,4634 pFBInfo->pu8FramebufferVRAM,4635 pFBInfo->u32LineSize,4636 pFBInfo->flags,4637 pFBInfo->pHostEvents,4638 pFBInfo->fDefaultFormat,4639 pFBInfo->dirtyRect.xLeft,4640 pFBInfo->dirtyRect.xRight,4641 pFBInfo->dirtyRect.yTop,4642 pFBInfo->dirtyRect.yBottom,4643 pFBInfo->fVBVAEnabled,4644 pFBInfo->fVBVAForceResize,4645 pFBInfo->pVBVAHostFlags4646 ));4647 }4648 #endif /* DEBUG_sunlover */4649 4650 DECLCALLBACK(int) Display::i_displayVBVAResize(PPDMIDISPLAYCONNECTOR pInterface, const PVBVAINFOVIEW pView,4651 const PVBVAINFOSCREEN pScreen, void *pvVRAM)4652 {4653 LogRelFlowFunc(("pScreen %p, pvVRAM %p\n", pScreen, pvVRAM));4654 4655 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);4656 Display *pThis = pDrv->pDisplay;4657 4658 DISPLAYFBINFO *pFBInfo = &pThis->maFramebuffers[pScreen->u32ViewIndex];4659 4660 if (pScreen->u16Flags & VBVA_SCREEN_F_DISABLED)4661 {4662 pThis->i_notifyCroglResize(pView, pScreen, pvVRAM);4663 4664 pFBInfo->fDisabled = true;4665 pFBInfo->flags = pScreen->u16Flags;4666 4667 /* Ask the framebuffer to resize using a default format. The framebuffer will be black.4668 * So if the frontend does not support GuestMonitorChangedEventType_Disabled event,4669 * the VM window will be black. */4670 uint32_t u32Width = pFBInfo->w ? pFBInfo->w : 640;4671 uint32_t u32Height = pFBInfo->h ? pFBInfo->h : 480;4672 pThis->i_handleDisplayResize(pScreen->u32ViewIndex, 0, (uint8_t *)NULL, 0,4673 u32Width, u32Height, pScreen->u16Flags);4674 4675 fireGuestMonitorChangedEvent(pThis->mParent->i_getEventSource(),4676 GuestMonitorChangedEventType_Disabled,4677 pScreen->u32ViewIndex,4678 0, 0, 0, 0);4679 return VINF_SUCCESS;4680 }4681 4682 /* If display was disabled or there is no framebuffer, a resize will be required,4683 * because the framebuffer was/will be changed.4684 */4685 bool fResize = pFBInfo->fDisabled || pFBInfo->pFramebuffer.isNull();4686 4687 if (pFBInfo->fVBVAForceResize)4688 {4689 /* VBVA was just enabled. Do the resize. */4690 fResize = true;4691 pFBInfo->fVBVAForceResize = false;4692 }4693 4694 /* Check if this is a real resize or a notification about the screen origin.4695 * The guest uses this VBVAResize call for both.4696 */4697 fResize = fResize4698 || pFBInfo->u16BitsPerPixel != pScreen->u16BitsPerPixel4699 || pFBInfo->pu8FramebufferVRAM != (uint8_t *)pvVRAM + pScreen->u32StartOffset4700 || pFBInfo->u32LineSize != pScreen->u32LineSize4701 || pFBInfo->w != pScreen->u32Width4702 || pFBInfo->h != pScreen->u32Height;4703 4704 bool fNewOrigin = pFBInfo->xOrigin != pScreen->i32OriginX4705 || pFBInfo->yOrigin != pScreen->i32OriginY;4706 4707 if (fNewOrigin || fResize)4708 pThis->i_notifyCroglResize(pView, pScreen, pvVRAM);4709 4710 if (pFBInfo->fDisabled)4711 {4712 pFBInfo->fDisabled = false;4713 fireGuestMonitorChangedEvent(pThis->mParent->i_getEventSource(),4714 GuestMonitorChangedEventType_Enabled,4715 pScreen->u32ViewIndex,4716 pScreen->i32OriginX, pScreen->i32OriginY,4717 pScreen->u32Width, pScreen->u32Height);4718 /* Continue to update pFBInfo. */4719 }4720 4721 pFBInfo->u32Offset = pView->u32ViewOffset; /* Not used in HGSMI. */4722 pFBInfo->u32MaxFramebufferSize = pView->u32MaxScreenSize; /* Not used in HGSMI. */4723 pFBInfo->u32InformationSize = 0; /* Not used in HGSMI. */4724 4725 pFBInfo->xOrigin = pScreen->i32OriginX;4726 pFBInfo->yOrigin = pScreen->i32OriginY;4727 4728 pFBInfo->w = pScreen->u32Width;4729 pFBInfo->h = pScreen->u32Height;4730 4731 pFBInfo->u16BitsPerPixel = pScreen->u16BitsPerPixel;4732 pFBInfo->pu8FramebufferVRAM = (uint8_t *)pvVRAM + pScreen->u32StartOffset;4733 pFBInfo->u32LineSize = pScreen->u32LineSize;4734 4735 pFBInfo->flags = pScreen->u16Flags;4736 4737 if (fNewOrigin)4738 {4739 fireGuestMonitorChangedEvent(pThis->mParent->i_getEventSource(),4740 GuestMonitorChangedEventType_NewOrigin,4741 pScreen->u32ViewIndex,4742 pScreen->i32OriginX, pScreen->i32OriginY,4743 0, 0);4744 }4745 4746 if (!fResize)4747 {4748 /* No parameters of the framebuffer have actually changed. */4749 if (fNewOrigin)4750 {4751 /* VRDP server still need this notification. */4752 LogRelFlowFunc(("Calling VRDP\n"));4753 pThis->mParent->i_consoleVRDPServer()->SendResize();4754 }4755 return VINF_SUCCESS;4756 }4757 4758 /* Do a regular resize. */4759 return pThis->i_handleDisplayResize(pScreen->u32ViewIndex, pScreen->u16BitsPerPixel,4760 (uint8_t *)pvVRAM + pScreen->u32StartOffset,4761 pScreen->u32LineSize, pScreen->u32Width, pScreen->u32Height, pScreen->u16Flags);4762 }4763 4764 DECLCALLBACK(int) Display::i_displayVBVAMousePointerShape(PPDMIDISPLAYCONNECTOR pInterface, bool fVisible, bool fAlpha,4765 uint32_t xHot, uint32_t yHot,4766 uint32_t cx, uint32_t cy,4767 const void *pvShape)4768 {4769 LogFlowFunc(("\n"));4770 4771 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);4772 Display *pThis = pDrv->pDisplay;4773 4774 size_t cbShapeSize = 0;4775 4776 if (pvShape)4777 {4778 cbShapeSize = (cx + 7) / 8 * cy; /* size of the AND mask */4779 cbShapeSize = ((cbShapeSize + 3) & ~3) + cx * 4 * cy; /* + gap + size of the XOR mask */4780 }4781 com::SafeArray<BYTE> shapeData(cbShapeSize);4782 4783 if (pvShape)4784 ::memcpy(shapeData.raw(), pvShape, cbShapeSize);4785 4786 /* Tell the console about it */4787 pDrv->pDisplay->mParent->i_onMousePointerShapeChange(fVisible, fAlpha,4788 xHot, yHot, cx, cy, ComSafeArrayAsInParam(shapeData));4789 4790 return VINF_SUCCESS;4791 }4792 #endif /* VBOX_WITH_HGSMI */4793 4794 /**4795 * @interface_method_impl{PDMIBASE,pfnQueryInterface}4796 */4797 DECLCALLBACK(void *) Display::i_drvQueryInterface(PPDMIBASE pInterface, const char *pszIID)4798 {4799 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);4800 PDRVMAINDISPLAY pDrv = PDMINS_2_DATA(pDrvIns, PDRVMAINDISPLAY);4801 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);4802 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIDISPLAYCONNECTOR, &pDrv->IConnector);4803 return NULL;4804 }4805 4806 4807 /**4808 * Destruct a display driver instance.4809 *4810 * @returns VBox status.4811 * @param pDrvIns The driver instance data.4812 */4813 DECLCALLBACK(void) Display::i_drvDestruct(PPDMDRVINS pDrvIns)4814 {4815 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);4816 PDRVMAINDISPLAY pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINDISPLAY);4817 LogRelFlowFunc(("iInstance=%d\n", pDrvIns->iInstance));4818 4819 pThis->pUpPort->pfnSetRenderVRAM(pThis->pUpPort, false);4820 4821 pThis->IConnector.pu8Data = NULL;4822 pThis->IConnector.cbScanline = 0;4823 pThis->IConnector.cBits = 32;4824 pThis->IConnector.cx = 0;4825 pThis->IConnector.cy = 0;4826 4827 if (pThis->pDisplay)4828 {4829 AutoWriteLock displayLock(pThis->pDisplay COMMA_LOCKVAL_SRC_POS);4830 #ifdef VBOX_WITH_VPX4831 pThis->pDisplay->i_VideoCaptureStop();4832 #endif4833 #ifdef VBOX_WITH_CRHGSMI4834 pThis->pDisplay->i_destructCrHgsmiData();4835 #endif4836 pThis->pDisplay->mpDrv = NULL;4837 pThis->pDisplay->mpVMMDev = NULL;4838 }4839 }4840 4841 4842 /**4843 * Construct a display driver instance.4844 *4845 * @copydoc FNPDMDRVCONSTRUCT4846 */4847 DECLCALLBACK(int) Display::i_drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)4848 {4849 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);4850 PDRVMAINDISPLAY pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINDISPLAY);4851 LogRelFlowFunc(("iInstance=%d\n", pDrvIns->iInstance));4852 4853 /*4854 * Validate configuration.4855 */4856 if (!CFGMR3AreValuesValid(pCfg, "Object\0"))4857 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;4858 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,4859 ("Configuration error: Not possible to attach anything to this driver!\n"),4860 VERR_PDM_DRVINS_NO_ATTACH);4861 4862 /*4863 * Init Interfaces.4864 */4865 pDrvIns->IBase.pfnQueryInterface = Display::i_drvQueryInterface;4866 4867 pThis->IConnector.pfnResize = Display::i_displayResizeCallback;4868 pThis->IConnector.pfnUpdateRect = Display::i_displayUpdateCallback;4869 pThis->IConnector.pfnRefresh = Display::i_displayRefreshCallback;4870 pThis->IConnector.pfnReset = Display::i_displayResetCallback;4871 pThis->IConnector.pfnLFBModeChange = Display::i_displayLFBModeChangeCallback;4872 pThis->IConnector.pfnProcessAdapterData = Display::i_displayProcessAdapterDataCallback;4873 pThis->IConnector.pfnProcessDisplayData = Display::i_displayProcessDisplayDataCallback;4874 #ifdef VBOX_WITH_VIDEOHWACCEL4875 pThis->IConnector.pfnVHWACommandProcess = Display::i_displayVHWACommandProcess;4876 #endif4877 #ifdef VBOX_WITH_CRHGSMI4878 pThis->IConnector.pfnCrHgsmiCommandProcess = Display::i_displayCrHgsmiCommandProcess;4879 pThis->IConnector.pfnCrHgsmiControlProcess = Display::i_displayCrHgsmiControlProcess;4880 #endif4881 #if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)4882 pThis->IConnector.pfnCrHgcmCtlSubmit = Display::i_displayCrHgcmCtlSubmit;4883 #endif4884 #ifdef VBOX_WITH_HGSMI4885 pThis->IConnector.pfnVBVAEnable = Display::i_displayVBVAEnable;4886 pThis->IConnector.pfnVBVADisable = Display::i_displayVBVADisable;4887 pThis->IConnector.pfnVBVAUpdateBegin = Display::i_displayVBVAUpdateBegin;4888 pThis->IConnector.pfnVBVAUpdateProcess = Display::i_displayVBVAUpdateProcess;4889 pThis->IConnector.pfnVBVAUpdateEnd = Display::i_displayVBVAUpdateEnd;4890 pThis->IConnector.pfnVBVAResize = Display::i_displayVBVAResize;4891 pThis->IConnector.pfnVBVAMousePointerShape = Display::i_displayVBVAMousePointerShape;4892 #endif4893 4894 /*4895 * Get the IDisplayPort interface of the above driver/device.4896 */4897 pThis->pUpPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIDISPLAYPORT);4898 if (!pThis->pUpPort)4899 {4900 AssertMsgFailed(("Configuration error: No display port interface above!\n"));4901 return VERR_PDM_MISSING_INTERFACE_ABOVE;4902 }4903 #if defined(VBOX_WITH_VIDEOHWACCEL) || defined(VBOX_WITH_CRHGSMI)4904 pThis->pVBVACallbacks = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIDISPLAYVBVACALLBACKS);4905 if (!pThis->pVBVACallbacks)4906 {4907 AssertMsgFailed(("Configuration error: No VBVA callback interface above!\n"));4908 return VERR_PDM_MISSING_INTERFACE_ABOVE;4909 }4910 #endif4911 /*4912 * Get the Display object pointer and update the mpDrv member.4913 */4914 void *pv;4915 int rc = CFGMR3QueryPtr(pCfg, "Object", &pv);4916 if (RT_FAILURE(rc))4917 {4918 AssertMsgFailed(("Configuration error: No/bad \"Object\" value! rc=%Rrc\n", rc));4919 return rc;4920 }4921 Display *pDisplay = (Display *)pv; /** @todo Check this cast! */4922 pThis->pDisplay = pDisplay;4923 pThis->pDisplay->mpDrv = pThis;4924 4925 /* Disable VRAM to a buffer copy initially. */4926 pThis->pUpPort->pfnSetRenderVRAM(pThis->pUpPort, false);4927 pThis->IConnector.cBits = 32; /* DevVGA does nothing otherwise. */4928 4929 /*4930 * Start periodic screen refreshes4931 */4932 pThis->pUpPort->pfnSetRefreshRate(pThis->pUpPort, 20);4933 4934 #ifdef VBOX_WITH_CRHGSMI4935 pDisplay->i_setupCrHgsmiData();4936 #endif4937 4938 #ifdef VBOX_WITH_VPX4939 ComPtr<IMachine> pMachine = pDisplay->mParent->i_machine();4940 BOOL fEnabled = false;4941 HRESULT hrc = pMachine->COMGETTER(VideoCaptureEnabled)(&fEnabled);4942 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED);4943 if (fEnabled)4944 {4945 rc = pDisplay->i_VideoCaptureStart();4946 fireVideoCaptureChangedEvent(pDisplay->mParent->i_getEventSource());4947 }4948 #endif4949 4950 return rc;4951 }4952 4953 4954 /**4955 * Display driver registration record.4956 */4957 const PDMDRVREG Display::DrvReg =4958 {4959 /* u32Version */4960 PDM_DRVREG_VERSION,4961 /* szName */4962 "MainDisplay",4963 /* szRCMod */4964 "",4965 /* szR0Mod */4966 "",4967 /* pszDescription */4968 "Main display driver (Main as in the API).",4969 /* fFlags */4970 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,4971 /* fClass. */4972 PDM_DRVREG_CLASS_DISPLAY,4973 /* cMaxInstances */4974 ~0U,4975 /* cbInstance */4976 sizeof(DRVMAINDISPLAY),4977 /* pfnConstruct */4978 Display::i_drvConstruct,4979 /* pfnDestruct */4980 Display::i_drvDestruct,4981 /* pfnRelocate */4982 NULL,4983 /* pfnIOCtl */4984 NULL,4985 /* pfnPowerOn */4986 NULL,4987 /* pfnReset */4988 NULL,4989 /* pfnSuspend */4990 NULL,4991 /* pfnResume */4992 NULL,4993 /* pfnAttach */4994 NULL,4995 /* pfnDetach */4996 NULL,4997 /* pfnPowerOff */4998 NULL,4999 /* pfnSoftReset */5000 NULL,5001 /* u32EndVersion */5002 PDM_DRVREG_VERSION5003 };5004 5005 1008 /* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note:
See TracChangeset
for help on using the changeset viewer.