如何在HLSL中处理8位字符数据?

4
我正在将一些OpenCL代码转换为DirectCompute,并需要在计算着色器中处理8位字符字符串,但没有找到"HLSL数据类型"的“byte”或“char”。OpenCL支持“char”类型,因此我希望有一种等效的方式来定义和访问数据。似乎可以通过将其视为一系列“uint”类型传递数据,并使用位移、AND运算等进行解包,但这似乎会导致不必要的开销。正确的方法是什么?
2个回答

4

我已经找到了两种方法来完成这个操作,但是它们都需要在 HLSL 中使用 int/uint 值来处理数据,因为我没有找到 8 位数据类型:

选项1:让“视图”来处理翻译:

  • 将原始数据作为字节/字符缓冲传递。
  • 设置着色器资源视图格式(D3D11_SHADER_RESOURCE_VIEW_DESC.Format)为 DXGI_FORMAT_R8_UINT
  • 将 HLSL 数据类型定义为 Buffer<uint>
  • 使用其字节偏移量引用每个字节(即将其视为字节而不是 uint 缓冲区)。每个字符会自动提升为 uint 值。

选项 2 是将每个 4 字节序列视为 uint,使用 DXGI_FORMAT_R32_UINT 格式,并手动提取每个字符,例如:

Buffer<uint> buffer;
uint offset = ...;    
uint ch1, ch2, ch3, ch4;
ch1 =  buffer[offset] >> 24;
ch2 = (buffer[offset] & 0x00ff0000) >> 16;
ch3 = (buffer[offset] & 0x0000ff00) >> 8;
ch4 = (buffer[offset] & 0x000000ff);

无论哪种方式,您最终都将使用32位值进行操作,但至少它们对应于单个字符。

这对我来说看起来很正确。还有ByteAddressBuffers,但它们也有相同的uint32粒度限制。 - fifoforlifo
它可以工作,但结构化缓冲区除外。它只支持2、4字节的访问。 - mopodafordeya

0
你还可以使用ByteAddressBuffer,在创建ByteAddressBuffer时,将stride设置为1,并将srv格式设置为DXGI_FORMAT_R8_UINT。
在Hlsl中,你可以使用"Load"函数加载uint32数据,使用0xFF000000掩码数据以获取前8位,最后进行位移以纠正位地址。
我在虚幻引擎中工作,以下是我的代码:
c++

create ByteAddressBuffer:
            MaskBufferRHI = RHICreateBuffer(DataLength * sizeof(uint8), BUF_Static | BUF_ByteAddressBuffer | BUF_ShaderResource, sizeof(uint8), ERHIAccess::SRVCompute, MaskCreateInfo); // MaskCreateInfo contain all the data I need.
create svr with uint8:
            RHICreateShaderResourceView(MaskBufferRHI, sizeof(uint8), PF_R8_UINT);


hlsl
define buffer:
            ByteAddressBuffer InMaskBuffer;
retrieve uint8 data to uint32:
            const uint InMask = (InMaskBuffer.Load(SomeID) & 0xFF000000) >> 24;

(load function fill uint32 InMask with 4 uint8 data in out buffer at once, we need to mask out those data.)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接