DiligentGraphics / DiligentEngine

A modern cross-platform low-level graphics library and rendering framework
http://diligentgraphics.com/diligent-engine/
Apache License 2.0
3.37k stars 318 forks source link

read wrong depth from stage texture? #280

Closed 9MW closed 4 months ago

9MW commented 4 months ago

version : diligent 2.4 backend : vulkan GPU : rx5700xt OS: windows11 I want use depth to get world position from point of screen on CPU side here.

auto pDSV = m_pSwapChain->GetDepthBufferDSV();
m_pImmediateContext->ClearDepthStencil(pDSV, CLEAR_DEPTH_FLAG, 1.f, 0, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);

statge texture code


            TextureDesc TexDesc;
            TexDesc.Name = "texture for depth read";
            TexDesc.Type = RESOURCE_DIM_TEX_2D;
            TexDesc.Usage = Diligent::USAGE::USAGE_STAGING;
            TexDesc.CPUAccessFlags = CPU_ACCESS_READ;
            TexDesc.BindFlags = BIND_NONE;
            TexDesc.Width = 4;
            TexDesc.Height = 4;
            TexDesc.Format = rt_.DepthBufferFormat;
            TexDesc.MipLevels = 0;
            _editmem.get<1>().pStagingTexture = NULL;
            rt_.m_pDevice->CreateTexture(TexDesc, NULL, &_editmem.get<1>().pStagingTexture);

depth format is TEX_FORMAT_D32_FLOAT copy code is `

    constexpr uint xs = 0x00FFFFFF;
    auto pRGBAData = reinterpret_cast<Uint32*>(MappedData.pData);
    if (twenty24bit)
    {
        for (Uint32 y = 0, cnt = 0; y < Height; ++y)
        {
            auto pRGBA = pRGBAData + MappedData.Stride * y;
            for (Uint32 x = 0; x < Width; ++x)
            {
                // Extract 24 depth bits
                num[cnt++] = static_cast<float>(pRGBA[x] & 0x00FFFFFF) / 16777215.0f;
            }
        }
    }
    else
    {
        for (Uint32 y = 0, cnt = 0; y < Height; ++y)
        {
            auto pRGBA = pRGBAData + MappedData.Stride * y;
            for (Uint32 x = 0; x < Width; ++x)
            {
                // depth bits
                num[cnt++] = static_cast<float>(pRGBA[x]);
            }
        }
    }

` the depth value read out is .06535322e+09 1.06535322e+09 1.06535322e+09 1.06535322e+09 1.06535322e+09 1.06535322e+09 1.06533402e+09 1.06533440e+09 1.06535322e+09 1.06535322e+09 1.06535322e+09 1.06535322e+09 1.06535322e+09 1.06535322e+09 1.06533478e+09 1.06533395e+09 1.06535322e+09 1.06535322e+09 1.06535322e+09 1.06535322e+09 1.06535322e+09 1.06535322e+09 1.06535322e+09 1.06533440e+09 1.06533510e+09 1.06535322e+09 1.06535322e+09 1.06535322e+09 1.06535322e+09 1.06533498e+09 1.06533382e+09 1.06535322e+09 1.06535322e+09 1.06535322e+09 1.06535322e+09 1.06535322e+09 1.06535322e+09

"1.06534010e+09" is the default read out after I called ClearDepthStencil funtion

notice that there are variations for depth read out that is due to I'm reading different point of depth texture, though such change of value should be right based my observation. I want know why is depth value not within range of [0,1]?

TheMostDiligent commented 4 months ago

Note that your code for 24-bit is incorrect. You are reading as if 24-bit depth was packed into 32-bit leaving each byte unused, which may not be the case.

How do you copy your depth texture to your staging texture?

9MW commented 4 months ago

Note that your code for 24-bit is incorrect. You are reading as if 24-bit depth was packed into 32-bit leaving each byte unused, which may not be the case.

How do you copy your depth texture to your staging texture?

