[Shader] Smooth pixel filtering

What do you mean when you say “apply the shader just before swapping the
window by calling SDL_RenderPresent() (and restore it after)”?

You cannot use a shader to modify the contents of the default framebuffer.
If you want to apply it as a post-processing step (as you seem to imply
here), you’ll need to render your whole scene into a texture and then use
that texture as an input to your shader.

2013/12/6 vlag <valentin.soudier at gmail.com>> Yeah, thanks for the code sample, it’s really helpful [image: Smile]

By the way, I tried to work with shader the last few days, and I’ve not
reached my goal to apply a shader when rendering.
It work fine when I copy a Gl texture or a SDL_Texture to the renderer,
but not if I try to apply the shader just before swapping the window by
calling SDL_RenderPresent() (and restore it after).
It also don’t work if I try with the SDL official shader exemple, where we
just use the OpenGL API.

Do you confirm that it is really possible to apply a shader when
rendering, or should I apply and restore the shader at each SDL/OpenGL draw
to the renderer?


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

You guessed right, apply a post-processing shader is exactely what I want to do :slight_smile:

Ok, this is what seemed to me. The only reason what I didn’t do that before is because I heard that render to a texture is slow and not supported by every modern hardware.
Am I right and should I apply the shader separately for each textures, or a hardware that support pixel shaders always support rendering to textures ?

2013/12/6 vlag <valentin.soudier at gmail.com>

You guessed right, apply a post-processing shader is exactely what I
want to do [image: Smile]

Ok, this is what seemed to me. The only reason what I didn’t do that
before is because I heard that render to a texture is slow and not
supported by every modern hardware.
Am I right and should I apply the shader separately for each textures, or
a hardware that support pixel shaders always support rendering to textures ?

Most OpenGL 2.0 capable hardware with up to date drivers is able to render
to off-screen
buffers, so unless you want to target over 10 year old hardware, you should
just assume
that this is always possible.

OpenGL 2 capable hardware seems to be old enough to assume it as a minimum requirement :slight_smile:

So now I wonder about the speed.
Is it faster to copy all textures on a render texture, and then apply the shader when copying on the window renderer, or to apply and restore the shader each times a texture is copied on the window renderer (and keep working without rendering to textures) ?

2013/12/6 vlag <valentin.soudier at gmail.com>

OpenGL 2 capable hardware seems to be old enough to assume it as a
minimum requirement [image: Smile]

So now I wonder about the speed.
Is it faster to copy all textures on a render texture, and then apply the
shader when copying on the window renderer, or to apply and restore the
shader each times a texture is copied on the window renderer (and keep
working without rendering to textures) ?

That entirely depends on your workload. If you render a lot of geometry per
frame,
it is generally advisable to render everything to a screen sized texture
and then
render it to the screen using your post processing shader. If it’s just a
handful of
things you are drawing, it might not be worth it. As always in the graphics
world:
Profile, profile, profile!

AFAIK, binding a shader costs more than binding a texture (or, more
accurately, binding a sampler to a shader.)

Minimizing state changes is always a performance win, so if you can get
away with binding the shader once then I’d suggest doing just that. As
Jonas said, you’d have to profile in order to get exact numbers.

2013/12/6 Jonas Kulla > 2013/12/6 vlag <valentin.soudier at gmail.com>

OpenGL 2 capable hardware seems to be old enough to assume it as a
minimum requirement [image: Smile]

So now I wonder about the speed.
Is it faster to copy all textures on a render texture, and then apply the
shader when copying on the window renderer, or to apply and restore the
shader each times a texture is copied on the window renderer (and keep
working without rendering to textures) ?

That entirely depends on your workload. If you render a lot of geometry
per frame,
it is generally advisable to render everything to a screen sized texture
and then
render it to the screen using your post processing shader. If it’s just a
handful of
things you are drawing, it might not be worth it. As always in the
graphics world:
Profile, profile, profile!


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

AFAIK, binding a shader costs more than binding a texture (or, more accurately, binding a sampler to a shader.)

Thanks ! That’s exactely what I wanted to know :slight_smile:

As always in the graphics world:

Profile, profile, profile!

Yep, that’s indeed the best things to do now :slight_smile:

I think I got enough global informations to have a good overview of where I go, and be able to continue by myself.
I’ll come back on this thread if something goes wrong :wink:

Thanks a lot everybody !

Hi again :slight_smile:

I’m getting lost with GLSL uniform variables.
I’ve reorganised the code to render on an intermediate SDL texture, bind it and draw it on the screen using OpenGL and a custom GLSL shader program if needed.

Everything seems to work except the uniform sampler2d, which means (if I understood correctly) that the shader can’t access to the texture, and then display a black screen. If I don’t 'apply a shader, everything works fine.

The C++ code can be found on the github page of the Solarus engine : the Shader class here https://github.com/christopho/solarus/blob/master/src/lowlevel/Shader.cpp and the VideoManager::shaded_render() method here https://github.com/christopho/solarus/blob/master/src/lowlevel/VideoManager.cpp#L497
The shader program seems to not find the binded texture using uniform variable.

Here is the test shader code (from the SDL exemple, so there is no error on this side)
Vertex shader :

Code:
varying vec4 v_color;
varying vec2 v_texCoord;

void main()
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
v_color = gl_Color;
v_texCoord = vec2(gl_MultiTexCoord0);
}

Fragment shader :

Code:
varying vec4 v_color;
varying vec2 v_texCoord;
uniform sampler2D solarus_sampler;

void main()
{
gl_FragColor = texture2D(solarus_sampler, v_texCoord) * v_color;
}

Two questions :

  • Do you know a reliable way to debug a shader ?
  • Any advice on how to proceed or what I forgot / make wrong (knowing that the official SDL testshader.c exemple works fine) ?

I’m open to all comments about the code :slight_smile:

2013/12/14 vlag <valentin.soudier at gmail.com>

Hi again [image: Smile]

I’m getting lost with GLSL uniform variables.
I’ve reorganised the code to render on an intermediate SDL texture, bind
it and draw it on the screen using OpenGL and a custom GLSL shader program
if needed.

Everything seems to work except the uniform sampler2d, which means (if I
understood correctly) that the shader can’t access to the texture, and then
display a black screen. If I don’t 'apply a shader, everything works fine.

The C++ code can be found on the github page of the Solarus engine : the
Shader class here
https://github.com/christopho/solarus/blob/master/src/lowlevel/Shader.cppand the VideoManager::shaded_render() method here
https://github.com/christopho/solarus/blob/master/src/lowlevel/VideoManager.cpp#L497
The shader program seems to not find the binded texture using uniform
variable.

Here is the test shader code (from the SDL exemple, so there is no error
on this side)
Vertex shader :

Code:

varying vec4 v_color;
varying vec2 v_texCoord;

void main()
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
v_color = gl_Color;
v_texCoord = vec2(gl_MultiTexCoord0);
}

Fragment shader :

Code:

varying vec4 v_color;
varying vec2 v_texCoord;
uniform sampler2D solarus_sampler;

void main()
{
gl_FragColor = texture2D(solarus_sampler, v_texCoord) * v_color;
}

Two questions :

  • Do you know a reliable way to debug a shader ?
  • Any advice on how to proceed or what I forgot / make wrong (knowing that
    the official SDL testshader.c exemple works fine) ?

I’m open to all comments about the code [image: Smile]

Okay, first off, debugging shaders is really hard. I think most people
still rely on the
"printf debugging" equivalent here, which is to use different outputs (eg.
flat colors)
and see how the shaders behave.

First of all, I would check that your geometry (your quad) is fine
otherwise, by not
sampling from the texture and instead outputting a constant color:

gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);

Looking at the SDL2 source for the desktop GL renderer, it should be doing
the right
thing during SDL_GL_BindTexture, as long as it is not a YUV texture (!!).

Sorry I forgot to mention that.
Yes the quad is drawed fine. With your exemple, the expected red rectangle is displayed.

That why I’m pretty sure the problem is related to the uniform variables.
How is the shader program supposed to ‘bind’ the texture to the sampler exactely ? It just check the given texture unit ?

I also wondered about these YUV textures too. It seems to be ok since the intermediate render texture is created with a packed32 pixel format :slight_smile:

2013/12/15 vlag <valentin.soudier at gmail.com>

Sorry I forgot to mention that.
Yes the quad is drawed fine. With your exemple, the expected red rectangle
is displayed.

That why I’m pretty sure the problem is related to the uniform variables.
How is the shader program supposed to ‘bind’ the texture to the sampler
exactely ? It just check the given texture unit ?

Yeah, the sampler2D uniform basically just holds the number to the texture
unit
from which the bound texture will be sampled from. Since all uniforms are
initialized
to zero at program link time, you will sample from texture unit 0 (the
default) without
having to do anything else, so in simple cases like this just plain binding
the texture
should work (assuming the active texture unit is always kept at 0).

I also wondered about these YUV textures too. It seems to be ok since the
intermediate render texture is created with a packed32 pixel format [image:
Smile]

I think you shouldn’t be worried about them unless you specifically told
SDL to
create one.

At this point, I can’t really find anything looking at your code. Maybe you
could
verify that you’re getting correct tex coords in the shader (by drawing
them as
a color), and if that’s correct, I would run the program through something
like
apitrace to make sure the correct texture is bound to unit 0 (this will
also let
you verify that the texture has the correct contents you want). You can
find it
here: https://github.com/apitrace/apitrace (most distributions should have
it
in their repositories though).

Just wanted to chime in; as a GL newbie, this exact scenario played out for
me too. I hope a GL pro can shed light on what is going wrong, and then
we’ll be able to answer future enquiries with a wiki link.

Regards,
Jeremy J.

2013/12/15 vlag <valentin.soudier at gmail.com>

Sorry I forgot to mention that.
Yes the quad is drawed fine. With your exemple, the expected red rectangle
is displayed.

That why I’m pretty sure the problem is related to the uniform variables.
How is the shader program supposed to ‘bind’ the texture to the sampler
exactely ? It just check the given texture unit ?

Yeah, the sampler2D uniform basically just holds the number to the texture
unit
from which the bound texture will be sampled from. Since all uniforms are
initialized
to zero at program link time, you will sample from texture unit 0 (the
default) without
having to do anything else, so in simple cases like this just plain binding
the texture
should work (assuming the active texture unit is always kept at 0).

I also wondered about these YUV textures too. It seems to be ok since the
intermediate render texture is created with a packed32 pixel format [image:
Smile]

I think you shouldn’t be worried about them unless you specifically told
SDL to
create one.

At this point, I can’t really find anything looking at your code. Maybe you
could
verify that you’re getting correct tex coords in the shader (by drawing
them as
a color), and if that’s correct, I would run the program through something
like
apitrace to make sure the correct texture is bound to unit 0 (this will
also let
you verify that the texture has the correct contents you want). You can
find it
here: https://github.com/apitrace/apitrace (most distributions should have
it
in their repositories though).Sent from my iPhone
On Dec 14, 2013, at 9:06 PM, Jonas Kulla wrote:


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

Ok I’ll try to debug this way later, there is 2 major bug to fix before, due to the new Video managment :wink:

In case someone still want to take a look on sources, there is new locations of shader-related code :
Shader : https://github.com/christopho/solarus/blob/master/src/lowlevel/Shader.cpp
Video::shaded_render : https://github.com/christopho/solarus/blob/master/src/lowlevel/Video.cpp#L503

You also may want to look at :
Video::create_window : https://github.com/christopho/solarus/blob/master/src/lowlevel/Video.cpp#L158 and
Video::initialize_video_modes : https://github.com/christopho/solarus/blob/master/src/lowlevel/Video.cpp#L682

Thanks you all :slight_smile:

2013/12/16 vlag <valentin.soudier at gmail.com>

Ok I’ll try to debug this way later, there is 2 major bug to fix before,
due to the new Video managment [image: Wink]

In case someone still want to take a look on sources, there is new
locations of shader-related code :
Shader :
https://github.com/christopho/solarus/blob/master/src/lowlevel/Shader.cpp
Video::shaded_render :
https://github.com/christopho/solarus/blob/master/src/lowlevel/Video.cpp#L503

