AMD GPU gets multiple render targets mixed up

Started by
3 comments, last by Ed Welch 3 weeks, 3 days ago

I am running a shader that outputs position and normal data to two different textures (using code very similar to this: https://learnopengl.com/Advanced-Lighting/Deferred-Shading).​ This works fine on a Nvidia GPU, but on a AMD Radeon RX Vega 6 the position and normal textures are mixed up. I use glBindFragDataLocation to set the order.

Anyone know what I could be doing wrong?

This is the code I use:

    // create gBuffer
    glGenFramebuffers(1, &m_fboGBuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, m_fboGBuffer);
    // position color buffer
    glGenTextures(1, &m_idPosition);
    glBindTexture(GL_TEXTURE_2D, m_idPosition);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, NULL);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_idPosition, 0);
    // normal color buffer
    glGenTextures(1, &m_idNormal);
    glBindTexture(GL_TEXTURE_2D, m_idNormal);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, NULL);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, m_idNormal, 0);
    // tell OpenGL which color attachments we'll use (of this framebuffer) for rendering 
    unsigned int attachments[2] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
    glDrawBuffers(2, attachments);
    // create and attach depth buffer (renderbuffer)
    glGenRenderbuffers(1, &m_fboDepth);
    glBindRenderbuffer(GL_RENDERBUFFER, m_fboDepth);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
	glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_fboDepth);
	int status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
	if (status != GL_FRAMEBUFFER_COMPLETE)
	{
		throw RacException("GBuffer not created");
	}
	Shader* pShader = g_shaderManager.GetShader(shaderGBuffer);
	pShader->Activate();
	glBindFragDataLocation(pShader->GetID(), 0, "gPosition");
	glBindFragDataLocation(pShader->GetID(), 1, "gNormal");
	m_ixMatrixM = pShader->AddUniform("matrixM");
// vertex shader
		uniform highp mat4 matrixPVM;
		uniform highp mat3 matrixVM;
		uniform highp mat4 matrixM;
		in highp vec3 inVertex;
		in lowp vec3 inNorm;
		out vec3 outVertex;
		out vec3 outNormal;
		void main(void)
		{
			outNormal = normalize(mat3(matrixM) * inNorm); 
			vec4 viewPos = matrixM * vec4(inVertex, 1.0);
			outVertex = viewPos.xyz; 
			gl_Position = matrixPVM * vec4(inVertex, 1.0);
		}

// fragment shader
		out vec3 gPosition;
		out vec3 gNormal;		
		in highp vec3 outVertex;
		in vec3 outNormal;
		void main (void)
		{
			// store the fragment position vector in the first gbuffer texture
			gPosition = outVertex;
			// also store the per-fragment normals into the gbuffer
			gNormal = normalize(outNormal);
		}
Advertisement

One potential problem could be that you do not assign a specific slot to the out-variables. I do not fully know whether or not GLSL/OpenGL guarantees to be in any order, but you might want to try to manually specify the slot:

layout(location = 0) out vec3 outPosition;

In both DirectX as well as GL, I always eigther make sure to manually specify slots, or use reflection to prevent issues like that.

I am using glBindFragDataLocation which does the same function as layout. Also, layout is only in 3.3 and I have to support old GPUs

I added #extension GL_ARB_explicit_attrib_location : enable and used the layout specification and now it works. It must be a bug in AMD drivers that glBindFragDataLocation doesn't work

Advertisement