Changeset 24373 in vbox for trunk/src/VBox
- Timestamp:
- Nov 5, 2009 9:51:34 AM (15 years ago)
- Location:
- trunk/src/VBox
- Files:
-
- 1 added
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Graphics/DevVGA.cpp
r24288 r24373 126 126 #include <VBox/pdmdev.h> 127 127 #include <VBox/pgm.h> 128 #ifdef IN_RING3 129 #include <iprt/alloc.h> 130 #endif /* IN_RING3 */ 128 131 #include <iprt/assert.h> 129 132 #include <iprt/asm.h> … … 4860 4863 } 4861 4864 4865 /* Internal worker called under pThis->lock. */ 4866 static int updateDisplayAll(PVGASTATE pThis) 4867 { 4868 PPDMDEVINS pDevIns = pThis->CTX_SUFF(pDevIns); 4869 4870 /* The dirty bits array has been just cleared, reset handlers as well. */ 4871 if (pThis->GCPhysVRAM && pThis->GCPhysVRAM != NIL_RTGCPHYS32) 4872 { 4873 PGMHandlerPhysicalReset(PDMDevHlpGetVM(pDevIns), pThis->GCPhysVRAM); 4874 } 4875 if (pThis->fRemappedVGA) 4876 { 4877 IOMMMIOResetRegion(PDMDevHlpGetVM(pDevIns), 0x000a0000); 4878 pThis->fRemappedVGA = false; 4879 } 4880 4881 pThis->graphic_mode = -1; /* force full update */ 4882 4883 return vga_update_display(pThis, true); 4884 } 4885 4862 4886 4863 4887 /** … … 4882 4906 AssertRC(rc); 4883 4907 4884 /* The dirty bits array has been just cleared, reset handlers as well. */ 4885 if (pThis->GCPhysVRAM && pThis->GCPhysVRAM != NIL_RTGCPHYS32) 4886 { 4887 PGMHandlerPhysicalReset(PDMDevHlpGetVM(pDevIns), pThis->GCPhysVRAM); 4888 } 4889 if (pThis->fRemappedVGA) 4890 { 4891 IOMMMIOResetRegion(PDMDevHlpGetVM(pDevIns), 0x000a0000); 4892 pThis->fRemappedVGA = false; 4893 } 4894 4895 pThis->graphic_mode = -1; /* force full update */ 4896 4897 rc = vga_update_display(pThis, true); 4908 rc = updateDisplayAll(pThis); 4898 4909 4899 4910 PDMCritSectLeave(&pThis->lock); … … 4933 4944 4934 4945 /** 4935 * Create a 32-bbp s napshot of the display.4946 * Create a 32-bbp screenshot of the display. Size of the bitmap scanline in bytes is 4*width. 4936 4947 * 4937 4948 * @param pInterface Pointer to this interface. 4938 * @param pvData Pointer the buffer to copy the bits to. 4939 * @param cbData Size of the buffer. 4940 * @param pcx Where to store the width of the bitmap. (optional) 4941 * @param pcy Where to store the height of the bitmap. (optional) 4942 * @param pcbData Where to store the actual size of the bitmap. (optional) 4943 * @see PDMIKEYBOARDPORT::pfnSnapshot() for details. 4949 * @param ppu8Data Where to store the pointer to the allocated buffer. 4950 * @param pcbData Where to store the actual size of the bitmap. 4951 * @param pcx Where to store the width of the bitmap. 4952 * @param pcy Where to store the height of the bitmap. 4953 * @see PDMIDISPLAYPORT::pfnTakeScreenshot() for details. 4944 4954 */ 4945 static DECLCALLBACK(int) vgaPortSnapshot(PPDMIDISPLAYPORT pInterface, void *pvData, size_t cbData, uint32_t *pcx, uint32_t *pcy, size_t *pcbData) 4946 { 4947 /* @todo r=sunlover: replace the method with a direct VRAM rendering like in vgaPortUpdateDisplayRect. */ 4948 PPDMIDISPLAYCONNECTOR pConnector; 4949 PDMIDISPLAYCONNECTOR Connector; 4950 int32_t graphic_mode; 4951 bool fRenderVRAM; 4952 size_t cbRequired; 4953 PVGASTATE pThis = IDISPLAYPORT_2_VGASTATE(pInterface); 4955 static DECLCALLBACK(int) vgaPortTakeScreenshot(PPDMIDISPLAYPORT pInterface, uint8_t **ppu8Data, size_t *pcbData, uint32_t *pcx, uint32_t *pcy) 4956 { 4957 PVGASTATE pThis = IDISPLAYPORT_2_VGASTATE(pInterface); 4954 4958 PDMDEV_ASSERT_EMT(VGASTATE2DEVINS(pThis)); 4955 LogFlow(("vgaPortSnapshot: pvData=%p cbData=%d pcx=%p pcy=%p pcbData=%p\n", pvData, cbData, pcx, pcy, pcbData)); 4959 4960 LogFlow(("vgaPortTakeScreenshot: ppu8Data=%p pcbData=%p pcx=%p pcy=%p\n", ppu8Data, pcbData, pcx, pcy)); 4956 4961 4957 4962 /* 4958 4963 * Validate input. 4959 4964 */ 4960 if (! pvData)4965 if (!RT_VALID_PTR(ppu8Data) || !RT_VALID_PTR(pcbData) || !RT_VALID_PTR(pcx) || !RT_VALID_PTR(pcy)) 4961 4966 return VERR_INVALID_PARAMETER; 4962 4967 4968 int rc = PDMCritSectEnter(&pThis->lock, VERR_SEM_BUSY); 4969 AssertRCReturn(rc, rc); 4970 4963 4971 /* 4964 * Do a regular refresh first to resolve any pending resize issues. 4965 * 4966 * 20060317 It used to be pfnUpdateDisplay, but by VBVA design 4967 * only pfnUpdateDisplayAll is allowed to be called in VBVA mode. 4968 * Also since the goal here is to have updated display for screenshot, 4969 * the UpdateDisplayAll is even more logical to call. (sunlover) 4972 * Do a complete screen update first to resolve any pending resize issues. 4970 4973 */ 4971 pInterface->pfnUpdateDisplayAll(pInterface); 4972 4973 int rc = PDMCritSectEnter(&pThis->lock, VERR_SEM_BUSY); 4974 AssertRC(rc); 4974 updateDisplayAll(pThis); 4975 4975 4976 4976 /* 4977 * Validate the buffer size.4977 * The display connector interface is temporarily replaced with the fake one. 4978 4978 */ 4979 cbRequired = RT_ALIGN_Z(pThis->last_scr_width, 4) * pThis->last_scr_height * 4; 4980 if (cbRequired > cbData) 4981 { 4982 Log(("vgaPortSnapshot: %d bytes are required, a buffer of %d bytes is profiled.\n", cbRequired, cbData)); 4983 PDMCritSectLeave(&pThis->lock); 4984 return VERR_BUFFER_OVERFLOW; 4985 } 4979 PDMIDISPLAYCONNECTOR Connector; 4980 memset(&Connector, 0, sizeof (PDMIDISPLAYCONNECTOR)); 4986 4981 4987 4982 /* 4988 * Temporarily replace the display connector interface with a fake one.4983 * Allocate the buffer for 32 bits per pixel bitmap. 4989 4984 */ 4990 Connector.pu8Data = (uint8_t*)pvData; 4991 Connector.cBits = 32; 4992 Connector.cx = pThis->pDrv->cx; 4993 Connector.cy = pThis->pDrv->cy; 4994 Connector.cbScanline = RT_ALIGN_32(Connector.cx, 4) * 4; 4995 Connector.pfnRefresh = vgaDummyRefresh; 4996 Connector.pfnResize = vgaDummyResize; 4997 Connector.pfnUpdateRect = vgaDummyUpdateRect; 4998 4999 /* save & replace state data. */ 5000 pConnector = pThis->pDrv; 5001 pThis->pDrv = &Connector; 5002 graphic_mode = pThis->graphic_mode; 5003 pThis->graphic_mode = -1; /* force a full refresh. */ 5004 fRenderVRAM = pThis->fRenderVRAM; 5005 pThis->fRenderVRAM = 1; /* force the guest VRAM rendering to the given buffer. */ 5006 5007 /* make the snapshot. 5008 * The second parameter is 'false' because the current display state, already updated by the 5009 * pfnUpdateDisplayAll call above, is being rendered to an external buffer using a fake connector. 5010 * That is if display is blanked, we expect a black screen in the external buffer. 5011 */ 5012 rc = vga_update_display(pThis, false); 5013 5014 /* restore */ 5015 pThis->pDrv = pConnector; 5016 pThis->graphic_mode = graphic_mode; 5017 pThis->fRenderVRAM = fRenderVRAM; 4985 size_t cbRequired = pThis->last_scr_width * 4 * pThis->last_scr_height; 4986 4987 uint8_t *pu8Data = (uint8_t *)RTMemAlloc(cbRequired); 4988 if (pu8Data == NULL) 4989 { 4990 rc = VERR_NO_MEMORY; 4991 } 4992 else 4993 { 4994 /* 4995 * Only 3 methods, assigned below, will be called during the screenshot update. 4996 * All other are already set to NULL. 4997 */ 4998 4999 Connector.pu8Data = pu8Data; 5000 Connector.cBits = 32; 5001 Connector.cx = pThis->last_scr_width; 5002 Connector.cy = pThis->last_scr_height; 5003 Connector.cbScanline = Connector.cx * 4; 5004 Connector.pfnRefresh = vgaDummyRefresh; 5005 Connector.pfnResize = vgaDummyResize; 5006 Connector.pfnUpdateRect = vgaDummyUpdateRect; 5007 5008 /* Save & replace state data. */ 5009 PPDMIDISPLAYCONNECTOR pConnectorSaved = pThis->pDrv; 5010 int32_t graphic_mode_saved = pThis->graphic_mode; 5011 bool fRenderVRAMSaved = pThis->fRenderVRAM; 5012 5013 pThis->pDrv = &Connector; 5014 pThis->graphic_mode = -1; /* force a full refresh. */ 5015 pThis->fRenderVRAM = 1; /* force the guest VRAM rendering to the given buffer. */ 5016 5017 /* Make the screenshot. 5018 * 5019 * The second parameter is 'false' because the current display state, already updated by the 5020 * pfnUpdateDisplayAll call above, is being rendered to an external buffer using a fake connector. 5021 * That is if display is blanked, we expect a black screen in the external buffer. 5022 */ 5023 rc = vga_update_display(pThis, false); 5024 5025 /* Restore. */ 5026 pThis->pDrv = pConnectorSaved; 5027 pThis->graphic_mode = graphic_mode_saved; 5028 pThis->fRenderVRAM = fRenderVRAMSaved; 5029 5030 if (rc == VINF_SUCCESS) 5031 { 5032 /* 5033 * Return the result. 5034 */ 5035 *ppu8Data = pu8Data; 5036 *pcbData = cbRequired; 5037 *pcx = Connector.cx; 5038 *pcy = Connector.cy; 5039 } 5040 } 5041 5018 5042 PDMCritSectLeave(&pThis->lock); 5019 5043 5020 if (rc != VINF_SUCCESS) 5021 return rc; 5022 5023 /* 5024 * Return the result. 5025 */ 5026 if (pcx) 5027 *pcx = Connector.cx; 5028 if (pcy) 5029 *pcy = Connector.cy; 5030 if (pcbData) 5031 *pcbData = cbRequired; 5032 LogFlow(("vgaPortSnapshot: returns VINF_SUCCESS (cx=%d cy=%d cbData=%d)\n", Connector.cx, Connector.cy, cbRequired)); 5033 return VINF_SUCCESS; 5034 } 5035 5044 LogFlow(("vgaPortTakeScreenshot: returns %Rrc (cbData=%d cx=%d cy=%d)\n", rc, cbRequired, Connector.cx, Connector.cy)); 5045 return rc; 5046 } 5047 5048 /** 5049 * Free a screenshot buffer allocated in vgaPortTakeScreenshot. 5050 * 5051 * @param pInterface Pointer to this interface. 5052 * @param pu8Data Pointer returned by vgaPortTakeScreenshot. 5053 * @see PDMIDISPLAYPORT::pfnFreeScreenshot() for details. 5054 */ 5055 static DECLCALLBACK(void) vgaPortFreeScreenshot(PPDMIDISPLAYPORT pInterface, uint8_t *pu8Data) 5056 { 5057 NOREF(pInterface); 5058 5059 LogFlow(("vgaPortFreeScreenshot: pu8Data=%p\n", pu8Data)); 5060 5061 RTMemFree(pu8Data); 5062 } 5036 5063 5037 5064 /** … … 5917 5944 pThis->Port.pfnQueryColorDepth = vgaPortQueryColorDepth; 5918 5945 pThis->Port.pfnSetRefreshRate = vgaPortSetRefreshRate; 5919 pThis->Port.pfnSnapshot = vgaPortSnapshot; 5946 pThis->Port.pfnTakeScreenshot = vgaPortTakeScreenshot; 5947 pThis->Port.pfnFreeScreenshot = vgaPortFreeScreenshot; 5920 5948 pThis->Port.pfnDisplayBlt = vgaPortDisplayBlt; 5921 5949 pThis->Port.pfnUpdateDisplayRect = vgaPortUpdateDisplayRect; -
trunk/src/VBox/Devices/Graphics/DevVGA.h
r24053 r24373 310 310 /** The display port interface. */ 311 311 PDMIDISPLAYPORT Port; 312 # if HC_ARCH_BITS == 32 313 uint32_t Padding8; 314 # endif 312 315 #if defined(VBOX_WITH_HGSMI) && defined(VBOX_WITH_VIDEOHWACCEL) 313 316 /** VBVA callbacks interface */ -
trunk/src/VBox/Main/DisplayImpl.cpp
r24301 r24373 41 41 # include <VBox/VBoxVideo.h> 42 42 #endif 43 44 #include <VBox/com/array.h> 45 43 46 /** 44 47 * Display driver instance data. … … 1533 1536 } 1534 1537 1538 static int displayTakeScreenshot(PVM pVM, struct DRVMAINDISPLAY *pDrv, BYTE *address, ULONG width, ULONG height) 1539 { 1540 uint8_t *pu8Data = NULL; 1541 size_t cbData = 0; 1542 uint32_t cx = 0; 1543 uint32_t cy = 0; 1544 1545 /* @todo pfnTakeScreenshot is probably callable from any thread, because it uses the VGA device lock. */ 1546 int vrc = VMR3ReqCallWait(pVM, VMCPUID_ANY, (PFNRT)pDrv->pUpPort->pfnTakeScreenshot, 5, 1547 pDrv->pUpPort, &pu8Data, &cbData, &cx, &cy); 1548 1549 if (RT_SUCCESS(vrc)) 1550 { 1551 if (cx == width && cy == height) 1552 { 1553 /* No scaling required. */ 1554 memcpy(address, pu8Data, cbData); 1555 } 1556 else 1557 { 1558 /* Scale. */ 1559 LogFlowFunc(("SCALE: %dx%d -> %dx%d\n", cx, cy, width, height)); 1560 1561 uint8_t *dst = address; 1562 uint8_t *src = pu8Data; 1563 int dstX = 0; 1564 int dstY = 0; 1565 int srcX = 0; 1566 int srcY = 0; 1567 int dstW = width; 1568 int dstH = height; 1569 int srcW = cx; 1570 int srcH = cy; 1571 gdImageCopyResampled (dst, 1572 src, 1573 dstX, dstY, 1574 srcX, srcY, 1575 dstW, dstH, srcW, srcH); 1576 } 1577 1578 /* This can be called from any thread. */ 1579 pDrv->pUpPort->pfnFreeScreenshot (pDrv->pUpPort, pu8Data); 1580 } 1581 1582 return vrc; 1583 } 1584 1535 1585 STDMETHODIMP Display::TakeScreenShot (BYTE *address, ULONG width, ULONG height) 1536 1586 { … … 1563 1613 LogFlowFunc (("Sending SCREENSHOT request\n")); 1564 1614 1565 /* 1566 * First try use the graphics device features for making a snapshot. 1567 * This does not support stretching, is an optional feature (returns 1568 * not supported). 1615 /* Leave lock because other thread (EMT) is called and it may initiate a resize 1616 * which also needs lock. 1569 1617 * 1570 * Note: It may cause a display resize. Watch out for deadlocks.1618 * This method does not need the lock anymore. 1571 1619 */ 1572 int rcVBox = VERR_NOT_SUPPORTED; 1573 if ( mpDrv->Connector.cx == width 1574 && mpDrv->Connector.cy == height) 1575 { 1576 size_t cbData = RT_ALIGN_Z(width, 4) * 4 * height; 1577 rcVBox = VMR3ReqCallWait(pVM, VMCPUID_ANY, (PFNRT)mpDrv->pUpPort->pfnSnapshot, 6, mpDrv->pUpPort, 1578 address, cbData, (uintptr_t)NULL, (uintptr_t)NULL, (uintptr_t)NULL); 1579 } 1580 1581 /* 1582 * If the function returns not supported, or if stretching is requested, 1583 * we'll have to do all the work ourselves using the framebuffer data. 1584 */ 1585 if (rcVBox == VERR_NOT_SUPPORTED || rcVBox == VERR_NOT_IMPLEMENTED) 1586 { 1587 /** @todo implement snapshot stretching & generic snapshot fallback. */ 1588 rc = setError (E_NOTIMPL, tr ("This feature is not implemented")); 1589 } 1590 else if (RT_FAILURE(rcVBox)) 1620 alock.leave(); 1621 1622 int vrc = displayTakeScreenshot(pVM, mpDrv, address, width, height); 1623 1624 if (vrc == VERR_NOT_IMPLEMENTED) 1625 rc = setError (E_NOTIMPL, 1626 tr ("This feature is not implemented")); 1627 else if (RT_FAILURE(vrc)) 1591 1628 rc = setError (VBOX_E_IPRT_ERROR, 1592 tr ("Could not take a screenshot (%Rrc)"), rcVBox);1629 tr ("Could not take a screenshot (%Rrc)"), vrc); 1593 1630 1594 1631 LogFlowFunc (("rc=%08X\n", rc)); … … 1600 1637 ComSafeArrayOut(BYTE, aScreenData)) 1601 1638 { 1602 HRESULT rc = S_OK; 1603 1604 rc = setError (E_NOTIMPL, tr ("This feature is not implemented")); 1605 1606 return rc; 1639 LogFlowFuncEnter(); 1640 LogFlowFunc (("width=%d, height=%d\n", 1641 width, height)); 1642 1643 CheckComArgSafeArrayNotNull(aScreenData); 1644 CheckComArgExpr(width, width != 0); 1645 CheckComArgExpr(height, height != 0); 1646 1647 AutoCaller autoCaller(this); 1648 CheckComRCReturnRC(autoCaller.rc()); 1649 1650 AutoWriteLock alock(this); 1651 1652 CHECK_CONSOLE_DRV (mpDrv); 1653 1654 Console::SafeVMPtr pVM (mParent); 1655 CheckComRCReturnRC(pVM.rc()); 1656 1657 HRESULT rc = S_OK; 1658 1659 LogFlowFunc (("Sending SCREENSHOT request\n")); 1660 1661 /* Leave lock because other thread (EMT) is called and it may initiate a resize 1662 * which also needs lock. 1663 * 1664 * This method does not need the lock anymore. 1665 */ 1666 alock.leave(); 1667 1668 size_t cbData = width * 4 * height; 1669 uint8_t *pu8Data = (uint8_t *)RTMemAlloc(cbData); 1670 1671 if (!pu8Data) 1672 return E_OUTOFMEMORY; 1673 1674 int vrc = displayTakeScreenshot(pVM, mpDrv, pu8Data, width, height); 1675 1676 if (RT_SUCCESS(vrc)) 1677 { 1678 com::SafeArray<BYTE> screenData (cbData); 1679 for (unsigned i = 0; i < cbData; i++) 1680 screenData[i] = pu8Data[i]; 1681 screenData.detachTo(ComSafeArrayOutArg(aScreenData)); 1682 } 1683 else if (vrc == VERR_NOT_IMPLEMENTED) 1684 rc = setError (E_NOTIMPL, 1685 tr ("This feature is not implemented")); 1686 else 1687 rc = setError (VBOX_E_IPRT_ERROR, 1688 tr ("Could not take a screenshot (%Rrc)"), vrc); 1689 1690 LogFlowFunc (("rc=%08X\n", rc)); 1691 LogFlowFuncLeave(); 1692 return rc; 1607 1693 } 1608 1694 -
trunk/src/VBox/Main/Makefile.kmk
r23848 r24373 615 615 MouseImpl.cpp \ 616 616 DisplayImpl.cpp \ 617 DisplayResampleImage.cpp \ 617 618 MachineDebuggerImpl.cpp \ 618 619 VBoxDriversRegister.cpp \ -
trunk/src/VBox/Main/include/DisplayImpl.h
r23643 r24373 339 339 }; 340 340 341 void gdImageCopyResampled (uint8_t *dst, uint8_t *src, 342 int dstX, int dstY, 343 int srcX, int srcY, 344 int dstW, int dstH, int srcW, int srcH); 345 346 341 347 #endif // ____H_DISPLAYIMPL 342 348 /* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note:
See TracChangeset
for help on using the changeset viewer.