I stopped use TEX_FORMAT_D24_UNORM_S8_UINT after found this format is not supported to copy back to RAM. Copied by

            math::v4f cursorZ;
            const float ClearColor[] = { 0.350f, 0.350f, 0.350f, 1.0f };
            auto& m_pSwapChain = this->p_rt->m_pSwapChain;
            auto pRTV = m_pSwapChain->GetCurrentBackBufferRTV();
            auto pDSV = m_pSwapChain->GetDepthBufferDSV();
            auto df = pDSV->GetTexture()->GetDesc();

            auto& pContext = this->p_rt->m_pImmediateContext;
            auto pdepthtex = pDSV->GetTexture();
            pContext->SetRenderTargets(0, nullptr, nullptr, RESOURCE_STATE_TRANSITION_MODE_NONE);
            auto& m_UploadCompleteFence = _editmem.get<1>().m_UploadCompleteFence;
            auto& cam = Camera::Main();
            inputmanager& ipt = *p_ipt;
            cursorZ.head<2>() = ipt.mouseinfo.operator pj2::mousestate::f2 & ();
            editmemCounters& memedit = _editmem.get<1>();
            cursorZ = cursorZ.cwiseMax(math::v4f::Ones()*4);
            cursorZ[0] = std::min((UINT32)cursorZ[0], cam.m_ProjAttribs.Width);
            cursorZ[1] = std::min((UINT32)cursorZ[1], cam.m_ProjAttribs.Height);
            //pContext->UnmapTextureSubresource(pStagingTexture, StartDstMip + mip, StartDstSlice + slice);
            Box SrcBox;
            SrcBox.MaxX = cursorZ[0];
            SrcBox.MinX = std::max(0u, SrcBox.MaxX - 3);
            SrcBox.MaxY = cursorZ[1];
            SrcBox.MinY = std::max(0u, SrcBox.MaxY - 3);
            CopyTextureAttribs CopyAttribs(pdepthtex, RESOURCE_STATE_TRANSITION_MODE_TRANSITION,
                memedit.pStagingTexture, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
            CopyAttribs.pSrcBox = &SrcBox;
            pContext->CopyTexture(CopyAttribs);
            pContext->EnqueueSignal(m_UploadCompleteFence, ++_editmem.get<1>().m_UploadCompleteFenceValue);

            const StateTransitionDesc Barrier{ pdepthtex, RESOURCE_STATE_COPY_SOURCE, RESOURCE_STATE_DEPTH_WRITE };
            pContext->TransitionResourceStates(1, &Barrier);
            pContext->SetRenderTargets(1, &pRTV, pDSV, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
TheMostDiligent commented 4 months ago

You may consider using GPUCompletionAwaitQueue

Here is the code that does what you need.

9MW commented 4 months ago

Thanks you reply, I'll try it.


inline void CvtDepth(edtmem& edtm, span<float> num) {
        constexpr int Mip = 0;
        auto& UploadBuffDesc = edtm.get<1>().UploadBuffDesc;
        const Uint32 Width = UploadBuffDesc.Width >> Mip;
        const Uint32 Height = UploadBuffDesc.Height >> Mip;
        auto& MappedData = edtm.get<1>().MappedData;
        constexpr uint xs = 0x00FFFFFF;
        auto pRGBAData = reinterpret_cast<float*>(MappedData.pData);
        {
            for (Uint32 y = 0, cnt = 0; y < Height; ++y)
            {
                auto pRGBA = pRGBAData + MappedData.Stride * y;
                for (Uint32 x = 0; x < Width; ++x)
                {
                    // depth bits
                    num[cnt++] = static_cast<float>(pRGBA[x]);
                }
            }
        }
    }
               inputmanager& ipt = *p_ipt;
            auto pdepthtex = rt_.m_pDepthDSV->GetTexture();
            auto& m_UploadCompleteFence = _editmem.get<1>().m_UploadCompleteFence;
            m_UploadCompleteFence->Wait(_editmem.get<1>().m_UploadCompleteFenceValue);
            math::v4f cursorZ, zero4 = {};
            inputmanager::updateParam uppara;

            auto& worldPos = std::get<0>(uppara);
            cursorZ.head<2>() = ipt.mouseinfo.operator pj2::mousestate::f2 & ();
            editmemCounters& memedit = _editmem.get<1>();
            cursorZ = cursorZ.cwiseMax(zero4);
            cursorZ[0] = std::min((UINT32)cursorZ[0], cam.m_ProjAttribs.Width);
            cursorZ[1] = std::min((UINT32)cursorZ[1], cam.m_ProjAttribs.Height);
            pContext->UnmapTextureSubresource(memedit.pStagingTexture, 0,0);
            pContext->MapTextureSubresource(memedit.pStagingTexture, 0, 0,
                MAP_READ,
                MAP_FLAG_DO_NOT_WAIT | MAP_FLAG_DISCARD | MAP_FLAG_NO_OVERWRITE, nullptr, memedit.MappedData);

            auto& UploadBuffDesc = _editmem.get<1>().UploadBuffDesc;
            UploadBuffDesc.Width = 1;
            UploadBuffDesc.Height = 1;
            assert(rt_.DepthBufferFormat != TEX_FORMAT_D24_UNORM_S8_UINT);
            std::array<float, 16> depthNorm;
            CvtDepth(_editmem, span(depthNorm.data(), 1));
            cursorZ[2] = depthNorm[0];
            const math::Matrix4f& inverse_projection_matrix = cam.m_ProjMatrix.inverse();
            const math::Matrix4f& inverse_View_matrix = cam.m_ViewMatrix.matrix().inverse();
            getRays(cursorZ, inverse_projection_matrix, worldPos, cam);
            worldPos = inverse_View_matrix * worldPos;
            freeUIVec = worldPos;

            ipt.update(uppara);

here is update function to read depth before call the CopyTexture Code posted previously

TheMostDiligent commented 4 months ago

Did you run this in Debug? Do you get any messages in the console?

This is incorrect:

            cursorZ[0] = std::min((UINT32)cursorZ[0], cam.m_ProjAttribs.Width);
            cursorZ[1] = std::min((UINT32)cursorZ[1], cam.m_ProjAttribs.Height);

It should be

            cursorZ[0] = std::min((UINT32)cursorZ[0], cam.m_ProjAttribs.Width - 1);
            cursorZ[1] = std::min((UINT32)cursorZ[1], cam.m_ProjAttribs.Height - 1);
TheMostDiligent commented 4 months ago

I suggest you look at the code I sent and do the same way.

9MW commented 4 months ago

I suggest you look at the code I sent and do the same way.

Appreciate you reply, I'll take a look.

9MW commented 4 months ago

solved by remove UnmapTextureSubresource and MapTextureSubresource call in update function. MapTextureSubresource once at init function would be enough. Maybe I need UnmapTextureSubresource before release, haven't try that

TheMostDiligent commented 4 months ago

You read the data between MapTextureSubresource and UnmapTextureSubresource. In you snippet, you unmap right before mapping again, which does not make a lot of sense. Once again, take a look at the code that I sent.