使用动态格式创建二维纹理时出错

error when creating 2d texture with dynamic format

我是 directx 的新手。 我在处理资源方面遇到了困难。

好的,首先,我创建了可以在 GPU 中 read/write 的纹理,并且效果很好。 现在,您可以查看我的代码,我也想在 CPU 中读取此纹理(从应用程序端读取),因此我将用法从 USAGE_DEFAULT 编辑为 USAGE_DYNAMIC。

Microsoft::WRL::ComPtr<ID3D11Texture2D> outputTexture;

D3D11_TEXTURE2D_DESC outputTex_desc;
outputTex_desc.Format = DXGI_FORMAT_R32_FLOAT;
outputTex_desc.Width = 3;
outputTex_desc.Height = 3;
outputTex_desc.MipLevels = 1;
outputTex_desc.ArraySize = 1;
outputTex_desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS | 
                           D3D11_BIND_SHADER_RESOURCE;
outputTex_desc.SampleDesc.Count = msCount;
outputTex_desc.SampleDesc.Quality = msQuality;
outputTex_desc.Usage = D3D11_USAGE_DYNAMIC;
outputTex_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
outputTex_desc.MiscFlags = 0;

// CREATE 'TEXTURE'
device->CreateTexture2D(      // FAIL HERE !!!
            &outputTex_desc,
            nullptr,
            outputTexture.GetAddressOf());
// CREATE 'SRV'
...
// CREATE 'UAV'
...

它在执行 'device->CreateTexture2D()'

时开始失败

任何建议都会很棒。

调试任何 Direct3D 11 程序的前两个步骤是:

  1. 确保检查每个 HRESULT 是否成功(SUCCEEDED 宏)或失败(FAILED 宏)。如果在运行时忽略 return 值是安全的,那么函数 returns void。参见 ThrowIfFailed
  2. 启用 Direct3D 调试设备并查找调试输出(a.k.a。在调试配置中使用 D3D11_CREATE_DEVICE_DEBUG)。

如果您启用 Direct3D debug device,您将获得有关 API return 为什么在许多情况下出现故障代码的详细信息。

如果这样做,您会看到以下代码的错误:

D3D11 ERROR: ID3D11Device::CreateTexture2D: A D3D11_USAGE_DYNAMIC Resource
may only have the D3D11_CPU_ACCESS_WRITE CPUAccessFlags set.
[ STATE_CREATION ERROR #98: CREATETEXTURE2D_INVALIDCPUACCESSFLAGS]

为了在 CPU 上 阅读 它,您必须先复制到 D3D11_USAGE_STAGING 资源。有关这样做的示例源代码,请参阅 ScreenGrab code from DirectX Tool Kit

您没有在此处提及您的 msCountmsQuality 值。我分别假设为 1 和 0。如果您使用任何其他值,您将得到:

D3D11 ERROR: ID3D11Device::CreateTexture2D: Multisampling is not supported
with the D3D11_BIND_UNORDERED_ACCESS BindFlag.  SampleDesc.Count must be 1
and SampleDesc.Quality must be 0.
[ STATE_CREATION ERROR #99: CREATETEXTURE2D_INVALIDBINDFLAGS]

为了从 cpu(读取模式)访问纹理,您需要创建一个单独的暂存纹理,然后将您的纹理复制到其中。

这些是仅 gpu 纹理的标志(请注意我将样本数强制设置为 1,因为多重采样纹理不允许无人机访问)

D3D11_TEXTURE2D_DESC gpuTexDesc;
gpuTexDesc.Format = DXGI_FORMAT_R32_FLOAT;
gpuTexDesc.Width = 3;
gpuTexDesc.Height = 3;
gpuTexDesc.MipLevels = 1;
gpuTexDesc.ArraySize = 1;
gpuTexDesc.BindFlags = D3D11_BIND_UNORDERED_ACCESS | 
                       D3D11_BIND_SHADER_RESOURCE;
gpuTexDesc.SampleDesc.Count = 1;
gpuTexDesc.SampleDesc.Quality = 0;
gpuTexDesc.Usage = D3D11_USAGE_DEFAULT;
gpuTexDesc.CPUAccessFlags = D3D11_CPU_ACCESS_NONE;
gpuTexDesc.MiscFlags = 0;

然后创建第二个纹理用于​​读取

D3D11_TEXTURE2D_DESC readTexDesc;
readTexDesc.Format = DXGI_FORMAT_R32_FLOAT;
readTexDesc.Width = 3;
readTexDesc.Height = 3;
readTexDesc.MipLevels = 1;
readTexDesc.ArraySize = 1;
readTexDesc.BindFlags = 0; //No bind flags allowed for staging
readTexDesc.SampleDesc.Count = 1;
readTexDesc.SampleDesc.Quality = 0;
readTexDesc.Usage = D3D11_USAGE_STAGING; //need staging flag for read
readTexDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
readTexDesc.MiscFlags = 0;

那么你可以使用 CopyResource:

deviceContext->CopyResource(readTex, gpuTex);

完成后,您终于可以使用Map

访问纹理数据进行读取
D3D11_MAPPED_SUBRESOURCE MappedResource;
deviceContext->Map(readTex, 0, D3D11_MAP_READ, 0, &MappedResource);

MappedResource 将使您能够访问 cpu 中的数据,完成处理后,不要忘记 Unmap 资源。

deviceContext->Unmap(readTex, 0);