Geometry color flickering to black Uniform Buffers

Started by
10 comments, last by Irusan, son of Arusan 5 years, 4 months ago

Hi everyone,

I have an issue where my geometry color would flicker from red to black. I narrowed the issue down to it being caused by my Uniform Buffers, but for the life of me I cannot figure out why its happening.

So I have two Uniform Buffers. One for my camera matrices and the other is for my material colors.

 

This is my first buffer, the camera buffer and this is how it looks like


struct SystemBuffer
{
	BF::Math::Matrix4 modelMatrix; 		// 0   + 4 bytes * 4 floats * 4 vector4 = 64 byte
	BF::Math::Matrix4 viewMatrix; 		// 64  + 4 bytes * 4 floats * 4 vector4 = 128 byte
	BF::Math::Matrix4 projectionMatrix; 	// 128 + 4 bytes * 4 floats * 4 vector4 = 192 byte
	BF::Math::Vector4f cameraPosition; 	// 192 + 4 bytes * 4 floats             = 208 byte
};

This is 208 bytes and is aligned perfectly for OpenGL std140 as far as I know.

 

This is my second buffer, the material buffer and this is how it looks like


struct ColorBuffer
{
	Color ambientColor; 	// 0  + 4 bytes * 4 floats = 16 byte
	Color diffuseColor; 	// 16 + 4 bytes * 4 floats = 32 byte
	Color specularColor; 	// 32 + 4 bytes * 4 floats = 48 byte
	float shininess = 0.0f; // 48 + 4 bytes            = 52 byte
};

This is 52 bytes and is also aligned perfectly for OpenGL std140 as far as I know.

 

My issue is that if I remove the shininess variable from my color buffer, my geometry does not flicker to black at all and the problem is solved the flickering is reduced a lot but still does not get better. However, when I add that variable back it goes back to flickering. I tried to add padding as in add 3 more floats under the shininess variable to make my ColorBuffer a multiple of 16 bytes but that did not help at all.

 

This is how my uniform buffer class looks like


namespace BF
{
	namespace Platform
	{
		namespace API
		{
			namespace OpenGL
			{
				GLConstantBuffer::GLConstantBuffer() :
					buffer(0), bindingIndex(0)
				{
				}

				GLConstantBuffer::~GLConstantBuffer()
				{
					GLCall(glDeleteBuffers(1, &buffer));
				}

				void GLConstantBuffer::Create(unsigned int size, unsigned int bindingIndex)
				{
					this->bindingIndex = bindingIndex;

					GLCall(glGenBuffers(1, &buffer));
					GLCall(glBindBufferBase(GL_UNIFORM_BUFFER, bindingIndex, buffer));
					GLCall(glBufferData(GL_UNIFORM_BUFFER, size, nullptr, GL_STATIC_DRAW));
					GLCall(glBindBuffer(GL_UNIFORM_BUFFER, 0));
				}

				void GLConstantBuffer::Update(const void* data, unsigned int size)
				{
					GLCall(glBindBufferBase(GL_UNIFORM_BUFFER, bindingIndex, buffer));
					GLCall(glBufferSubData(GL_UNIFORM_BUFFER, 0, size, data));
					GLCall(glBindBuffer(GL_UNIFORM_BUFFER, 0));
				}
			}
		}
	}
}

 

This is my usage for the buffers


void Camera::Initialize()
{
	constantBuffer.Create(sizeof(SystemBuffer), 0);
}

void Camera::Update()
{
	constantBuffer.Update(&systemBuffer, sizeof(SystemBuffer));
}

//------

void ForwardRenderer::Initialize()
{
	materialConstantBuffer.Create(sizeof(MeshMaterial::ColorBuffer), 2);
}

void ForwardRenderer::Render()
{
	// clear depth + color buffers

	for (size_t i = 0; i < meshes.size(); i++)
	{
        	//transform meshe
            constantBuffer.Update(&systemBuffer, sizeof(SystemBuffer));                             
        	materialConstantBuffer.Update(&meshes[i]->material->colorBuffer, sizeof(MeshMaterial::ColorBuffer));
		//draw
    	}
}

 

