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

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,普通纹理(包括纹理数组)不能直接绑定到根描述符位置,必须通过描述符表绑定。

  • 替代方案
    若想避免描述符表的一级间接寻址,可考虑两种方向:

    1. 使用纹理图集:将多张子纹理合并到一张大纹理中,通过计算UV偏移访问不同区域。这种方式能把单个纹理作为根描述符绑定,但需要在着色器中手动处理UV,适合子纹理尺寸统一的场景。
    2. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 00:24:51