#if 0 #/* # * Reduced test case for tessellation problem with radeonsi. # * # * Usage: sh tessellation.cpp # * # * Requirements: SDL 2, libepoxy # */ input="$0" output="${input%.*}" "${CXX:-g++}" "$input" -o "$output" -lSDL2 -lepoxy -std=c++11 || exit 1 exec "$output" exit 1 #endif #include #include #include #include #include static GLAPIENTRY void debug_callback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar * message, const void * userParam) { std::cerr << "GL debug: " << message << '\n'; } static int init_debug() { glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); glDebugMessageCallbackARB(debug_callback, 0); glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, 0, GL_TRUE); std::string debug_message = "GL debug output enabled"; glDebugMessageInsertARB(GL_DEBUG_SOURCE_APPLICATION_ARB, GL_DEBUG_TYPE_OTHER_ARB, 1, GL_DEBUG_SEVERITY_LOW_ARB, debug_message.size(), debug_message.c_str()); } static const GLuint vertex_attrib_location = 0; static const char vertex_shader[] = R"glsl( #version 330 in vec2 vertex_position; out vec2 corner_position; void main() { corner_position = vertex_position * 0.8; } )glsl"; static const char tessellation_control_shader[] = R"glsl( #version 330 #extension GL_ARB_tessellation_shader : enable layout(vertices = 4) out; in vec2 corner_position[]; out vec2 corner_positions[]; patch out vec4 patch_color; uniform int invocation; void main() { corner_positions[gl_InvocationID] = corner_position[gl_InvocationID]; if(gl_InvocationID == invocation) { gl_TessLevelInner[0] = 3; gl_TessLevelInner[1] = 3; gl_TessLevelOuter[0] = 3; gl_TessLevelOuter[1] = 3; gl_TessLevelOuter[2] = 3; gl_TessLevelOuter[3] = 3; } barrier(); if(gl_InvocationID == 0) { patch_color = vec4(gl_TessLevelOuter[3] / 3.f, 1.f, 0.f, 1.f); } } )glsl"; static const char tessellation_evaluation_shader[] = R"glsl( #version 330 #extension GL_ARB_tessellation_shader : enable layout(quads, fractional_odd_spacing, ccw) in; in vec2 corner_positions[]; patch in vec4 patch_color; out vec4 color; void main() { color = patch_color; vec2 a = mix(corner_positions[0], corner_positions[1], gl_TessCoord.x); vec2 b = mix(corner_positions[3], corner_positions[2], gl_TessCoord.x); vec2 pos = mix(a, b, gl_TessCoord.y); gl_Position = vec4(pos, 0.f, 1.f); } )glsl"; static const char fragment_shader[] = R"glsl( #version 330 in vec4 color; void main() { gl_FragColor = color; } )glsl"; static void compile_shader(GLuint program, GLenum type, const char * source) { GLuint vertex = glCreateShader(type); glShaderSource(vertex, 1, &source, 0); glCompileShader(vertex); glAttachShader(program, vertex); } static GLuint compile_program() { GLuint program = glCreateProgram(); compile_shader(program, GL_VERTEX_SHADER, vertex_shader); compile_shader(program, GL_TESS_CONTROL_SHADER, tessellation_control_shader); compile_shader(program, GL_TESS_EVALUATION_SHADER, tessellation_evaluation_shader); compile_shader(program, GL_FRAGMENT_SHADER, fragment_shader); glBindAttribLocation(program, vertex_attrib_location, "vertex_position"); glLinkProgram(program); return program; } int main() { SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); 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 = 800, h = 600; Uint32 flags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; SDL_Window * window = SDL_CreateWindow("tessellation", x, y, w, h, flags); SDL_GLContext context = SDL_GL_CreateContext(window); SDL_GL_SetSwapInterval(1); std::cout << "GL version: " << glGetString(GL_VERSION) << '\n'; init_debug(); glViewport(0, 0, w, h); GLuint program = compile_program(); glUseProgram(program); GLuint vao; glCreateVertexArrays(1, &vao); glBindVertexArray(vao); GLuint vbo; glCreateBuffers(1, &vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo); float data[][2] = { { -1.f, -1.f }, { -1.f, 1.f }, { 1.f, 1.f }, { 1.f, -1.f }, }; glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW); glVertexAttribPointer(vertex_attrib_location, 2, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(vertex_attrib_location); glPatchParameteri(GL_PATCH_VERTICES, 4); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); GLint invocation = 0; GLint instance_location = glGetUniformLocation(program, "invocation"); bool invocation_changed = true; if(glGetError()) { return 1; } while(true) { SDL_Event event; while(SDL_PollEvent(&event)) { switch(event.type) { case SDL_WINDOWEVENT: { if(event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) { w = event.window.data1, h = event.window.data2; glViewport(0, 0, w, h); } break; } case SDL_KEYDOWN: { switch(event.key.keysym.sym) { case SDLK_DOWN: case SDLK_LEFT: { invocation = (invocation + 3) % 4; invocation_changed = true; break; } case SDLK_UP: case SDLK_RIGHT: { invocation = (invocation + 1) % 4; invocation_changed = true; break; } case SDLK_SPACE: case SDLK_RETURN: { invocation = (invocation == 3 ? 0 : 3); invocation_changed = true; break; } case SDLK_q: case SDLK_ESCAPE: { return 0; } } break; } case SDL_QUIT: return 0; } } if(invocation_changed) { std::cout << "if(gl_InvocationID == " << invocation << ") { … }" << '\n'; glUniform1i(instance_location, invocation); invocation_changed = false; } glClearColor(0.f, 0.f, 0.f, 0.f); glClear(GL_COLOR_BUFFER_BIT); glDrawArrays(GL_PATCHES, 0, 4); SDL_GL_SwapWindow(window); } return 1; }