RenderTarget texture got deleted between RenderPresent

Hi,
I want to cache some buttons which I compose from several drawing operations as textures. But they only show up at the first SDL_RenderPresent call. On the second they are gone. Why? What am I doing wrong.
I work with SDL2 on a Raspberrypi.

This is what I did:

window = SDL_CreateWindow("YaPS", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1024, 768, SDL_WINDOW_SHOWN);
renderer = SDL_CreateRenderer(window, 0, SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
SDL_GetRendererInfo(renderer, &info);
if (!(info.flags & SDL_RENDERER_TARGETTEXTURE))
{
        // check if renderer fail to use target texture, it does not fail
	printlog(LOG_ERROR,"Renderer does not support SetRenderTarget\n",SDL_GetError());
	return 1;
}
ob->tx  = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, ob->r.w, ob->r.h);
//	ob->tx=background;
if (!ob->tx)
{
	printlog(LOG_ERROR, "Cannot create object texture %i '%s': %s\n", id, text, SDL_GetError());
	return ob;
}
SDL_SetTextureBlendMode(ob->tx, SDL_BLENDMODE_BLEND);  // allow transparency
    
// now "draw" the button onto the texture

// set render output to texture
SDL_SetRenderTarget(renderer, ob->tx);
// set the background color
SDL_SetRenderDrawColor2(renderer, (ob->flags&SELECTED)?ob->style->bgcolor_selected:ob->style->bgcolor);
// draw the button's background
SDL_RenderFillRect(renderer, &ob->r);
// set render target to screen
SDL_SetRenderTarget(renderer, NULL);
	
SDL_RenderCopy(renderer, ob->tx, NULL, &ob->r);
SDL_RenderPresent(renderer);
puts("pause1"); getchar(); 
SDL_RenderCopy(renderer, ob->tx, NULL, &ob->r);
SDL_RenderPresent(renderer);
puts("pause2"); getchar();

When program reaches “pause1” I see the blue rectangle on the screen. At “pause2” it is gone.
You might say, that the SDL_TEXTUREACCESS_STREAMING is wrong. I would say yes, but if I set it to SDL_TEXTUREACCESS_STATIC, nothing happens at all. I never see my blue rectangle.

Hm. I don’t see a problem with your code right now. Technically, this should work… I think. Do you not clear the default render target after SDL_RenderPresent?

I happen to have some Raspberry Pis running in front of me and will try to reproduce it. Which Raspberry Pi version are you using? What SDL video driver is SDL2 using? Are you using the new vc4 driver? If it’s enabled, the file /dev/dri/card0 should exist.

When I do a SDL_RenderClear at the beginning of each drawing cycle I only get a black screen and don’t see my rectangle at all. It seems the renderer ignores the render target and always renders to screen.

But if I use a texture which is created by loading an image with IMG_LoadTexture, then it works as desired. So it seems it has something to with the target texture. A workaround is to use surfaces to build the cached elements and then create textures from them on the fly. But that’s not really nice.

I am using a Raspberrypi 2 Modell B. SDL says it is using the driver “opengles2”. There is no directory /dev/dri. So I think it’s an older version.

uname says it is “Linux raspberrypi 3.18.11-v7+”

I don’t really want to do an update if not absolutely necessary, because it took ages to compile all the SDL stuff and other things. And I am not a Linux expert at all.

Oh yes, compiling on these machines is rather painful.

That’s odd. I have too look into why it would just ignore the render target. One more thing: What does SDL_GetCurrentVideoDriver give you after SDL_Init?

to debug this kind of problems I would do

  1. just after creating the renderer, clear it with some color (eg: grey, but not black)

  2. after RenderPresent, the SDL doc says you should expect the buffer to be modified randomly.
    Hence you should always do a Clear before drawing anything else.

another thing, you can try setting SDL_RenderSetClipRect to NULL

I wasn’t able to reproduce the issue.

Is that the kernel from wheezy? Seems really old. Shouldn’t have any connection with this issue, though.

Hi, sorry for the delay. I was at the Maker Faire, so didn’t had time to work on my project.
The thing with clearing the randerer I tried already. The clearing works, I get the screen in the given color, but my rectangle is invisible anyway. Also Setting the clipping rectangle does not help.

@ChliHug: Thank you for trying. Maybe my Linux and it’s drivers are really too old. I will check if I find a new SD card and try a newer Installation. But that may be take a while. I have not so much time at the moment. I will Keep you informed.

