Color artifacts remain after continuous copy of texture with SDL_SetTextureAlphaMod

I have 2 SDL_PIXELFORMAT_RGBA32 textures, one for the current frame, the other for the last frame. The last frame is set to some higher than 0 alpha value with SDL_SetTextureAlphaMod. The goal of this is some blur effect, which works, except for this thing.
I start each render cycle with clearing current frame, rendering last frame into current (with this alpha value), then rendering the new scene on the current frame. After this I render the current frame into the window, display it and then render the current frame back into the last.
The result, after the blur effect goes away is these color artifacts.


What I noticed is that the higher the alpha set with SDL_SetTextureAlphaMod the more visible these remain. Here is the source for inspection: Making sure you're not a bot! . You can inspect CreateAlphaTextures, where they are created and Data[“Alpha”][1] where there is the alpha specific code.
I get that this is some rounding issue, what I’m not sure is how to solve it.

One more thing I just noticed. If the background color is completely black (not the dark gray in this picture), then this does not happen

What happens if you set the texture as a target, set the render draw color either full white or black but zero alpha, then sdl.renderClear() the texture directly after creating it? (right about line 410)

That did not change the behavior. Thanks to this I’ve found a half workaround, if I know the draw color won’t change, unlike in the image where it is set to cycle through rainbow colors, then I can clear the last frame with the color I will draw with, and that causes the entire texture to have the artifact, which is less visible than lines, it’s “just” a wrong background color. However, this does not work in this rainbow mode, as different colors cause different colored artifacts and with higher alpha values making it more noticeable, after some alpha value barely anything could be seen for the entire window.

I was wrong about it not happenning with black background, I just couldn’t see it

Hmm. I don’t know Lua, so I’m kind of bogging my way through the code. I appreciate the excellent comments you have left.

If I understand the problem correctly, you want that one pixel in the middle to be pink, but you are seeing radiating colors bleeding out from the pixel?

You might try setting the texture’s scalemode to SDL_SCALEMODE_PIXELART or SDL_SCALEMODE_NEAREST to prevent color bleeding. Here’s the function: sdl.setTextureScaleMode

I think you will need to set that for both textures, or use sdl.setDefaultTextureScaleMode in the beginning of your code.

I apologize for mixing C/C++ names where I don’t know the Lua equivalents.

Thank you for trying to help!
You can use the regular C/C++ names, I understand that.
Here is a video for it in action, to better see it. https://0x0.st/KX-q.mp4 Where ever something was drawn, these lighter or darker, depending on foreground and background color used, marks remain.
I tried SDL_SCALEMODE now, and it did not change the behavior.

Thank you, the video helps.

So the image is “burning and dodging” rather than fading out.

I vaguely remember running into something like this when I was writing a small drawing program that used images as brushes.

Try messing with setting SDL_BlendMode, you can experiment with settings for the renderDrawCommands but I think the textureBlendMode is the more likely to hold the solution.

1 Like

Thank you for the pointers! I have tried this once before, and then I couldn’t get it to work, but now I have spent some more hours on it and I finally got it working. https://0x0.st/KXqA.mp4
What I have done was I made a “fade” texture, that is just cleared once with {0, 0, 0, AlphaToRemove}, and then I set it’s blend mode to a custom one
local FadeBlend = sdl.composeCustomBlendMode(sdl.BLENDFACTOR_ONE,
sdl.BLENDFACTOR_ONE, sdl.BLENDOPERATION_REV_SUBTRACT, sdl.BLENDFACTOR_ONE,
sdl.BLENDFACTOR_ONE, sdl.BLENDOPERATION_REV_SUBTRACT)
This blend mode subtracts both color and alpha of the fade texture from the destination texture, however since I fill color with zeroes, that is not affected.
Then, in the render cycle instead of clearing and copying previous frame, I copy this fade texture that subtracts the alpha. For it to not affect the background and optional grid lines, those always get rendered to the window instead. Compared to how it was done before, this is more performant, since last frames are not needed to be copied into a texture, which is one less SDL_RenderTexture call. A single nitpick I have with it is that I have to have the fade texture that is just a single RGBA value for the entire window size, but I had to have that texture previously as well, just that it contained the last frame then, so it’s not that different.

1 Like

To replace your fade texture, this might be an option:

I think you could replace the fade texture render call by using that other function SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND), then set the rendercolor to a low alpha version of your background color, and finally use SDL_RenderFillRect(renderer, NULL) to fill the whole area.

I think you could keep SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND) all through your program if it doesn’t hurt performance, or you could set it at fade time, then reset to SDL_BLENDMODE_NONE for your other rendering needs.

I apologize for guessing again, I think the normal blend mode is good enough for this step, but I haven’t tested it against your code.

However, you might want to keep that fade texture, since that’s essentially your background. It could be used for many background effects like setting a series of images as the background that rotate at beats of the music, play a simulation of stars at warp-speed, or it could even be a streamed texture with a video that kind of leaves an after-image trail as things move.

(If video sounds fun, you’d want to look into the gstreamer or openCV libraries).

Edit: I keep forgetting that SDL3 has web-cam support, so you could stream from that without any other external libraries.

In case you were curious, yes, all of my personal projects suffer from scope-creep.

With SDL_BLENDMODE_BLEND the problem was that it always got to some kind of middle point between the foreground and background color, I think. That middle point was what remained visible. So with a low alpha version it still wouldn’t reach 0, only some value between the two.
However, I have not thought of using SDL_RenderFillRect, so I tried that now, and it seems blend mode is not used in that case. Or somehow neither SDL_BLENDMODE_BLEND, SDL_BLENDMODE_NONE nor my own blend mode produced a different color, when I used SDL_RenderFillRect on the texture, which I tried with both NULL SDL_FRect and one for the entire window, in case that mattered.

Actually, the fade texture is not the background. The fade texture is only applied to the foreground. Background color and the grid are drawn directly on the window, and they are not affected by anything that goes on in the foreground, so I indeed could put something in the background. And I actually have a mode, where the background color changes between rainbow colors, but it can cause a headache, so I don’t use it.

Hah, I can imagine. This very small program already has 37 options, from which only 2 would I say is not related to usage, one is saving default settings, the other is displaying the help text.

Someone that only has SDL2 wanted to use the program, and when making it support both versions, I discovered that SDL_RenderFillRect does work with the custom blend mode, i just had to use SDL_SetRenderDrawBlendMode, as the docs suggest. So now that texture is no more, resize is faster with not having to create/fill 2 textures but only one, and most likely filling the entire texture with a color instead of another texture is faster too (which happened on every frame)