and this is how my shader looks like


vertexShader = R"(
#version 450 core
layout(location = 0) in vec3 inPosition;

layout (std140, binding = 0) uniform camera_data
{
	mat4 buffer_modelMatrix;
	mat4 buffer_viewMatrix;
	mat4 buffer_projectionMatrix;
	vec4 cameraPos;
};

void main()
{
	vec4 worldSpace = buffer_modelMatrix * vec4(inPosition.xyz, 1.0f);
	gl_Position = buffer_projectionMatrix * buffer_viewMatrix * worldSpace;
}
)";

pixelShader = R"(
#version 450 core

struct Material
{
	vec4 ambientColor;
	vec4 diffuseColor;
	vec4 specularColor;

	float shininess;
};

layout (std140, binding = 2) uniform MaterialUniform
{
	Material material;
};

out vec4 color;

void main() 
{
	color = material.ambientColor * material.diffuseColor * material.specularColor;
}
)";

 

hmm.thumb.JPG.94c9cd2a16c1406276517e3f88699873.JPG

All these planes will flicker randomly to black then back to red.

 

Any help would be greatly appreciated.

 

Advertisement

 

Update:

After 2 full days of debugging... the only way I seem to solve this problem is by adding 3 x vector4 as padding to get the size of my struct to 256 bytes. This seems to solve the problem. But I don't understand why. I understand the struct size has to be a multiple of 16 bytes. 208 bytes is multiple of 16. 208 / 16 = 13. So why do I get color flickering when my camera struct is at 208 bytes but not at 256 bytes????

 

if I query "GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT" it returns 256bytes. but from my understanding, that this is only necessary if you want to have multiple buffers on the same binding point, each buffer has to be 256 bytes. That is not the case for me. The system Buffer is bound at point 0 and the color buffer is bound at point 2.   

 


GLint uniformBufferAlignSize = 0;
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniformBufferAlignSize); 

struct SystemBuffer
{
	BF::Math::Matrix4 modelMatrix; 		// 0   + 4 bytes * 4 floats * 4 vector4 	= 64 byte
	BF::Math::Matrix4 viewMatrix; 		// 64  + 4 bytes * 4 floats * 4 vector4 	= 128 byte
	BF::Math::Matrix4 projectionMatrix; 	// 128 + 4 bytes * 4 floats * 4 vector4 	= 192 byte
	BF::Math::Vector4f cameraPosition; 	// 192 + 4 bytes * 4 floats             	= 208 byte
	BF::Math::Vector4f pading[3];		// 208 + 4 bytes * 4 floats * 3 array elements  = 256 byte
};

 

Never mind. That still didn't solve anything..... ☹️

Did you add the 3-float padding to both the struct and the shader layout?

How is your Color struct defined?

 

.:vinterberg:.

15 minutes ago, vinterberg said:

Did you add the 3-float padding to both the struct and the shader layout?

How is your Color struct defined?

 

No, only to my C++ struct. I tried both and that didn't help.

You can see my ColorBuffer in my original post up top.

 

The SystemBuffer in C++ corresponds to camera_data in the shader.

The ColorBuffer in C++ corresponds to MaterialUniform in the shader.

 

I assume you can have multiple uniform buffers, one for the camera and one for the material and you can update both for a single shader. Am I right?

 

 

Ignore. I was talking tosh.

Ok, this is actually driving me crazy...

  1. If I enable v-sync the issue is fixed.
  2. If I disable v-sync and let the program run at 2000+ FPS the issue is fixed.
  3. If I disable v-sync and limit my frame rate to 60 or anything under 60 like let's say 40 FPS using C++ timer my issue comes back.
  4. If I do point 3 and attach RenderDoc to my engine the issue is fixed.
  5. If I only have a single uniform buffer the issue is fixed.
  6. If I increase the number of planes rendered on the screen from 25 planes to 1000 planes the issue is fixed.
  7. if I increase my buffer size to 256 bytes the issue is fixed.
  8. If I only update my materials uniform buffer once the issue is fixed.
  9. If I set the output Color manually in the fragment shader like so (color = vec4(1.0, 0, 0, 1.0);) without using any uniform buffer objects the issue is fixed.

