VirtualBox

Changeset 24373 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Nov 5, 2009 9:51:34 AM (15 years ago)
Author:
vboxsync
Message:

Updated screenshot API (xTracker 4364).

Location:
trunk/src/VBox
Files:
1 added
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Graphics/DevVGA.cpp

    r24288 r24373  
    126126#include <VBox/pdmdev.h>
    127127#include <VBox/pgm.h>
     128#ifdef IN_RING3
     129#include <iprt/alloc.h>
     130#endif /* IN_RING3 */
    128131#include <iprt/assert.h>
    129132#include <iprt/asm.h>
     
    48604863}
    48614864
     4865/* Internal worker called under pThis->lock. */
     4866static 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
    48624886
    48634887/**
     
    48824906    AssertRC(rc);
    48834907
    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);
    48984909
    48994910    PDMCritSectLeave(&pThis->lock);
     
    49334944
    49344945/**
    4935  * Create a 32-bbp snapshot of the display.
     4946 * Create a 32-bbp screenshot of the display. Size of the bitmap scanline in bytes is 4*width.
    49364947 *
    49374948 * @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.
    49444954 */
    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);
     4955static 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);
    49544958    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));
    49564961
    49574962    /*
    49584963     * Validate input.
    49594964     */
    4960     if (!pvData)
     4965    if (!RT_VALID_PTR(ppu8Data) || !RT_VALID_PTR(pcbData) || !RT_VALID_PTR(pcx) || !RT_VALID_PTR(pcy))
    49614966        return VERR_INVALID_PARAMETER;
    49624967
     4968    int rc = PDMCritSectEnter(&pThis->lock, VERR_SEM_BUSY);
     4969    AssertRCReturn(rc, rc);
     4970
    49634971    /*
    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.
    49704973     */
    4971     pInterface->pfnUpdateDisplayAll(pInterface);
    4972 
    4973     int rc = PDMCritSectEnter(&pThis->lock, VERR_SEM_BUSY);
    4974     AssertRC(rc);
     4974    updateDisplayAll(pThis);
    49754975
    49764976    /*
    4977      * Validate the buffer size.
     4977     * The display connector interface is temporarily replaced with the fake one.
    49784978     */
    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));
    49864981
    49874982    /*
    4988      * Temporarily replace the display connector interface with a fake one.
     4983     * Allocate the buffer for 32 bits per pixel bitmap.
    49894984     */
    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
    50185042    PDMCritSectLeave(&pThis->lock);
    50195043
    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 */
     5055static 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}
    50365063
    50375064/**
     
    59175944    pThis->Port.pfnQueryColorDepth      = vgaPortQueryColorDepth;
    59185945    pThis->Port.pfnSetRefreshRate       = vgaPortSetRefreshRate;
    5919     pThis->Port.pfnSnapshot             = vgaPortSnapshot;
     5946    pThis->Port.pfnTakeScreenshot       = vgaPortTakeScreenshot;
     5947    pThis->Port.pfnFreeScreenshot       = vgaPortFreeScreenshot;
    59205948    pThis->Port.pfnDisplayBlt           = vgaPortDisplayBlt;
    59215949    pThis->Port.pfnUpdateDisplayRect    = vgaPortUpdateDisplayRect;
  • trunk/src/VBox/Devices/Graphics/DevVGA.h

    r24053 r24373  
    310310    /** The display port interface. */
    311311    PDMIDISPLAYPORT             Port;
     312# if HC_ARCH_BITS == 32
     313    uint32_t                    Padding8;
     314# endif
    312315#if defined(VBOX_WITH_HGSMI) && defined(VBOX_WITH_VIDEOHWACCEL)
    313316    /** VBVA callbacks interface */
  • trunk/src/VBox/Main/DisplayImpl.cpp

    r24301 r24373  
    4141# include <VBox/VBoxVideo.h>
    4242#endif
     43
     44#include <VBox/com/array.h>
     45
    4346/**
    4447 * Display driver instance data.
     
    15331536}
    15341537
     1538static 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
    15351585STDMETHODIMP Display::TakeScreenShot (BYTE *address, ULONG width, ULONG height)
    15361586{
     
    15631613    LogFlowFunc (("Sending SCREENSHOT request\n"));
    15641614
    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.
    15691617     *
    1570      * Note: It may cause a display resize. Watch out for deadlocks.
     1618     * This method does not need the lock anymore.
    15711619     */
    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))
    15911628        rc = setError (VBOX_E_IPRT_ERROR,
    1592             tr ("Could not take a screenshot (%Rrc)"), rcVBox);
     1629                       tr ("Could not take a screenshot (%Rrc)"), vrc);
    15931630
    15941631    LogFlowFunc (("rc=%08X\n", rc));
     
    16001637                                          ComSafeArrayOut(BYTE, aScreenData))
    16011638{
    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;
    16071693}
    16081694
  • trunk/src/VBox/Main/Makefile.kmk

    r23848 r24373  
    615615        MouseImpl.cpp \
    616616        DisplayImpl.cpp \
     617        DisplayResampleImage.cpp \
    617618        MachineDebuggerImpl.cpp \
    618619        VBoxDriversRegister.cpp \
  • trunk/src/VBox/Main/include/DisplayImpl.h

    r23643 r24373  
    339339};
    340340
     341void 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
    341347#endif // ____H_DISPLAYIMPL
    342348/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette