Odd texture flickering/repositioning problem

Started by adambiser, September 21, 2014, 23:41:19

Previous topic - Next topic

adambiser

EDIT: Unless I figure something else out, I'm chalking this up to a bad card or drivers.  Using only vertex and fragment shaders works fine, but the presence of a geometry shader makes the card glitch.

Hello, I have a strange problem that has baffled me for a couple days now.  I've searched but haven't found anything that sounded like this problem.

I have a tile-based map that is 100 tiles wide and 20 tiles high (hard coded for testing).  I have a buffer set up that contains the map tile codes and map xy coordinates for each tile code.  I have shaders set up to take the map tile code and xy coordinates and render textured quads from them.  I'm using a 256x256 pixel tile atlas for the texture.  I'm currently sending all map tiles to the shader and letting the viewport handle what gets drawn.

The game renders correctly on one computer, but on another I get a strange flicker.  I've attached a screenshot of how it looks when the flicker is not happening and one when it is.  No values are changing between renders, so the image should be static.  Different areas flicker for a frame.  It looks like strands of 8 tiles are being drawn in the wrong position, but I can't figure out why.

Has anyone experienced anything like this?

Thanks for any help and suggestions!

For anyone curious, here is my render code:
               GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
		// Start the shader
		GL20.glUseProgram(this.shader.getProgramID());
		GL20.glUniformMatrix4(this.shader.projectionMatrixLocation, false, DisplayHelper.screenProjectionMatrix);
		GL20.glUniform1i(this.shader.textureSamplerLocation, 0);
		// Set up the texture.
		GL13.glActiveTexture(GL13.GL_TEXTURE0);
		GL11.glBindTexture(GL11.GL_TEXTURE_2D, this.texture.textureID);
		// Set up the data buffer.
		GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, this.bufferHandle);
		GL15.glBufferData(GL15.GL_ARRAY_BUFFER, this.buffer, GL15.GL_STATIC_DRAW);
		// Set up the vertex attrib pointers.
		GL20.glEnableVertexAttribArray(0);
		GL20.glEnableVertexAttribArray(1);
		GL20.glVertexAttribPointer(0, 1, GL11.GL_FLOAT, false, TILE_CODE_STRIDE, TILE_CODE_OFFSET);
		GL20.glVertexAttribPointer(1, 2, GL11.GL_FLOAT, false, POSITION_STRIDE, POSITION_OFFSET);
		// Draw.
		GL11.glDrawArrays(GL11.GL_POINTS, 0, TILES_ON_SCREEN);
		// Clean up.
		GL20.glDisableVertexAttribArray(0);
		GL20.glDisableVertexAttribArray(1);
		GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
		GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
		GL20.glUseProgram(0);


