D3D12下GPU端DXGI_FORMAT_R8G8B8A8_UNORM转DXGI_FORMAT_B8G8R8A8_UNORM方案
实现方案
R8G8B8A8_UNORM到B8G8R8A8_UNORM的转换本质是交换R和B通道,全程GPU执行不需要CPU介入,可选择以下两种方案实现,转换后的资源可直接用于NVENC注册。
前提要求
- 源资源(DXGI_FORMAT_R8G8B8A8_UNORM)需配置
D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE或D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE状态权限 - 目标资源(DXGI_FORMAT_B8G8R8A8_UNORM)必须放在
D3D12_HEAP_TYPE_DEFAULT堆上,且配置对应方案需要的权限(Compute方案需D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS,RTV方案需D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET),同时满足NVENC注册要求:2D纹理、Mip等级为1、多重采样计数为1。
方案1:Compute Shader通道重排(推荐,性能开销最低)
- 编写极简Compute Shader完成通道交换,代码如下:
RWTexture2D<float4> g_Output : register(u0); Texture2D<float4> g_Input : register(t0); [numthreads(8, 8, 1)] void main(uint3 threadId : SV_DispatchThreadID) { float4 color = g_Input[threadId.xy]; // 交换R、B通道,保留G、A通道 g_Output[threadId.xy] = float4(color.b, color.g, color.r, color.a); }
- 编译Shader为CSO,配置仅包含1个SRV、1个UAV的根签名,创建Compute管线状态对象。
- 执行转换前做资源状态转换:
- 源资源切换到
D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE - 目标资源切换到
D3D12_RESOURCE_STATE_UNORDERED_ACCESS
- 源资源切换到
- 绑定SRV、UAV到Compute管线,按照纹理尺寸向上取整计算Dispatch线程组数量(宽/8、高/8)后触发Dispatch。
- 转换完成后将目标资源切换到
D3D12_RESOURCE_STATE_GENERIC_READ或D3D12_RESOURCE_STATE_VIDEO_ENCODE_SOURCE状态,即可直接用于NVENC注册。
该方案全程无CPU介入,仅占用极少量GPU计算单元,带宽开销仅为一次纹理读写
方案2:Render Target全屏绘制(适配已有渲染管线场景)
如果当前项目已有成熟的渲染管线,不想额外维护Compute管线,可以用全屏三角形绘制的方式实现转换:
- 编写Pixel Shader完成通道交换:
Texture2D g_Input : register(t0); SamplerState g_Sampler : register(s0); float4 main(float2 uv : TEXCOORD0) : SV_Target { float4 color = g_Input.Sample(g_Sampler, uv); return float4(color.b, color.g, color.r, color.a); }
- 创建目标资源的RTV,将源资源作为SRV绑定到像素Shader阶段,绘制全屏三角形覆盖整个纹理范围即可完成转换。
NVENC注册注意事项
- 注册时
NV_ENC_REGISTER_RESOURCE结构体的resourceType需设置为NV_ENC_INPUT_RESOURCE_TYPE_DIRECT3D12,bufferFormat设置为NV_ENC_BUFFER_FORMAT_ARGB,和B8G8R8A8_UNORM格式完全匹配。 - 不需要对目标资源做CPU映射或拷贝操作,直接传递D3D12资源指针即可完成注册。
注意:不要尝试用
CopyResource或CopyRegion直接做两个格式的资源拷贝,D3D12不支持不同格式资源的直接拷贝操作,必须通过管线做通道转换。
内容的提问来源于stack exchange,提问作者Anand Rathi
相关产品推荐
相关产品推荐