I now have reinstalled my Pi with the latest Raspian (the light version without X). Then installed the SDL2 stuff including development stuff. I can compile my program, but it does not find a video device:

Cannot initialize SDL: No available video device

Why this? With the old installation I can start my program even via ssh and get the screen output on the console and also the keyboard input from the attached USB keyboard. What is wrong now?

Now I have rebuilt the SDL2 libraries from scratch which took hours to complete. First I could not compile smpeg2, but after a patch that worked. So finally I could compile everything without error. But it does not start.
When creating the SDL window I get the following error now:

Could not create Window: Could not initialize OpenGL / GLES library

Any ideas?

I’m not sure there is anything Raspberry Pi specific to all the other SDL libraries, the packages from the repositories should be just fine.

As for SDL2 itself, check what video drivers you now have with SDL_GetNumVideoDrivers and SDL_GetVideoDriver. If one of them is rpi, then you have support for the firmware-side Raspberry Pi driver.

If you get that error message when you initialized SDL with the rpi driver, it may be related to the issue that the default OpenGL attributes will default to OpenGL 2.1. You can workaround this by disabling OpenGL when building SDL or setting the OpenGL attributes of your application to one of the OpenGL ES versions with (see SDL_GL_SetAttribute). This also has just been fixed in the latest development version of SDL. Have a look at this site on how to get the latest source code. The latest version also has a new KMSDRM video driver which, if enabled, will work with the new vc4 driver for the Raspberry Pi.

I now uninstalled mesa-common-dev because I found that at several places in the web. But it does not help. Then I added a list of the videodrivers, as suggested by ChliHug.

