I'm trying to write in a texture with compute shader in 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) :`
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
The problem is that I bound an UAV and a SRV on the same texture.
I resolved the problem creating two textures : one bound to an UAV and another bound to a 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);
The problem now is the performance, CopyResource
is a costly operation. Does it have an other solution less expensive ?
Thanks for your help ! :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). 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.
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);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.