如何创建与渲染目标匹配的ID3D11Texture2D暂存纹理?
问题描述
我通过以下代码创建了DirectX 11交换链及相关资源:
DXGI_SWAP_CHAIN_DESC swapchainDesc; // Clear out the struct for use ZeroMemory(&swapchainDesc, sizeof(DXGI_SWAP_CHAIN_DESC)); // Fill the swap chain description struct swapchainDesc.BufferCount = 1; // one back buffer swapchainDesc.BufferDesc.Width = width; swapchainDesc.BufferDesc.Height = height; swapchainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // use 32-bit color swapchainDesc.BufferDesc.RefreshRate.Numerator = 60; swapchainDesc.BufferDesc.RefreshRate.Denominator = 1; swapchainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // how swap chain is to be used swapchainDesc.OutputWindow = hWnd; // the window to be used swapchainDesc.SampleDesc.Count = 1; // how many multisamples swapchainDesc.SampleDesc.Quality = 0; // multisample quality level swapchainDesc.Windowed = TRUE; // windowed/full-screen mode // Configure DX feature level D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0 }; UINT numFeatureLevels = ARRAYSIZE(featureLevels); char devname_dx[128]; bool device_ok = getAdapter(&adapter, devname_dx); DXGI_ADAPTER_DESC adapterDesc; adapter->GetDesc(&adapterDesc); std::cout << "DirectX GPU " << devname_dx << " : [BusID " << adapterDesc.DeviceId << " | DevID " << adapterDesc.SubSysId << "]" << std::endl; // Create a device, device context and swap chain using the information in the scd struct hr = D3D11CreateDeviceAndSwapChain( adapter, // graphics adapter, which was already checked for CUDA support D3D_DRIVER_TYPE_UNKNOWN, // If adapter is not NULL, we need to use UNKNOWN NULL, // software NULL, // flags featureLevels, // D3D features to enable numFeatureLevels, // D3D feature count D3D11_SDK_VERSION, // D3D SDK version (here 11) &swapchainDesc, // swap chain description &swapchain, // swap chain &device, // D3D device NULL, // supported feature level &device_context); // D3D device context if (FAILED(hr)) { std::string msg = std::string("Failed to create DX device and swap chain: ") + std::to_string(hr); throw std::exception(msg.c_str()); } // 释放适配器 adapter->Release(); // 获取设备上下文 device->GetImmediateContext(&device_context); // 获取交换链的后台缓冲区纹理 hr = swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&texture_rgb); // 创建渲染目标视图 hr = device->CreateRenderTargetView(texture_rgb, nullptr, &rtv);
我需要创建一个与texture_rgb属性匹配的暂存纹理(STAGING),用于查询像素数据并后续与CUDA集成。我尝试获取texture_rgb的描述,仅修改Usage为D3D11_USAGE_STAGING后创建纹理:
D3D11_TEXTURE2D_DESC texture_rgb_debugDesc; texture_rgb->GetDesc(&texture_rgb_debugDesc); // 仅修改Usage字段 texture_rgb_debugDesc.Usage = D3D11_USAGE::D3D11_USAGE_STAGING; ID3D11Texture2D* texture_rgb_debug = nullptr; hr = device->CreateTexture2D(&texture_rgb_debugDesc, nullptr, &texture_rgb_debug);
但执行时DirectX报错:
E_INVALIDARG One or more arguments are invalid.
将Usage改回D3D11_USAGE_DEFAULT则纹理可正常创建,请问如何解决这个问题?
解决方案
创建暂存纹理(D3D11_USAGE_STAGING)时,仅修改Usage字段是不够的,还需要调整以下两个关键参数——暂存纹理的使用规则与渲染目标纹理存在本质差异:
- 清空绑定标志(BindFlags):暂存纹理不能绑定到任何渲染管线阶段(比如作为渲染目标),必须将
BindFlags设置为0。交换链的后台缓冲区纹理默认带有D3D11_BIND_RENDER_TARGET标志,直接复用该描述会导致参数冲突。 - 设置CPU访问权限(CPUAccessFlags):暂存纹理的核心用途是CPU与GPU之间的数据传输,必须指定CPU的访问权限,比如
D3D11_CPU_ACCESS_READ(用于从GPU读取数据到CPU)或D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE(双向访问)。
修改后的创建代码如下:
D3D11_TEXTURE2D_DESC texture_rgb_debugDesc; texture_rgb->GetDesc(&texture_rgb_debugDesc); // 调整暂存纹理所需的参数 texture_rgb_debugDesc.Usage = D3D11_USAGE_STAGING; texture_rgb_debugDesc.BindFlags = 0; // 暂存纹理不能有绑定 texture_rgb_debugDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; // 根据需求选择读写权限 // 可选:如果原纹理是多重采样(SampleDesc.Count > 1),需将暂存纹理设置为非多重采样 // texture_rgb_debugDesc.SampleDesc.Count = 1; // texture_rgb_debugDesc.SampleDesc.Quality = 0; ID3D11Texture2D* texture_rgb_debug = nullptr; hr = device->CreateTexture2D(&texture_rgb_debugDesc, nullptr, &texture_rgb_debug); if (FAILED(hr)) { // 处理错误逻辑 }
修改完成后,即可成功创建与原纹理尺寸、格式匹配的暂存纹理。后续可通过ID3D11DeviceContext::CopyResource将原纹理的数据复制到暂存纹理,再调用Map方法获取CPU可访问的指针来读取像素数据。
内容的提问来源于stack exchange,提问作者rbaleksandar
相关产品推荐
相关产品推荐

