Strange texture flickering/repositioning problem

Started by
4 comments, last by adambiser 9 years, 7 months ago

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'm new to the forums and hope that I have the right place. I've searched, but didn't find a topic that seemed to be about the problem I'm having. I'm using Java and LWJGL, which uses OpenGL, and I get a strange flickering or repositioning problem with one of the video cards on which I've tested.

My game uses the NES resolution of 256x224, and I'm using a tile atlas texture that is 256x256 pixels and contains textures that are 16x16 pixels. I'm passing a vertex buffer containing map tile codes and their map coordinates to my shaders. The geometry shader then emits a 4 vertex triangle strip to make a quad from the given point and calculates the UV texture coordinates based on the map tile passed it.

I have tested my code on two systems, both Win 7x64. The problem occurs only on one machine, which has an NVIDIA Quadro NVS 295, and it has this problem using both 311.35 and 340.66 drivers. The system that works has an NVIDIA GeForce 9400 GT with 311.06.

It's hard for me to describe the problem, so I've attached an image of what it should look like (screen-good.png) and a shot of the flickering when it occurs (screen-bad.png). This flicker only happens for a frame and it's not always the same spot on the screen. I'm not changing any values and I've tried to strip things down to the most basic code in an attempt to track down the problem. As the screenshot shows, it's sometimes drawing the wrong tiles in the wrong place and not drawing certain areas. My "map" is 100 tiles by 14 tiles, so it is drawing outside the viewport/screen.

As a side note, which may or may not be important, if I use "FragColor = vec4(1.0, 1.0, 1.0, 1.0);" as my fragment shader, the screen will be white as expected and no flickering will occur.

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;

const float TILE_DRAW_SIZE = 16.0;

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);
}

Am I missing something that might be causing things to fail on one card, but not the other?

If I need to post more code, let me know. I posted what I thought would be most relavent.

Thanks for any help!

Advertisement

Looks like that row of tiles that's missing has been moved up two tiles.

Strange.. could be just a driver problem, but try glVertexAttribIPointer and use actual integer data, and write your shader code so there are no conversions from floats to integers. If it's still strange try to redesign so you don't use integers at all. It looks like that card is pretty old, and probably driver-updates don't address it anymore.

My guess is a driver problem as well, but this is my first attempt at using geometry shaders and getting away from immediate mode, so I thought it could easily be something I've overlooked.

Since it was quicker to change the shader code so it only uses floats, I did that first and the flickering still persists. I will try passing integer data only soon.

The only work around I've found is to do this:


		for (int y = 0; y < 14; y++) {
			GL11.glDrawArrays(GL11.GL_POINTS, y * TILES_WIDE, 16);
		}

Since 16 is the width of the viewport in tiles. (Hard coded numbers just for demonstration.) The glitch doesn't become noticeable until I change the count from 16 to 20, which would mean 4 tiles off the right side of the viewport.

I'll have to dig around and see about finding some older drivers for this card, too.

I tried passing in integer data, but could not get that to work either because of my card/drivers or because of something I overlooked in the code.

I'm wondering if the geometry shader support in this card is just really bad. If I glBufferData my data right after loading it and then remove the glBufferData call from my render loop, I get the glitching back even with small sizes. But if I do a glBufferData right before glDrawArrays. the glitching stops. I'll have to try things out without a geometry shader when I get the chance to see if that's really the issue.

It's really pointing toward a bad card / driver, but I've not noticed these issues before.

A geometry shader is definitely not needed and not very useful, but doesn't seem to be your problem. Try hardcoding the texture coords so it always pics a specific tile. Is part of your texture atlas black? Can you make it green to very it is actually using your texture and not some random texture/memory that happens to be cleared to all black?

NBA2K, Madden, Maneater, Killing Floor, Sims http://www.pawlowskipinball.com/pinballeternal

A geometry shader is definitely not needed and not very useful, but doesn't seem to be your problem. Try hardcoding the texture coords so it always pics a specific tile. Is part of your texture atlas black? Can you make it green to very it is actually using your texture and not some random texture/memory that happens to be cleared to all black?

I saw the geometry shader as something that would make a simple tile-based game very easy.

Every tile on the atlas had something in it, even if just grid lines at the border.

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. However, I think this can probably just be chalked up as a bad video card or bad drivers and I haven't found drivers to fix it yet. 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.

This topic is closed to new replies.

Advertisement