Safe/acceptable to call SDL_SetTextureColorMod a lot?

As a simple way to render multiple textures that are the same other than color I load a plain white circle in to an SDL_Texture then just call SDL_SetTextureColorMod() giving it the color I want to make the circle.

This all works fine if the textures are individual (Example 1) but if I am sharing the SDL_Texture so that multiple objects all reference it, it means that SDL_SetTextureColorMod() must be called every render frame before the object renders the texture since the color it gave last time may have been changed by another object (Example 2).

Is calling SDL_SetTextureColorMod() every render frame, for potentially quite a lot of objects sharing a texture, going to cause major performance issues?

The reason it is required is the system is designed using a shared texture functionality with basic reference counting (I understand that there are probably better ways to do this using smart pointers but that is not the topic for discussion here). Is it going to be better to just let each object have it’s own copy of the SDL_Texture so it only has to set the color once (or whenever it needs to change) rather than every render frame?

Example 1:

Code:
SDL_Texture* tex1;
SDL_Texture* tex2;
SDL_Texture* tex3;

// All 3 instances have their own SDL_Texture
MyObject A(tex1);
MyObject B(tex2);
MyObject C(tex3);

// A call to set the color of the texture is only required once for each class

Example 2:

Code:
SDL_Texture* tex;

// All 3 instances share the SDL_Texture
MyObject A(tex);
MyObject B(tex);
MyObject C(tex);

// A call to set the color of the texture must be made before rendering
// each object to ensure that any other object has not set a different color.
// E.g if the draw order was A, B, C and the color was set to be different
// for each object then before rendering B, each frame it would need to set
// the color again otherwise it would have the color of A and the same
// for the others

Edit: This would also extend to SDL_SetTextureAlphaMod() and SDL_SetTextureBlendMode() or other similar functions