You also may want to look at :
Video::create_window :
https://github.com/christopho/solarus/blob/master/src/lowlevel/Video.cpp#L158and
Video::initialize_video_modes :
https://github.com/christopho/solarus/blob/master/src/lowlevel/Video.cpp#L682

Thanks you all [image: Smile]

Hey,

I went ahead and tried debugging this myself. Funnily enough I discovered
that I had downloaded
and played with the solaris engine before, no idea why I didn’t remember
that =P Anyway, I
captured a trace of a little gameplay, and I think I have caught the
culprit: for whatever reason,
SDL2 defaults to rectangle textures, even when the npot2 extension is
available. The glsl syntax
for sampling from these is different from normal textures, ie.

uniform sampler2D tex;
void main() { glFragColor = texture2D(tex, gl_TexCoord[0].st); }

with normal textures becomes

uniform sampler2DRect tex;
void main() { glFragColor = texture2DRect(tex, gl_TexCoord[0].st); }

with rectangle textures (really it’s just a ‘Rect’ appended everywhere).
Looking at the SDL2
sources, it seems rectangle textures will always be preferred when their
ARB extension
is present. The way SDL2 internally deals with this with their own shaders
is by simply
prepending two defines when the rectangle extension is present:

#define sampler2D sampler2DRect
#define texture2D texture2DRect

Jonas

That seems like it should be fixed. I would expect npot to be preferred.

Jonny DOn Mon, Dec 16, 2013 at 5:08 AM, Jonas Kulla wrote:

2013/12/16 vlag <valentin.soudier at gmail.com>

Ok I’ll try to debug this way later, there is 2 major bug to fix
before, due to the new Video managment [image: Wink]

In case someone still want to take a look on sources, there is new
locations of shader-related code :
Shader :
https://github.com/christopho/solarus/blob/master/src/lowlevel/Shader.cpp
Video::shaded_render :
https://github.com/christopho/solarus/blob/master/src/lowlevel/Video.cpp#L503

You also may want to look at :
Video::create_window :
https://github.com/christopho/solarus/blob/master/src/lowlevel/Video.cpp#L158and
Video::initialize_video_modes :
https://github.com/christopho/solarus/blob/master/src/lowlevel/Video.cpp#L682

Thanks you all [image: Smile]

Hey,

I went ahead and tried debugging this myself. Funnily enough I discovered
that I had downloaded
and played with the solaris engine before, no idea why I didn’t remember
that =P Anyway, I
captured a trace of a little gameplay, and I think I have caught the
culprit: for whatever reason,
SDL2 defaults to rectangle textures, even when the npot2 extension is
available. The glsl syntax
for sampling from these is different from normal textures, ie.

uniform sampler2D tex;
void main() { glFragColor = texture2D(tex, gl_TexCoord[0].st); }

with normal textures becomes

uniform sampler2DRect tex;
void main() { glFragColor = texture2DRect(tex, gl_TexCoord[0].st); }

with rectangle textures (really it’s just a ‘Rect’ appended everywhere).
Looking at the SDL2
sources, it seems rectangle textures will always be preferred when their
ARB extension
is present. The way SDL2 internally deals with this with their own shaders
is by simply
prepending two defines when the rectangle extension is present:

#define sampler2D sampler2DRect
#define texture2D texture2DRect

Jonas


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

2013/12/16 Jonathan Dearborn

That seems like it should be fixed. I would expect npot to be preferred.

Hm, I pulled in the latest changes from hg, but this part from
render/opengl/SDL_render_gl.c (GL_CreateTexture) is still unchanged:

if ((renderdata->GL_ARB_texture_rectangle_supported)
    /* && texture->access != SDL_TEXTUREACCESS_TARGET */){
    data->type = GL_TEXTURE_RECTANGLE_ARB;
    texture_w = texture->w;
    texture_h = texture->h;
    data->texw = (GLfloat) texture_w;
    data->texh = (GLfloat) texture_h;
} else {
    data->type = GL_TEXTURE_2D;
    texture_w = power_of_2(texture->w);
    texture_h = power_of_2(texture->h);
    data->texw = (GLfloat) (texture->w) / texture_w;
    data->texh = (GLfloat) texture->h / texture_h;
}

