I'm trying to render the typical OpenGL color triangle in a gamma correct way by following this guide and consulting the SDL2 documentation on how to enable SRGB support on the default framebuffer.
This is the code I've written, which draws the triangle:
#include <SDL.h>
// Header file generated with glLoadGen
#include "gl_core_3_3.h"
#include <cstdlib>
void sdl_loop(SDL_Window* window);
static const char* const vertexSource = R"(
#version 330
in vec2 position;
in vec3 color;
out vec3 vs_color;
void main()
{
gl_Position = vec4(position, 0.0, 1.0);
vs_color = color;
}
)";
static const char* const fragmentSource = R"(
#version 330
in vec3 vs_color;
out vec4 fragColor;
void main()
{
fragColor = vec4(vs_color, 1.0);
}
)";
static const float vertices[] = {
// X Y R G B
-0.9f, -0.9f, 1.0f, 0.0f, 0.0f,
0.9f, -0.9f, 0.0f, 1.0f, 0.0f,
0.0f, 0.9f, 0.0f, 0.0f, 1.0f,
};
static const unsigned short indices[] = { 0, 1, 2 };
void sdl_loop(SDL_Window* window)
{
glClearColor(0.0f, 0.1f, 0.2f, 1.0f);
glEnable(GL_FRAMEBUFFER_SRGB);
auto program = glCreateProgram();
auto vertexShader = glCreateShader(GL_VERTEX_SHADER);
auto fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(vertexShader, 1, &vertexSource, nullptr);
glShaderSource(fragmentShader, 1, &fragmentSource, nullptr);
glCompileShader(vertexShader);
glCompileShader(fragmentShader);
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
glBindFragDataLocation(program, 0, "fragColor");
glLinkProgram(program);
glDetachShader(program, vertexShader);
glDetachShader(program, fragmentShader);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
auto positionAttr = glGetAttribLocation(program, "position");
auto colorAttr = glGetAttribLocation(program, "color");
unsigned vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
unsigned vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
unsigned indexBuffer;
glGenBuffers(1, &indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
size_t stride = 5 * sizeof(float);
size_t offset = 0;
glEnableVertexAttribArray(positionAttr);
glVertexAttribPointer(positionAttr, 2, GL_FLOAT, false, stride, (void*) offset);
offset += 2 * sizeof(float);
glEnableVertexAttribArray(colorAttr);
glVertexAttribPointer(colorAttr, 3, GL_FLOAT, false, stride, (void*) offset);
offset += 3 * sizeof(float);
glUseProgram(program);
SDL_Event evt;
for (;;) {
while (SDL_PollEvent(&evt)) {
if (evt.type == SDL_QUIT) {
goto out;
}
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, nullptr);
SDL_GL_SwapWindow(window);
}
out:
glDeleteProgram(program);
glDeleteBuffers(1, &vertexBuffer);
glDeleteBuffers(1, &indexBuffer);
glDeleteVertexArrays(1, &vao);
}
int main()
{
if (SDL_Init(SDL_INIT_EVERYTHING) < 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"Couldn't initialize SDL: %s", SDL_GetError());
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,
"Couldn't initialize SDL", SDL_GetError(), nullptr);
return EXIT_FAILURE;
}
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 8);
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
// Commenting this line out doesn't give you an sRGB framebuffer on Intel GPUs
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
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);
SDL_GL_SetAttribute(SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, 1);
auto* window = SDL_CreateWindow("Hello OpenGL 3!",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
800, 600,
SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL);
if (window == nullptr) {
SDL_LogError(
SDL_LOG_CATEGORY_APPLICATION,
"Couldn't initialize SDL window: %s", SDL_GetError());
SDL_ShowSimpleMessageBox(
SDL_MESSAGEBOX_ERROR,
"Couldn't create SDL window", SDL_GetError(), nullptr);
return EXIT_FAILURE;
}
auto context = SDL_GL_CreateContext(window);
SDL_GL_MakeCurrent(window, context);
SDL_GL_SetSwapInterval(1);
ogl_LoadFunctions();
sdl_loop(window);
SDL_GL_DeleteContext(context);
SDL_DestroyWindow(window);
SDL_Quit();
return EXIT_SUCCESS;
}
I'm running on Ubuntu 16.04 (with the HWE drivers) and the machine I'm using has both an Intel HD 4000 GPU and a dedicated nvidia GPU with Optimus. In theory, I should be getting an sRGB framebuffer. However, I'm getting an sRGB framebuffer only when running under the nvidia GPU or when using ApiTrace. If I'm running under the Intel GPU, I'm only getting an sRGB framebuffer if I specify a non-zero alpha size with SDL2. If I specify a zero size for alpha (or don't specify one at all), I'm getting a linear framebuffer instead.
This is how my example looks when running under the nvidia GPU (and the Intel GPU with a non-zero alpha bit size):
This is how it looks when running under the Intel GPU with a zero alpha bit size (sRGB incorrect):
And this is what I get with ApiTrace:
I also ran glxinfo -t
and from what I can tell, I should be getting sRGB support even with zero alpha bits set (EDIT: That's not the case. The output of glxinfo
should display s
es in the sRGB column, but that doesn't happen for some reason or other):
40 GLX Visuals
Vis Vis Visual Trans buff lev render DB ste r g b a s aux dep ste accum buffer MS MS
ID Depth Type parent size el type reo sz sz sz sz flt rgb buf th ncl r g b a num bufs caveats
--------------------------------------------------------------------------------------------------------------------
0x 21 24 TrueColor 0 32 0 rgba 1 0 8 8 8 8 . . 0 24 8 0 0 0 0 0 0 None
0x 22 24 DirectColor 0 32 0 rgba 1 0 8 8 8 8 . . 0 24 8 0 0 0 0 0 0 None
0x b7 24 TrueColor 0 32 0 rgba 1 0 8 8 8 8 . . 0 0 0 0 0 0 0 0 0 None
0x b8 24 TrueColor 0 32 0 rgba 0 0 8 8 8 8 . . 0 0 0 0 0 0 0 0 0 None
0x b9 24 TrueColor 0 32 0 rgba 0 0 8 8 8 8 . . 0 24 8 0 0 0 0 0 0 None
0x ba 24 TrueColor 0 24 0 rgba 1 0 8 8 8 0 . . 0 0 0 0 0 0 0 0 0 None
0x bb 24 TrueColor 0 24 0 rgba 0 0 8 8 8 0 . . 0 0 0 0 0 0 0 0 0 None
0x bc 24 TrueColor 0 24 0 rgba 1 0 8 8 8 0 . . 0 24 8 0 0 0 0 0 0 None
0x bd 24 TrueColor 0 24 0 rgba 0 0 8 8 8 0 . . 0 24 8 0 0 0 0 0 0 None
0x be 24 TrueColor 0 32 0 rgba 1 0 8 8 8 8 . . 0 24 8 16 16 16 16 0 0 Slow
0x bf 24 TrueColor 0 24 0 rgba 1 0 8 8 8 0 . . 0 24 8 0 0 0 0 0 0 None
0x c0 24 TrueColor 0 24 0 rgba 1 0 8 8 8 0 . . 0 24 8 16 16 16 0 0 0 Slow
0x c1 24 TrueColor 0 32 0 rgba 1 0 8 8 8 8 . . 0 0 0 0 0 0 0 4 1 None
0x c2 24 TrueColor 0 32 0 rgba 1 0 8 8 8 8 . . 0 0 0 0 0 0 0 8 1 None
0x c3 24 TrueColor 0 32 0 rgba 1 0 8 8 8 8 . . 0 24 8 0 0 0 0 4 1 None
0x c4 24 TrueColor 0 32 0 rgba 1 0 8 8 8 8 . . 0 24 8 0 0 0 0 8 1 None
0x c5 24 TrueColor 0 24 0 rgba 1 0 8 8 8 0 . . 0 0 0 0 0 0 0 4 1 None
0x c6 24 TrueColor 0 24 0 rgba 1 0 8 8 8 0 . . 0 0 0 0 0 0 0 8 1 None
0x c7 24 TrueColor 0 24 0 rgba 1 0 8 8 8 0 . . 0 24 8 0 0 0 0 4 1 None
0x c8 24 TrueColor 0 24 0 rgba 1 0 8 8 8 0 . . 0 24 8 0 0 0 0 8 1 None
0x c9 24 DirectColor 0 32 0 rgba 1 0 8 8 8 8 . . 0 0 0 0 0 0 0 0 0 None
0x ca 24 DirectColor 0 32 0 rgba 0 0 8 8 8 8 . . 0 0 0 0 0 0 0 0 0 None
0x cb 24 DirectColor 0 32 0 rgba 0 0 8 8 8 8 . . 0 24 8 0 0 0 0 0 0 None
0x cc 24 DirectColor 0 24 0 rgba 1 0 8 8 8 0 . . 0 0 0 0 0 0 0 0 0 None
0x cd 24 DirectColor 0 24 0 rgba 0 0 8 8 8 0 . . 0 0 0 0 0 0 0 0 0 None
0x ce 24 DirectColor 0 24 0 rgba 1 0 8 8 8 0 . . 0 24 8 0 0 0 0 0 0 None
0x cf 24 DirectColor 0 24 0 rgba 0 0 8 8 8 0 . . 0 24 8 0 0 0 0 0 0 None
0x d0 24 DirectColor 0 32 0 rgba 1 0 8 8 8 8 . . 0 24 8 0 0 0 0 0 0 None
0x d1 24 DirectColor 0 32 0 rgba 1 0 8 8 8 8 . . 0 24 8 16 16 16 16 0 0 Slow
0x d2 24 DirectColor 0 24 0 rgba 1 0 8 8 8 0 . . 0 24 8 0 0 0 0 0 0 None
0x d3 24 DirectColor 0 24 0 rgba 1 0 8 8 8 0 . . 0 24 8 16 16 16 0 0 0 Slow
0x d4 24 DirectColor 0 32 0 rgba 1 0 8 8 8 8 . . 0 0 0 0 0 0 0 4 1 None
0x d5 24 DirectColor 0 32 0 rgba 1 0 8 8 8 8 . . 0 0 0 0 0 0 0 8 1 None
0x d6 24 DirectColor 0 32 0 rgba 1 0 8 8 8 8 . . 0 24 8 0 0 0 0 4 1 None
0x d7 24 DirectColor 0 32 0 rgba 1 0 8 8 8 8 . . 0 24 8 0 0 0 0 8 1 None
0x d8 24 DirectColor 0 24 0 rgba 1 0 8 8 8 0 . . 0 0 0 0 0 0 0 4 1 None
0x d9 24 DirectColor 0 24 0 rgba 1 0 8 8 8 0 . . 0 0 0 0 0 0 0 8 1 None
0x da 24 DirectColor 0 24 0 rgba 1 0 8 8 8 0 . . 0 24 8 0 0 0 0 4 1 None
0x db 24 DirectColor 0 24 0 rgba 1 0 8 8 8 0 . . 0 24 8 0 0 0 0 8 1 None
0x 76 32 TrueColor 0 32 0 rgba 1 0 8 8 8 8 . . 0 24 8 0 0 0 0 0 0 None
64 GLXFBConfigs:
Vis Vis Visual Trans buff lev render DB ste r g b a s aux dep ste accum buffer MS MS
ID Depth Type parent size el type reo sz sz sz sz flt rgb buf th ncl r g b a num bufs caveats
--------------------------------------------------------------------------------------------------------------------
0x 77 0 TrueColor 0 16 0 rgba 1 0 5 6 5 0 . . 0 0 0 0 0 0 0 0 0 None
0x 78 0 TrueColor 0 16 0 rgba 0 0 5 6 5 0 . . 0 0 0 0 0 0 0 0 0 None
0x 79 0 TrueColor 0 16 0 rgba 1 0 5 6 5 0 . . 0 16 0 0 0 0 0 0 0 None
0x 7a 0 TrueColor 0 16 0 rgba 0 0 5 6 5 0 . . 0 16 0 0 0 0 0 0 0 None
0x 7b 0 TrueColor 0 16 0 rgba 1 0 5 6 5 0 . . 0 24 8 0 0 0 0 0 0 None
0x 7c 0 TrueColor 0 16 0 rgba 0 0 5 6 5 0 . . 0 24 8 0 0 0 0 0 0 None
0x 7d 24 TrueColor 0 32 0 rgba 1 0 8 8 8 8 . . 0 0 0 0 0 0 0 0 0 None
0x 7e 24 TrueColor 0 32 0 rgba 0 0 8 8 8 8 . . 0 0 0 0 0 0 0 0 0 None
0x 7f 24 TrueColor 0 32 0 rgba 1 0 8 8 8 8 . . 0 24 8 0 0 0 0 0 0 None
0x 80 24 TrueColor 0 32 0 rgba 0 0 8 8 8 8 . . 0 24 8 0 0 0 0 0 0 None
0x 81 24 TrueColor 0 24 0 rgba 1 0 8 8 8 0 . . 0 0 0 0 0 0 0 0 0 None
0x 82 24 TrueColor 0 24 0 rgba 0 0 8 8 8 0 . . 0 0 0 0 0 0 0 0 0 None
0x 83 24 TrueColor 0 24 0 rgba 1 0 8 8 8 0 . . 0 24 8 0 0 0 0 0 0 None
0x 84 24 TrueColor 0 24 0 rgba 0 0 8 8 8 0 . . 0 24 8 0 0 0 0 0 0 None
0x 85 0 TrueColor 0 16 0 rgba 1 0 5 6 5 0 . . 0 16 0 0 0 0 0 0 0 None
0x 86 0 TrueColor 0 16 0 rgba 1 0 5 6 5 0 . . 0 16 0 16 16 16 0 0 0 Slow
0x 87 32 TrueColor 0 32 0 rgba 1 0 8 8 8 8 . . 0 24 8 0 0 0 0 0 0 None
0x 88 24 TrueColor 0 32 0 rgba 1 0 8 8 8 8 . . 0 24 8 16 16 16 16 0 0 Slow
0x 89 24 TrueColor 0 24 0 rgba 1 0 8 8 8 0 . . 0 24 8 0 0 0 0 0 0 None
0x 8a 24 TrueColor 0 24 0 rgba 1 0 8 8 8 0 . . 0 24 8 16 16 16 0 0 0 Slow
0x 8b 0 TrueColor 0 16 0 rgba 1 0 5 6 5 0 . . 0 0 0 0 0 0 0 4 1 None
0x 8c 0 TrueColor 0 16 0 rgba 1 0 5 6 5 0 . . 0 0 0 0 0 0 0 8 1 None
0x 8d 0 TrueColor 0 16 0 rgba 1 0 5 6 5 0 . . 0 16 0 0 0 0 0 4 1 None
0x 8e 0 TrueColor 0 16 0 rgba 1 0 5 6 5 0 . . 0 16 0 0 0 0 0 8 1 None
0x 8f 24 TrueColor 0 32 0 rgba 1 0 8 8 8 8 . . 0 0 0 0 0 0 0 4 1 None
0x 90 24 TrueColor 0 32 0 rgba 1 0 8 8 8 8 . . 0 0 0 0 0 0 0 8 1 None
0x 91 24 TrueColor 0 32 0 rgba 1 0 8 8 8 8 . . 0 24 8 0 0 0 0 4 1 None
0x 92 24 TrueColor 0 32 0 rgba 1 0 8 8 8 8 . . 0 24 8 0 0 0 0 8 1 None
0x 93 24 TrueColor 0 24 0 rgba 1 0 8 8 8 0 . . 0 0 0 0 0 0 0 4 1 None
0x 94 24 TrueColor 0 24 0 rgba 1 0 8 8 8 0 . . 0 0 0 0 0 0 0 8 1 None
0x 95 24 TrueColor 0 24 0 rgba 1 0 8 8 8 0 . . 0 24 8 0 0 0 0 4 1 None
0x 96 24 TrueColor 0 24 0 rgba 1 0 8 8 8 0 . . 0 24 8 0 0 0 0 8 1 None
0x 97 0 DirectColor 0 16 0 rgba 1 0 5 6 5 0 . . 0 0 0 0 0 0 0 0 0 None
0x 98 0 DirectColor 0 16 0 rgba 0 0 5 6 5 0 . . 0 0 0 0 0 0 0 0 0 None
0x 99 0 DirectColor 0 16 0 rgba 1 0 5 6 5 0 . . 0 16 0 0 0 0 0 0 0 None
0x 9a 0 DirectColor 0 16 0 rgba 0 0 5 6 5 0 . . 0 16 0 0 0 0 0 0 0 None
0x 9b 0 DirectColor 0 16 0 rgba 1 0 5 6 5 0 . . 0 24 8 0 0 0 0 0 0 None
0x 9c 0 DirectColor 0 16 0 rgba 0 0 5 6 5 0 . . 0 24 8 0 0 0 0 0 0 None
0x 9d 24 DirectColor 0 32 0 rgba 1 0 8 8 8 8 . . 0 0 0 0 0 0 0 0 0 None
0x 9e 24 DirectColor 0 32 0 rgba 0 0 8 8 8 8 . . 0 0 0 0 0 0 0 0 0 None
0x 9f 24 DirectColor 0 32 0 rgba 1 0 8 8 8 8 . . 0 24 8 0 0 0 0 0 0 None
0x a0 24 DirectColor 0 32 0 rgba 0 0 8 8 8 8 . . 0 24 8 0 0 0 0 0 0 None
0x a1 24 DirectColor 0 24 0 rgba 1 0 8 8 8 0 . . 0 0 0 0 0 0 0 0 0 None
0x a2 24 DirectColor 0 24 0 rgba 0 0 8 8 8 0 . . 0 0 0 0 0 0 0 0 0 None
0x a3 24 DirectColor 0 24 0 rgba 1 0 8 8 8 0 . . 0 24 8 0 0 0 0 0 0 None
0x a4 24 DirectColor 0 24 0 rgba 0 0 8 8 8 0 . . 0 24 8 0 0 0 0 0 0 None
0x a5 0 DirectColor 0 16 0 rgba 1 0 5 6 5 0 . . 0 16 0 0 0 0 0 0 0 None
0x a6 0 DirectColor 0 16 0 rgba 1 0 5 6 5 0 . . 0 16 0 16 16 16 0 0 0 Slow
0x a7 24 DirectColor 0 32 0 rgba 1 0 8 8 8 8 . . 0 24 8 0 0 0 0 0 0 None
0x a8 24 DirectColor 0 32 0 rgba 1 0 8 8 8 8 . . 0 24 8 16 16 16 16 0 0 Slow
0x a9 24 DirectColor 0 24 0 rgba 1 0 8 8 8 0 . . 0 24 8 0 0 0 0 0 0 None
0x aa 24 DirectColor 0 24 0 rgba 1 0 8 8 8 0 . . 0 24 8 16 16 16 0 0 0 Slow
0x ab 0 DirectColor 0 16 0 rgba 1 0 5 6 5 0 . . 0 0 0 0 0 0 0 4 1 None
0x ac 0 DirectColor 0 16 0 rgba 1 0 5 6 5 0 . . 0 0 0 0 0 0 0 8 1 None
0x ad 0 DirectColor 0 16 0 rgba 1 0 5 6 5 0 . . 0 16 0 0 0 0 0 4 1 None
0x ae 0 DirectColor 0 16 0 rgba 1 0 5 6 5 0 . . 0 16 0 0 0 0 0 8 1 None
0x af 24 DirectColor 0 32 0 rgba 1 0 8 8 8 8 . . 0 0 0 0 0 0 0 4 1 None
0x b0 24 DirectColor 0 32 0 rgba 1 0 8 8 8 8 . . 0 0 0 0 0 0 0 8 1 None
0x b1 24 DirectColor 0 32 0 rgba 1 0 8 8 8 8 . . 0 24 8 0 0 0 0 4 1 None
0x b2 24 DirectColor 0 32 0 rgba 1 0 8 8 8 8 . . 0 24 8 0 0 0 0 8 1 None
0x b3 24 DirectColor 0 24 0 rgba 1 0 8 8 8 0 . . 0 0 0 0 0 0 0 4 1 None
0x b4 24 DirectColor 0 24 0 rgba 1 0 8 8 8 0 . . 0 0 0 0 0 0 0 8 1 None
0x b5 24 DirectColor 0 24 0 rgba 1 0 8 8 8 0 . . 0 24 8 0 0 0 0 4 1 None
0x b6 24 DirectColor 0 24 0 rgba 1 0 8 8 8 0 . . 0 24 8 0 0 0 0 8 1 None
Why am I not getting an sRGB framebuffer in that case? Is it possible that I have hit an Intel driver bug?
Apparently the culprit is this bug in the Intel Mesa driver (thanks to SO user genpfault for finding it in the freedesktop bugzilla).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With