Created
December 7, 2013 03:44
-
-
Save anonymous/7837036 to your computer and use it in GitHub Desktop.
Minimal code example to re-produce a glGenerateTextureMipmapEXT related bug found in the AMD OpenGL driver.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Minimal code example to re-produce a bug found in the AMD OpenGL driver. | |
// The problem occurs when using glGenerateTextureMipmapEXT in conjunction | |
// with glTextureStorage2DEXT, which results in no mip maps being generated | |
// and no errors being captured by glGetError or ARB_debug_output. | |
// This program should produce a red screen if there is no driver bug. | |
#include <GL/glew.h> | |
#include <GLFW/glfw3.h> | |
#include <stdlib.h> | |
#include <stdio.h> | |
#include <string.h> | |
#define GLSL(src) "#version 430 core\n" #src | |
enum VERTEX_ATTRIB | |
{ | |
POSITION_ATTRIB, | |
TEXCOORD_ATTRIB | |
}; | |
void debug_callback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *msg, GLvoid *data) | |
{ | |
printf("OpenGL debug: %s\n", msg); | |
} | |
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) | |
{ | |
if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) | |
glfwSetWindowShouldClose(window, GL_TRUE); | |
} | |
void init_debug() | |
{ | |
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); | |
glDebugMessageCallback(debug_callback, NULL); | |
glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE); | |
const char debug_message[] = "Debug output enabled."; | |
glDebugMessageInsert(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_OTHER, 0, GL_DEBUG_SEVERITY_LOW, sizeof(debug_message), debug_message); | |
} | |
GLuint create_program(const char *vertex_source, const char *fragment_source) | |
{ | |
GLuint vs = glCreateShader(GL_VERTEX_SHADER); | |
glShaderSource(vs, 1, &vertex_source, NULL); | |
glCompileShader(vs); | |
unsigned int fs = glCreateShader(GL_FRAGMENT_SHADER); | |
glShaderSource(fs, 1, &fragment_source, NULL); | |
glCompileShader(fs); | |
GLuint shader_program = glCreateProgram(); | |
glAttachShader(shader_program, fs); | |
glAttachShader(shader_program, vs); | |
glLinkProgram(shader_program); | |
return shader_program; | |
} | |
const char* vertex_shader = GLSL( | |
layout(location = 0) in vec3 vertex_position; | |
layout(location = 1) in vec2 vertex_tex_coord; | |
out vec2 tex_coord; | |
void main() | |
{ | |
tex_coord = vertex_tex_coord; | |
gl_Position = vec4(vertex_position, 1.0); | |
} | |
); | |
const char* fragment_shader = GLSL( | |
layout(location = 0) uniform sampler2D texture; | |
in vec2 tex_coord; | |
out vec4 frag_color; | |
void main() | |
{ | |
frag_color = textureLod(texture, tex_coord, tex_coord.x * 9.0); | |
} | |
); | |
int main(int argc, char *argv[]) | |
{ | |
if(!glfwInit()) | |
exit(EXIT_FAILURE); | |
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); | |
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); | |
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); | |
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); | |
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); | |
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE); | |
GLFWwindow* window = glfwCreateWindow(512, 512, "OpenGL", NULL, NULL); | |
if(!window) | |
{ | |
glfwTerminate(); | |
exit(EXIT_FAILURE); | |
} | |
glfwSetKeyCallback(window, key_callback); | |
glfwMakeContextCurrent(window); | |
GLenum glewError = glewInit(); | |
if(glewError != GLEW_OK) | |
{ | |
glfwTerminate(); | |
exit(EXIT_FAILURE); | |
} | |
printf("OpenGL version: %s\n", glGetString(GL_VERSION)); | |
init_debug(); | |
float position[] = | |
{ | |
1.0f, 1.0f, 0.0f, | |
-1.0f, 1.0f, 0.0f, | |
1.0f, -1.0f, 0.0f, | |
-1.0f, -1.0f, 0.0f | |
}; | |
float texcoord[] = | |
{ | |
1.0f, 0.0f, | |
0.0f, 0.0f, | |
1.0f, 1.0f, | |
0.0f, 1.0f | |
}; | |
unsigned short indices[] = | |
{ | |
1, 0, 2, | |
3, 1, 2 | |
}; | |
GLuint index_buffer = 0; | |
GLuint vertex_buffers[2] = {0}; | |
glGenBuffers(1, &index_buffer); | |
glGenBuffers(2, vertex_buffers); | |
glNamedBufferDataEXT(index_buffer, sizeof(indices), &indices, GL_STATIC_DRAW); | |
glNamedBufferDataEXT(vertex_buffers[POSITION_ATTRIB], sizeof(position), &position, GL_STATIC_DRAW); | |
glNamedBufferDataEXT(vertex_buffers[TEXCOORD_ATTRIB], sizeof(texcoord), &texcoord, GL_STATIC_DRAW); | |
GLuint vao = 0; | |
glGenVertexArrays(1, &vao); | |
glVertexArrayVertexAttribOffsetEXT(vao, vertex_buffers[POSITION_ATTRIB], POSITION_ATTRIB, 3, GL_FLOAT, GL_FALSE, 0, 0); | |
glEnableVertexArrayAttribEXT(vao, POSITION_ATTRIB); | |
glVertexArrayVertexAttribOffsetEXT(vao, vertex_buffers[TEXCOORD_ATTRIB], TEXCOORD_ATTRIB, 2, GL_FLOAT, GL_FALSE, 0, 0); | |
glEnableVertexArrayAttribEXT(vao, TEXCOORD_ATTRIB); | |
glBindVertexArray(vao); | |
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer); | |
GLuint shader_program = create_program(vertex_shader, fragment_shader); | |
glUseProgram(shader_program); | |
glProgramUniform1i(shader_program, 0, 0); | |
// Set up a buffer for an all red 512x512 RBGA image | |
unsigned int* image_buffer = (unsigned int*)malloc(512*512*4); | |
unsigned int i; | |
for(i = 0; i < 512*512; i++) | |
image_buffer[i] = 0xFF0000FF; | |
/* ######################## HERE BE DRAGONS ######################## */ | |
GLuint texture = 0; | |
glGenTextures(1, &texture); | |
glTextureStorage2DEXT(texture, GL_TEXTURE_2D, 10, GL_RGBA8, 512, 512); | |
glTextureSubImage2DEXT(texture, GL_TEXTURE_2D, 0, 0, 0, 512, 512, GL_RGBA, GL_UNSIGNED_BYTE, image_buffer); | |
// if we add glBindTexture(GL_TEXTURE_2D, texture); here it will work for some odd reason | |
glGenerateTextureMipmapEXT(texture, GL_TEXTURE_2D); | |
glBindMultiTextureEXT(GL_TEXTURE0, GL_TEXTURE_2D, texture); | |
/* ######################## HERE BE DRAGONS ######################## */ | |
free(image_buffer); | |
GLuint trilinear = 0; | |
glGenSamplers(1, &trilinear); | |
glSamplerParameteri(trilinear, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
glSamplerParameteri(trilinear, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
glSamplerParameteri(trilinear, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); | |
glSamplerParameteri(trilinear, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
glBindSampler(0, trilinear); | |
while(!glfwWindowShouldClose(window)) | |
{ | |
glClear(GL_COLOR_BUFFER_BIT); | |
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, NULL); | |
glfwSwapBuffers(window); | |
glfwPollEvents(); | |
} | |
glfwDestroyWindow(window); | |
glfwTerminate(); | |
exit(EXIT_SUCCESS); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment