VOID APIENTRY VBoxDispDrvDisableSurface(DHPDEV dhpdev)
{
    PVBOXDISPDEV pDev = (PVBOXDISPDEV)dhpdev;
    LOGF_ENTER();

    if (pDev->surface.hSurface)
    {
        EngDeleteSurface(pDev->surface.hSurface);
        pDev->surface.hSurface = NULL;
    }

    if (pDev->surface.psoBitmap)
    {
        Assert(pDev->surface.hBitmap);
        EngUnlockSurface(pDev->surface.psoBitmap);
        pDev->surface.psoBitmap = NULL;
    }

    if (pDev->surface.hBitmap)
    {
        EngDeleteSurface((HSURF) pDev->surface.hBitmap);
        pDev->surface.hBitmap = NULL;
    }

    int rc;
    rc = VBoxDispMPUnmapMemory(pDev);
    VBOX_WARNRC(rc);

    LOGF_LEAVE();
}
Beispiel #2
0
void VBoxDispVHWAInit(PVBOXDISPDEV pDev)
{
    VHWAQUERYINFO info;
    int rc;

    rc = VBoxDispMPVHWAQueryInfo(pDev->hDriver, &info);
    VBOX_WARNRC(rc);

    if (RT_SUCCESS(rc))
    {
        pDev->vhwa.offVramBase = info.offVramBase;
    }
}
ULONG APIENTRY VBoxDispDrvEscape(SURFOBJ *pso, ULONG iEsc, ULONG cjIn, PVOID pvIn, ULONG cjOut, PVOID pvOut)
{
    PVBOXDISPDEV pDev = (PVBOXDISPDEV)pso->dhpdev;
    LOGF_ENTER();

    switch (iEsc)
    {
#ifdef VBOX_WITH_CROGL
        case OPENGL_GETINFO:
        {
            if (pvOut && cjOut >= sizeof(OPENGL_INFO))
            {
                POPENGL_INFO pInfo = (POPENGL_INFO)pvOut;

                pInfo->dwVersion        = 2;
                pInfo->dwDriverVersion  = 1;
                pInfo->szDriverName[0]  = 'V';
                pInfo->szDriverName[1]  = 'B';
                pInfo->szDriverName[2]  = 'o';
                pInfo->szDriverName[3]  = 'x';
                pInfo->szDriverName[4]  = 'O';
                pInfo->szDriverName[5]  = 'G';
                pInfo->szDriverName[6]  = 'L';
                pInfo->szDriverName[7]  = 0;

                LOG(("OPENGL_GETINFO ok"));
                return cjOut;
            }
            else
            {
                WARN(("OPENGL_GETINFO invalid parms"));
                return 0;
            }
        }
        case QUERYESCSUPPORT:
        {
            if (pvIn && cjIn == sizeof(DWORD))
            {
                DWORD nEscapeQuery = *(DWORD *)pvIn;

                if (nEscapeQuery==OPENGL_GETINFO)
                {
                    LOG(("QUERYESCSUPPORT OPENGL_GETINFO"));
                    return 1;
                }
                else
                {
                    LOG(("QUERYESCSUPPORT unsupported query %d", nEscapeQuery));
                    return 0;
                }
            }
            else
            {
                WARN(("QUERYESCSUPPORT invalid parms"));
                return 0;
            }
        }
#endif
        case VBOXESC_ISVRDPACTIVE:
        {
            if (pDev && pDev->vbvaCtx.pVBVA && pDev->vbvaCtx.pVBVA->hostFlags.u32HostEvents&VBVA_F_MODE_VRDP)
            {
                LOGF(("VBOXESC_ISVRDPACTIVE: 1"));
                return 1;
            }
            LOGF(("VBOXESC_ISVRDPACTIVE: 0"));
            return 0;
        }
        case VBOXESC_SETVISIBLEREGION:
        {
            LOGF(("VBOXESC_SETVISIBLEREGION"));
            LPRGNDATA lpRgnData = (LPRGNDATA)pvIn;
            DWORD cRects;

            if (    cjIn >= sizeof(RGNDATAHEADER)
                &&  pvIn
                &&  lpRgnData->rdh.dwSize == sizeof(RGNDATAHEADER)
                &&  lpRgnData->rdh.iType  == RDH_RECTANGLES
                &&  (cRects = lpRgnData->rdh.nCount) <= _1M
                &&  cjIn == cRects * (uint64_t)sizeof(RECT) + sizeof(RGNDATAHEADER))
            {
                /** @todo this whole conversion thing could maybe be skipped
                 *        since RTRECT matches the RECT layout. */
#if 0
                AssertCompile(sizeof(RTRECT) == sizeof(RECT));
                AssertCompileMembersSameSizeAndOffset(RTRECT, xLeft,    RECT, left);
                AssertCompileMembersSameSizeAndOffset(RTRECT, xBottom,  RECT, bottom);
                AssertCompileMembersSameSizeAndOffset(RTRECT, xRight,   RECT, right);
                AssertCompileMembersSameSizeAndOffset(RTRECT, xTop,     RECT, top);

                rc = VBoxDispMPSetVisibleRegion(pDev->hDriver, (PRTRECT)&lpRgnData->Buffer[0], cRects);
                VBOX_WARNRC(rc);
#else
                DWORD   i;
                PRTRECT pRTRect;
                int     rc;
                RECT   *pRect = (RECT *)&lpRgnData->Buffer;

                pRTRect = (PRTRECT) EngAllocMem(0, cRects*sizeof(RTRECT), MEM_ALLOC_TAG);
                if (!pRTRect)
                {
                    WARN(("failed to allocate %d bytes", cRects*sizeof(RTRECT)));
                    break;
                }

                for (i = 0; i < cRects; ++i)
                {
                    LOG(("New visible rectangle (%d,%d) (%d,%d)",
                         pRect[i].left, pRect[i].bottom, pRect[i].right, pRect[i].top));
                    pRTRect[i].xLeft   = pRect[i].left;
                    pRTRect[i].yBottom = pRect[i].bottom;
                    pRTRect[i].xRight  = pRect[i].right;
                    pRTRect[i].yTop    = pRect[i].top;
                }

                rc = VBoxDispMPSetVisibleRegion(pDev->hDriver, pRTRect, cRects);
                VBOX_WARNRC(rc);

                EngFreeMem(pRTRect);

#endif
                if (RT_SUCCESS(rc))
                {
                    LOGF_LEAVE();
                    return 1;
                }
            }
            else
            {
                if (pvIn)
                {
                    WARN(("check failed rdh.dwSize=%x iType=%d size=%d expected size=%d",
                          lpRgnData->rdh.dwSize, lpRgnData->rdh.iType, cjIn,
                          lpRgnData->rdh.nCount * sizeof(RECT) + sizeof(RGNDATAHEADER)));
                }
            }
            break;
        }
        default:
        {
            LOG(("unsupported iEsc %#x", iEsc));
        }
    }

    LOGF_LEAVE();
    return 0;
}
/* First function which is called after entry point, provides info about device to GDI.
 * Returns pointer to our driver private info structure which would be passed by GDI to our other callbacks.
 */
