简体   繁体   English

DirectX:使用计算着色器写入纹理

[英]DirectX : Write to texture with Compute Shader

I'm trying to write in a texture with compute shader in HLSL.我正在尝试在 HLSL 中使用计算着色器编写纹理。

Creation of the texture :纹理的创建:

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);

Creation of the UAV :无人机的创建:

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);

Creation of the SRV (to see the texture) :`创建 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);

The shader :着色器:

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);
}

The problem is that the texture is always black (the compute shader doesn't write to the texture).问题是纹理总是黑色的(计算着色器不写入纹理)。

Thanks for your help !感谢您的帮助! :D :D

The problem is that I bound an UAV and a SRV on the same texture.问题是我在同一个纹理上绑定了一个 UAV 和一个 SRV。

I resolved the problem creating two textures : one bound to an UAV and another bound to a SRV.我解决了创建两个纹理的问题:一个绑定到无人机,另一个绑定到 SRV。

The compute shader write on the UAV and, each frame, I copy the data on the SRV with deviceContext->CopyResource(m_texSRV, m_texUAV);计算着色器在 UAV 上写入,并且在每一帧中,我使用deviceContext->CopyResource(m_texSRV, m_texUAV);复制 SRV 上的数据deviceContext->CopyResource(m_texSRV, m_texUAV);

The problem now is the performance, CopyResource is a costly operation.现在的问题是性能, CopyResource是一个代价高昂的操作。 Does it have an other solution less expensive ?它有其他更便宜的解决方案吗?

Thanks for your help !感谢您的帮助! :D :D

The issue is that you need to cause the GPU to flush the surface before using it as an input in a different shader invocation (draw/PS).问题是您需要先让 GPU 刷新表面,然后才能将其用作不同着色器调用(绘制/PS)中的输入。 You do this by binding a null resource to the previous shader stage.您可以通过将空资源绑定到前一个着色器阶段来实现此目的。

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

This should be enough to tell the graphics driver to flush or transition the resource from a write to a read resource.这应该足以告诉图形驱动程序刷新或将资源从写入资源转换为读取资源。

If you use D3D12 or vulkan you will need a resource barrier when going from write to read.如果您使用 D3D12 或 vulkan,则在从写入到读取时需要一个资源屏障。

Example render loop:示例渲染循环:

    // 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);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM