int vmsvga3dSaveExec(PVGASTATE pThis, PSSMHANDLE pSSM)
{
    PVMSVGA3DSTATE pState = pThis->svga.p3dState;
    AssertReturn(pState, VERR_NO_MEMORY);
    int            rc;

    /* Save a copy of the generic 3d state first. */
    rc = SSMR3PutStructEx(pSSM, pState, sizeof(*pState), 0, g_aVMSVGA3DSTATEFields, NULL);
    AssertRCReturn(rc, rc);

#ifdef VMSVGA3D_OPENGL
    /* Save the shared context. */
    if (pState->SharedCtx.id == VMSVGA3D_SHARED_CTX_ID)
    {
        rc = vmsvga3dSaveContext(pThis, pSSM, &pState->SharedCtx);
        AssertRCReturn(rc, rc);
    }
#endif

    /* Save all active contexts. */
    for (uint32_t i = 0; i < pState->cContexts; i++)
    {
        rc = vmsvga3dSaveContext(pThis, pSSM, pState->papContexts[i]);
        AssertRCReturn(rc, rc);
    }

    /* Save all active surfaces. */
    for (uint32_t sid = 0; sid < pState->cSurfaces; sid++)
    {
        PVMSVGA3DSURFACE pSurface = pState->papSurfaces[sid];

        /* Save the id first. */
        rc = SSMR3PutU32(pSSM, pSurface->id);
        AssertRCReturn(rc, rc);

        if (pSurface->id != SVGA3D_INVALID_ID)
        {
            /* Save a copy of the surface structure first. */
            rc = SSMR3PutStructEx(pSSM, pSurface, sizeof(*pSurface), 0, g_aVMSVGA3DSURFACEFields, NULL);
            AssertRCReturn(rc, rc);

            /* Save the mip map level info. */
            for (uint32_t face=0; face < pSurface->cFaces; face++)
            {
                for (uint32_t i = 0; i < pSurface->faces[0].numMipLevels; i++)
                {
                    uint32_t idx = i + face * pSurface->faces[0].numMipLevels;
                    PVMSVGA3DMIPMAPLEVEL pMipmapLevel = &pSurface->pMipmapLevels[idx];

                    /* Save a copy of the mip map level struct. */
                    rc = SSMR3PutStructEx(pSSM, pMipmapLevel, sizeof(*pMipmapLevel), 0, g_aVMSVGA3DMIPMAPLEVELFields, NULL);
                    AssertRCReturn(rc, rc);
                }
            }

            /* Save the mip map level data. */
            for (uint32_t face=0; face < pSurface->cFaces; face++)
            {
                for (uint32_t i = 0; i < pSurface->faces[0].numMipLevels; i++)
                {
                    uint32_t idx = i + face * pSurface->faces[0].numMipLevels;
                    PVMSVGA3DMIPMAPLEVEL pMipmapLevel = &pSurface->pMipmapLevels[idx];

                    Log(("Surface sid=%d: save mipmap level %d with %x bytes data.\n", sid, i, pMipmapLevel->cbSurface));

                    if (!VMSVGA3DSURFACE_HAS_HW_SURFACE(pSurface))
                    {
                        if (pMipmapLevel->fDirty)
                        {
                            /* Data follows */
                            rc = SSMR3PutBool(pSSM, true);
                            AssertRCReturn(rc, rc);

                            Assert(pMipmapLevel->cbSurface);
                            rc = SSMR3PutMem(pSSM, pMipmapLevel->pSurfaceData, pMipmapLevel->cbSurface);
                            AssertRCReturn(rc, rc);
                        }
                        else
                        {
                            /* No data follows */
                            rc = SSMR3PutBool(pSSM, false);
                            AssertRCReturn(rc, rc);
                        }
                    }
                    else
                    {
#ifdef VMSVGA3D_DIRECT3D
                        void            *pData;
                        bool             fRenderTargetTexture = false;
                        bool             fTexture = false;
                        bool             fSkipSave = false;
                        HRESULT          hr;

                        Assert(pMipmapLevel->cbSurface);
                        pData = RTMemAllocZ(pMipmapLevel->cbSurface);
                        AssertReturn(pData, VERR_NO_MEMORY);

                        switch (pSurface->enmD3DResType)
                        {
                        case VMSVGA3D_D3DRESTYPE_CUBE_TEXTURE:
                        case VMSVGA3D_D3DRESTYPE_VOLUME_TEXTURE:
                            AssertFailed(); /// @todo
                            fSkipSave = true;
                            break;
                        case VMSVGA3D_D3DRESTYPE_SURFACE:
                        case VMSVGA3D_D3DRESTYPE_TEXTURE:
                        {
                            if (pSurface->surfaceFlags & SVGA3D_SURFACE_HINT_DEPTHSTENCIL)
                            {
                               /** @todo unable to easily fetch depth surface data in d3d 9 */
                               fSkipSave = true;
                               break;
                            }

                            fTexture = (pSurface->enmD3DResType == VMSVGA3D_D3DRESTYPE_TEXTURE);
                            fRenderTargetTexture = fTexture && (pSurface->surfaceFlags & SVGA3D_SURFACE_HINT_RENDERTARGET);

                            D3DLOCKED_RECT LockedRect;

                            if (fTexture)
                            {
                                if (pSurface->bounce.pTexture)
                                {
                                    if (    !pSurface->fDirty
                                        &&  fRenderTargetTexture
                                        &&  i == 0 /* only the first time */)
                                    {
                                        IDirect3DSurface9 *pSrc, *pDest;

                                        /** @todo stricter checks for associated context */
                                        uint32_t cid = pSurface->idAssociatedContext;
                                        if (    cid >= pState->cContexts
                                            ||  pState->papContexts[cid]->id != cid)
                                        {
                                            Log(("vmsvga3dSaveExec invalid context id (%x - %x)!\n", cid, (cid >= pState->cContexts) ? -1 : pState->papContexts[cid]->id));
                                            AssertFailedReturn(VERR_INVALID_PARAMETER);
                                        }
                                        PVMSVGA3DCONTEXT pContext = pState->papContexts[cid];

                                        hr = pSurface->bounce.pTexture->GetSurfaceLevel(i, &pDest);
                                        AssertMsgReturn(hr == D3D_OK, ("vmsvga3dSaveExec: GetSurfaceLevel failed with %x\n", hr), VERR_INTERNAL_ERROR);

                                        hr = pSurface->u.pTexture->GetSurfaceLevel(i, &pSrc);
                                        AssertMsgReturn(hr == D3D_OK, ("vmsvga3dSaveExec: GetSurfaceLevel failed with %x\n", hr), VERR_INTERNAL_ERROR);

                                        hr = pContext->pDevice->GetRenderTargetData(pSrc, pDest);
                                        AssertMsgReturn(hr == D3D_OK, ("vmsvga3dSaveExec: GetRenderTargetData failed with %x\n", hr), VERR_INTERNAL_ERROR);

                                        pSrc->Release();
                                        pDest->Release();
                                    }

                                    hr = pSurface->bounce.pTexture->LockRect(i, /* texture level */
                                                                             &LockedRect,
                                                                             NULL,
                                                                             D3DLOCK_READONLY);
                                }
                                else
                                    hr = pSurface->u.pTexture->LockRect(i, /* texture level */
                                                                        &LockedRect,
                                                                        NULL,
                                                                        D3DLOCK_READONLY);
                            }
                            else
                                hr = pSurface->u.pSurface->LockRect(&LockedRect,
                                                                    NULL,
                                                                    D3DLOCK_READONLY);
                            AssertMsgReturn(hr == D3D_OK, ("vmsvga3dSaveExec: LockRect failed with %x\n", hr), VERR_INTERNAL_ERROR);

                            /* Copy the data one line at a time in case the internal pitch is different. */
                            for (uint32_t j = 0; j < pMipmapLevel->cBlocksY; ++j)
                            {
                                uint8_t *pu8Dst = (uint8_t *)pData + j * pMipmapLevel->cbSurfacePitch;
                                const uint8_t *pu8Src = (uint8_t *)LockedRect.pBits + j * LockedRect.Pitch;
                                memcpy(pu8Dst, pu8Src, pMipmapLevel->cbSurfacePitch);
                            }

                            if (fTexture)
                            {
                                if (pSurface->bounce.pTexture)
                                {
                                    hr = pSurface->bounce.pTexture->UnlockRect(i);
                                    AssertMsgReturn(hr == D3D_OK, ("vmsvga3dSaveExec: UnlockRect failed with %x\n", hr), VERR_INTERNAL_ERROR);
                                }
                                else
                                    hr = pSurface->u.pTexture->UnlockRect(i);
                            }
                            else
                                hr = pSurface->u.pSurface->UnlockRect();
                            AssertMsgReturn(hr == D3D_OK, ("vmsvga3dSaveExec: UnlockRect failed with %x\n", hr), VERR_INTERNAL_ERROR);
                            break;
                        }

                        case VMSVGA3D_D3DRESTYPE_VERTEX_BUFFER:
                        case VMSVGA3D_D3DRESTYPE_INDEX_BUFFER:
                        {
                            /* Current type of the buffer. */
                            const bool fVertex = (pSurface->enmD3DResType == VMSVGA3D_D3DRESTYPE_VERTEX_BUFFER);

                            uint8_t *pD3DData;

                            if (fVertex)
                                hr = pSurface->u.pVertexBuffer->Lock(0, 0, (void **)&pD3DData, D3DLOCK_READONLY);
                            else
                                hr = pSurface->u.pIndexBuffer->Lock(0, 0, (void **)&pD3DData, D3DLOCK_READONLY);
                            AssertMsg(hr == D3D_OK, ("vmsvga3dSaveExec: Lock %s failed with %x\n", (fVertex) ? "vertex" : "index", hr));

                            memcpy(pData, pD3DData, pMipmapLevel->cbSurface);

                            if (fVertex)
                                hr = pSurface->u.pVertexBuffer->Unlock();
                            else
                                hr = pSurface->u.pIndexBuffer->Unlock();
                            AssertMsg(hr == D3D_OK, ("vmsvga3dSaveExec: Unlock %s failed with %x\n", (fVertex) ? "vertex" : "index", hr));
                            break;
                        }

                        default:
                            AssertFailed();
                            break;
                        }

                        if (!fSkipSave)
                        {
                            /* Data follows */
                            rc = SSMR3PutBool(pSSM, true);
                            AssertRCReturn(rc, rc);

                            /* And write the surface data. */
                            rc = SSMR3PutMem(pSSM, pData, pMipmapLevel->cbSurface);
                            AssertRCReturn(rc, rc);
                        }
                        else
                        {
                            /* No data follows */
                            rc = SSMR3PutBool(pSSM, false);
                            AssertRCReturn(rc, rc);
                        }

                        RTMemFree(pData);
#elif defined(VMSVGA3D_OPENGL)
                        void *pData = NULL;

                        PVMSVGA3DCONTEXT pContext = &pState->SharedCtx;
                        VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext);

                        Assert(pMipmapLevel->cbSurface);

                        switch (pSurface->enmOGLResType)
                        {
                        default:
                            AssertFailed();
                            RT_FALL_THRU();
                        case VMSVGA3D_OGLRESTYPE_RENDERBUFFER:
                            /** @todo fetch data from the renderbuffer. Not used currently. */
                            /* No data follows */
                            rc = SSMR3PutBool(pSSM, false);
                            AssertRCReturn(rc, rc);
                            break;

                        case VMSVGA3D_OGLRESTYPE_TEXTURE:
                        {
                            GLint activeTexture;

                            pData = RTMemAllocZ(pMipmapLevel->cbSurface);
                            AssertReturn(pData, VERR_NO_MEMORY);

                            glGetIntegerv(GL_TEXTURE_BINDING_2D, &activeTexture);
                            VMSVGA3D_CHECK_LAST_ERROR_WARN(pState, pContext);

                            glBindTexture(GL_TEXTURE_2D, pSurface->oglId.texture);
                            VMSVGA3D_CHECK_LAST_ERROR_WARN(pState, pContext);

                            /* Set row length and alignment of the output data. */
                            VMSVGAPACKPARAMS SavedParams;
                            vmsvga3dOglSetPackParams(pState, pContext, pSurface, &SavedParams);

                            glGetTexImage(GL_TEXTURE_2D,
                                          i,
                                          pSurface->formatGL,
                                          pSurface->typeGL,
                                          pData);
                            VMSVGA3D_CHECK_LAST_ERROR_WARN(pState, pContext);

                            vmsvga3dOglRestorePackParams(pState, pContext, pSurface, &SavedParams);

                            /* Data follows */
                            rc = SSMR3PutBool(pSSM, true);
                            AssertRCReturn(rc, rc);

                            /* And write the surface data. */
                            rc = SSMR3PutMem(pSSM, pData, pMipmapLevel->cbSurface);
                            AssertRCReturn(rc, rc);

                            /* Restore the old active texture. */
                            glBindTexture(GL_TEXTURE_2D, activeTexture);
                            VMSVGA3D_CHECK_LAST_ERROR_WARN(pState, pContext);
                            break;
                        }

                        case VMSVGA3D_OGLRESTYPE_BUFFER:
                        {
                            uint8_t *pBufferData;

                            pState->ext.glBindBuffer(GL_ARRAY_BUFFER, pSurface->oglId.buffer);
                            VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);

                            pBufferData = (uint8_t *)pState->ext.glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY);
                            VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
                            Assert(pBufferData);

                            /* Data follows */
                            rc = SSMR3PutBool(pSSM, true);
                            AssertRCReturn(rc, rc);

                            /* And write the surface data. */
                            rc = SSMR3PutMem(pSSM, pBufferData, pMipmapLevel->cbSurface);
                            AssertRCReturn(rc, rc);

                            pState->ext.glUnmapBuffer(GL_ARRAY_BUFFER);
                            VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);

                            pState->ext.glBindBuffer(GL_ARRAY_BUFFER, 0);
                            VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);

                        }
                        }
                        if (pData)
                            RTMemFree(pData);
#else
#error "Unexpected 3d backend"
#endif
                    }
                }
            }
        }
    }
    return VINF_SUCCESS;
}
コード例 #2
0
/**
 * Implements the SVGA_3D_CMD_SURFACE_DMA command (fifo).
 *
 * @returns VBox status code (currently ignored).
 * @param   pThis               The VGA device instance data.
 * @param   guest               .
 * @param   host                .
 * @param   transfer            .
 * @param   cCopyBoxes          .
 * @param   paBoxes             .
 */