However, in all of these cases, the issue is not really fixed. This is really driving me crazy.....

I tested this one a GTX 970 and GTX 950M and I get the same issue. I would test it on an AMD card if I had one :/

I changed my drivers and that didn't help...

Is there any way I can debug this better? I'm literally getting nowhere...

How are you ensuring your buffers are synced before writing to them again?

3 hours ago, Irusan, son of Arusan said:

How are you ensuring your buffers are synced before writing to them again?

I'm not. I didn't know you had to do that !!

How do you do that?

18 hours ago, FantasyVII said:

I'm not. I didn't know you had to do that !!

How do you do that?

I'm afraid I don't know, exactly. My knowledge of OpenGL is somewhat out of date (I'm using DirectX myself) but you can start reading about it here in the OpenGL docs, and I think you probably want some kind of Fence object.

However, I think your problem is actually a bit more fundamental: your approach of repeatedly updating the same buffer is probably not the correct way to do this. What you likely want to do is set the camera uniform before you start looping over the meshes as it should be constant across your scene, and change the way you pass in the material to have a BufferRange containing the material information that you need to change rarely, if at all, and is again set once before you start looping across the meshes in the scene. You then want each mesh to have a material index defined on it that allows you to identify the correct material within your BufferRange. Doing it this way reduces the number of state changes that the graphics card needs to make and the number of times that things need to be synced up between CPU and GPU, so in general you get more efficient rendering if you change your buffers as rarely as possible.

On 12/8/2018 at 3:36 PM, Irusan, son of Arusan said:

I'm afraid I don't know, exactly. My knowledge of OpenGL is somewhat out of date (I'm using DirectX myself) but you can start reading about it here in the OpenGL docs, and I think you probably want some kind of Fence object.

However, I think your problem is actually a bit more fundamental: your approach of repeatedly updating the same buffer is probably not the correct way to do this. What you likely want to do is set the camera uniform before you start looping over the meshes as it should be constant across your scene, and change the way you pass in the material to have a BufferRange containing the material information that you need to change rarely, if at all, and is again set once before you start looping across the meshes in the scene. You then want each mesh to have a material index defined on it that allows you to identify the correct material within your BufferRange. Doing it this way reduces the number of state changes that the graphics card needs to make and the number of times that things need to be synced up between CPU and GPU, so in general you get more efficient rendering if you change your buffers as rarely as possible.

 

Apologies for the late response. I have had a very busy two weeks.

 

Quote

your approach of repeatedly updating the same buffer is probably not the correct way to do this. What you likely want to do is set the camera uniform before you start looping over the meshes as it should be constant across your scene

 

But I have to do it that way. I have to update my camera buffer before I draw each mesh because each mesh has a different model matrix. I can't simply set the buffer once for all my meshes or every mesh will be at the same position in the world.

 

Quote

and change the way you pass in the material to have a BufferRange containing the material information that you need to change rarely, if at all, and is again set once before you start looping across the meshes in the scene.

 

That I could understand. I could set the material once and rarely change it again. That is fine but the camera buffer though needs to be updated every draw call.

 

Quote

You then want each mesh to have a material index defined on it that allows you to identify the correct material within your BufferRange. Doing it this way reduces the number of state changes that the graphics card needs to make and the number of times that things need to be synced up between CPU and GPU, so in general you get more efficient rendering if you change your buffers as rarely as possible.

 

That is a cool idea. Thanks.

 

But my issue here, again, I thought that constant (DX11) or uniform buffers (GL) allow you to update them before you do a draw call. Like how do I handle this now? I need to update my camera buffer before I do a draw call. I need to update my camera matrices model and view before I do a draw call.

 

 

 

This topic is closed to new replies.

Advertisement