HLSL根签名中能否将Texture2DArray作为根描述符?
问题描述
我在HLSL着色器中声明根描述符时,尝试将Texture2DArray设为根描述符,触发错误X4614:根签名验证失败,映射到根描述符SRV的寄存器对应的资源为纹理,而SRV/UAV根描述符仅支持Raw或Structured缓冲区。我想确认纹理数组是否完全无法作为根描述符,还是必须自行制作纹理图集?我的需求是避免描述符表带来的一级间接寻址。
问题中的着色器代码
#define PI_F 3.14159265358979323846264338327950288419716939f Texture2DArray screenTexArrays : register(t0); SamplerState screenTexSampler : register(s0); struct PixelInput { float4 pos : SV_Position; float4 uvds : TEXCOORD0; }; cbuffer uniformsCB : register(b1) { uint4 dwNumPlayers; }; [RootSignature( "RootFlags( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |"\ " DENY_HULL_SHADER_ROOT_ACCESS |"\ " DENY_DOMAIN_SHADER_ROOT_ACCESS |"\ " DENY_GEOMETRY_SHADER_ROOT_ACCESS ),"\ " SRV( t0, space = 0, visibility=SHADER_VISIBILITY_PIXEL ),"\ " RootConstants( num32BitConstants=4,"\ " b1,"\ " space = 0,"\ " visibility=SHADER_VISIBILITY_PIXEL ),"\ " StaticSampler( s0,"\ " filter=FILTER_MIN_MAG_MIP_POINT,"\ " addressU = TEXTURE_ADDRESS_CLAMP,"\ " addressV = TEXTURE_ADDRESS_CLAMP,"\ " addressW = TEXTURE_ADDRESS_CLAMP,"\ " visibility = SHADER_VISIBILITY_PIXEL )" )] float4 main( PixelInput inPixel ) : SV_Target { float fPlayerPerTheta = dwNumPlayers.x/(2.0f*PI_F); float2 vPixVecFromMiddle = normalize(inPixel.uvds.xy - float2(0.5f, 0.5f)); float fCosThetaFromXAxis = dot(float2(1.f,0.f),vPixVecFromMiddle); float fPlayer = floor(acos(fCosThetaFromXAxis) * fPlayerPerTheta); return screenTexArrays.Sample(screenTexSampler,float3(inPixel.uvds.xy,fPlayer)); }
问题中的编译脚本
@echo off if not defined DevEnvDir ( call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat" ) if not defined DevEnvDir ( call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" ) if "%Platform%" neq "x64" ( echo ERROR: Platform is not "x64" - previous bat call failed. exit /b 1 ) set SHADERFLAGS=/WX /D__SHADER_TARGET_MAJOR=5 /D__SHADER_TARGET_MINOR=0 set POSTPROCESSPIXELSHADER=PostProcessAndCompositePixelShader.hlsl fxc /nologo /T ps_5_0 /O3 %SHADERFLAGS% /Qstrip_reflect /Qstrip_debug /Qstrip_priv %POSTPROCESSPIXELSHADER% /Fh postProcessCompositeShader.h /Vn postProcessCompositeShaderBlob
解答
纹理数组确实无法直接作为根描述符
根据DX12根签名规范,根描述符仅支持Raw缓冲区或结构化缓冲区的SRV/UAV,普通纹理(包括纹理数组)不能直接绑定到根描述符位置,必须通过描述符表绑定。替代方案
若想避免描述符表的一级间接寻址,可考虑两种方向:- 使用纹理图集:将多张子纹理合并到一张大纹理中,通过计算UV偏移访问不同区域。这种方式能把单个纹理作为根描述符绑定,但需要在着色器中手动处理UV,适合子纹理尺寸统一的场景。
- DX12 Ultimate特性(SM 6.6+):若平台支持,可通过结构化缓冲区存储纹理的GPU虚拟地址,再将该缓冲区绑定为根描述符,着色器通过地址直接访问纹理。但这种方式需手动管理GPU地址,实现复杂度较高。
当前代码的修改建议
如果无法使用DX12 Ultimate特性,最直接的解决方式是将Texture2DArray通过描述符表绑定,修改根签名定义即可:
[RootSignature( "RootFlags( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |"\ " DENY_HULL_SHADER_ROOT_ACCESS |"\ " DENY_DOMAIN_SHADER_ROOT_ACCESS |"\ " DENY_GEOMETRY_SHADER_ROOT_ACCESS ),"\ " DescriptorTable(SRV(t0), space = 0, visibility=SHADER_VISIBILITY_PIXEL ),"\ " RootConstants( num32BitConstants=4,"\ " b1,"\ " space = 0,"\ " visibility=SHADER_VISIBILITY_PIXEL ),"\ " StaticSampler( s0,"\ " filter=FILTER_MIN_MAG_MIP_POINT,"\ " addressU = TEXTURE_ADDRESS_CLAMP,"\ " addressV = TEXTURE_ADDRESS_CLAMP,"\ " addressW = TEXTURE_ADDRESS_CLAMP,"\ " visibility = SHADER_VISIBILITY_PIXEL )" )]
这是当前规范下的标准做法,虽然存在一级间接寻址,但能正常使用纹理数组。
内容的提问来源于stack exchange,提问作者yosmo78
相关产品推荐
相关产品推荐

