[Bindless][AMD]Weird shader linking error after driver update

Hi all,

I am using the following OpenGL scheme for my 2D engine:

  • If 4.3 is supported, create a 4.3 context. Otherwise, try to create a 3.3 context.
  • If a 4.3 context has been created and both ARB_bindless_texture and ARB_shader_storage_buffer_object are supported, use “bindless mode” for sprites.

This means that each vertex/fragment shader is internally created twice: One for quickly drawing quads from an SSBO using bindless textures, the other a more “vanilla” approach. This is achieved by injecting the appropriate #define in every fragment/vertex shader code.

A bare minimum “passthrough” vertex shader looks something like this:

#if defined(TEXMODE_BINDLESS)
	#extension GL_ARB_bindless_texture : require
	#extension GL_ARB_shader_storage_buffer_object : require
#else
	layout (location = 0) in vec3 aPos;
	layout (location = 1) in vec4 aColor;
	layout (location = 2) in vec2 aTexCoord;
#endif

#if defined(TEXMODE_BINDLESS) && defined(MODE_QUAD)
	flat out sampler2D baseTex;
	uniform int offsetInt;
	uniform int offsetFloat;
	
	layout(std430, binding = 0) readonly buffer buffer_ssbo_uint
	{
		uint data_SSBO_uint[];
	};

	layout(std430, binding = 1) readonly buffer buffer_ssbo_float
	{
		float data_SSBO_float[];
	};

	const vec4 mx = vec4(0.0, 1.0, 1.0, 0.0);
	const vec4 my = vec4(0.0, 0.0, 1.0, 1.0);
#endif

#if defined(TEXMODE_BINDLESS) && defined(MODE_GENERIC)
	layout (location = 0) in vec3 aPos;
	layout (location = 1) in vec4 aColor;
	layout (location = 2) in vec2 aTexCoord;
#endif

out vec2 TexCoord;
out vec4 vColor;
uniform mat4 projView;

const float pr = 3.141592/180.0;

void main()
{	
	#if defined (TEXMODE_BINDLESS) && defined(MODE_QUAD)
		const int quadID = gl_VertexID >> 2;
		const int indexi = offsetInt + quadID * 6;
		baseTex = sampler2D(uvec2(data_SSBO_uint[indexi], data_SSBO_uint[indexi + 1]));
		const int ioffset = int(data_SSBO_uint[indexi+2]);
		const uint color = data_SSBO_uint[indexi+3];
		const uint texcoord1 = data_SSBO_uint[indexi+4];
		const uint texcoord2 = data_SSBO_uint[indexi+5];
		
		const int indexf = offsetFloat + quadID * 5;
		const vec2 vScale = vec2(data_SSBO_float[indexf], data_SSBO_float[indexf+1]);
		const float vRotate = data_SSBO_float[indexf+2];
		const vec2 vTranslate = vec2(data_SSBO_float[indexf+3], data_SSBO_float[indexf+4]);
		
		const vec2 vOffset = vec2( float( (ioffset & 65535)-32768 ), float( ((ioffset >> 16) & 65535)-32768 ) );
		vColor = unpackUnorm4x8(color);
		const vec2 tSize = vec2(textureSize(baseTex,0));
		const vec2 tc1 = vec2( float(texcoord1 & 65535), float((texcoord1 >> 16) & 65535) ) / tSize;
		const vec2 tc2 = vec2( float(texcoord2 & 65535), float((texcoord2 >> 16) & 65535) ) / tSize;
		const vec2 dim = vec2( abs(tc2.x - tc1.x), abs(tc2.y - tc1.y) ) * tSize;
		
		const int quadIndex = gl_VertexID & 3; // = gl_VertexID % 4 . x % y = x & (y-1) if y is a power of 2

		const vec4 tcu = vec4( tc1.x, tc2.x, tc2.x, tc1.x );
		const vec4 tcv = vec4( tc1.y, tc1.y, tc2.y, tc2.y );
		TexCoord = vec2(tcu[quadIndex], tcv[quadIndex]);
	
		vec2 pos = dim * vec2(mx[quadIndex], my[quadIndex]);
		pos -= vOffset;
		pos *= vScale;
		float ang = -vRotate*pr;
		const float ds = sin(ang);
		const float dc = cos(ang);
		vec3 position = vec3(vec2(pos.x*dc - pos.y*ds, pos.x*ds + pos.y*dc) + vTranslate, 0.0);	
	#endif
	
	#if defined(TEXMODE_BINDLESS) && defined (MODE_GENERIC)
		vColor = aColor;
		TexCoord = aTexCoord;
		vec2 pos = aPos.xy;
		vec3 position = aPos;
	#endif
	
	#if !defined(TEXMODE_BINDLESS)
		vColor = aColor;
		TexCoord = aTexCoord;
		vec2 pos = aPos.xy;
		vec3 position = aPos;
	#endif

    gl_Position = projView * vec4(position, 1.0);

}

As convoluted as this seems, it does work, it is easy to derive any other vertex handling shader from it and it does offer superior performance whenever bindless/SSBO mode is supported. So here is the question:

Today I updated my AMD drivers to Adrenaline 23.9.2 (I have an RX580). I hadn’t updated for quite some time. I found out that buffer object streaming (the orphaning variation) was a bit too slow and I just tried updating in case the implementation has gotten any smarter.

After the update and a PC reboot, I tried running my program. Unfortunately, I was immediately greeted with a shader program linking error. After some tinkering, I found out that the culprit was the following line (inside the bindless/SSBO path):

baseTex = sampler2D(uvec2(data_SSBO_uint[indexi], data_SSBO_uint[indexi + 1]));

To my surprise, replacing it with the following:

uint i1 = data_SSBO_uint[indexi];
uint i2 = data_SSBO_uint[indexi + 1];
uvec2 p = uvec2(i1,i2);
baseTex = sampler2D(p);

Caused linking to work again. Problems gone (and, incidentally, buffer object streaming seems to be working very well with the new drivers - but that’s beside the point of my question).

So…is this a driver bug? Or am I doing something silly in my shader that may bite me in the butt later? Remember, the program crashed at the very start, during shader linking. The vert shader compiles without errors, the frag shader compiles without errors, linking fails without even an error message (I get the usual “atio6axx.pdb not loaded” message).

SSBOs are part of 4.3; if you created a 4.3 context, you already have it.

Also, most of your code is not shared between the two forms of your shader. I’d suggest splitting them into separate files, or at least having the two pieces of code be more visually separated. Like, there seem to be 5 lines of code that are shared.

Yes; the code should be equivalent.