PDA

View Full Version : GLSL line rendering is slower than fix function.



HanWu
10-31-2017, 03:39 AM
Recently I plan to switch my old fix function rendering method to GLSL, but the GLSL method is a lot slower than the fix function.

Here is my Vertex Shader



#version 330 core


uniform mat4 u_MVPMatrix; // A constant representing the combined model/view/projection matrix.


layout(location = 0) in vec4 a_Position; // Per-vertex position information we will pass in.


// The entry point for our vertex shader.
void main()
{
// gl_Position is a special variable used to store the final position.
// Multiply the vertex by the matrix to get the final point in normalized screen coordinates.
gl_Position = u_MVPMatrix * a_Position;
}


Fragment Shader



#version 330 core


precision mediump float; // Set the default precision to medium. We don't need as high of a
// precision in the fragment shader.
out vec4 v_Color; // This is the color from the vertex shader interpolated across the
// triangle per fragment.
uniform vec4 LineColor;


// The entry point for our fragment shader.
void main()
{
// Pass through the color
v_Color=LineColor;
}





ShaderSelect tempS = SelectShaders;
//Buffer
tempS.UseProgram();


EnableVertexAttribArrayARB(0);
VertexAttribPointerfARB(0, 3, 0, 0, vertices);


glUniform4fARB(tempS.mLineColor, color[0], color[1], color[2], color[3]);


glUniformMatrix4fvARB(tempS.mMVPMatrixHandle, 1, 0, CombineMatrix); // Fix combine matrix

Gl.glDrawArrays(Gl.GL_LINE_LOOP, 0, num);


DisableVertexAttribArray(0);


tempS.Disable();


This is the Fix Function


Gl.glEnableClientState(Gl.GL_VERTEX_ARRAY);
Gl.glVertexPointer(3, Gl.GL_DOUBLE, 0, point);
if (closed)
Gl.glDrawArrays(Gl.GL_LINE_LOOP, 0, num);
else
Gl.glDrawArrays(Gl.GL_LINE_STRIP, 0, num);
// Gl.glFinish();
Gl.glDisableClientState(Gl.GL_VERTEX_ARRAY);

By rendering 100000 of circle and each circle with 40 points.

Fix function give 7 to 8 fps.
GLSL give only 1 to 2 fps.


Is it by design? Or do I did anything wrong on the code?

Dark Photon
10-31-2017, 07:35 AM
Recently I plan to switch my old fix function rendering method to GLSL, but the GLSL method is a lot slower than the fix function.
...
By rendering 100000 of circle and each circle with 40 points.

Fix function give 7 to 8 fps.
GLSL give only 1 to 2 fps.

Is it by design? Or do I did anything wrong on the code?

Both of your implementations are very inefficient. You're doing more to profile your CPU than your GPU or the GL driver.

There's no need to:


constantly unbind a program after use,
re-bind a program that's already bound,
disable a vertex attribute after use,
needlessly re-enable it again for the next batch (glDraw* call),
continually re-set a vertex attribute to the same value (not sure if you're doing this with color or not), or even
to have separate batches for each circle.

The first 5 can be trivially cleaned up. Also, now that you're playing with GLSL, consider using hardware geometry instancing, either via Instanced arrays (https://www.khronos.org/opengl/wiki/Instanced_Array#Instanced_arrays) or glDraw*Instanced* calls and gl_InstanceID in the shader (https://www.khronos.org/opengl/wiki/Vertex_Rendering#Instancing). You could potentially render all of your 100k circles with one draw call.

There are other techniques you can use to stop re-uploading your shape data to the GPU every frame and re-specifying your batch parameters for every batch (e.g. VBOs, and VAOs or bindless), potentially netting you even more speed-up for both the shader and fixed-function test cases.

Just out of curiosity, what GPU and GL driver/version are you using?

mhagain
10-31-2017, 09:50 AM
Another observation - you're mixing the GL_ARB_shader_objects extension with GLSL 330 shaders - that's not a good practice because GL_ARB_shader_objects was never actually promoted to core (and therefore has limited or no guarantee of compatibility with later functionality), so you really should be just using the core GL 2.0 entry points instead.

HanWu
10-31-2017, 07:58 PM
Thanks for the advise. After did some modification on the code



/// only call once
ShaderSelect tempS = SelectShaders;
//Buffer
tempS.UseProgram();
EnableVertexAttribArrayARB(0);
/// only call once end


/// loop for 100000 circle

// each circle position at different location and store in vertices
VertexAttribPointerfARB(0, 3, 0, 0, vertices);
// each circle has different color.
glUniform4fARB(tempS.mLineColor, color[0], color[1], color[2], color[3]);
glUniformMatrix4fvARB(tempS.mMVPMatrixHandle, 1, 0, CombineMatrix); // Fix combine matrix
Gl.glDrawArrays(Gl.GL_LINE_LOOP, 0, num);


/// only call once
DisableVertexAttribArray(0);
tempS.Disable();
/// only call once end


By doing this, I can have up to 5 to 6 fps but still a bit slower than the fix function.

mhagain
10-31-2017, 09:14 PM
Is that glUniform4fARB (again, please stop using the -ARB versions of these) intended to replace a glColor4f in the fixed version? If so, you should replace it with a glVertexAttrib4f (don't use -ARB, the -ARB versions are for the GL_ARB_vertex_program extension, not for GL 2.0+) then rework your shaders to pass this attrib from VS to FS for use as a colour.

HanWu
11-01-2017, 01:37 AM
Another observation - you're mixing the GL_ARB_shader_objects extension with GLSL 330 shaders - that's not a good practice because GL_ARB_shader_objects was never actually promoted to core (and therefore has limited or no guarantee of compatibility with later functionality), so you really should be just using the core GL 2.0 entry points instead.

Hi, Thanks for the advise.