int vmsvga3dSurfaceDMA(PVGASTATE pThis, SVGA3dGuestImage guest, SVGA3dSurfaceImageId host, SVGA3dTransferType transfer,
                       uint32_t cCopyBoxes, SVGA3dCopyBox *paBoxes)
{
    int rc = VINF_SUCCESS;

    PVMSVGA3DSTATE pState = pThis->svga.p3dState;
    AssertReturn(pState, VERR_NO_MEMORY);

    uint32_t sid = host.sid;
    Assert(sid < SVGA3D_MAX_SURFACE_IDS);
    AssertReturn(sid < pState->cSurfaces, VERR_INVALID_PARAMETER);
    PVMSVGA3DSURFACE pSurface = pState->papSurfaces[sid];
    AssertReturn(pSurface && pSurface->id == sid, VERR_INVALID_PARAMETER);

    if (pSurface->flags & SVGA3D_SURFACE_HINT_TEXTURE)
        Log(("vmsvga3dSurfaceDMA TEXTURE guestptr gmr=%x offset=%x pitch=%x host sid=%x face=%d mipmap=%d transfer=%s cCopyBoxes=%d\n", guest.ptr.gmrId, guest.ptr.offset, guest.pitch, host.sid, host.face, host.mipmap, (transfer == SVGA3D_WRITE_HOST_VRAM) ? "READ" : "WRITE", cCopyBoxes));
    else
        Log(("vmsvga3dSurfaceDMA guestptr gmr=%x offset=%x pitch=%x host sid=%x face=%d mipmap=%d transfer=%s cCopyBoxes=%d\n", guest.ptr.gmrId, guest.ptr.offset, guest.pitch, host.sid, host.face, host.mipmap, (transfer == SVGA3D_WRITE_HOST_VRAM) ? "READ" : "WRITE", cCopyBoxes));

    AssertMsg(host.face == 0, ("host.face=%#x\n", host.face));
    AssertMsgReturn(pSurface->faces[0].numMipLevels > host.mipmap, ("numMipLevels %d, host.mipmap %d", pSurface->faces[0].numMipLevels, host.mipmap), VERR_INVALID_PARAMETER);
    PVMSVGA3DMIPMAPLEVEL pMipLevel = &pSurface->pMipmapLevels[host.mipmap];

    if (!VMSVGA3DSURFACE_HAS_HW_SURFACE(pSurface))
    {
        /*
         * Not realized in host hardware/library yet, we have to work with
         * the copy of the data we've got in VMSVGA3DMIMAPLEVEL::pvSurfaceData.
         */
        AssertReturn(pSurface->pMipmapLevels[host.mipmap].pSurfaceData, VERR_INTERNAL_ERROR);

        for (unsigned i = 0; i < cCopyBoxes; i++)
        {
            unsigned uDestOffset;
            unsigned cbSrcPitch;
            uint8_t *pBufferStart;

            Log(("Copy box %d (%d,%d,%d)(%d,%d,%d) dest (%d,%d)\n", i, paBoxes[i].srcx, paBoxes[i].srcy, paBoxes[i].srcz, paBoxes[i].w, paBoxes[i].h, paBoxes[i].d, paBoxes[i].x, paBoxes[i].y));
            /* Apparently we're supposed to clip it (gmr test sample) */
            if (paBoxes[i].x + paBoxes[i].w > pMipLevel->size.width)
                paBoxes[i].w = pMipLevel->size.width - paBoxes[i].x;
            if (paBoxes[i].y + paBoxes[i].h > pMipLevel->size.height)
                paBoxes[i].h = pMipLevel->size.height - paBoxes[i].y;
            if (paBoxes[i].z + paBoxes[i].d > pMipLevel->size.depth)
                paBoxes[i].d = pMipLevel->size.depth - paBoxes[i].z;

            if (    !paBoxes[i].w
                ||  !paBoxes[i].h
                ||  !paBoxes[i].d
                ||   paBoxes[i].x > pMipLevel->size.width
                ||   paBoxes[i].y > pMipLevel->size.height
                ||   paBoxes[i].z > pMipLevel->size.depth)
            {
                Log(("Empty box; skip\n"));
                continue;
            }

            uDestOffset = paBoxes[i].x * pSurface->cbBlock + paBoxes[i].y * pMipLevel->cbSurfacePitch + paBoxes[i].z * pMipLevel->size.height * pMipLevel->cbSurfacePitch;
            AssertReturn(uDestOffset + paBoxes[i].w * pSurface->cbBlock * paBoxes[i].h * paBoxes[i].d <= pMipLevel->cbSurface, VERR_INTERNAL_ERROR);

            cbSrcPitch = (guest.pitch == 0) ? paBoxes[i].w * pSurface->cbBlock : guest.pitch;
#ifdef MANUAL_FLIP_SURFACE_DATA
            pBufferStart =    (uint8_t *)pMipLevel->pSurfaceData
                            + paBoxes[i].x * pSurface->cbBlock
                            + pMipLevel->cbSurface - paBoxes[i].y * pMipLevel->cbSurfacePitch
                            - pMipLevel->cbSurfacePitch;      /* flip image during copy */
#else
            pBufferStart = (uint8_t *)pMipLevel->pSurfaceData + uDestOffset;
#endif
            rc = vmsvgaGMRTransfer(pThis,
                                   transfer,
                                   pBufferStart,
#ifdef MANUAL_FLIP_SURFACE_DATA
                                   -(int32_t)pMipLevel->cbSurfacePitch,
#else
                                   (int32_t)pMipLevel->cbSurfacePitch,
#endif
                                   guest.ptr,
                                   paBoxes[i].srcx * pSurface->cbBlock + (paBoxes[i].srcy + paBoxes[i].srcz * paBoxes[i].h) * cbSrcPitch,
                                   cbSrcPitch,
                                   paBoxes[i].w * pSurface->cbBlock,
                                   paBoxes[i].d * paBoxes[i].h);

            Log4(("first line:\n%.*Rhxd\n", pMipLevel->cbSurfacePitch, pMipLevel->pSurfaceData));

            AssertRC(rc);
        }
        pSurface->pMipmapLevels[host.mipmap].fDirty = true;
        pSurface->fDirty = true;
    }
    else
    {
        /*
         * Because of the clipping below, we're doing a little more
         * here before calling the backend specific code.
         */
#ifdef VMSVGA3D_DIRECT3D
        /* Flush the drawing pipeline for this surface as it could be used in a shared context. */
        vmsvga3dSurfaceFlush(pThis, pSurface);
        PVMSVGA3DCONTEXT pContext = NULL;

#else /* VMSVGA3D_OPENGL */
        PVMSVGA3DCONTEXT pContext = &pState->SharedCtx;
        VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext);
#endif

        for (unsigned i = 0; i < cCopyBoxes; i++)
        {
            /* Apparently we're supposed to clip it (gmr test sample) */
            if (paBoxes[i].x + paBoxes[i].w > pMipLevel->size.width)
                paBoxes[i].w = pMipLevel->size.width - paBoxes[i].x;
            if (paBoxes[i].y + paBoxes[i].h > pMipLevel->size.height)
                paBoxes[i].h = pMipLevel->size.height - paBoxes[i].y;
            if (paBoxes[i].z + paBoxes[i].d > pMipLevel->size.depth)
                paBoxes[i].d = pMipLevel->size.depth - paBoxes[i].z;

            Assert((paBoxes[i].d == 1 || paBoxes[i].d == 0) && paBoxes[i].z == 0);

            if (    !paBoxes[i].w
                ||  !paBoxes[i].h
                ||   paBoxes[i].x > pMipLevel->size.width
                ||   paBoxes[i].y > pMipLevel->size.height)
            {
                Log(("Empty box; skip\n"));
                continue;
            }

            Log(("Copy box %d (%d,%d,%d)(%d,%d,%d) dest (%d,%d)\n", i, paBoxes[i].srcx, paBoxes[i].srcy, paBoxes[i].srcz, paBoxes[i].w, paBoxes[i].h, paBoxes[i].d, paBoxes[i].x, paBoxes[i].y));

            uint32_t cbSrcPitch = (guest.pitch == 0) ? paBoxes[i].w * pSurface->cbBlock : guest.pitch;
            rc = vmsvga3dBackSurfaceDMACopyBox(pThis, pState, pSurface, host.mipmap, guest.ptr, cbSrcPitch, transfer,
                                               &paBoxes[i], pContext, rc, i);
        }
    }

    return rc;
}
コード例 #3
0
/**
 * Implements the SVGA_3D_CMD_SURFACE_DEFINE_V2 and SVGA_3D_CMD_SURFACE_DEFINE
 * commands (fifo).
 *
 * @returns VBox status code (currently ignored).
 * @param   pThis               The VGA device instance data.
 * @param   sid                 The ID of the surface to (re-)define.
 * @param   surfaceFlags        .
 * @param   format              .
 * @param   face                .
 * @param   multisampleCount    .
 * @param   autogenFilter       .
 * @param   cMipLevels          .
 * @param   paMipLevelSizes     .
 */