DHPDEV APIENTRY
VBoxDispDrvEnablePDEV(DEVMODEW *pdm, LPWSTR pwszLogAddress, ULONG cPat, HSURF *phsurfPatterns,
                      ULONG cjCaps, ULONG *pdevcaps,
                      ULONG cjDevInfo, DEVINFO  *pdi,
                      HDEV  hdev, PWSTR pwszDeviceName, HANDLE hDriver)
{
    PVBOXDISPDEV pDev = NULL;
    GDIINFO gdiInfo;
    DEVINFO devInfo;
    int rc;

    /* Next 3 are only used for printer drivers */
    NOREF(pwszLogAddress);
    NOREF(cPat);
    NOREF(phsurfPatterns);
    NOREF(pwszDeviceName);

    LOGF_ENTER();

    pDev = (PVBOXDISPDEV) EngAllocMem(FL_ZERO_MEMORY, sizeof(VBOXDISPDEV), MEM_ALLOC_TAG);
    if (!pDev)
    {
        WARN(("EngAllocMem failed!\n"));
        return NULL;
    }
    pDev->hDriver = hDriver;

    /* Initialize device structure and query miniport to fill device and gdi infos */
    rc = VBoxDispInitDevice(pDev, pdm, &gdiInfo, &devInfo);
    if (RT_FAILURE(rc))
    {
        VBOX_WARNRC(rc);
        EngFreeMem(pDev);
        return NULL;
    }

    /* Initialize mouse pointer caps */
    rc = VBoxDispInitPointerCaps(pDev, &devInfo);
    if (RT_FAILURE(rc))
    {
        VBOX_WARNRC(rc);
    }

    /* Initialize palette */
    rc = VBoxDispInitPalette(pDev, &devInfo);
    if (RT_FAILURE(rc))
    {
        VBOX_WARNRC(rc);
        EngFreeMem(pDev);
        return NULL;
    }

    if(g_EngineVersionDDI >= DDI_DRIVER_VERSION_NT5)
    {
        devInfo.flGraphicsCaps2 |= GCAPS2_RESERVED1;
    }

    /* Copy gathered info to supplied buffers */
    memcpy(pdevcaps, &gdiInfo, min(sizeof(GDIINFO), cjCaps));
    memcpy(pdi, &devInfo, min(sizeof(DEVINFO), cjDevInfo));

    LOGF_LEAVE();
    return (DHPDEV)pDev;
}
/* Called to get supported DirectDraw caps */
BOOL APIENTRY
VBoxDispDrvGetDirectDrawInfo(DHPDEV dhpdev, DD_HALINFO *pHalInfo, DWORD *pdwNumHeaps,
                             VIDEOMEMORY *pvmList, DWORD *pdwNumFourCCCodes, DWORD *pdwFourCC)
{
    PVBOXDISPDEV pDev = (PVBOXDISPDEV)dhpdev;
    LOGF_ENTER();

    VBoxDispGetDDHalInfo(pDev, pHalInfo);

#ifdef VBOX_WITH_VIDEOHWACCEL
    int rc;

    if (!pvmList && !pdwFourCC) /* first call */
    {
        rc = VBoxDispVHWAInitHostInfo1(pDev);
        VBOX_WARNRC_NOBP(rc);
    }

    if (pDev->vhwa.bEnabled)
    {
        rc = VBoxDispVHWAUpdateDDHalInfo(pDev, pHalInfo);
        VBOX_WARNRC(rc);

        pDev->vhwa.bEnabled = RT_SUCCESS(rc);
    }
#endif

    /* we could only have 1 heap, so it's not really a list */
    if (pvmList && pDev->layout.cbDDrawHeap>0)
    {
        pvmList->dwFlags = VIDMEM_ISLINEAR;
        pvmList->fpStart = pDev->layout.offDDrawHeap;
        pvmList->fpEnd   = pDev->layout.offDDrawHeap + pDev->layout.cbDDrawHeap - 1;
#ifdef VBOX_WITH_VIDEOHWACCEL
        if (pDev->vhwa.bEnabled)
        {
            pvmList->ddsCaps.dwCaps = 0;
        }
        else
#endif
        {
            pvmList->ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
        }
        pvmList->ddsCapsAlt.dwCaps = 0;

    }

    /* Always report number of heaps and supported FourCC's*/
    *pdwNumHeaps = (pDev->layout.cbDDrawHeap>0) ? 1:0;

#ifndef VBOX_WITH_VIDEOHWACCEL
    *pdwNumFourCCCodes = 0;
#else
    if (pDev->vhwa.bEnabled)
    {
        *pdwNumFourCCCodes = pDev->vhwa.numFourCC;
        if (pdwFourCC && pDev->vhwa.numFourCC)
        {
            rc = VBoxDispVHWAInitHostInfo2(pDev, pdwFourCC);
            VBOX_WARNRC(rc);

            if (RT_FAILURE(rc))
            {
                *pdwNumFourCCCodes = 0;
                pDev->vhwa.numFourCC = 0;
            }
        }

        pHalInfo->GetDriverInfo = VBoxDispDDGetDriverInfo;
        pHalInfo->dwFlags |= DDHALINFO_GETDRIVERINFOSET;
    }
#endif

    LOGF_LEAVE();
    return TRUE;
}
/* Lock specified area of surface */
DWORD APIENTRY VBoxDispDDLock(PDD_LOCKDATA lpLock)
{
    PVBOXDISPDEV pDev = (PVBOXDISPDEV) lpLock->lpDD->dhpdev;
    LOGF_ENTER();

    DD_SURFACE_LOCAL* pSurf = lpLock->lpDDSurface;

    lpLock->ddRVal = DD_OK;

#if 0
#ifdef VBOX_WITH_VIDEOHWACCEL
    if(pDev->vhwa.bEnabled)
    {
        PVBOXVHWASURFDESC pDesc = (PVBOXVHWASURFDESC) pSurf->lpGbl->dwReserved1;
        RECTL tmpRect, *pRect;

        if (!pDesc)
        {
            WARN(("!pDesc, memory overwrite somewhere?"));
            lpLock->ddRVal = DDERR_GENERIC;
            return DDHAL_DRIVER_HANDLED;
        }

        /* Check if host is still processing drawing commands */
        if (ASMAtomicUoReadU32(&pDesc->cPendingBltsSrc)
            || ASMAtomicUoReadU32(&pDesc->cPendingFlipsCurr)
            || ASMAtomicUoReadU32(&pDesc->cPendingBltsDst)
            || ASMAtomicUoReadU32(&pDesc->cPendingFlipsTarg))
        {
            VBoxDispVHWACommandCheckHostCmds(pDev);
            if(ASMAtomicUoReadU32(&pDesc->cPendingBltsSrc)
               || ASMAtomicUoReadU32(&pDesc->cPendingFlipsCurr)
               || ASMAtomicUoReadU32(&pDesc->cPendingBltsDst)
               || ASMAtomicUoReadU32(&pDesc->cPendingFlipsTarg))
            {
                lpLock->ddRVal = DDERR_WASSTILLDRAWING;
                return DDHAL_DRIVER_HANDLED;
            }
        }

        if (lpLock->bHasRect)
        {
            pRect = &lpLock->rArea;
        }
        else
        {
            tmpRect.left = 0;
            tmpRect.top = 0;
            tmpRect.right = pSurf->lpGbl->wWidth-1;
            tmpRect.bottom = pSurf->lpGbl->wHeight-1;
            pRect = &tmpRect;
        }

        if (lpLock->dwFlags & DDLOCK_DISCARDCONTENTS)
        {
            VBoxDispVHWARegionTrySubstitute(&pDesc->NonupdatedMemRegion, pRect);
            VBoxDispVHWARegionAdd(&pDesc->UpdatedMemRegion, pRect);
        }
        else if (!VBoxDispVHWARegionIntersects(&pDesc->NonupdatedMemRegion, pRect))
        {
            VBoxDispVHWARegionAdd(&pDesc->UpdatedMemRegion, pRect);
        }
        else
        {
            VBOXVHWACMD *pCmd;
            pCmd = VBoxDispVHWACommandCreate(pDev, VBOXVHWACMD_TYPE_SURF_LOCK, sizeof(VBOXVHWACMD_SURF_LOCK));

            if (pCmd)
            {
                VBOXVHWACMD_SURF_LOCK *pBody = VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_SURF_LOCK);
                memset(pBody, 0, sizeof(VBOXVHWACMD_SURF_LOCK));

                pBody->u.in.offSurface = VBoxDispVHWAVramOffsetFromPDEV(pDev, pSurf->lpGbl->fpVidMem);

                VBoxDispVHWAFromRECTL(&pBody->u.in.rect, &pDesc->NonupdatedMemRegion.Rect);
                pBody->u.in.rectValid = 1;

                pBody->u.in.hSurf = pDesc->hHostHandle;

                /* wait for the surface to be locked and memory buffer updated */
                VBoxDispVHWACommandSubmit(pDev, pCmd);
                VBOX_WARNRC(pCmd->rc);
                VBoxDispVHWACommandRelease(pDev, pCmd);
                VBoxDispVHWARegionClear(&pDesc->NonupdatedMemRegion);
            }
            else
            {
                WARN(("VBoxDispVHWACommandCreate failed!"));
                lpLock->ddRVal = DDERR_GENERIC;
            }
        }

        return DDHAL_DRIVER_NOTHANDLED;
    }
