SDL3 drawing on texture instead of screen

I have a situation where i use a texture to render an image on the screen with HW accel to consume few CPUs.
The problem is if i draw some objects, it will be drawn on the screen and i want to have the image data (“imageData”) with the object drawn on it and be able to send, save, or manipulate it.

The first thing that comes to my mind is to use texture created with the flag SDL_TEXTUREACCESS_TARGET, according to the documentation i can render it to texture instead of the screen, and then i can have the final image with a rectangle drawn.

If i create texture with SDL_TEXTUREACCESS_TARGET, SDL3 crash (core dump) here:

I haven’t found a way to make this work, using SDL_SetRenderTarget still crashes.

The second situation is if “imageData” is a dma buf, isn’t there a way to pass fd to it so there is 0-copy involved?

Regarding the first situation (SDL_TEXTUREACCESS_TARGET), drawing on the texture, i was thinking something like this:

SDL_LockTexture(texture, 0, (void **)&texture_data, &texture_pitch);
memcpy(texture_data, (void *)imageData, frameSize_texture);
SDL_UnlockTexture(texture);
.
.
Draw objects on texture
.
.
Render it on screen
.
//
// copy the texture data back to my imageData
//
SDL_LockTexture(texture, 0, (void **)&texture_data, &texture_pitch);
memcpy((void *)imageData, texture_data, frameSize_texture);
SDL_UnlockTexture(texture);

For reference:
The left image is the “imageData”, and the right one is the objects drawn on screen.

Note:
“imageData” in the link is not dma buf but the NEW updated version is.

“imageData” is RGB24 , dma buf.

The docs for SDL_LockTexture seems to say that it only supports textures that have been created with SDL_TEXTUREACCESS_STREAMING.


Note that SDL_LockTexture only gives you write access to the pixels.

The docs for SDL_LockTexture says:

As an optimization, the pixels made available for editing don’t necessarily contain the old texture data. This is a write-only operation, and if you need to keep a copy of the texture data you should do that at the application level.

Right, so the idea to read back the texture data won’t work.

Please, note the core dump happens on the “write data to the texture”.

Maybe passing fd to Texture is a good idea, we can save 2 memcpy, but i don’t know how to do it. Is that possible? It sounds very similar to “importing a drm fd”…

Passing an fd would solve a lot of things, with no memcpy involved, and the application would have the imageData everything that is drawn on texture, i think…

I tried to play a bit more with the texture, i got some strange results.
Maybe i don’t understand how SDL_RenderTexture and SDL_RenderPresent really work.

First, i changed memcpy to a HW 2D copy and got 3~4 fps more, and ~5% CPU usage less.

    //draw_recta(imageData, screen_width, screen_height, channel, 100, 100, 100, 100, 255, 0, 0, alphablend);
    //draw_recta(imageData, screen_width, screen_height, channel, 100, 200, 100, 100, 0, 255, 0, alphablend);
    
    SDL_LockTexture(texture, 0, (void **)&texture_data, &texture_pitch);
    //memcpy(texture_data, (void *)imageData, frameSize_texture);
    fast_rga_buf(screen_width, screen_height, RK_FORMAT_RGB_888, (char *)imageData,
                 screen_width, screen_height, RK_FORMAT_RGB_888, (char *)texture_data);
    SDL_UnlockTexture(texture);
    SDL_RenderTexture(renderer, texture, NULL, NULL);
    
    //draw_recta(imageData, screen_width, screen_height, channel, 100, 100, 100, 100, 255, 0, 0, alphablend);
    //draw_recta(imageData, screen_width, screen_height, channel, 100, 200, 100, 100, 0, 255, 0, alphablend);

    SDL_RenderPresent(renderer);

Second, i draw the objects directly on the imageData instead of using SDL, but i get some weird results.

imageData is VirtAddr of dma buf, since i copied imageData to texture data, i thought if i changed the contents of imageData after SDL_RenderTexture(); these changes would not get into the screen, but it does.

    SDL_LockTexture(texture, 0, (void **)&texture_data, &texture_pitch);
    fast_rga_buf(screen_width, screen_height, RK_FORMAT_RGB_888, (char *)imageData,
                 screen_width, screen_height, RK_FORMAT_RGB_888, (char *)texture_data);
    SDL_UnlockTexture(texture);
    SDL_RenderTexture(renderer, texture, NULL, NULL);
    
    draw_recta(imageData, screen_width, screen_height, channel, 100, 100, 100, 100, 255, 0, 0, alphablend);
    draw_recta(imageData, screen_width, screen_height, channel, 100, 200, 100, 100, 0, 255, 0, alphablend);

    SDL_RenderPresent(renderer);

the drawn objects appear on the screen although not completely drawn
.
Like this:

If i draw the rects before copying it into texture data, it is ok.

here is my draw_recta:

static void draw_recta(void *imageData, int width, int height, int channel, int x, int y, int w, int h, unsigned char r, unsigned char g, unsigned char b, unsigned char a) 
{
    int xx = 0, yy = 0, w3 = w * channel;
    int line_len = width * channel;
    char *pix_pointer = (char *)((char *)imageData + (y * line_len + x * channel));

    for (yy = 0; yy < h; yy += 1) {
        for (xx = 0; xx < w; xx += 1) {
            *pix_pointer = ((a * r + (255 - a) * (*pix_pointer)) >> 8);
            pix_pointer += 1;
            *pix_pointer = ((a * g + (255 - a) * (*pix_pointer)) >> 8);
            pix_pointer += 1;
            *pix_pointer = ((a * b + (255 - a) * (*pix_pointer)) >> 8);
            pix_pointer += 1;
        }
        pix_pointer += (line_len - w3);
    }
}

Note that there is also SDL_UpdateTexture that you can use to update the texture. I think you can use it instead of SDL_LockTexture to pass imageData directly without having to use memcpy.

But I’m afraid both SDL_LockTexture and SDL_UpdateTexture are pretty slow. It would probably be faster if you managed to only update the texture with the SDL_Render* functions (e.g. SDL_RenderTexture, SDL_RenderFillRect, etc.) because that can take advantage of your graphics hardware.

But how can i get texture_data address without SDL_LockTexture?

Oh, i see:

pixels the raw pixel data in the format of the texture, this will be imageData.

FYI, tested with SDL_UpdateTexture and found it a bit faster than SDL_LockTexture.

34.6 fps vs 34.0 fps (SDL_UpdateTexture vs SDL_LockTexture) with maximum CPU freq and DRAM freq.

27.5 fps vs 26.4 fps (SDL_UpdateTexture vs SDL_LockTexture) with a slow CPU freq and DRAM freq.