int vmsvga3dSurfaceDefine(PVGASTATE pThis, uint32_t sid, uint32_t surfaceFlags, SVGA3dSurfaceFormat format,
                          SVGA3dSurfaceFace face[SVGA3D_MAX_SURFACE_FACES], uint32_t multisampleCount,
                          SVGA3dTextureFilter autogenFilter, uint32_t cMipLevels, SVGA3dSize *paMipLevelSizes)
{
    PVMSVGA3DSURFACE pSurface;
    PVMSVGA3DSTATE   pState = pThis->svga.p3dState;
    AssertReturn(pState, VERR_NO_MEMORY);

    Log(("vmsvga3dSurfaceDefine: sid=%x surfaceFlags=%x format=%s (%x) multiSampleCount=%d autogenFilter=%d, cMipLevels=%d size=(%d,%d,%d)\n",
         sid, surfaceFlags, vmsvgaLookupEnum((int)format, &g_SVGA3dSurfaceFormat2String), format, multisampleCount, autogenFilter,
         cMipLevels, paMipLevelSizes->width, paMipLevelSizes->height, paMipLevelSizes->depth));

    AssertReturn(sid < SVGA3D_MAX_SURFACE_IDS, VERR_INVALID_PARAMETER);
    AssertReturn(cMipLevels >= 1, VERR_INVALID_PARAMETER);
    /* Assuming all faces have the same nr of mipmaps. */
    AssertReturn(!(surfaceFlags & SVGA3D_SURFACE_CUBEMAP) || cMipLevels == face[0].numMipLevels * 6, VERR_INVALID_PARAMETER);
    AssertReturn((surfaceFlags & SVGA3D_SURFACE_CUBEMAP) || cMipLevels == face[0].numMipLevels, VERR_INVALID_PARAMETER);

    if (sid >= pState->cSurfaces)
    {
        /* Grow the array. */
        uint32_t cNew = RT_ALIGN(sid + 15, 16);
        void *pvNew = RTMemRealloc(pState->papSurfaces, sizeof(pState->papSurfaces[0]) * cNew);
        AssertReturn(pvNew, VERR_NO_MEMORY);
        pState->papSurfaces = (PVMSVGA3DSURFACE *)pvNew;
        while (pState->cSurfaces < cNew)
        {
            pSurface = (PVMSVGA3DSURFACE)RTMemAllocZ(sizeof(*pSurface));
            AssertReturn(pSurface, VERR_NO_MEMORY);
            pSurface->id = SVGA3D_INVALID_ID;
            pState->papSurfaces[pState->cSurfaces++] = pSurface;
        }
    }
    pSurface = pState->papSurfaces[sid];

    /* If one already exists with this id, then destroy it now. */
    if (pSurface->id != SVGA3D_INVALID_ID)
        vmsvga3dSurfaceDestroy(pThis, sid);

    RT_ZERO(*pSurface);
    pSurface->id                    = sid;
#ifdef VMSVGA3D_OPENGL
    pSurface->idWeakContextAssociation = SVGA3D_INVALID_ID;
#else
    pSurface->idAssociatedContext   = SVGA3D_INVALID_ID;
#endif
#ifdef VMSVGA3D_DIRECT3D
    pSurface->hSharedObject         = NULL;
    pSurface->pSharedObjectTree     = NULL;
#else
    pSurface->oglId.buffer = OPENGL_INVALID_ID;
#endif

    /* The surface type is sort of undefined now, even though the hints and format can help to clear that up.
     * In some case we'll have to wait until the surface is used to create the D3D object.
     */
    switch (format)
    {
    case SVGA3D_Z_D32:
    case SVGA3D_Z_D16:
    case SVGA3D_Z_D24S8:
    case SVGA3D_Z_D15S1:
    case SVGA3D_Z_D24X8:
    case SVGA3D_Z_DF16:
    case SVGA3D_Z_DF24:
    case SVGA3D_Z_D24S8_INT:
        surfaceFlags |= SVGA3D_SURFACE_HINT_DEPTHSTENCIL;
        break;

    /* Texture compression formats */
    case SVGA3D_DXT1:
    case SVGA3D_DXT2:
    case SVGA3D_DXT3:
    case SVGA3D_DXT4:
    case SVGA3D_DXT5:
    /* Bump-map formats */
    case SVGA3D_BUMPU8V8:
    case SVGA3D_BUMPL6V5U5:
    case SVGA3D_BUMPX8L8V8U8:
    case SVGA3D_BUMPL8V8U8:
    case SVGA3D_V8U8:
    case SVGA3D_Q8W8V8U8:
    case SVGA3D_CxV8U8:
    case SVGA3D_X8L8V8U8:
    case SVGA3D_A2W10V10U10:
    case SVGA3D_V16U16:
    /* Typical render target formats; we should allow render target buffers to be used as textures. */
    case SVGA3D_X8R8G8B8:
    case SVGA3D_A8R8G8B8:
    case SVGA3D_R5G6B5:
    case SVGA3D_X1R5G5B5:
    case SVGA3D_A1R5G5B5:
    case SVGA3D_A4R4G4B4:
        surfaceFlags |= SVGA3D_SURFACE_HINT_TEXTURE;
        break;

    case SVGA3D_LUMINANCE8:
    case SVGA3D_LUMINANCE4_ALPHA4:
    case SVGA3D_LUMINANCE16:
    case SVGA3D_LUMINANCE8_ALPHA8:
    case SVGA3D_ARGB_S10E5:   /* 16-bit floating-point ARGB */
    case SVGA3D_ARGB_S23E8:   /* 32-bit floating-point ARGB */
    case SVGA3D_A2R10G10B10:
    case SVGA3D_ALPHA8:
    case SVGA3D_R_S10E5:
    case SVGA3D_R_S23E8:
    case SVGA3D_RG_S10E5:
    case SVGA3D_RG_S23E8:
    case SVGA3D_G16R16:
    case SVGA3D_A16B16G16R16:
    case SVGA3D_UYVY:
    case SVGA3D_YUY2:
    case SVGA3D_NV12:
    case SVGA3D_AYUV:
    case SVGA3D_BC4_UNORM:
    case SVGA3D_BC5_UNORM:
        break;

    /*
     * Any surface can be used as a buffer object, but SVGA3D_BUFFER is
     * the most efficient format to use when creating new surfaces
     * expressly for index or vertex data.
     */
    case SVGA3D_BUFFER:
        break;

    default:
        break;
    }

    pSurface->flags             = surfaceFlags;
    pSurface->format            = format;
    memcpy(pSurface->faces, face, sizeof(pSurface->faces));
    pSurface->cFaces            = 1;        /* check for cube maps later */
    pSurface->multiSampleCount  = multisampleCount;
    pSurface->autogenFilter     = autogenFilter;
    Assert(autogenFilter != SVGA3D_TEX_FILTER_FLATCUBIC);
    Assert(autogenFilter != SVGA3D_TEX_FILTER_GAUSSIANCUBIC);
    pSurface->pMipmapLevels     = (PVMSVGA3DMIPMAPLEVEL)RTMemAllocZ(cMipLevels * sizeof(VMSVGA3DMIPMAPLEVEL));
    AssertReturn(pSurface->pMipmapLevels, VERR_NO_MEMORY);

    for (uint32_t i=0; i < cMipLevels; i++)
        pSurface->pMipmapLevels[i].size = paMipLevelSizes[i];

    pSurface->cbBlock = vmsvga3dSurfaceFormatSize(format);

#ifdef VMSVGA3D_DIRECT3D
    /* Translate the format and usage flags to D3D. */
    pSurface->formatD3D         = vmsvga3dSurfaceFormat2D3D(format);
    pSurface->multiSampleTypeD3D= vmsvga3dMultipeSampleCount2D3D(multisampleCount);
    pSurface->fUsageD3D         = 0;
    if (surfaceFlags & SVGA3D_SURFACE_HINT_DYNAMIC)
        pSurface->fUsageD3D |= D3DUSAGE_DYNAMIC;
    if (surfaceFlags & SVGA3D_SURFACE_HINT_RENDERTARGET)
        pSurface->fUsageD3D |= D3DUSAGE_RENDERTARGET;
    if (surfaceFlags & SVGA3D_SURFACE_HINT_DEPTHSTENCIL)
        pSurface->fUsageD3D |= D3DUSAGE_DEPTHSTENCIL;
    if (surfaceFlags & SVGA3D_SURFACE_HINT_WRITEONLY)
        pSurface->fUsageD3D |= D3DUSAGE_WRITEONLY;
    if (surfaceFlags & SVGA3D_SURFACE_AUTOGENMIPMAPS)
        pSurface->fUsageD3D |= D3DUSAGE_AUTOGENMIPMAP;
    pSurface->fu32ActualUsageFlags = 0;
#else
    vmsvga3dSurfaceFormat2OGL(pSurface, format);
#endif

    switch (surfaceFlags & (SVGA3D_SURFACE_HINT_INDEXBUFFER | SVGA3D_SURFACE_HINT_VERTEXBUFFER | SVGA3D_SURFACE_HINT_TEXTURE | SVGA3D_SURFACE_HINT_RENDERTARGET | SVGA3D_SURFACE_HINT_DEPTHSTENCIL | SVGA3D_SURFACE_CUBEMAP))
    {
    case SVGA3D_SURFACE_CUBEMAP:
        Log(("SVGA3D_SURFACE_CUBEMAP\n"));
        pSurface->cFaces = 6;
        break;

    case SVGA3D_SURFACE_HINT_INDEXBUFFER:
        Log(("SVGA3D_SURFACE_HINT_INDEXBUFFER\n"));
        /* else type unknown at this time; postpone buffer creation */
        break;

    case SVGA3D_SURFACE_HINT_VERTEXBUFFER:
        Log(("SVGA3D_SURFACE_HINT_VERTEXBUFFER\n"));
        /* Type unknown at this time; postpone buffer creation */
        break;

    case SVGA3D_SURFACE_HINT_TEXTURE:
        Log(("SVGA3D_SURFACE_HINT_TEXTURE\n"));
        break;

    case SVGA3D_SURFACE_HINT_RENDERTARGET:
        Log(("SVGA3D_SURFACE_HINT_RENDERTARGET\n"));
        break;

    case SVGA3D_SURFACE_HINT_DEPTHSTENCIL:
        Log(("SVGA3D_SURFACE_HINT_DEPTHSTENCIL\n"));
        break;

    default:
        /* Unknown; decide later. */
        break;
    }

    Assert(!VMSVGA3DSURFACE_HAS_HW_SURFACE(pSurface));

    /* Allocate buffer to hold the surface data until we can move it into a D3D object */
    for (uint32_t iFace=0; iFace < pSurface->cFaces; iFace++)
    {
        for (uint32_t i=0; i < pSurface->faces[iFace].numMipLevels; i++)
        {
            uint32_t idx = i + iFace * pSurface->faces[0].numMipLevels;

            Log(("vmsvga3dSurfaceDefine: face %d mip level %d (%d,%d,%d)\n", iFace, i, pSurface->pMipmapLevels[idx].size.width, pSurface->pMipmapLevels[idx].size.height, pSurface->pMipmapLevels[idx].size.depth));
            Log(("vmsvga3dSurfaceDefine: cbPitch=%x cbBlock=%x \n", pSurface->cbBlock * pSurface->pMipmapLevels[idx].size.width, pSurface->cbBlock));

            pSurface->pMipmapLevels[idx].cbSurfacePitch = pSurface->cbBlock * pSurface->pMipmapLevels[idx].size.width;
            pSurface->pMipmapLevels[idx].cbSurface      = pSurface->pMipmapLevels[idx].cbSurfacePitch * pSurface->pMipmapLevels[idx].size.height * pSurface->pMipmapLevels[idx].size.depth;
            pSurface->pMipmapLevels[idx].pSurfaceData   = RTMemAllocZ(pSurface->pMipmapLevels[idx].cbSurface);
            AssertReturn(pSurface->pMipmapLevels[idx].pSurfaceData, VERR_NO_MEMORY);
        }
    }
    return VINF_SUCCESS;
}
コード例 #4
0
/**
 * Implements the SVGA_3D_CMD_SURFACE_STRETCHBLT command (fifo).
 *
 * @returns VBox status code (currently ignored).
 * @param   pThis               The VGA device instance data.
 * @param   sid                 The ID of the surface to destroy.
 */