#endif /*VBOX_WITH_VIDEOHWACCEL*/
#endif

    /* We only care about primary surface as we'd have to report dirty rectangles to the host in the DDUnlock*/
    if (pSurf->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
    {
        pDev->ddpsLock.bLocked = TRUE;

        if (lpLock->bHasRect)
        {
            pDev->ddpsLock.rect = lpLock->rArea;
        }
        else
        {
            pDev->ddpsLock.rect.left = 0;
            pDev->ddpsLock.rect.top = 0;
            pDev->ddpsLock.rect.right = pDev->mode.ulWidth;
            pDev->ddpsLock.rect.bottom = pDev->mode.ulHeight;
        }
    }

    LOGF_LEAVE();
    return DDHAL_DRIVER_NOTHANDLED;
}
/* Called to create DirectDraw surface.
 * Note: we always return DDHAL_DRIVER_NOTHANDLED, which asks DirectDraw memory manager
 * to perform actual memory allocation in our DDraw heap.
 */
DWORD APIENTRY VBoxDispDDCreateSurface(PDD_CREATESURFACEDATA lpCreateSurface)
{
    PVBOXDISPDEV pDev = (PVBOXDISPDEV) lpCreateSurface->lpDD->dhpdev;
    LOGF_ENTER();

    PDD_SURFACE_LOCAL pSurf = lpCreateSurface->lplpSList[0];

    if (pSurf->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
    {
        LOG(("primary surface"));
        pSurf->lpGbl->fpVidMem = 0;
    }
    else
    {
        LOG(("non primary surface"));
        pSurf->lpGbl->fpVidMem = DDHAL_PLEASEALLOC_BLOCKSIZE;
    }
    pSurf->lpGbl->dwReserved1 = 0;

#ifdef VBOX_WITH_VIDEOHWACCEL
    if(pDev->vhwa.bEnabled)
    {
        VBOXVHWACMD* pCmd;

        pCmd = VBoxDispVHWACommandCreate(pDev, VBOXVHWACMD_TYPE_SURF_CREATE, sizeof(VBOXVHWACMD_SURF_CREATE));
        if (pCmd)
        {
            VBOXVHWACMD_SURF_CREATE *pBody = VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_SURF_CREATE);
            PVBOXVHWASURFDESC pDesc;
            int rc;

            memset(pBody, 0, sizeof(VBOXVHWACMD_SURF_CREATE));
            rc = VBoxDispVHWAFromDDSURFACEDESC(&pBody->SurfInfo, lpCreateSurface->lpDDSurfaceDesc);
            VBOX_WARNRC(rc);

            pBody->SurfInfo.surfCaps = VBoxDispVHWAFromDDSCAPS(pSurf->ddsCaps.dwCaps);
            pBody->SurfInfo.flags |= DDSD_CAPS;

            pBody->SurfInfo.height = pSurf->lpGbl->wHeight;
            pBody->SurfInfo.width = pSurf->lpGbl->wWidth;
            pBody->SurfInfo.flags |= DDSD_HEIGHT | DDSD_WIDTH;

            VBoxDispVHWAFromDDPIXELFORMAT(&pBody->SurfInfo.PixelFormat, &pSurf->lpGbl->ddpfSurface);
            pBody->SurfInfo.flags |= VBOXVHWA_SD_PIXELFORMAT;

            if (pSurf->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
            {
                pBody->SurfInfo.offSurface = VBoxDispVHWAVramOffsetFromPDEV(pDev, 0);
            }
            else
            {
                pBody->SurfInfo.offSurface = VBOXVHWA_OFFSET64_VOID;
            }

            pDesc = VBoxDispVHWASurfDescAlloc();
            if (pDesc)
            {
                VBoxDispVHWACommandSubmit(pDev, pCmd);
                if (RT_SUCCESS(pCmd->rc))
                {
                    uint32_t surfSizeX = pBody->SurfInfo.sizeX;
                    uint32_t surfSizeY = pBody->SurfInfo.sizeY;
                    pDesc->hHostHandle = pBody->SurfInfo.hSurf;

                    if(!!(pSurf->ddsCaps.dwCaps & DDSCAPS_OVERLAY)
                       && !!(pSurf->ddsCaps.dwCaps & DDSCAPS_VISIBLE))
                    {
                        pDesc->bVisible = true;
                    }

                    pSurf->lpGbl->dwBlockSizeX = pBody->SurfInfo.sizeX;
                    pSurf->lpGbl->dwBlockSizeY = pBody->SurfInfo.sizeY;
                    pSurf->lpGbl->lPitch       = pBody->SurfInfo.pitch;

                    lpCreateSurface->lpDDSurfaceDesc->lPitch = pSurf->lpGbl->lPitch;
                    lpCreateSurface->lpDDSurfaceDesc->dwFlags |= DDSD_PITCH;


                    /*@todo: it's probably a memory leak, because DDDestroySurface wouldn't be called for
                     *       primary surfaces.
                     */
                    pSurf->lpGbl->dwReserved1 = (ULONG_PTR)pDesc;
                }
                else
                {
                    WARN(("VBoxDispVHWACommandSubmit failed with rc=%#x", rc));
                    VBoxDispVHWASurfDescFree(pDesc);
                }
            }
            else
            {
                WARN(("VBoxDispVHWASurfDescAlloc failed"));
            }
            VBoxDispVHWACommandRelease(pDev, pCmd);
        }
        else
        {
            WARN(("VBoxDispVHWACommandCreate failed"));
        }
        return DDHAL_DRIVER_NOTHANDLED;
    }
#endif /*VBOX_WITH_VIDEOHWACCEL*/

    LPDDSURFACEDESC pDesc = lpCreateSurface->lpDDSurfaceDesc;

    if (pDesc->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED4)
    {
        pSurf->lpGbl->lPitch = RT_ALIGN_T(pSurf->lpGbl->wWidth/2, 32, LONG);
    }
    else
    if (pDesc->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8)
    {
        pSurf->lpGbl->lPitch = RT_ALIGN_T(pSurf->lpGbl->wWidth, 32, LONG);
    }
    else
    {
        pSurf->lpGbl->lPitch = pSurf->lpGbl->wWidth*(pDesc->ddpfPixelFormat.dwRGBBitCount/8);
    }

    pSurf->lpGbl->dwBlockSizeX = pSurf->lpGbl->lPitch;
    pSurf->lpGbl->dwBlockSizeY = pSurf->lpGbl->wHeight;

    pDesc->lPitch = pSurf->lpGbl->lPitch;
    pDesc->dwFlags |= DDSD_PITCH;

    LOGF_LEAVE();
    return DDHAL_DRIVER_NOTHANDLED;
}