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!