Skip to content

Instantly share code, notes, and snippets.

Created December 6, 2013 06:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/7819317 to your computer and use it in GitHub Desktop.
Save anonymous/7819317 to your computer and use it in GitHub Desktop.
Testcase for AMD Linux GL driver bug: imageStore stops working after using glTexImage2D to resize GL_R32UI texture
#if 0
#
# Testcase for AMD Linux GL driver bug:
# imageStore stops working after using glTexImage2D to resize GL_R32UI texture
#
# Description: The screen should be green, which indicates that imageStore
# successfully wrote the value. Press any key to resize the texture, which triggers
# the bug (screen turns blue).
# Bonus: red means your GPU/driver is potato.
#
input="$0"
output="${input%.*}"
"${CXX:-g++}" "$input" -o "$output" -lSDL2 -lGLEW -lGL || exit 1
exec "$output"
exit 1
#endif
#include <iostream>
#include <iomanip>
#include <string>
#include <SDL2/SDL.h>
#include <GL/glew.h>
#ifdef _WIN32
#define MY_GLAPIENTRY __stdcall
#else
#define MY_GLAPIENTRY
#endif
static MY_GLAPIENTRY void debug_callback(GLenum source, GLenum type, GLuint id,
GLenum severity, GLsizei length,
const GLchar * message, void * userParam)
{
std::cerr << "GL debug: " << message << '\n';
}
int init_debug()
{
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
glDebugMessageCallback(debug_callback, 0);
glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, 0, GL_TRUE);
std::string debug_message = "GL debug output enabled";
glDebugMessageInsert(GL_DEBUG_SOURCE_APPLICATION_ARB, GL_DEBUG_TYPE_OTHER_ARB,
1, GL_DEBUG_SEVERITY_LOW_ARB, debug_message.size(),
debug_message.c_str());
}
void allocate_texture(GLuint texture, GLsizei s)
{
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32UI, s, s, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, 0);
glBindTexture(GL_TEXTURE_2D, GL_NONE);
}
void check_fbo(GLuint fbo)
{
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
glBindFramebuffer(GL_FRAMEBUFFER, GL_NONE);
if (status != GL_FRAMEBUFFER_COMPLETE) {
std::cerr << "GL framebuffer errror: 0x" << std::hex << status << std::endl;
}
}
static const GLuint vertex_attrib_location = 0;
const char vertex_source[] =
"#version 430 core\n"
"in vec3 vertex_position;\n"
"void main() {\n"
" gl_Position = vec4(vertex_position, 1.0f);\n"
"}\n";
const char fragment_write_source[] =
"#version 430 core\n"
"layout(binding = 0, r32ui) coherent uniform uimage2D integer_image;\n"
"void main() {\n"
" imageStore(integer_image, ivec2(0, 0), uvec4(42));\n"
"}\n";
const char fragment_read_source[] =
"#version 430 core\n"
"layout(binding = 0) uniform usampler2D integer_texture;\n"
"void main() {\n"
" uint value = texelFetch(integer_texture, ivec2(0, 0), 0)[0];\n"
" if (value == 42) {\n"
" // good (stored color)\n"
" gl_FragColor = vec4(0.0f, 1.0f, 0.0f, 1.0f);\n"
" } else if (value == 0) {\n"
" // bad (clear color)\n"
" gl_FragColor = vec4(0.0f, 0.0f, 1.0f, 1.0f);\n"
" } else {\n"
" // wtf (garbage)\n"
" gl_FragColor = vec4(1.0f, 0.0f, 0.0f, 1.0f);\n"
" }\n"
"}\n";
void link_shader(GLuint program, GLenum type, const char * source)
{
GLuint vertex = glCreateShader(type);
glShaderSource(vertex, 1, &source, 0);
glCompileShader(vertex);
glAttachShader(program, vertex);
}
GLuint link_program(const char * fragment_source)
{
GLuint program = glCreateProgram();
link_shader(program, GL_VERTEX_SHADER, vertex_source);
link_shader(program, GL_FRAGMENT_SHADER, fragment_source);
glBindAttribLocation(program, vertex_attrib_location, "vertex_position");
glLinkProgram(program);
return program;
}
int main()
{
//////////////////////////////////////////////////////////////////////////////////////
// Window and context creation
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
int x = SDL_WINDOWPOS_UNDEFINED, y = SDL_WINDOWPOS_UNDEFINED;
int w = 1024, h = 768;
SDL_Window * window = SDL_CreateWindow("driver bug", x, y, w, h, SDL_WINDOW_OPENGL);
SDL_GLContext context = SDL_GL_CreateContext(window);
glewInit();
(void)glGetError(); // broken libs
std::cout << "GL version: " << glGetString(GL_VERSION) << '\n';
init_debug();
glViewport(0, 0, w, h);
//////////////////////////////////////////////////////////////////////////////////////
// Create objects
GLuint texture;
glGenTextures(1, &texture);
allocate_texture(texture, 8);
GLuint clear_fbo;
glGenFramebuffers(1, &clear_fbo);
glBindFramebuffer(GL_FRAMEBUFFER, clear_fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glBindFramebuffer(GL_FRAMEBUFFER, GL_NONE);
check_fbo(clear_fbo);
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
float data[][3] = {
{ -1.f, -1.f, 0.f },
{ -1.f, 1.f, 0.f },
{ 1.f, -1.f, 0.f },
{ 1.f, 1.f, 0.f }
};
glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
glVertexAttribPointer(vertex_attrib_location, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(vertex_attrib_location);
// keep bound
GLuint write_program = link_program(fragment_write_source);
GLuint read_program = link_program(fragment_read_source);
//////////////////////////////////////////////////////////////////////////////////////
// Render loop
while (true) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT: return 0;
case SDL_KEYDOWN: {
// Trigger the driver bug
// Any size differing from the original breaks it
allocate_texture(texture, 16);
check_fbo(clear_fbo);
break;
}
}
}
// Clear the texture
glBindFramebuffer(GL_FRAMEBUFFER, clear_fbo);
glClearColor(0.f, 0.f, 0.f, 0.f);
glClear(GL_COLOR_BUFFER_BIT);
glBindFramebuffer(GL_FRAMEBUFFER, GL_NONE);
glMemoryBarrier(GL_ALL_BARRIER_BITS);
// Write to the texture
glDrawBuffer(GL_NONE);
glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
glUseProgram(write_program);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glMemoryBarrier(GL_ALL_BARRIER_BITS);
// Read the texture, render to backbuffer
glDrawBuffer(GL_BACK);
glBindTexture(GL_TEXTURE_2D, texture);
glUseProgram(read_program);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
SDL_GL_SwapWindow(window);
if (GLenum error = glGetError()) {
std::cerr << "GL error 0x" << std::hex << error << std::endl;
break;
}
}
return 1;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment