You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无CPU拷贝下跨设备复制格式不兼容的ID3D11Texture2D方法

D3D11纹理跨设备复制+格式转换+CUDA兼容解决方案(Dolphin模拟器场景)

问题根源

  • 直接修改D3D11_TEXTURE2D_DESC::Format后CopyResource失败:CopyResource要求源/目标纹理格式必须完全兼容(同格式或硬件原生支持的无转换兼容对),DXGI_FORMAT_R10G10B10A2_UNORM和DXGI_FORMAT_R8G8B8A8_UNORM不在此列,因此操作静默失效。
  • 不修改格式时cudaGraphicsD3D11RegisterResource失败:CUDA不支持R10G10B10A2_UNORM格式,仅支持有限的标准格式(如R8G8B8A8_UNORM、R32_FLOAT等)。

无CPU拷贝的实现步骤

1. 创建符合要求的目标纹理

要同时满足格式转换和CUDA共享的需求,目标纹理的参数必须正确配置:

D3D11_TEXTURE2D_DESC targetDesc = {};
// 匹配源纹理的尺寸、层级数
targetDesc.Width = srcDesc.Width;
targetDesc.Height = srcDesc.Height;
targetDesc.MipLevels = 1;
targetDesc.ArraySize = 1;
// 设置为CUDA支持的R8G8B8A8_UNORM
targetDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
targetDesc.SampleDesc.Count = 1;
targetDesc.SampleDesc.Quality = 0;
// 默认用法,GPU读写
targetDesc.Usage = D3D11_USAGE_DEFAULT;
// 绑定渲染目标(用于格式转换)、着色器资源、无序访问(可选)
targetDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS;
// 开启跨设备共享
targetDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
// 禁止CPU访问,避免拷贝
targetDesc.CPUAccessFlags = 0;

ID3D11Texture2D* targetTex = nullptr;
HRESULT hr = d3dDevice->CreateTexture2D(&targetDesc, nullptr, &targetTex);

2. 用GPU渲染管线完成格式转换

不能直接用CopyResource,必须通过像素着色器做格式转换:

  • 编写极简像素着色器(HLSL):
Texture2D inputTex : register(t0);
SamplerState linearSampler : register(s0);

float4 PS(float2 uv : TEXCOORD0) : SV_Target
{
    // 直接采样源纹理,UNORM格式下R10G10B10A2转R8G8B8A8仅需截断,GPU自动处理
    return inputTex.Sample(linearSampler, uv);
}
  • 设置渲染目标为targetTex,绘制全屏四边形,将源纹理内容渲染到目标纹理上。这一步完全在GPU端完成,无CPU参与。

3. 跨设备共享目标纹理

获取共享句柄并在CUDA关联的D3D设备上打开:

IDXGIResource* dxgiRes = nullptr;
targetTex->QueryInterface(__uuidof(IDXGIResource), (void**)&dxgiRes);
HANDLE sharedHandle = nullptr;
dxgiRes->GetSharedHandle(&sharedHandle);
dxgiRes->Release();

// 在CUDA对应的D3D11设备上打开共享资源
ID3D11Texture2D* cudaSharedTex = nullptr;
cudaD3dDevice->OpenSharedResource(sharedHandle, __uuidof(ID3D11Texture2D), (void**)&cudaSharedTex);

4. 注册到CUDA供CNN使用

现在纹理格式符合要求,直接注册并映射:

cudaGraphicsResource* cudaRes = nullptr;
cudaError_t err = cudaGraphicsD3D11RegisterResource(&cudaRes, cudaSharedTex, cudaGraphicsRegisterFlagsNone);
if (err == cudaSuccess) {
    // 映射资源到CUDA地址空间
    cudaGraphicsMapResources(1, &cudaRes, nullptr);
    uint8_t* devPtr = nullptr;
    size_t pitch = 0;
    cudaGraphicsResourceGetMappedPointer((void**)&devPtr, &pitch, cudaRes);
    // 将devPtr传入CNN处理(注意pitch对应的行字节数)
    cudaGraphicsUnmapResources(1, &cudaRes, nullptr);
}

注意事项

  • 确保两个D3D11设备(Dolphin的设备和CUDA关联设备)均支持DirectX 11及以上,且驱动支持跨设备共享。
  • 绘制全屏四边形时,要正确设置视口与UV坐标,避免画面拉伸或错位。
  • 追求性能的话,可改用Compute Shader完成格式转换,减少渲染管线的状态切换开销。

内容的提问来源于stack exchange,提问作者Emre Tekmen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 10:28:26