My shader code. I have them all in one file and separate them by name using anything above the first name (#version 330 core) in all three.
#version 330 core

>> vertex <<

layout(location = 0) attribute in float TileCode;
layout(location = 1) attribute in vec2 VertexPosition;

out int tile;

void main() {
	tile = int(TileCode);
	gl_Position = vec4(VertexPosition, 0.0, 1.0);
}

>> geometry <<

layout(points) in;
layout(triangle_strip, max_vertices=4) out;

const int TILES_PER_TEXTURE_ROW = 16;
const float TILE_DRAW_SIZE = 16.0;
const float TEXTURE_SIZE = 256.0;

uniform mat4 projectionMatrix;

in int tile[];

out vec2 texCoord;

void main() {
	int code = tile[0];
	if (code == 0) {
		return;
	}
	// Set up the tile bound points.
	vec4 topLeft = gl_in[0].gl_Position;
	topLeft.x = topLeft.x * TILE_DRAW_SIZE;
	topLeft.y = topLeft.y * TILE_DRAW_SIZE;
	vec4 bottomRight = topLeft;
	bottomRight.x += TILE_DRAW_SIZE;
	bottomRight.y += TILE_DRAW_SIZE;
	// Calculate tile texture coordinates.
	int cx = code % TILES_PER_TEXTURE_ROW;
	int cy = code / TILES_PER_TEXTURE_ROW;
	float tx = (float(cx) * TILE_DRAW_SIZE) / TEXTURE_SIZE;
	float ty = (float(cy) * TILE_DRAW_SIZE) / TEXTURE_SIZE;
	float tx2 = (float(cx + 1) * TILE_DRAW_SIZE) / TEXTURE_SIZE;
	float ty2 = (float(cy + 1) * TILE_DRAW_SIZE) / TEXTURE_SIZE;
	// Top left.
	gl_Position = projectionMatrix * vec4(topLeft.x, topLeft.y, 0.0, 1.0);
	texCoord = vec2(tx, ty);
	EmitVertex();
	// Top right.
	gl_Position = projectionMatrix * vec4(bottomRight.x, topLeft.y, 0.0, 1.0);
	texCoord = vec2(tx2, ty);
	EmitVertex();
	// Bottom left.
	gl_Position = projectionMatrix * vec4(topLeft.x, bottomRight.y, 0.0, 1.0);
	texCoord = vec2(tx, ty2);
	EmitVertex();
	// Bottom right.
	gl_Position = projectionMatrix * vec4(bottomRight.x, bottomRight.y, 0.0, 1.0);
	texCoord = vec2(tx2, ty2);
	EmitVertex();
	EndPrimitive();
}

>> fragment <<

layout(location = 0) out vec4 FragColor;

uniform sampler2D Texture0;

in vec2 texCoord;

void main() {
//	FragColor = vec4(1.0, 1.0, 1.0, 1.0);
	FragColor = texture2D(Texture0, texCoord);
}

Cornix

Do you have VSync enabled? If not, try enabling it.

adambiser

Quote from: Cornix on September 21, 2014, 23:45:19
Do you have VSync enabled? If not, try enabling it.
I did not, but the problem still exists after turning it on.

Is it possible for video cards to just go glitchy if attempting to render too far outside of the viewport?

If instead of sending the entire map buffer to the shaders, I tried this:
for (int y = 0; y < 14; y++) {
			GL11.glDrawArrays(GL11.GL_POINTS, y * TILES_WIDE, 16);
		}

The flickering goes away, but changing the 16 to 30 makes it come back.  But even if I change the geometry shader so it doesn't do anything with tiles that are not going to be drawn, the glitch still happens with 30.

Cornix

I am not going to read through your entire code, I dont have the time for that. But its possible that you are making a mistake somewhere and 2 different drivers of 2 different graphics cards behave differently to this error. Not every error will cause a crash, and not every error will be registered as an error. Sometimes its just undefined behavior, I had that too once.

Try to make it simpler. Try to slim down your program to the bare basics and test from there until you find the cause of the error.

abcdef

I had some flickering issues when I was doing some development and it turned out to be a depth problem. I increased the depth buffer when I created the display and it fixed the issue.

adambiser

Quote from: Cornix on September 22, 2014, 10:47:45
I am not going to read through your entire code, I dont have the time for that. But its possible that you are making a mistake somewhere and 2 different drivers of 2 different graphics cards behave differently to this error. Not every error will cause a crash, and not every error will be registered as an error. Sometimes its just undefined behavior, I had that too once.

Try to make it simpler. Try to slim down your program to the bare basics and test from there until you find the cause of the error.
I only included the code for anyone who felt like looking at it.  I tried to explain the description of the problem at the top so that the code wouldn't be necessary and would hopefully sounds similar to a problem someone else had.  The code is about as slimmed down as it can get, I think.  What I gave is basically my program, except for setting up the Display, shaders, and data buffers, which I didn't think would be relevant.

I'm beginning to think that the problematic card just doesn't handle geometry shaders well.  If I don't glBindBuffer my data every single frame, I get this glitch no matter what count I use for glDrawArrays.

adambiser

Quote from: abcdef on September 22, 2014, 12:06:05
I had some flickering issues when I was doing some development and it turned out to be a depth problem. I increased the depth buffer when I created the display and it fixed the issue.
I had actually disabled depth testing since it's a 2D game.  I just tried enabling it and the glitch persisted.

Thanks to everyone for their suggestions so far.

abcdef

have a look at this too

GL15.glBufferData(GL15.GL_ARRAY_BUFFER, this.buffer, GL15.GL_STATIC_DRAW);


You are saying the data is static but you are updating it every render cycle. Maybe change that to GL_STREAM_DRAW.

adambiser

Quote from: abcdef on September 23, 2014, 08:24:28
have a look at this too

GL15.glBufferData(GL15.GL_ARRAY_BUFFER, this.buffer, GL15.GL_STATIC_DRAW);


You are saying the data is static but you are updating it every render cycle. Maybe change that to GL_STREAM_DRAW.
I found that if I didn't glBufferData the data every frame (despite that the buffer data had not changed), the glitching is even worse.  I didn't try GL_STREAM_DRAW though.  I'll see about doing that.

In order to be able to move ahead, I took out the geometry shaders and did all the vertex and texture calculation in the Java code and glBufferData'ing that data.  Without the geometry shader, glBufferData behaves as expected and isn't needed every frame.

I wonder if my video card doesn't like having "float" as an vertex shader input array.  Seems strange if that's true, but it'll be worth a shot when I get the chance to work on the code later.

adambiser

I think either my video card is crap (NVIDIA Quadro NVS 295) or drivers are and I haven't found drivers to fix it (tried 311.35 and 340.66 so far).  The problematic system is not one on which I play games often or use graphics-intensive software (obviously, given the age), so I don't know if this glitching occurs in other programs or not.

Things I've noticed:

  • Hard-coding the geometry shader to always choose the same tile still glitches.
  • When I change the fragment shader to use a solid color instead of the texture, every tile will be that color and there will be no glitching.
  • Hard-coding the fragment shader to use the same texture coordinates everywhere (using a spot that always has color), it still glitches.
  • If I move texture coordinate calculation into the vertex shader (removing it from the geometry shader), the glitching reduces, but is still there.
  • If I get rid of the geometry shader and instead calculate all the vertex and texture coordinates in my code and send them via buffer that to the shader (after making adjustments to handle the new data in the shader also), things work as expected.

I chose to do the last one for now, but left things so that I can switch over to try out new ideas to fix the geometry shader problem as I think of them.

If I figure out the cause, I will be sure to post here.