Using read-only and uav buffers in GLSL vs HLSL

Discussion area about developing with Ogre-Next (2.1, 2.2 and beyond)


User avatar
bishopnator
Gnome
Posts: 333
Joined: Thu Apr 26, 2007 11:43 am
Location: Slovakia / Switzerland
x 16

Using read-only and uav buffers in GLSL vs HLSL

Post by bishopnator »

In D3D11 (hlsl), the uav buffers are bound to ux registers, but in GL3Plus (glsl) with glBindBufferRange( GL_SHADER_STORAGE_BUFFER, ...).
For read-only buffers, the D3D11 uses tx registers, but Gl3Plus uses either SSBO, texture buffer or GL_TEXTURE0+slot/GL_PIXEL_UNPACK_BUFFER.

Regardless of the macros for HLMS to cover such differences, I am confused about the consistency of the binding slots on c++ side. For example if my HLSL shader uses 2 read-only buffers and 2 uav buffers, I can bind them to t0, t1 and u0, u1. However in GLSL I cannot use same slots. On modern hardware, both buffer types are created as SSBO and I have to use bindings 0, 1, 2, 3.

What is the idea in Ogre to handle different binding slots in HLSL and GLSL? Is it intended to use conditions in c++ code to verify whether we are in d3d11 or gl3plus and whether ssbo is supported, etc. (actually I need to assume it is, as I need to use uav buffers).

Another idea is to use in HLSL the registers tx and ux as identical - assuming e.g. u0 is same as t0 and don't bind the buffers to both and keep the gl3plus happy, but it sounds like a waste.

User avatar
bishopnator
Gnome
Posts: 333
Joined: Thu Apr 26, 2007 11:43 am
Location: Slovakia / Switzerland
x 16

Re: Using read-only and uav buffers in GLSL vs HLSL

Post by bishopnator »

Throwing here also some example shaders.
HLSL:

Code: Select all

struct ps_in
{
	float4 position : SV_POSITION;
}

struct ps_out
{
	float4 color0 : SV_Target0;
	float4 color1 : SV_Target1;
};

cbuffer myConstBuffer1 : register(b0)
{
	float4 some_data;
};
cbuffer myConstBuffer2 : register(b1)
{
	float4 some_data;
};

StructuredBuffer<float4> myReadOnlyBuffer1 : register(t0);
StructuredBuffer<float4> myReadOnlyBuffer2 : register(t1);
StructuredBuffer<float4> myReadOnlyBuffer3 : register(t2);

RWStructuredBuffer<float4> myUAV0 : register(u2);
RWStructuredBuffer<float4> myUAV1 : register(u3);

ps_out main(ps_in input)
{
	// some computation using the data from input buffers
	...
	
// read-write to UAV buffers
...

// initialize the output
ps_out output;
output.color0 = float4(...);
output.color1 = float4(...;
return output;
}

GLSL:

Code: Select all

#version 450
layout(std140) uniform;

layout(location = 0) out vec4 color0;
layout(location = 1) out vec4 color1;

// const buffers
layout(binding = 0, std140) uniform MyConstBuffer1
{
    vec4 some_data;
} myConstBuffer1;
layout(binding = 1, std140) uniform MyConstBuffer2
{
    vec4 some_data;
} myConstBuffer2;

// read-only buffers
layout(binding = 0, std430) readonly buffer MyReadOnlyBuffer1
{
    vec4 data[];
} myReadOnlyBuffer1;
layout(binding = 1, std430) readonly buffer MyReadOnlyBuffer2
{
    vec4 data[];
} myReadOnlyBuffer2;
layout(binding = 2, std430) readonly buffer MyReadOnlyBuffer3
{
    vec4 data[];
} myReadOnlyBuffer3;

// uav buffers
layout(binding = 3, std430) buffer MyUAV0;
{
    vec4 data[];
} myUAV0;
layout(binding = 4, std430) buffer MyUAV1;
{
    vec4 data[];
} myUAV1;

void main()
{
	// some computation using the data from input buffers
	...
	
// read-write to UAV buffers
...

// initialize the output
color0 = vec4(...);
color1 = vec4(...;
}

You can see that in HLSL the UAVs are bound to u2 and u3 (as shader uses 2 output color buffers), but in GLSL, the corresponding SSBOs must be bound to slots 3 and 4 as the slots 0-2 are used by read-only buffers.

User avatar
bishopnator
Gnome
Posts: 333
Joined: Thu Apr 26, 2007 11:43 am
Location: Slovakia / Switzerland
x 16

Re: Using read-only and uav buffers in GLSL vs HLSL

Post by bishopnator »

I think the problem is that in D3D11, the Ogre adds automatically offset to the uav slot according to the active output color buffers. In the HLSL shader template it looks like:

Code: Select all

struct ps_out
{
	float4 color0 : SV_Target@counter(rtv_target); // u0
	float4 color1 : SV_Target@counter(rtv_target); // u1
};

RWStructuredBuffer<float4> myUAV0 : register(u@counter(rtv_target)); // u2
RWStructuredBuffer<float4> myUAV1 : register(u@counter(rtv_target)); // u3

In GLSL it is little bit more complicated as the offset is based on the number of active read-only buffers which is not known in Ogre at the time of binding UAVs. From the implementation side in c++, I would like to keep setting of "start" slot 0 and leave the work on Ogre which should do the job according to the active RenderSystem. The HLMS outputs the description of bindings (root layouts), which can be used here - the offset is defined by the number of used read-only buffers.