2
\$\begingroup\$

I've implemented some postprocessing effects (DOF, HDR, Bloom) into my engine. I've tested it on AMD card which supports OpenGL 4.2. Yesterday I've made a test on NVidia card which supports only OpenGL 3.3. I tried to write my code to works also in OpenGL 3.3 but I was suprised when I saw something like on the screen:

enter image description here

It seems that textures are filled with random values and never change during app life (only when I'm changing dimensions of textures so basically recreate them). It happens mostly when I want downscale texture to some size (I use 2 textures to do that and a shader). Here is some examples of my code which implements Bloom effect:

Creating framebuffer:

if (!_p_buffer)glGenFramebuffers(1, &_p_buffer); // generate postprocess buffer
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _p_buffer);

    for (int i = 0; i < 2; i++){
        _lens[i].create(x / D.lensDownsample(), y / D.lensDownsample(), 0, IMAGE_16F_3, IMAGE_2D, true, FILTER_LINEAR); // create Lens Flare texture (with half resolution)
        glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT2 + i, GL_TEXTURE_2D, _lens[i].get(), 0);
    }

Render-to-texture:

glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _p_buffer);

// first downsample image
glDrawBuffer(GL_COLOR_ATTACHMENT2);
glClear(GL_COLOR_BUFFER_BIT);

glActiveTexture(GL_TEXTURE0);
_aux[_aux_number].lock();

Shaders["ScaleBias"].set(true);
Shaders["ScaleBias"].set("scale", Vector4(1.2f));
Shaders["ScaleBias"].set("bias", Vector4(-0.4));
Shaders["ScaleBias"].set("texelSize", Vector2(1 / (float)D.x() * D.lensDownsample(), 1 / (float)D.y() * (float)D.lensDownsample()));

glViewport(0, 0, D.x() / D.lensDownsample(), D.y() / D.lensDownsample());
Quad();

ScaleBias shader:

void main() {
    FragColor = max(vec4(0.0), texture(col, gl_FragCoord.xy*texelSize) + bias) * scale;
}

What "create" method actually does here:

if(!_image)glGenTextures(1, &_image);

glBindTexture(GL_TEXTURE_2D, _image);

glTexParameteri(_gl_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(_gl_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(_gl_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glTexParameteri(_gl_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(_gl_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, x, y, 0, GL_RGB,GL_FLOAT, NULL);

I used debug extension to check if there is any invalid parameters but debuging shows nothing interesting. I tried make G-Buffer textures as GL_FLOAT but they works ok. I tried make shader as simple as possible (return color texture) but error still was valid. I've observed similar problem on newer NVidia cards but the only difference was that textures are clear (black). But they still didn't update. Framebuffer doesn't output any errors.

Could you point me out the cause of this bug or give some clue?

\$\endgroup\$
4
\$\begingroup\$

There isn't much info to go on so I'm going to throw out a few things to try and see if the driver/card likes it better that way:

RGBA instead of RGB

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, x, y, 0, GL_RGBA, GL_FLOAT, NULL);

Check that GL_MAX_COLOR_ATTACHMENTS is 4 or more on this graphic card (GL_COLOR_ATTACHMENT2 + 1 == 4th color attachment)

Try attaching starting at GL_COLOR_ATTACHMENT0

try different locations for FragColor (does it matches GL_COLOR_ATTACHMENTn ?)

layout(location = 2) out vec4 FragColor;

Did you unbind the texture before trying to render to it?

glBindTexture(GL_TEXTURE_2D, 0);

Cheers,

\$\endgroup\$
0
\$\begingroup\$

Thank you Stephane for your answer. It helped me find the real problem source. I'll explain it in this answer and will provide short answers to your post. Maybe it will be useful for someone.

My AMD card is Radeon HD5770 (supporting OpenGL 4.2) and my NVidia card GeForce 9500GT (supporting OpenGL 3.3). Both cards support max 8 color attachments.

try different locations for FragColor (does it matches GL_COLOR_ATTACHMENTn ?)

layout(location = 2) out vec4 FragColor;

I played with glBindFragDataLocation function, because I had to dynamically change output location (for example when blurring I had 2 passes - one for vertical and one for horizontal blur - and 2 color attachements used).

I observed that I didn't need to set location — OpenGL draws to the color attachment set in glDrawBuffer() without any extra hints.


Solution

I stored all textures used in postprocessing in one framebuffer. These textures have different dimensions. The smallest texture has size 1x1. I've found text which could explain why I had these artifacts:

When you use more than one buffer, some restrictions apply: All attachments to the FBO must have the same width and height. All color buffers must use the same format. For example, you cannot attach a RGBA8 and a RGBA16f Texture to the same FBO, even if they have the same width and height. OpenGL 3.0 does relax this restriction, by allowing attachments of different sizes to be attached. But only the smallest area covered by all attachments can be written to.

So possibly only one pixel was changing and newer versions of OpenGL seem to have removed this restriction, since it works on my AMD card.

So to solve my problem, I simply created separate framebuffers for each postprocess effect. And it works!

\$\endgroup\$
  • \$\begingroup\$ Most likely, AMD is not strictly following the standard and being too permissive. There's a similar issue with the [ #line x y ] directive where both x and y must be a number but AMD & nVidia allows y to be a string, Intel drivers do not and neither does MESA3D (the open source drivers). Its the most annoying thing I find with OpenGL: the lack of conformance control. Another gotcha I found was that Rectangle textures don't allow mipmaps according to the specs but a lot of drivers don't care and some will crash or have garbage in some of the mip levels if enabled. Always fun times :) \$\endgroup\$ – Stephane Hockenhull Dec 10 '14 at 20:47
  • \$\begingroup\$ Yes, I have some problems with shaders which compiles only on AMD and NV compiler returns lots of errors. For example AMD compiles C-style arrays while on NVidia only vec2 xxx = vec2[](); construction works (it also works on AMD). This is why GeForce will probably be my next GPU. \$\endgroup\$ – Harry Dec 10 '14 at 21:36
  • \$\begingroup\$ @Anko Thanks for grammar correction :) Now I see how many grammatical errors I make. It's good for polishing language skills :) \$\endgroup\$ – Harry Dec 11 '14 at 16:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.