// Compile with c++ -std=c++11 [filepath] -Wall $(pkg-config --cflags --libs sdl2 gl) #define GL_GLEXT_PROTOTYPES #include #include #include #include #include const GLchar * const vertex_shader_source = R"( #version 330 core void main() { gl_Position = vec4( float(gl_VertexID % 2) * 4.0 - 1.0, float(gl_VertexID / 2) * 4.0 - 1.0, 0.5, 1.0); } )"; const GLchar * const fragment_shader_source = R"( #version 330 core void main() { // Uncomment this line to work around the bug // gl_FragDepth = gl_FragCoord.z; // Discard every other column of fragments if (bool((uint(gl_FragCoord.x) % 2u) == 1u)) discard; } )"; int main() { constexpr const auto textureSize = 16u; SDL_Init(SDL_INIT_VIDEO); SDL_Window * const window = SDL_CreateWindow( "Test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 256, 256, SDL_WINDOW_OPENGL); if (!window) { std::cerr << "Could not create window: " << SDL_GetError() << '\n'; return 1; } SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG | SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); SDL_GLContext gl_context = SDL_GL_CreateContext(window); if (gl_context == NULL) { std::cerr << "Could not create OpenGL 3.3 context: " << SDL_GetError() << '\n'; return 1; } GLuint texture; glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexStorage2D(GL_TEXTURE_2D, 1, GL_DEPTH_COMPONENT16, textureSize, textureSize); GLuint framebuffer; glGenFramebuffers(1, &framebuffer); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer); glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, texture, 0); glEnable(GL_DEPTH_TEST); glClear(GL_DEPTH_BUFFER_BIT); const GLenum framebuffer_status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); if (framebuffer_status == GL_FRAMEBUFFER_UNSUPPORTED) { std::cerr << "framebuffer is not supported.\n"; return 1; } // If it is not complete or unsupported, there is a programming error. assert(framebuffer_status == GL_FRAMEBUFFER_COMPLETE); const GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertex_shader, 1, const_cast(&vertex_shader_source), 0); glCompileShader(vertex_shader); { GLint is_compiled; glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &is_compiled); if (is_compiled == GL_FALSE) { GLint max_length; glGetShaderiv(vertex_shader, GL_INFO_LOG_LENGTH, &max_length); char * vertex_info_log = new char[max_length]; glGetShaderInfoLog(vertex_shader, max_length, &max_length, vertex_info_log); std::cerr << "Error compiling vertex shader:\n" << vertex_info_log; return 1; } } const GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragment_shader, 1, const_cast(&fragment_shader_source), 0); glCompileShader(fragment_shader); { GLint is_compiled; glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &is_compiled); if (is_compiled == GL_FALSE) { GLint max_length; glGetShaderiv(fragment_shader, GL_INFO_LOG_LENGTH, &max_length); char * fragment_info_log = new char[max_length]; glGetShaderInfoLog(fragment_shader, max_length, &max_length, fragment_info_log); std::cerr << "Error compiling fragment shader:\n" << fragment_info_log; return 1; } } const GLuint shader_program = glCreateProgram(); glAttachShader(shader_program, vertex_shader); glAttachShader(shader_program, fragment_shader); glLinkProgram(shader_program); { GLint is_linked; glGetProgramiv(shader_program, GL_LINK_STATUS, &is_linked); if (is_linked == GL_FALSE) { GLint max_length; glGetProgramiv(shader_program, GL_INFO_LOG_LENGTH, &max_length); char * program_info_log = new char[max_length]; glGetProgramInfoLog(shader_program, max_length, &max_length, program_info_log); std::cerr << "Error linking shader:\n" << program_info_log; return 1; } } glUseProgram(shader_program); GLuint vertex_array; glGenVertexArrays(1, &vertex_array); glBindVertexArray(vertex_array); glDrawArrays(GL_TRIANGLES, 0, 3); GLushort colour[textureSize][textureSize]; glGetTexImage(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, &colour); assert(glGetError() == GL_NO_ERROR); std::cout << colour[0][0] << ", " << colour[1][0] << ", " << colour[2][1] << ", " << colour[3][1] << "\n"; // column 0 should have been drawn over. assert(colour[0][0] < 57343); assert(colour[1][0] < 57343); // column 1 should not haven been draw over due to discards. // It was cleared beforehand. assert(colour[2][1] == 65535); assert(colour[3][1] == 65535); SDL_GL_DeleteContext(gl_context); SDL_DestroyWindow(window); SDL_Quit(); }