int vmsvga3dSurfaceStretchBlt(PVGASTATE pThis, SVGA3dSurfaceImageId const *pDstSfcImg, SVGA3dBox const *pDstBox,
                              SVGA3dSurfaceImageId const *pSrcSfcImg, SVGA3dBox const *pSrcBox, SVGA3dStretchBltMode enmMode)
{
    PVMSVGA3DSTATE pState = pThis->svga.p3dState;

    AssertReturn(pState, VERR_NO_MEMORY);

    uint32_t const sidSrc = pSrcSfcImg->sid;
    Assert(sidSrc < SVGA3D_MAX_SURFACE_IDS);
    AssertReturn(sidSrc < pState->cSurfaces, VERR_INVALID_PARAMETER);
    PVMSVGA3DSURFACE pSrcSurface  = pState->papSurfaces[sidSrc];
    AssertReturn(pSrcSurface && pSrcSurface->id == sidSrc, VERR_INVALID_PARAMETER);

    uint32_t const sidDst = pDstSfcImg->sid;
    Assert(sidDst < SVGA3D_MAX_SURFACE_IDS);
    AssertReturn(sidDst < pState->cSurfaces, VERR_INVALID_PARAMETER);
    PVMSVGA3DSURFACE pDstSurface = pState->papSurfaces[sidDst];
    AssertReturn(pDstSurface && pDstSurface->id == sidDst, VERR_INVALID_PARAMETER);

    Assert(pSrcSfcImg->face == 0);
    AssertReturn(pSrcSfcImg->mipmap < pSrcSurface->faces[0].numMipLevels, VERR_INVALID_PARAMETER);
    Assert(pDstSfcImg->face == 0);
    AssertReturn(pDstSfcImg->mipmap < pDstSurface->faces[0].numMipLevels, VERR_INVALID_PARAMETER);

    PVMSVGA3DCONTEXT pContext;
#ifdef VMSVGA3D_OPENGL
    Log(("vmsvga3dSurfaceStretchBlt: src sid=%x (%d,%d)(%d,%d) dest sid=%x (%d,%d)(%d,%d) mode=%x\n",
         sidSrc, pSrcBox->x, pSrcBox->y, pSrcBox->x + pSrcBox->w, pSrcBox->y + pSrcBox->h,
         sidDst, pDstBox->x, pDstBox->y, pDstBox->x + pDstBox->w, pDstBox->y + pDstBox->h, enmMode));
    pContext = &pState->SharedCtx;
    VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext);