Am I missing something? According to this, rectangle textures are still
unconditionally preferred when available.

I meant in the near-future sense. :wink: Rectangular textures are more of an
incompatibility than a feature in my eyes. A proper patch would probably
add renderdata->GL_ARB_texture_non_power_of_two.

Jonny DOn Mon, Dec 16, 2013 at 10:49 AM, Jonas Kulla wrote:

2013/12/16 Jonathan Dearborn <@Jonathan_Dearborn>

That seems like it should be fixed. I would expect npot to be preferred.

Hm, I pulled in the latest changes from hg, but this part from
render/opengl/SDL_render_gl.c (GL_CreateTexture) is still unchanged:

if ((renderdata->GL_ARB_texture_rectangle_supported)
    /* && texture->access != SDL_TEXTUREACCESS_TARGET */){
    data->type = GL_TEXTURE_RECTANGLE_ARB;
    texture_w = texture->w;
    texture_h = texture->h;
    data->texw = (GLfloat) texture_w;
    data->texh = (GLfloat) texture_h;
} else {
    data->type = GL_TEXTURE_2D;
    texture_w = power_of_2(texture->w);
    texture_h = power_of_2(texture->h);
    data->texw = (GLfloat) (texture->w) / texture_w;
    data->texh = (GLfloat) texture->h / texture_h;
}

Am I missing something? According to this, rectangle textures are still
unconditionally preferred when available.


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

2013/12/16 Jonathan Dearborn

I meant in the near-future sense. :wink: Rectangular textures are more of an
incompatibility than a feature in my eyes. A proper patch would probably
add renderdata->GL_ARB_texture_non_power_of_two.

Ahh, grammar fail on my part =P You meant “should be fixed” as in
"ought to be fixed", I see. Yeah, I totally agree, I was really surprised
to find
rectangle textures in the SDL2 sources in the first place, as it’s mostly a
relic
of the past with very widespread npot support these days. I think it
wouldn’t
be too hard to add it, possibly just a check for the npot extension in the
block
of code I posted that has higher priority than the rect texture check.

OMG, I would have never found it by myself ^^

You’re perfectly right, switching to a uniform sampler2DRect works just fine \o/
So I documented a little about these rectangle sampler, and it seems that they are prefered and optimized for post-processing effects (it gets much easier for the programmer to work with non-normalized texture coordinates). The main drawback is that some fetch sampler features are unavailable for a rectangle sampler.

Found on another forum :

  • Rect samplers support CLAMP, CLAMP_TO_EDGE, CLAMP_TO_BORDER wrapping. Fetch samplers return undefined results for border texels.

  • Rect samplers support filtering, including min/mag crossover (even though there is only one LOD, the switchover may change from nearest to linear filtering.) Fetch samplers only support nearest filtering.

  • Rect samplers support shadow comparison. Fetch samplers don’t.

Am I guaranteed that using sampler2DRect into shader sources will always work with SDL and a OpenGL / ES2 context ?

Rectangular textures are more of an incompatibility than a feature in my eyes.

I’m still pretty new with modern display features. Why should rectangle sampler be avoided ?

Anyway, a big thanks to everybody !

As a quick fix, one could even just make
rendererdata->GL_ARB_texture_rectangle_supported
to be false when npot is available.

Jonny DOn Mon, Dec 16, 2013 at 11:29 AM, Jonas Kulla wrote:

2013/12/16 Jonathan Dearborn <@Jonathan_Dearborn>

I meant in the near-future sense. :wink: Rectangular textures are more of an
incompatibility than a feature in my eyes. A proper patch would probably
add renderdata->GL_ARB_texture_non_power_of_two.

Ahh, grammar fail on my part =P You meant “should be fixed” as in
"ought to be fixed", I see. Yeah, I totally agree, I was really surprised
to find
rectangle textures in the SDL2 sources in the first place, as it’s mostly
a relic
of the past with very widespread npot support these days. I think it
wouldn’t
be too hard to add it, possibly just a check for the npot extension in the
block
of code I posted that has higher priority than the rect texture check.


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org