For reference I’m using SDL2.------------------------
The Z-Buffer (http://www.zamma.co.uk)

Looking at the code SDL_SetTextureColorMod() seems to alter the state of
the SDL_COPY_MODULATE_COLOR flag, which in turn might cause a texture
reallocation (if I understand the meaning of SDL_InvalidateMap() right)

so the worst case boils down to this code sequence:
SDL_SetTextureColorMod(tex, 255, 255, 255);
SDL_SetTextureColorMod(tex, anyR, anyG, anyB);
SDL_SetTextureColorMod(tex, 255, 255, 255);

so if you make sure never to call it with 100% white you should be fine
(I would do some benchmarks though)

the same seems to be true for those other functions just with other
value combinations

If SDL_gpu would work for you and you have actual performance needs, then I
would recommend that. It has GPU_CreateAliasImage() which you can use for
shallow copies of textures (same texture data, different render settings -
like color). It also uses sprite batching to minimize the overhead of
multiple GL calls.

Jonny DOn Sat, Jul 26, 2014 at 7:42 AM, Robotic-Brain wrote:

Looking at the code SDL_SetTextureColorMod() seems to alter the state of
the SDL_COPY_MODULATE_COLOR flag, which in turn might cause a texture
reallocation (if I understand the meaning of SDL_InvalidateMap() right)

so the worst case boils down to this code sequence:
SDL_SetTextureColorMod(tex, 255, 255, 255);
SDL_SetTextureColorMod(tex, anyR, anyG, anyB);
SDL_SetTextureColorMod(tex, 255, 255, 255);

so if you make sure never to call it with 100% white you should be fine
(I would do some benchmarks though)

the same seems to be true for those other functions just with other value
combinations


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

which in turn might cause a texture
reallocation (if I understand the meaning of SDL_InvalidateMap() right)

so the worst case boils down to this code sequence:
SDL_SetTextureColorMod(tex, 255, 255, 255);
SDL_SetTextureColorMod(tex, anyR, anyG, anyB);
SDL_SetTextureColorMod(tex, 255, 255, 255);

so if you make sure never to call it with 100% white you should be fine
(I would do some benchmarks though)

Hello, thank you for responding. If it is only changing the value of the SDL_COPY_MODULATE_COLOR flag (through bitwise operations) why would there be a texture reallocation? I’m also not quite sure what you mean regarding the worst case code sequence especially why I shouldn’t set to 100% white?

Code:

SDL_render.c

596 int
597 SDL_SetTextureColorMod(SDL_Texture * texture, Uint8 r, Uint8 g, Uint8 b)
598 {
599 SDL_Renderer *renderer;
600
601 CHECK_TEXTURE_MAGIC(texture, -1);
602
603 renderer = texture->renderer;
604 if (r < 255 || g < 255 || b < 255) {
605 texture->modMode |= SDL_TEXTUREMODULATE_COLOR;
606 } else {
607 texture->modMode &= ~SDL_TEXTUREMODULATE_COLOR;
608 }
609 texture->r = r;
610 texture->g = g;
611 texture->b = b;
612 if (texture->native) {
613 return SDL_SetTextureColorMod(texture->native, r, g, b);
614 } else if (renderer->SetTextureColorMod) {
615 return renderer->SetTextureColorMod(renderer, texture);
616 } else {
617 return 0;
618 }
619 }------------------------
My Site (http://www.zamma.co.uk)

  Code:

SDL_render.c

596 int
597 SDL_SetTextureColorMod(SDL_Texture * texture, Uint8 r, Uint8 g,
Uint8 b)
598 {
599 SDL_Renderer *renderer;
600
601 CHECK_TEXTURE_MAGIC(texture, -1);
602
603 renderer = texture->renderer;
604 if (r < 255 || g < 255 || b < 255) {
605 texture->modMode |= SDL_TEXTUREMODULATE_COLOR;
606 } else {
607 texture->modMode &= ~SDL_TEXTUREMODULATE_COLOR;
608 }
609 texture->r = r;
610 texture->g = g;
611 texture->b = b;
612 if (texture->native) {
613 return SDL_SetTextureColorMod(texture->native, r, g, b);
614 } else if (renderer->SetTextureColorMod) {
615 return renderer->SetTextureColorMod(renderer, texture);
616 } else {
617 return 0;
618 }
619 }

as you can see in line 615 it just forwards the call to some renderer
defined function
As far as I could see directFB is the only implementation, which
actually maps this to a no-op
therefore all other renderers seem to use the implementation from
SW_SetTextureColorMod which redirects to SDL_SetSurfaceColorMod

the 100% white restriction comes from the if statements in line 324 and
line 329

http://hg.libsdl.org/SDL/file/6d059ed9b6ca/src/video/SDL_surface.c#l310

Code:

310 int
311 SDL_SetSurfaceColorMod(SDL_Surface * surface, Uint8 r, Uint8 g, 

Uint8 b)
312 {
313 int flags;
314
315 if (!surface) {
316 return -1;
317 }
318
319 surface->map->info.r = r;
320 surface->map->info.g = g;
321 surface->map->info.b = b;
322
323 flags = surface->map->info.flags;
324 if (r != 0xFF || g != 0xFF || b != 0xFF) {
325 surface->map->info.flags |= SDL_COPY_MODULATE_COLOR;
326 } else {
327 surface->map->info.flags &= ~SDL_COPY_MODULATE_COLOR;
328 }
329 if (surface->map->info.flags != flags) {
330 SDL_InvalidateMap(surface->map);
331 }
332 return 0;
333 }Am 26.07.2014 14:45, schrieb Zammalad:

I had to look up to make sure.

Neither the OpenGL nor the Direct3D renderers seem to define a texture
color modulation function… WTF? This is a really simple function for
the GPU (even for immediate mode OpenGL, jeez), why isn’t this
supported directly by those renderers in the first place? Or am I
misunderstanding the code?

The color modulation happens at draw time (inside GL_RenderCopy etc.), via GL_SetColor in the OpenGL backend of SDL_Render.
It is very cheap.On Jul 26, 2014, at 3:44 PM, Sik the hedgehog <sik.the.hedgehog at gmail.com> wrote:

I had to look up to make sure.

Neither the OpenGL nor the Direct3D renderers seem to define a texture
color modulation function… WTF? This is a really simple function for
the GPU (even for immediate mode OpenGL, jeez), why isn’t this
supported directly by those renderers in the first place? Or am I
misunderstanding the code?


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

OK that makes a lot more of sense I suppose.

2014-07-26 15:46 GMT-03:00, Alex Szpakowski :> The color modulation happens at draw time (inside GL_RenderCopy etc.), via

GL_SetColor in the OpenGL backend of SDL_Render.
It is very cheap.

On Jul 26, 2014, at 3:44 PM, Sik the hedgehog <@Sik_the_hedgehog> wrote:

I had to look up to make sure.

Neither the OpenGL nor the Direct3D renderers seem to define a texture
color modulation function… WTF? This is a really simple function for
the GPU (even for immediate mode OpenGL, jeez), why isn’t this
supported directly by those renderers in the first place? Or am I
misunderstanding the code?


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


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

It is cheap unless you are rendering thousands of sprites… then you need
to batch them to avoid the glColor calls which certainly add up.

Jonny DOn Saturday, July 26, 2014, Sik the hedgehog <sik.the.hedgehog at gmail.com> wrote:

OK that makes a lot more of sense I suppose.

2014-07-26 15:46 GMT-03:00, Alex Szpakowski <aszpakowski at gmail.com
<javascript:;>>:

The color modulation happens at draw time (inside GL_RenderCopy etc.),
via
GL_SetColor in the OpenGL backend of SDL_Render.
It is very cheap.

On Jul 26, 2014, at 3:44 PM, Sik the hedgehog < sik.the.hedgehog at gmail.com <javascript:;>> wrote:

I had to look up to make sure.

Neither the OpenGL nor the Direct3D renderers seem to define a texture
color modulation function… WTF? This is a really simple function for
the GPU (even for immediate mode OpenGL, jeez), why isn’t this
supported directly by those renderers in the first place? Or am I
misunderstanding the code?


SDL mailing list
SDL at lists.libsdl.org <javascript:;>
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org


SDL mailing list
SDL at lists.libsdl.org <javascript:;>
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org


SDL mailing list
SDL at lists.libsdl.org <javascript:;>
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

The actual draw calls will be the bottleneck in that case, not the glColor calls (again, they?re very cheap, plus they don?t cause the draw calls to do much more state validation.)On Jul 26, 2014, at 4:37 PM, Jonathan Dearborn wrote:

It is cheap unless you are rendering thousands of sprites… then you need to batch them to avoid the glColor calls which certainly add up.

Jonny D


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

So… overall what would be the answer to my question - Can I safely call SDL_SetTextureColorMod and similar functions potentially many many times a render frame? Think for example if I was using particles all sharing the same texture but being drawn different colors?

The only alternative I can see is to have individual instances of the texture which would surely be a large overhead itself.------------------------
My Site (http://www.zamma.co.uk)

For something like particles - which, I assume, are rarely 100% white -
it is totally save.
If you often have to alternate between 100% white and any other color,
only a benchmark test can give you an answer

Pseudo code:

loop:
SDL_SetTextureColorMod(tex, 255, 255, 255);
Render
SDL_SetTextureColorMod(tex, 0, 125, 255);
Render
end loop

you could also look into what Jonathan Dearborn suggested If you need
more speedAm 26.07.2014 23:26, schrieb Zammalad:

So… overall what would be the answer to my question - Can I safely
call SDL_SetTextureColorMod and similar functions potentially many
many times a render frame? Think for example if I was using particles
all sharing the same texture but being drawn different colors?

The only alternative I can see is to have individual instances of the
texture which would surely be a large overhead itself.


My Site [1]

Links:

[1] http://www.zamma.co.uk


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

For something like particles - which, I assume, are rarely 100% white -
it is totally save.
If you often have to alternate between 100% white and any other color,
only a benchmark test can give you an answer

Pseudo code:

loop:
SDL_SetTextureColorMod(tex, 255, 255, 255);
Render
SDL_SetTextureColorMod(tex, 0, 125, 255);
Render
end loop

The thing I don’t get about this though is why is it not safe to set to 100% white. Why would that be any different to setting it to a different color? I’m obviously missing something but I can’t see what that is. I know you mentioned specific lines in the code, but why is that a limitation?------------------------
My Site (http://www.zamma.co.uk)

Look closely at the if statement I quoted [1]
here with some comments:

       // store the flag state

323 flags = surface->map->info.flags;
// 0xFF equals 255…
// if you invert every boolean expression and flip AND / OR
this becomes clearer:
// if red == 255 AND green == 255 AND blue == 255 jump to else
block
// -> aka "if 100% white reset flag, else set it (remember: if
and else are flipped)"
324 if (r != 0xFF || g != 0xFF || b != 0xFF) {
// this sets the flag
325 surface->map->info.flags |= SDL_COPY_MODULATE_COLOR;
326 } else {
// this resets it
327 surface->map->info.flags &= ~SDL_COPY_MODULATE_COLOR;
328 }
// compare new flag state to stored state…
329 if (surface->map->info.flags != flags) {
// …if they differ InvalidateMap
330 SDL_InvalidateMap(surface->map);
331 }

now I don’t exactly know what SDL_InvalidateMap() does…
But to me it looks like it stores the pixel data in a native and a user
defined version.
If the requested format changes, it deallocates the native version. (it
also seems to do some reference counting)

Now if you are deallocating stuff in there, it must be allocated
somewhere else to keep a balance. (or else you would release more than
you allocated)

So I assume the drawing functions check the texture and re-create it if
necessary.
As you should know any kind of heap alloc/dealloc is potentially
expensive. (unless SDL uses it’s own optimized allocator, which I highly
doubt since this is highly application specific)

The overall structure seems to be the same for the other functions you
asked about, just the values are different

[1]
http://hg.libsdl.org/SDL/file/6d059ed9b6ca/src/video/SDL_surface.c#l310Am 27.07.2014 01:13, schrieb Zammalad:

The thing I don’t get about this though is why is it not safe to set
to 100% white. Why would that be any different to setting it to a
different color? I’m obviously missing something but I can’t see what
that is. I know you mentioned specific lines in the code, but why is
that a limitation?

Most of the time you’ll be using a hardware renderer and changing colors
will be very very cheap. If you’re concerned about performance, try
rendering with all the colors and then render with all of them white and
see if you see any performance difference.

Cheers!On Sat, Jul 26, 2014 at 6:06 PM, Robotic-Brain wrote:

Look closely at the if statement I quoted [1]
here with some comments:

      // store the flag state

323 flags = surface->map->info.flags;
// 0xFF equals 255…
// if you invert every boolean expression and flip AND / OR this
becomes clearer:
// if red == 255 AND green == 255 AND blue == 255 jump to else
block
// -> aka “if 100% white reset flag, else set it (remember: if
and else are flipped)”

324 if (r != 0xFF || g != 0xFF || b != 0xFF) {
// this sets the flag

325 surface->map->info.flags |= SDL_COPY_MODULATE_COLOR;
326 } else {
// this resets it

327 surface->map->info.flags &= ~SDL_COPY_MODULATE_COLOR;
328 }
// compare new flag state to stored state…

329 if (surface->map->info.flags != flags) {
// …if they differ InvalidateMap
330 SDL_InvalidateMap(surface->map);
331 }

now I don’t exactly know what SDL_InvalidateMap() does…
But to me it looks like it stores the pixel data in a native and a user
defined version.
If the requested format changes, it deallocates the native version. (it
also seems to do some reference counting)

Now if you are deallocating stuff in there, it must be allocated somewhere
else to keep a balance. (or else you would release more than you allocated)

So I assume the drawing functions check the texture and re-create it if
necessary.
As you should know any kind of heap alloc/dealloc is potentially
expensive. (unless SDL uses it’s own optimized allocator, which I highly
doubt since this is highly application specific)

The overall structure seems to be the same for the other functions you
asked about, just the values are different

[1] http://hg.libsdl.org/SDL/file/6d059ed9b6ca/src/video/SDL_
surface.c#l310

Am 27.07.2014 01:13, schrieb Zammalad:

The thing I don’t get about this though is why is it not safe to set

to 100% white. Why would that be any different to setting it to a
different color? I’m obviously missing something but I can’t see what
that is. I know you mentioned specific lines in the code, but why is
that a limitation?


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

I can see what you are saying but unless I am mistaken (highly possible) surely the flag will change whatever color you set it to UNLESS you are setting it to the same color? So the 100% white limitation isn’t actually an issue it is just used in that if statement for a different optimised way to set the flag. If the flag was white and you set it to pure blue then SDL_InvalidateMap would be called in the same way if you had set it from blue to pure white.

Robotic-Brain wrote:> Look closely at the if statement I quoted [1]

here with some comments:

// store the flag state
323 flags = surface->map->info.flags;
// 0xFF equals 255…
// if you invert every boolean expression and flip AND / OR
this becomes clearer:
// if red == 255 AND green == 255 AND blue == 255 jump to else
block
// -> aka "if 100% white reset flag, else set it (remember: if
and else are flipped)"
324 if (r != 0xFF || g != 0xFF || b != 0xFF) {
// this sets the flag
325 surface->map->info.flags |= SDL_COPY_MODULATE_COLOR;
326 } else {
// this resets it
327 surface->map->info.flags &= ~SDL_COPY_MODULATE_COLOR;
328 }
// compare new flag state to stored state…
329 if (surface->map->info.flags != flags) {
// …if they differ InvalidateMap
330 SDL_InvalidateMap(surface->map);
331 }

now I don’t exactly know what SDL_InvalidateMap() does…
But to me it looks like it stores the pixel data in a native and a user
defined version.
If the requested format changes, it deallocates the native version. (it
also seems to do some reference counting)

Now if you are deallocating stuff in there, it must be allocated
somewhere else to keep a balance. (or else you would release more than
you allocated)

So I assume the drawing functions check the texture and re-create it if
necessary.
As you should know any kind of heap alloc/dealloc is potentially
expensive. (unless SDL uses it’s own optimized allocator, which I highly
doubt since this is highly application specific)

The overall structure seems to be the same for the other functions you
asked about, just the values are different

[1]
http://hg.libsdl.org/SDL/file/6d059ed9b6ca/src/video/SDL_surface.c#l310

Am 27.07.2014 01:13, schrieb Zammalad:

The thing I don’t get about this though is why is it not safe to set
to 100% white. Why would that be any different to setting it to a
different color? I’m obviously missing something but I can’t see what
that is. I know you mentioned specific lines in the code, but why is
that a limitation?


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


My Site (http://www.zamma.co.uk)

I think you got it…
The issue is not setting it to white per se. The issue is changing it TO
or FROM white

But as I said only an actual benchmark can tell you if this is really
significant…Am 27.07.2014 12:13, schrieb Zammalad:

I can see what you are saying but unless I am mistaken (highly
possible) surely the flag will change whatever color you set it to
UNLESS you are setting it to the same color? So the 100% white
limitation isn’t actually an issue it is just used in that if
statement for a different optimised way to set the flag. If the flag
was white and you set it to pure blue then SDL_InvalidateMap would be
called in the same way if you had set it from blue to pure white.

Ah right I think I understand now, thanks. From what Sam said though it should be safe to do but yes I will do some benchmarking when the codebase is in a position to.

Robotic-Brain wrote:> I think you got it…

The issue is not setting it to white per se. The issue is changing it TO
or FROM white

But as I said only an actual benchmark can tell you if this is really
significant…

Am 27.07.2014 12:13, schrieb Zammalad:

I can see what you are saying but unless I am mistaken (highly
possible) surely the flag will change whatever color you set it to
UNLESS you are setting it to the same color? So the 100% white
limitation isn’t actually an issue it is just used in that if
statement for a different optimised way to set the flag. If the flag
was white and you set it to pure blue then SDL_InvalidateMap would be
called in the same way if you had set it from blue to pure white.


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


My Site (http://www.zamma.co.uk)

I did some digging and also compiled SDL with debugging symbols so I could walk through the code. Seems that it is completely safe to do this as pretty much for most HW implementations (except directfb) renderer->SetTextureColorMod is NULL meaning the color and flag are set.------------------------
My Site (http://www.zamma.co.uk)