PDA

View Full Version : sRGB doesn't work on FBO with attached depth



yuriks
10-24-2011, 12:24 AM
Hello, while writing a deferred renderer I ran into a weird issue with sRGB FBOs. If I enable framebuffer sRGB with glEnable(GL_FRAMEBUFFER_SRGB); and then try drawing onto an FBO with a sRGB color attachment, the colors aren't converted to sRGB, they are written as-is, ONLY if there is also a depth buffer attached to the FBO. If I don't attach the depth texture it works as expected. I'm on an nvidia 9600gt. I tested on a friend's AMD card and it works fine either way there. Am I doing something wrong here, am I misinterpreting the spec (which doesn't mention anything about this not working.) or is this a bug?

Here's a test case project: http://dl.dropbox.com/u/1990844/2011-10/gamma-bug.7z

And the main file:



#include "gl/VertexArrayObject.hpp"
#include "gl/Shader.hpp"
#include "gl/ShaderProgram.hpp"
#include "gl/Framebuffer.h"
#include "gl/Texture.hpp"
#include "image/ImageLoader.hpp"

#include <iostream>
#include <fstream>

#include "gl3w.hpp"

#include <GL/glfw.h>

void APIENTRY debug_callback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, GLvoid* userParam)
{
if ((type != GL_DEBUG_TYPE_PERFORMANCE_ARB &amp;&amp; type != GL_DEBUG_TYPE_OTHER_ARB) || severity != GL_DEBUG_SEVERITY_LOW_ARB)
std::cerr << message << std::endl;
if ((type != GL_DEBUG_TYPE_PERFORMANCE_ARB &amp;&amp; type != GL_DEBUG_TYPE_OTHER_ARB) || severity == GL_DEBUG_SEVERITY_HIGH_ARB)
__asm int 3; // Breakpoint
}

bool init_window()
{
if (glfwInit() != GL_TRUE)
{
char tmp;
std::cerr << "Failed to initialize GLFW." << std::endl;
std::cin >> tmp;
return false;
}

glfwOpenWindowHint(GLFW_OPENGL_VERSION_MAJOR, 3);
glfwOpenWindowHint(GLFW_OPENGL_VERSION_MINOR, 3);
glfwOpenWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwOpenWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);
glfwOpenWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
if (glfwOpenWindow(800, 600, 8, 8, 8, 8, 24, 8, GLFW_WINDOW) != GL_TRUE)
{
char tmp;
std::cerr << "Failed to open window." << std::endl;
std::cin >> tmp;
return false;
}

glfwSwapInterval(1);

if (gl3wInit() != 0) {
char tmp;
std::cerr << "Failed to initialize gl3w." << std::endl;
std::cin >> tmp;
return false;
} else if (!gl3wIsSupported(3, 3)) {
char tmp;
std::cerr << "OpenGL 3.3 not supported." << std::endl;
std::cin >> tmp;
return false;
}

if (glDebugMessageCallbackARB) {
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, 0, GL_TRUE);
glDebugMessageCallbackARB(debug_callback, 0);
}

return true;
}

int main(int argc, char *argv[])
{
if (!init_window())
return 1;

{
gl::Shader vertex_shader(GL_VERTEX_SHADER);
gl::Shader frag_shader(GL_FRAGMENT_SHADER);
{
std::ifstream f("hack.vert");
vertex_shader.setSource(f);
}
{
std::ifstream f("hack.frag");
frag_shader.setSource(f);
}
vertex_shader.compile();
frag_shader.compile();

gl::ShaderProgram shader_program;
shader_program.attachShader(vertex_shader);
shader_program.attachShader(frag_shader);
shader_program.link();
if (!shader_program.linkSuccess())
shader_program.printInfoLog(std::cerr);

shader_program.use();

gl::VertexArrayObject vao;
vao.bind();
GLuint vbo;
glGenBuffers(1, &amp;vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
static const unsigned int foodata[] = {0, 1, 2};
glBufferData(GL_ARRAY_BUFFER, sizeof(foodata), &amp;foodata, GL_STATIC_DRAW);
glVertexAttribPointer(0, 1, GL_UNSIGNED_INT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);

gl::Texture source_tex;
{
image::Image img;
std::ifstream f("texture.png", std::ios::in | std::ios::binary);
if (!f)
return -1;
image::Image::loadPNGFileRGBA8(img, f);

source_tex.bind(GL_TEXTURE_2D);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

source_tex.width = img.getWidth();
source_tex.height = img.getHeight();

glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB, source_tex.width, source_tex.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img.getData());
}

glUniform1i(shader_program.getUniformLocation("tex"), 0);

gl::Texture depth_tex;
depth_tex.bind(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, 800, 600, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, 0);

gl::Texture color_tex;
color_tex.bind(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB8_ALPHA8, 800, 600, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);

gl::Framebuffer fbo;
fbo.bind(GL_DRAW_FRAMEBUFFER);
// COMMENT THIS NEXT LINE!!!
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_tex, 0);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color_tex, 0);
glDrawBuffer(GL_COLOR_ATTACHMENT0);

glClearColor(0.f, 0.f, 0.f, 1.f);
glEnable(GL_FRAMEBUFFER_SRGB);

bool running = true;
while (running) {
fbo.bind(GL_DRAW_FRAMEBUFFER);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
source_tex.bind(GL_TEXTURE_2D);
glDrawArrays(GL_TRIANGLES, 0, 3);

glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
color_tex.bind(GL_TEXTURE_2D);
glDrawArrays(GL_TRIANGLES, 0, 3);

glfwSwapBuffers();

running = glfwGetWindowParam(GLFW_OPENED) != 0 &amp;&amp; glfwGetKey(GLFW_KEY_ESC) != GLFW_PRESS;
}
}

glfwTerminate();

return 0;
}

yuriks
10-24-2011, 07:12 PM
After a bit more of investigation, this looks like a driver bug. If I comment out the first glClear call, it now works properly (even if I only clear the color, and not the depth buffer). Furthermore, if after clearing I disable and re-enable GL_FRAMEBUFFER_SRGB, it also makes it work.

How can I report this to nVidia? For now I'm heading over to their developer forums.



// Workaround
fbo.bind(GL_DRAW_FRAMEBUFFER);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDisable(GL_FRAMEBUFFER_SRGB);
glEnable(GL_FRAMEBUFFER_SRGB);
source_tex.bind(GL_TEXTURE_2D);
glDrawArrays(GL_TRIANGLES, 0, 3);

shiyan
11-18-2011, 01:23 PM
Hi,

Can you also attach the right and wrong images?

Thanks.