-1

I'm using SDL2 with SDL_TEXTUREACCESS_STREAMING without OpenGL and I want to transfer/combine some Textures from my function to my main loop. So, I decided to change my Access type from STREAMING to TARGET, use SDL_SetRenderTarget with SDL_RenderCopy and again put the Access type to STREAMING, but when I preview it with the SDL_RenderPresent not is showing the sended texture.

Here is my function to Open the textures:

TUserFunc(
    void, OpenTTF, Reference font, int32_t align, int32_t x, int32_t y, Reference txt, int32_t scl)
{    
    int tgt_w = g_w;
    int tgt_h = g_h; 
 
    TTF_Font * ttfFont = TTF_OpenFont(pu->refToAstr(CP_THREAD_ACP, font).c_str(), scl);
    if(ttfFont == nullptr) { 
        SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "SDL ERROR", "Error cargando la direccion de las fuentes", NULL);
        quitGame();
    } 
    
    SDL_Surface * surfaceText = TTF_RenderText_Blended(ttfFont, (pu->refToAstr(CP_THREAD_ACP, txt).c_str()), color);
    if(surfaceText == nullptr){
        SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "SDL ERROR", "Error creando Superficie", NULL);
        quitGame();
    } 
    
    textureText = SDL_CreateTextureFromSurface(g_renderer,surfaceText); 
    if(textureText == nullptr){
        SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "SDL ERROR", "Error creando Texturas", NULL);
        quitGame();
    } 

    SDL_Rect rectangle;
    rectangle.x = x;
    rectangle.y = y;
    rectangle.w = surfaceText->w;
    rectangle.h = surfaceText->h;

//The Problem Start from here

    unlockTarget(); 
    g_target = SDL_CreateTexture(g_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, tgt_w, tgt_h);

    SDL_SetRenderTarget(g_renderer, g_target);
    SDL_RenderCopy(g_renderer, textureText, NULL, &rectangle);
    SDL_SetRenderTarget(g_renderer, NULL);
     
    g_target = SDL_CreateTexture(g_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, tgt_w, tgt_h);
    lockTarget();
}

lockTarget() and unlockTarget() it's for a simple way to lock and unlock the texture, and how you can see, I use the CreateTexture to change to TARGET, put my SetRenderTarget and RenderCopy and again use the CreateTexture to change back to STREAMING

And this is my main loop to show the graphics:

TUserFunc(void, Flip)
{       

    if(g_target){
        unlockTarget();
        SDL_RenderCopy(g_renderer, g_target, nullptr, nullptr); 
        lockTarget();
    }     
    SDL_RenderPresent(g_renderer);
}

but if I add this, the texture is showed, but not same texture, I mean, not is combined with g_target

TUserFunc(void, Flip)
{       

    if(g_target){
        unlockTarget();
        SDL_RenderCopy(g_renderer, g_target, nullptr, nullptr); 
        lockTarget();
    }    
    if(textureText){
        unlockTarget();
        SDL_RenderCopy(g_renderer, textureText, nullptr, nullptr); 
        lockTarget();
    }
    SDL_RenderPresent(g_renderer);
}

Here you can see the other functions to have a better view about the problem:

TUserFunc(bool, Init...)
{
...
        // This is the main and unique call to g_target
    g_target = SDL_CreateTexture(g_renderer, SDL_PIXELFORMAT_ARGB8888,
            SDL_TEXTUREACCESS_STREAMING, w, h);
    SDL_SetTextureBlendMode(g_target, SDL_BLENDMODE_NONE);
...
}

void lockTarget()
{
    if(g_target) SDL_LockTexture(g_target, nullptr, (void**)&g_pix, &g_pitch);
    if(textureText) SDL_LockTexture(textureText, nullptr, (void**)&g_pix, &g_pitch);
}

void unlockTarget()
{
    if(g_target) SDL_UnlockTexture(g_target);
    if(textureText) SDL_UnlockTexture(textureText);
}
  • 1
    Who told you that you could use `SDL_CreateTexture` to change a texture's access pattern? There are several things wrong with your code but that's probably the main issue. – Nelfeal Jul 25 '23 at 10:12

1 Answers1

-1

The problem

This can't work:

unlockTarget(); 
g_target = SDL_CreateTexture(g_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, tgt_w, tgt_h);

SDL_SetRenderTarget(g_renderer, g_target);
SDL_RenderCopy(g_renderer, textureText, NULL, &rectangle);
SDL_SetRenderTarget(g_renderer, NULL);
 
g_target = SDL_CreateTexture(g_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, tgt_w, tgt_h);
lockTarget();

You create a texture, render another one onto it, and then proceed to get rid of its pointer and create a new one.

SDL_CreateTexture, as its name implies, creates a texture.

With this line:

g_target = SDL_CreateTexture(g_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, tgt_w, tgt_h);

You are essentially throwing away whatever g_target held and replaces it with a new, empty texture with STREAMING access.

I use the CreateTexture to change to TARGET, put my SetRenderTarget and RenderCopy and again use the CreateTexture to change back to STREAMING

This simply not how it works. You can't change a texture's access mode once it has been created. All that SDL_CreateTexture does is creating yet another texture.

As a result, all you do is leaking memory and get non-working code.

The clean solution

An SDL_Texture, according to the documentation (archive), is:

A structure that contains an efficient, driver-specific representation of pixel data.

You aren't supposed to do anything with SDL_Textures besides rendering them or rendering other textures onto it. Changing their access mode in real time is not possible.

If you really need to render textures on top of others and then access their pixel data, then use SDL_Surfaces (archive):

A structure that contains a collection of pixels used in software blitting.

You can blit those on top of others as well, using SDL_BlitSurface. Plus, you can access SDL_Surfaces' pixel data for further editing.

And only THEN, where you are DONE touching to pixel data, convert it into a texture using SDL_CreateTextureFromSurface and render it.

It might be slower than trying to mess directly with textures, but at least it works and is meant to be done.

Sure, STREAMING mode exists on textures for a reason, but all you can do with it is hacky trickery to get things poorly done where using surfaces would have been much better.

And besides, you can't change a texture's access mode from TARGET to STREAMING as I have already said, so you don't really have a choice here. You need to use surfaces.

RedStoneMatt
  • 465
  • 3
  • 11
  • FYI, a downvote doesn't denote an answer is "wrong", it means that the user didn't find it helpful or useful (as noted in the tooltip). – Thom A Aug 04 '23 at 14:49
  • Indeed, let me reformulate then: I'm always open to improving my answers, but I can't if I am not being told why it isn't helpful. I believe that my answer solves OP's problem, as it demonstrates why they ask for cannot be done and gives an alternative for them to do what they need. – RedStoneMatt Aug 04 '23 at 14:55
  • 1
    All up/down votes are anonymous by design. There are plenty of duplicates about this on [meta.se]. – Thom A Aug 04 '23 at 14:58