Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Combine multiple opengl fragment shaders

I'm wanting to port some image processing work to OpenGL for performance using OpenGL ES. I've got a very simple thresholding algorithm in place but I'd like to combine additional filters to the image (such as contrast).

My first thought would be to complete this by using multiple fragment shaders. However, I'd like to do this pretty quickly so would this cause a lot of state change? The only method I've read about is to do this by working on a texture and then calling 'use program' multiple times.

Is there a more efficient way to do this? Ideally, I'd like to perform a contrast stretch and a histogram balance as part of the steps.

Unless I can combine this into a single shader would an FBO work for me here?

I'm a bit new to OpenGL (in case you couldn't tell).

Thanks!

Simon

like image 254
Simon Avatar asked Mar 21 '11 09:03

Simon


People also ask

Can you use multiple shaders OpenGL?

You can have as many shader objects (shaders loaded into memory and compiled) as you want; only one can be bound (active) at a time. In terms of implementation, in every frame I use glUseProgram(1) and glUseProgram(2) to change shaders?

Are compute shaders faster than fragment shaders?

This turns out to be 50% faster than the fragment shader! (It can be embiggened, which you may wish to do if you're having trouble reading the text.)

How many times does a fragment shader run?

In this case, your fragment shader runs once for every fragment within that quad. For this program, that means 100 * 100 = 10000 times, once for every pixel on your screen. However, not every fragment rendered in the shader has to be displayed on the screen.

Is fragment shader same as pixel shader?

A fragment shader is the same as pixel shader. One main difference is that a vertex shader can manipulate the attributes of vertices. which are the corner points of your polygons. The fragment shader on the other hand takes care of how the pixels between the vertices look.


2 Answers

You can't "merge" fragment shader unless you do it manually, so the only sane choice is to do "ping-pong" rendering using FBOs. You have 2 FBOs, draw to one and read from another, then switch FBOs and repeat, switching fragment shaders between rendering.

like image 93
Dr. Snoopy Avatar answered Sep 29 '22 10:09

Dr. Snoopy


Ping pong rendering is quite nice for this purpose, actually! Here's a code sample that works within LibGDX, where there is a 'batch' object that actually draws to the screen, the input to which we can capture with FrameBuffers:

FrameBuffer ping = fbo; // the framebuffer containing your rendered texture
for (ShaderProgram shader : shaders) {
    pong.clear();
    pong.begin();
    batch.begin();
    batch.setShader(shader);
    batch.draw(ping.getColorBufferTexture(), 0, 0, width, height);
    batch.end();
    pong.end();
    ping = pong;
}
batch.begin();
batch.draw(pong.getColorBufferTexture(), 0, 0, width, height);
batch.end();

The clear call to pong (in my case, making a new framebuffer) is expensive, so preallocating might offer some speedups. This is more of a followup to Matias' answer than an answer in itself, but wouldn't fit in a comment.

like image 31
Daryl Avatar answered Sep 29 '22 08:09

Daryl