#else
    Log(("vmsvga3dSurfaceStretchBlt: src sid=%x cid=%x (%d,%d)(%d,%d) dest sid=%x cid=%x (%d,%d)(%d,%d) mode=%x\n",
         sidSrc, pSrcSurface->idAssociatedContext, pSrcBox->x, pSrcBox->y, pSrcBox->x + pSrcBox->w, pSrcBox->y + pSrcBox->h,
         sidDst, pDstSurface->idAssociatedContext, pDstBox->x, pDstBox->y, pDstBox->x + pDstBox->w, pDstBox->y + pDstBox->h, enmMode));

    /** @todo stricter checks for associated context */
    uint32_t cid = pDstSurface->idAssociatedContext;
    if (cid == SVGA3D_INVALID_ID)
        cid = pSrcSurface->idAssociatedContext;

    if (    cid >= pState->cContexts
        ||  pState->papContexts[cid]->id != cid)
    {
        Log(("vmsvga3dSurfaceStretchBlt invalid context id!\n"));
        AssertFailedReturn(VERR_INVALID_PARAMETER);
    }
    pContext = pState->papContexts[cid];
#endif

    int rc;
    if (!VMSVGA3DSURFACE_HAS_HW_SURFACE(pSrcSurface))
    {
        /* Unknown surface type; turn it into a texture, which can be used for other purposes too. */
        Log(("vmsvga3dSurfaceStretchBlt: unknown src surface id=%x type=%d format=%d -> create texture\n", sidSrc, pSrcSurface->flags, pSrcSurface->format));
        rc = vmsvga3dBackCreateTexture(pState, pContext, pContext->id, pSrcSurface);
        AssertRCReturn(rc, rc);
    }

    if (!VMSVGA3DSURFACE_HAS_HW_SURFACE(pDstSurface))
    {
        /* Unknown surface type; turn it into a texture, which can be used for other purposes too. */
        Log(("vmsvga3dSurfaceStretchBlt: unknown dest surface id=%x type=%d format=%d -> create texture\n", sidDst, pDstSurface->flags, pDstSurface->format));
        rc = vmsvga3dBackCreateTexture(pState, pContext, pContext->id, pDstSurface);
        AssertRCReturn(rc, rc);
    }

    return vmsvga3dBackSurfaceStretchBlt(pThis, pState,
                                         pDstSurface, pDstSfcImg->mipmap, pDstBox,
                                         pSrcSurface, pSrcSfcImg->mipmap, pSrcBox,
                                         enmMode, pContext);
}