Beispiel #1
0
/* destroys all swapchains for the given context
 * */
VOID vboxWddmSwapchainCtxDestroyAll(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pContext)
{
    VBOXWDDM_HTABLE_ITERATOR Iter;
    do
    {
        ExAcquireFastMutex(&pDevExt->ContextMutex);
        vboxWddmHTableIterInit(&pContext->Swapchains, &Iter);
        PVBOXWDDM_SWAPCHAIN pSwapchain = (PVBOXWDDM_SWAPCHAIN)vboxWddmHTableIterNext(&Iter, NULL);
        if (!pSwapchain)
            break;

        /* yes, we can call remove locked even when using iterator */
        vboxWddmSwapchainCtxRemoveLocked(pDevExt, pContext, pSwapchain);

        ExReleaseFastMutex(&pDevExt->ContextMutex);
        /* we must not do vboxWddmSwapchainDestroy inside a context mutex */
        vboxWddmSwapchainDestroy(pDevExt, pSwapchain);
        /* start from the very beginning, we will quit the loop when no swapchains left */
    } while (1);

    /* no swapchains left, we exiteed the while loop via the "break", and we still owning the mutex */
    ExReleaseFastMutex(&pDevExt->ContextMutex);
}
HRESULT VBoxD3DIfCreateForRc(struct VBOXWDDMDISP_RESOURCE *pRc)
{
    PVBOXWDDMDISP_DEVICE pDevice = pRc->pDevice;
    HRESULT hr = E_FAIL;
    IDirect3DDevice9 * pDevice9If = VBOXDISP_D3DEV(pDevice);

    if (VBOXWDDMDISP_IS_TEXTURE(pRc->RcDesc.fFlags))
    {
        PVBOXWDDMDISP_ALLOCATION pAllocation = &pRc->aAllocations[0];
        IDirect3DBaseTexture9 *pD3DIfTex;
        HANDLE hSharedHandle = pAllocation->hSharedHandle;
        void **pavClientMem = NULL;
        VBOXDISP_D3DIFTYPE enmD3DIfType = VBOXDISP_D3DIFTYPE_UNDEFINED;
        hr = S_OK;
        if (pRc->RcDesc.enmPool == D3DDDIPOOL_SYSTEMMEM)
        {
            pavClientMem = (void**)RTMemAlloc(sizeof (pavClientMem[0]) * pRc->cAllocations);
            Assert(pavClientMem);
            if (pavClientMem)
            {
                for (UINT i = 0; i < pRc->cAllocations; ++i)
                {
                    Assert(pRc->aAllocations[i].pvMem);
                    pavClientMem[i] = pRc->aAllocations[i].pvMem;
                }
            }
            else
                hr = E_FAIL;
        }

#ifdef DEBUG
        if (!pRc->RcDesc.fFlags.CubeMap)
        {
            PVBOXWDDMDISP_ALLOCATION pAlloc = &pRc->aAllocations[0];
            uint32_t tstW = pAlloc->SurfDesc.width;
            uint32_t tstH = pAlloc->SurfDesc.height;
            for (UINT i = 1; i < pRc->cAllocations; ++i)
            {
                tstW /= 2;
                tstH /= 2;
                pAlloc = &pRc->aAllocations[i];
                Assert((pAlloc->SurfDesc.width == tstW) || (!tstW && (pAlloc->SurfDesc.width==1)));
                Assert((pAlloc->SurfDesc.height == tstH) || (!tstH && (pAlloc->SurfDesc.height==1)));
            }
        }
#endif

        if (SUCCEEDED(hr))
        {
            if (pRc->RcDesc.fFlags.CubeMap)
            {
                if ( (pAllocation->SurfDesc.width!=pAllocation->SurfDesc.height)
                     || (pRc->cAllocations%6!=0))
                {
                    WARN(("unexpected cubemap texture config: (%d ; %d), allocs: %d",
                            pAllocation->SurfDesc.width, pAllocation->SurfDesc.height, pRc->cAllocations));
                    hr = E_INVALIDARG;
                }
                else
                {
                    hr = pDevice->pAdapter->D3D.D3D.pfnVBoxWineExD3DDev9CreateCubeTexture((IDirect3DDevice9Ex *)pDevice9If,
                                                pAllocation->SurfDesc.d3dWidth,
                                                VBOXDISP_CUBEMAP_LEVELS_COUNT(pRc),
                                                vboxDDI2D3DUsage(pRc->RcDesc.fFlags),
                                                vboxDDI2D3DFormat(pRc->RcDesc.enmFormat),
                                                vboxDDI2D3DPool(pRc->RcDesc.enmPool),
                                                (IDirect3DCubeTexture9**)&pD3DIfTex,
#ifdef VBOXWDDMDISP_DEBUG_NOSHARED
                                                NULL,
#else
                                                pRc->RcDesc.fFlags.SharedResource ? &hSharedHandle : NULL,
#endif
                                                pavClientMem);
                        Assert(hr == S_OK);
                        Assert(pD3DIfTex);
                        enmD3DIfType = VBOXDISP_D3DIFTYPE_CUBE_TEXTURE;
                }
            }
            else if (pRc->RcDesc.fFlags.Volume)
            {
                hr = pDevice->pAdapter->D3D.D3D.pfnVBoxWineExD3DDev9CreateVolumeTexture((IDirect3DDevice9Ex *)pDevice9If,
                                            pAllocation->SurfDesc.d3dWidth,
                                            pAllocation->SurfDesc.height,
                                            pAllocation->SurfDesc.depth,
                                            pRc->cAllocations,
                                            vboxDDI2D3DUsage(pRc->RcDesc.fFlags),
                                            vboxDDI2D3DFormat(pRc->RcDesc.enmFormat),
                                            vboxDDI2D3DPool(pRc->RcDesc.enmPool),
                                            (IDirect3DVolumeTexture9**)&pD3DIfTex,
#ifdef VBOXWDDMDISP_DEBUG_NOSHARED
                                            NULL,
#else
                                            pRc->RcDesc.fFlags.SharedResource ? &hSharedHandle : NULL,
#endif
                                            pavClientMem);
                Assert(hr == S_OK);
                Assert(pD3DIfTex);
                enmD3DIfType = VBOXDISP_D3DIFTYPE_VOLUME_TEXTURE;
            }
            else
            {
                hr = pDevice->pAdapter->D3D.D3D.pfnVBoxWineExD3DDev9CreateTexture((IDirect3DDevice9Ex *)pDevice9If,
                                            pAllocation->SurfDesc.d3dWidth,
                                            pAllocation->SurfDesc.height,
                                            pRc->cAllocations,
                                            vboxDDI2D3DUsage(pRc->RcDesc.fFlags),
                                            vboxDDI2D3DFormat(pRc->RcDesc.enmFormat),
                                            vboxDDI2D3DPool(pRc->RcDesc.enmPool),
                                            (IDirect3DTexture9**)&pD3DIfTex,
#ifdef VBOXWDDMDISP_DEBUG_NOSHARED
                                            NULL,
#else
                                            pRc->RcDesc.fFlags.SharedResource ? &hSharedHandle : NULL,
#endif
                                            pavClientMem);
                Assert(hr == S_OK);
                Assert(pD3DIfTex);
                enmD3DIfType = VBOXDISP_D3DIFTYPE_TEXTURE;
            }

            if (SUCCEEDED(hr))
            {
                Assert(pD3DIfTex);
                Assert(enmD3DIfType != VBOXDISP_D3DIFTYPE_UNDEFINED);
#ifndef VBOXWDDMDISP_DEBUG_NOSHARED
                Assert(!!(pRc->RcDesc.fFlags.SharedResource) == !!(hSharedHandle));
#endif
                for (UINT i = 0; i < pRc->cAllocations; ++i)
                {
                    PVBOXWDDMDISP_ALLOCATION pAlloc = &pRc->aAllocations[i];
                    pAlloc->enmD3DIfType = enmD3DIfType;
                    pAlloc->pD3DIf = pD3DIfTex;
                    pAlloc->hSharedHandle = hSharedHandle;
                    if (i > 0)
                        pD3DIfTex->AddRef();
                }
            }
        }

        if (pavClientMem)
            RTMemFree(pavClientMem);
    }
    else if (pRc->RcDesc.fFlags.RenderTarget || pRc->RcDesc.fFlags.Primary)
    {
        for (UINT i = 0; i < pRc->cAllocations; ++i)
        {
            PVBOXWDDMDISP_ALLOCATION pAllocation = &pRc->aAllocations[i];
            HANDLE hSharedHandle = pAllocation->hSharedHandle;
            IDirect3DSurface9* pD3D9Surf;
            if (
#ifdef VBOX_WITH_CROGL
                    (pDevice->pAdapter->u32VBox3DCaps & CR_VBOX_CAP_TEX_PRESENT) ||
#endif
                    pAllocation->enmType == VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC)
            {
                hr = pDevice9If->CreateRenderTarget(pAllocation->SurfDesc.width,
                        pAllocation->SurfDesc.height,
                        vboxDDI2D3DFormat(pRc->RcDesc.enmFormat),
                        vboxDDI2D3DMultiSampleType(pRc->RcDesc.enmMultisampleType),
                        pRc->RcDesc.MultisampleQuality,
                        !pRc->RcDesc.fFlags.NotLockable /* BOOL Lockable */,
                        &pD3D9Surf,
#ifdef VBOXWDDMDISP_DEBUG_NOSHARED
                        NULL
#else
                        pRc->RcDesc.fFlags.SharedResource ? &hSharedHandle : NULL
#endif
                );
                Assert(hr == S_OK);
            }
            else if (pAllocation->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE)
            {
                do {
                    BOOL bNeedPresent;
                    if (pRc->cAllocations != 1)
                    {
                        WARN(("unexpected config: more than one (%d) shared primary for rc", pRc->cAllocations));
                        hr = E_FAIL;
                        break;
                    }
                    PVBOXWDDMDISP_SWAPCHAIN pSwapchain = vboxWddmSwapchainFindCreate(pDevice, pAllocation, &bNeedPresent);
                    Assert(bNeedPresent);
                    if (!pSwapchain)
                    {
                        WARN(("vboxWddmSwapchainFindCreate failed"));
                        hr = E_OUTOFMEMORY;
                        break;
                    }

                    hr = vboxWddmSwapchainChkCreateIf(pDevice, pSwapchain);
                    if (!SUCCEEDED(hr))
                    {
                        WARN(("vboxWddmSwapchainChkCreateIf failed hr 0x%x", hr));
                        Assert(pAllocation->enmD3DIfType == VBOXDISP_D3DIFTYPE_UNDEFINED);
                        Assert(!pAllocation->pD3DIf);
                        vboxWddmSwapchainDestroy(pDevice, pSwapchain);
                        break;
                    }

                    Assert(pAllocation->enmD3DIfType == VBOXDISP_D3DIFTYPE_SURFACE);
                    Assert(pAllocation->pD3DIf);
                    pD3D9Surf = (IDirect3DSurface9*)pAllocation->pD3DIf;
                    break;
                } while (0);
            }
            else
            {
                WARN(("unexpected alloc type %d", pAllocation->enmType));
                hr = E_FAIL;
            }

            if (SUCCEEDED(hr))
            {
                Assert(pD3D9Surf);
                pAllocation->enmD3DIfType = VBOXDISP_D3DIFTYPE_SURFACE;
                pAllocation->pD3DIf = pD3D9Surf;
#ifndef VBOXWDDMDISP_DEBUG_NOSHARED
                Assert(!!(pRc->RcDesc.fFlags.SharedResource) == !!(hSharedHandle));
#endif
                pAllocation->hSharedHandle = hSharedHandle;
                hr = S_OK;
                continue;

                /* fail branch */
                pD3D9Surf->Release();
            }

            for (UINT j = 0; j < i; ++j)
            {
                pRc->aAllocations[j].pD3DIf->Release();
            }
            break;
        }

        if (SUCCEEDED(hr))
        {
            if (pRc->RcDesc.enmPool == D3DDDIPOOL_SYSTEMMEM)
            {
                Assert(0);
                vboxDispD3DIfSurfSynchMem(pRc);
            }
        }
    }
    else if (pRc->RcDesc.fFlags.ZBuffer)
    {
        for (UINT i = 0; i < pRc->cAllocations; ++i)
        {
            PVBOXWDDMDISP_ALLOCATION pAllocation = &pRc->aAllocations[i];
            IDirect3DSurface9 *pD3D9Surf;
            hr = pDevice9If->CreateDepthStencilSurface(pAllocation->SurfDesc.width,
                    pAllocation->SurfDesc.height,
                    vboxDDI2D3DFormat(pRc->RcDesc.enmFormat),
                    vboxDDI2D3DMultiSampleType(pRc->RcDesc.enmMultisampleType),
                    pRc->RcDesc.MultisampleQuality,
                    TRUE /* @todo: BOOL Discard */,
                    &pD3D9Surf,
                    NULL /*HANDLE* pSharedHandle*/);
            Assert(hr == S_OK);
            if (hr == S_OK)
            {
                Assert(pD3D9Surf);
                pAllocation->enmD3DIfType = VBOXDISP_D3DIFTYPE_SURFACE;
                pAllocation->pD3DIf = pD3D9Surf;
            }
            else
            {
                for (UINT j = 0; j < i; ++j)
                {
                    pRc->aAllocations[j].pD3DIf->Release();
                }
                break;
            }
        }

        if (SUCCEEDED(hr))
        {
            if (pRc->RcDesc.enmPool == D3DDDIPOOL_SYSTEMMEM)
            {
                vboxDispD3DIfSurfSynchMem(pRc);
            }
        }
    }
    else if (pRc->RcDesc.fFlags.VertexBuffer)
    {
        for (UINT i = 0; i < pRc->cAllocations; ++i)
        {
            PVBOXWDDMDISP_ALLOCATION pAllocation = &pRc->aAllocations[i];
            IDirect3DVertexBuffer9  *pD3D9VBuf;
            hr = pDevice9If->CreateVertexBuffer(pAllocation->SurfDesc.width,
                    vboxDDI2D3DUsage(pRc->RcDesc.fFlags)
                    & (~D3DUSAGE_DYNAMIC) /* <- avoid using dynamic to ensure wine does not switch do user buffer */
                    ,
                    pRc->RcDesc.Fvf,
                    vboxDDI2D3DPool(pRc->RcDesc.enmPool),
                    &pD3D9VBuf,
                    NULL /*HANDLE* pSharedHandle*/);
            Assert(hr == S_OK);
            if (hr == S_OK)
            {
                Assert(pD3D9VBuf);
                pAllocation->enmD3DIfType = VBOXDISP_D3DIFTYPE_VERTEXBUFFER;
                pAllocation->pD3DIf = pD3D9VBuf;
            }
            else
            {
                for (UINT j = 0; j < i; ++j)
                {
                    pRc->aAllocations[j].pD3DIf->Release();
                }
                break;
            }
        }

        if (SUCCEEDED(hr))
        {
            if (pRc->RcDesc.enmPool == D3DDDIPOOL_SYSTEMMEM)
            {
                vboxDispD3DIfSurfSynchMem(pRc);
            }
        }
    }
    else if (pRc->RcDesc.fFlags.IndexBuffer)
    {
        for (UINT i = 0; i < pRc->cAllocations; ++i)
        {
            PVBOXWDDMDISP_ALLOCATION pAllocation = &pRc->aAllocations[i];
            IDirect3DIndexBuffer9  *pD3D9IBuf;
            hr = pDevice9If->CreateIndexBuffer(pAllocation->SurfDesc.width,
                    vboxDDI2D3DUsage(pRc->RcDesc.fFlags),
                    vboxDDI2D3DFormat(pRc->RcDesc.enmFormat),
                    vboxDDI2D3DPool(pRc->RcDesc.enmPool),
                    &pD3D9IBuf,
                    NULL /*HANDLE* pSharedHandle*/
                  );
            Assert(hr == S_OK);
            if (hr == S_OK)
            {
                Assert(pD3D9IBuf);
                pAllocation->enmD3DIfType = VBOXDISP_D3DIFTYPE_INDEXBUFFER;
                pAllocation->pD3DIf = pD3D9IBuf;
            }
            else
            {
                for (UINT j = 0; j < i; ++j)
                {
                    pRc->aAllocations[j].pD3DIf->Release();
                }
                break;
            }
        }

        if (SUCCEEDED(hr))
        {
            if (pRc->RcDesc.enmPool == D3DDDIPOOL_SYSTEMMEM)
            {
                vboxDispD3DIfSurfSynchMem(pRc);
            }
        }
    }
    else
    {
        hr = E_FAIL;
        WARN(("unsupported rc flags, %d", pRc->RcDesc.fFlags.Value));
    }

    return hr;
}
Beispiel #3
0
/* process the swapchain info passed from user-mode display driver & synchronizes the driver state with it */
NTSTATUS vboxWddmSwapchainCtxEscape(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pContext, PVBOXDISPIFESCAPE_SWAPCHAININFO pSwapchainInfo, UINT cbSize)
{
    Assert((cbSize >= RT_OFFSETOF(VBOXDISPIFESCAPE_SWAPCHAININFO, SwapchainInfo.ahAllocs[0])));
    if (cbSize < RT_OFFSETOF(VBOXDISPIFESCAPE_SWAPCHAININFO, SwapchainInfo.ahAllocs[0]))
        return STATUS_INVALID_PARAMETER;
    Assert(cbSize >= RT_OFFSETOF(VBOXDISPIFESCAPE_SWAPCHAININFO, SwapchainInfo.ahAllocs[pSwapchainInfo->SwapchainInfo.cAllocs]));
    if (cbSize < RT_OFFSETOF(VBOXDISPIFESCAPE_SWAPCHAININFO, SwapchainInfo.ahAllocs[pSwapchainInfo->SwapchainInfo.cAllocs]))
        return STATUS_INVALID_PARAMETER;

    PVBOXWDDM_SWAPCHAIN pSwapchain = NULL;
    PVBOXWDDM_ALLOCATION *apAlloc = NULL;
    Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
    NTSTATUS Status = STATUS_SUCCESS;

    do {
        if (pSwapchainInfo->SwapchainInfo.cAllocs)
        {
            apAlloc = (PVBOXWDDM_ALLOCATION *)vboxWddmMemAlloc(sizeof (PVBOXWDDM_ALLOCATION) * pSwapchainInfo->SwapchainInfo.cAllocs);
            Assert(apAlloc);
            if (!apAlloc)
            {
                Status = STATUS_NO_MEMORY;
                break;
            }
            for (UINT i = 0; i < pSwapchainInfo->SwapchainInfo.cAllocs; ++i)
            {
                DXGKARGCB_GETHANDLEDATA GhData;
                GhData.hObject = pSwapchainInfo->SwapchainInfo.ahAllocs[i];
                GhData.Type = DXGK_HANDLE_ALLOCATION;
                GhData.Flags.Value = 0;
                PVBOXWDDM_ALLOCATION pAlloc = (PVBOXWDDM_ALLOCATION)pDevExt->u.primary.DxgkInterface.DxgkCbGetHandleData(&GhData);
                Assert(pAlloc);
                if (!pAlloc)
                {
                    Status = STATUS_INVALID_PARAMETER;
                    break;
                }
                apAlloc[i] = pAlloc;
            }

            if (!NT_SUCCESS(Status))
                break;
        }

        if (pSwapchainInfo->SwapchainInfo.hSwapchainKm)
        {
            ExAcquireFastMutex(&pDevExt->ContextMutex);
            pSwapchain = (PVBOXWDDM_SWAPCHAIN)vboxWddmHTableGet(&pContext->Swapchains, (VBOXWDDM_HANDLE)pSwapchainInfo->SwapchainInfo.hSwapchainKm);
            Assert(pSwapchain);
            if (!pSwapchain)
            {
                ExReleaseFastMutex(&pDevExt->ContextMutex);
                Status = STATUS_INVALID_PARAMETER;
                break;
            }
            Assert(pSwapchain->hSwapchainKm == pSwapchainInfo->SwapchainInfo.hSwapchainKm);
            Assert(pSwapchain->pContext == pContext);
            if (pSwapchain->pContext != pContext)
            {
                ExReleaseFastMutex(&pDevExt->ContextMutex);
                Status = STATUS_INVALID_PARAMETER;
                break;
            }
        }
        else if (pSwapchainInfo->SwapchainInfo.cAllocs)
        {
            pSwapchain = vboxWddmSwapchainCreate();
            if (!pSwapchain)
            {
                Status = STATUS_NO_MEMORY;
                break;
            }

            ExAcquireFastMutex(&pDevExt->ContextMutex);
            BOOLEAN bRc = vboxWddmSwapchainCtxAddLocked(pDevExt, pContext, pSwapchain);
            Assert(bRc);
        }
        else
        {
            Status = STATUS_INVALID_PARAMETER;
            break;
        }

        memset(&pSwapchain->ViewRect, 0, sizeof (pSwapchain->ViewRect));
        if (pSwapchain->pLastReportedRects)
        {
            vboxVideoCmCmdRelease(pSwapchain->pLastReportedRects);
            pSwapchain->pLastReportedRects = NULL;
        }

        vboxWddmSwapchainAllocRemoveAll(pDevExt, pSwapchain);

        if (pSwapchainInfo->SwapchainInfo.cAllocs)
        {
            for (UINT i = 0; i < pSwapchainInfo->SwapchainInfo.cAllocs; ++i)
            {
                vboxWddmSwapchainAllocAdd(pDevExt, pSwapchain, apAlloc[i]);
            }
            pSwapchain->hSwapchainUm = pSwapchainInfo->SwapchainInfo.hSwapchainUm;
        }
        else
        {
            vboxWddmSwapchainCtxRemoveLocked(pDevExt, pContext, pSwapchain);
        }

        ExReleaseFastMutex(&pDevExt->ContextMutex);

        if (pSwapchainInfo->SwapchainInfo.cAllocs)
        {
            Assert(pSwapchain->pContext);
            Assert(pSwapchain->hSwapchainKm);
            pSwapchainInfo->SwapchainInfo.hSwapchainKm = pSwapchain->hSwapchainKm;
        }
        else
        {
            vboxWddmSwapchainDestroy(pDevExt, pSwapchain);
            pSwapchainInfo->SwapchainInfo.hSwapchainKm = 0;
        }

        Assert(Status == STATUS_SUCCESS);
    } while (0);

    /* cleanup */
    if (apAlloc)
        vboxWddmMemFree(apAlloc);

    return Status;
}