This is my initialization code:

    // start SDL video
    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO)<0)
    {
            printlog(LOG_ERROR,"Cannot initialize SDL: %s",SDL_GetError());
            return 1;
    }
    atexit(GUI_quit); // remember to quit SDL
    
    for (i=0; i<SDL_GetNumVideoDrivers();i++)
            printlog(LOG_DEBUG,"Videodriver found: %s",SDL_GetVideoDriver(i));
    
    if (flags != Mix_Init(flags))
    {
            printlog(LOG_ERROR, "Cannot initialize SDL_Mixer: %s", SDL_GetError());
            return 1;
    }
    
    // open the screen window
    window = SDL_CreateWindow("YaPS", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1024, 768, SDL_WINDOW_SHOWN);
    if (!window)
    {
            printlog(LOG_ERROR, "Could not create Window: %s",SDL_GetError());
            return 1;
    }
    
    renderer = SDL_CreateRenderer(window, 0, SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
    if (!renderer)
    {
            printlog(LOG_ERROR, "Could not create Renderer: %s",SDL_GetError());
            return 1;
    }

And this is my output (I run my application as root to avoid user rights problems with the framebuffer):

G1 Full KMS:

05.09.2017,17:42:01: ERROR  : Cannot initialize SDL:

G2 Fake KMS:
G3 None:

05.09.2017,17:46:16: DEBUG  : Videodriver found: RPI
05.09.2017,17:46:16: DEBUG  : Videodriver found: dummy
05.09.2017,17:46:16: ERROR  : Could not create Window: Could not initialize OpenGL / GLES library

As you can see. If I activate Full KMS it could not initialize at all. The other cases initialize SDL and see the RPI driver but fail to create the window.

I built SDL2 with the following config:

../configure --host=armv7l-raspberry-linux-gnueabihf --disable-pulseaudio --disable-esd --disable-video-mir --disable-video-wayland --disable-video-x11 --disable-video-opengl

So there should be no false opengl because of --disable-video-opengl

I have to check the latest development sources now as suggested by ChliHug. But why? Everything was fine on my old Raspian.

Now I have compiled the latest Mercurial snapshot of SDL2. But there is no change at all. All video modes/drivers are as described above.

So I had a little renderer problem at first and now have a complete failure. The only thing I can think of now is to reinstall the raspi with the full featured version of Raspian (not the light version) and hope that it works then.

Or not use SDL or other bloated libraries and draw directly on the framebuffer. My GUI application (not a game) does not need all that high sophisticated stuff of SDL. I only need some nice text rendering, some blitting of images (png and jpg) and non-waiting keyboard entry. Maybe at a later stage video playing, but I think that’s beyond my abilities anyway.

Any more ideas.

The SDL KMSDRM driver is disabled by default right now. Enable it with --enable-video-kmsdrm on the configure line. It also requires libgbm. Should be available with the libgbm-dev package.

You either need to select the “Fake KMS” or “Full KMS” option if you want to use it. This will disable the old driver and the SDL RPI driver doesn’t work anymore. Not a problem if the KMSDRM driver works, of course.

Yeah, that’s odd. I was certain that would work.

I’m guessing you had a special package and not the one from the Debian repository.

I’ll check again why it could throw that message there.

Edit: Oh, and check what driver actually got initialized with SDL_GetCurrentVideoDriver. Just to make sure.

Edit2: Arblgarg! They changed the file names. Known since July 2016, someone mentioned SDL will break, no bug report in the SDL bug tracker. Absolutely terrific.

At least we have environment variables to work around it. Set SDL_VIDEO_GL_DRIVER=/opt/vc/lib/libbrcmGLESv2.so and SDL_VIDEO_EGL_DRIVER=/opt/vc/lib/libbrcmEGL.so before you start your application if you want to use the RPI driver.

With the option --enable-video-kmsdrm I cannot compile the SDL sources I get the following error:

In file included from /home/pi/SDL-2.0.6-11426/src/video/raspberry/SDL_rpievents.c:29:0:
/home/pi/SDL-2.0.6-11426/src/video/raspberry/SDL_rpivideo.h:47:5: error: unknown type name 'EGL_DISPMANX_WINDOW_'
 EGL_DISPMANX_WINDOW_T dispman_window;
 ^~~~~~~~~~~~~~~~~~~~~

I set the mentioned environment variables, but that doesn’t change anything. I cannot output the SDL_GetCurrentVideoDriver when using KSM because SDL does not initialize at all. It just stops with an empty error string as mentioned above.

If I use fake_KSM I get this output:

07.09.2017,19:11:44: DEBUG  : Videodriver found: RPI
07.09.2017,19:11:44: DEBUG  : Videodriver found: dummy
07.09.2017,19:11:44: DEBUG  : Using display driver 'RPI'.
07.09.2017,19:11:44: ERROR  : Could not create Window: Could not initialize OpenGL / GLES library

Since SDL2 seems to be broken, I have either revert to my old setting, living with the texture bug and never ever update Linux. Or I have to skip SDL and draw directly on the framebuffer. Or maybe use SDL1. Maybe the last would be the best solution.

The files do exist, right?

I’ll check if this is an issue with the lite version and write down all the steps.

You mean the SDL_rpi… include files? Yes they exist. Maybe there is some EGL stuff missing on the light version.

Hm, SDL_rpivideo.h includes some files I do not find:

#include “bcm_host.h”
#include “GLES/gl.h”
#include “EGL/egl.h”
#include “EGL/eglext.h”

Were should they be?
Edit: ok, found them in the chronos subdir. I searched the whole src folder of SDL for that EGL_DISPMAN string and I found it exactly at one place: in that mentiones include file. Nowwhere else.

chronos? They should be in /opt/vc/include. At least they are on my Raspbian Stretch.

I put Raspbian Stretch Lite on an SD card and executed these commands. Got me a working SDL2 with the RPI and KMSDRM driver.

sed 's/^#deb-src/deb-src/' /etc/apt/sources.list | sudo dd of=/etc/apt/sources.list   # Activate sources
sudo apt-get update                      # Update package list
sudo apt-get upgrade                     # Upgrade installed packages
sudo apt-get install mercurial           # Install mercurial
sudo apt-get build-dep libsdl2           # Install most build dependencies
sudo apt-get install libgbm-dev          # Install the libgbm dependency
sudo apt-get install libgl1-mesa-dri     # Install the vc4 driver
hg clone https://hg.libsdl.org/SDL       # Get the source with mercurial
mkdir SDL/out                            # Create build directory
cd SDL/out
../configure --disable-video-x11 --disable-video-wayland --enable-video-kmsdrm --host arm-raspberry-linux-gnueabihf --disable-rpath 
make -j4
sudo make install                        # Install into /usr/local
sudo ldconfig                            # Update ld cache to make the linker aware of the new library

The firmwire-side driver should work with this immediately.

Change over to the KMS driver with raspi-config to test the KMSDRM driver. Because the RPI and KMSDRM driver bite each other a bit, you have to start your application with more environment variables:

SDL_VIDEODRIVER=kmsdrm SDL_VIDEO_GL_DRIVER=libGL.so.1 SDL_VIDEO_EGL_DRIVER=libEGL.so ./application

This isn’t necessary if you just don’t build it with the RPI driver.

The first command you have does nothing. I would use

sudo sed -i 's/^#deb-src/deb-src/' /etc/apt/sources.list