【问题标题】:DirectX : Write to texture with Compute ShaderDirectX:使用计算着色器写入纹理
【发布时间】:2017-06-05 20:30:44
【问题描述】:

我正在尝试在 HLSL 中使用计算着色器写入纹理。

纹理的创建:

D3D11_TEXTURE2D_DESC textureDesc;
ZeroMemory(&textureDesc, sizeof(textureDesc));
textureDesc.Width = 512;
textureDesc.Height = 512;
textureDesc.MipLevels = 1;
textureDesc.ArraySize = 1;
textureDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
textureDesc.SampleDesc.Count = 1;
textureDesc.SampleDesc.Quality = 0;
textureDesc.Usage = D3D11_USAGE_DEFAULT;
textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS;
textureDesc.CPUAccessFlags = 0;
textureDesc.MiscFlags = 0;
m_tex = 0;
hr = device->CreateTexture2D(&textureDesc, 0, &m_tex);

无人机的创造:

D3D11_UNORDERED_ACCESS_VIEW_DESC descUAV;
ZeroMemory(&descUAV, sizeof(descUAV));
descUAV.Format = DXGI_FORMAT_UNKNOWN;
descUAV.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D;
descUAV.Texture2D.MipSlice = 0;
hr = device->CreateUnorderedAccessView(m_tex, &descUAV, &m_uavAccess);

创建 SRV(查看纹理):`

D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
srvDesc.Format = textureDesc.Format;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MostDetailedMip = 0;
srvDesc.Texture2D.MipLevels = 1;
hr = device->CreateShaderResourceView(m_tex, &srvDesc, &m_srvTexOutput);

着色器:

RWTexture2D<float4> gOutput : register(u0);

[numthreads(16, 16, 1)]
void main(int3 dispatchThreadID : SV_DispatchThreadID) // Thread ID
{
    gOutput[dispatchThreadID.xy] = float4(0.0f, 1.0f, 0.0f, 1.0f);
}

问题是纹理总是黑色的(计算着色器不写入纹理)。

感谢您的帮助! :D

【问题讨论】:

  • 您的dispatch 电话在哪里?
  • deviceContext->VSSetShader(NULL, NULL, 0); deviceContext->PSSetShader(NULL, NULL, 0); deviceContext->CSetShader(m_computeShader, NULL, 0); deviceContext->CSSetUnorderedAccessViews(0, 1, &m_uavAccess, 0); deviceContext->Dispatch(16, 16, 1);
  • 你试过D3D11_CREATE_DEVICE_DEBUG吗? UAV 和 SRV 使用后会卸载吗?
  • 另外从你的线程组数量和numthreads 来看,你只覆盖了纹理的 1/4,这当然不能解释纹理是完全黑色的事实。顺便说一句,您如何检查?可以分享一下渲染代码吗?
  • 我使用这个像素着色器在四边形上渲染纹理:float4 main(PixelShaderInput input) : SV_TARGET { return shaderTexture.Sample(SampleTypePoint, input.tex); } 这适用于其他纹理。

标签: c++ directx-11 hlsl compute-shader


【解决方案1】:

问题是我将 UAV 和 SRV 绑定在同一个纹理上。

我解决了创建两个纹理的问题:一个绑定到 UAV,另一个绑定到 SRV。

计算着色器在 UAV 上写入数据,每一帧,我使用deviceContext-&gt;CopyResource(m_texSRV, m_texUAV); 复制 SRV 上的数据

现在的问题是性能,CopyResource 是一项昂贵的操作。它有其他更便宜的解决方案吗?

感谢您的帮助! :D

【讨论】:

  • 您绝对不需要两个单独的纹理,这是一个代价高昂的解决方法。同样,您需要使用 D3D11_CREATE_DEVICE_DEBUG 调试图形,这可能表明您在 DispatchDrawPrimitive 之后没有重置 UAV 和/或 SRV,或者如果不是这种情况,它会让您调试着色器。
  • 你有没有弄清楚问题是什么?我在使用 D3D12 时遇到了同样的问题。调试层等有零错误。我可以看到 GPU 使用率从计算着色器上升,但当我从中采样时它只是黑色。
【解决方案2】:

问题是您需要先让 GPU 刷新表面,然后再将其用作不同着色器调用 (draw/PS) 中的输入。为此,您可以将 null 资源绑定到前一个着色器阶段。

    ID3D11UnorderedAccessView *NullUav = nullptr;
    m_DeviceContext->CSSetUnorderedAccessViews(0, 1, &NullUav, nullptr);

这应该足以告诉图形驱动程序刷新或将资源从写入资源转换为读取资源。

如果您使用 D3D12 或 vulkan,则在从写入到读取时将需要资源屏障。

渲染循环示例:

    // Run compute kernel output to UAV.
    m_DeviceContext->CSSetShader(m_ComputeShader, NULL, 0);
    m_DeviceContext->CSSetUnorderedAccessViews(0, 1, &m_UAV, nullptr);
    m_DeviceContext->Dispatch(DispatchX, DispatchY, DispatchZ);

    // Run the raster pipeline to present the UAV values to screen.
    ID3D11UnorderedAccessView *NullUav = nullptr;
    ID3D11ShaderResourceView* NullSrv = nullptr;
    ID3D11DepthStencilView *NullDsv = nullptr;
    m_DeviceContext->PSSetShader(m_PixelShader, NULL, 0);
    m_DeviceContext->VSSetShader(m_VertexShader, NULL, 0);
    m_DeviceContext->CSSetUnorderedAccessViews(0, 1, &NullUav, nullptr);
    m_DeviceContext->PSSetShaderResources(0, 1, &m_SRV);
    m_DeviceContext->IASetIndexBuffer(m_IndexBuffer, DXGI_FORMAT_R32_UINT, 0);
    m_DeviceContext->PSSetSamplers(0, 1, &m_SamplerState);
    m_DeviceContext->OMSetRenderTargets(1, &m_RenderTarget, NullDsv);
    m_ViewPort.Width = (float)RTWidth;
    m_ViewPort.Height = (float)RTHeight;
    m_ViewPort.MaxDepth = 1.0f;
    m_DeviceContext->RSSetViewports(1, &m_ViewPort);
    m_DeviceContext->DrawIndexed(4, 0, 0);

    //  Present the final result.
    int Result = m_SwapChain->Present(1, 0);
    if (Result == DXGI_ERROR_DEVICE_REMOVED || Result == DXGI_ERROR_DEVICE_RESET) {
        // Reinitialize the renderer..
    }

    // Unset the SRV
    m_DeviceContext->PSSetShaderResources(0, 1, &NullSrv);

【讨论】:

    猜你喜欢
    • 2015-02-14
    • 1970-01-01
    • 1970-01-01
    • 2015-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多