// Compile with c++ [filepath] -std=c++11 -Wall $(pkg-config --cflags --libs sdl2 gl) #define GL_GLEXT_PROTOTYPES #include #include #include #include #include #define GL_ZERO_TO_ONE 0x935F 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 layout(location = 0) out vec4 c; void main() { c = vec4(1.0); } )"; int main() { constexpr const auto textureSizeX = 1u; constexpr const auto textureSizeY = 5u; SDL_Init(SDL_INIT_VIDEO); SDL_Window * const window = SDL_CreateWindow( "Test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, 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; } // Setting GL_CLIP_ORIGIN to GL_UPPER_LEFT is necessary to reproduce // the bug. typedef void (APIENTRYP PFNGLCLIPCONTROLPROC) (GLenum origin, GLenum depth); const auto glClipControl = reinterpret_cast( SDL_GL_GetProcAddress("glClipControl")); glClipControl(GL_UPPER_LEFT, GL_ZERO_TO_ONE); GLuint texture; glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexStorage2D(GL_TEXTURE_2D, 1, GL_R8, textureSizeX, textureSizeY); GLuint framebuffer; glGenFramebuffers(1, &framebuffer); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer); glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0); const GLenum framebuffer_status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); assert(framebuffer_status == GL_FRAMEBUFFER_COMPLETE); glClear(GL_COLOR_BUFFER_BIT); 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); glViewport(0,1,1,3); GLuint vertex_array; glGenVertexArrays(1, &vertex_array); glBindVertexArray(vertex_array); glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); GLfloat colours[textureSizeX * textureSizeY]; glGetTexImage(GL_TEXTURE_2D, 0, GL_RED, GL_FLOAT, colours); assert(glGetError() == GL_NO_ERROR); std::cout << colours[0] << ", " << colours[2] << "\n"; // This was outside the viewport, so should be black from the clear assert(colours[0] == 0.0f); // This was inside the viewport, so should be red from the draw assert(colours[2] == 1.0f); // Expected output is "1, 0". SDL_GL_DeleteContext(gl_context); SDL_DestroyWindow(window); SDL_Quit(); }