0
votes

I am making a 2D game with SDL2 and have some issues rendering the map to the screen. The map scrolls when you move around so I decided to load the map in chunks so I can simply clip an SDL_Texture based on the player's location to display the relevant section of the map to the screen. The problem is that after displaying the map once, on all subsequent frames I get a black screen, or actually a screen with whatever the renderer drawing color is set to. I know this sounds like I am calling SDL_RenderClear in the wrong place but bear with me, this issue is more complicated.

First of all, everything is fine when I use a software renderer, but this takes up too much render time to run at 60 fps, so that's why I created a hardware accelerated renderer, which introduced the problem.

The gist of my SDL-related code is this:

When the map is loaded, a couple tiles (or "chunks") are initialized. As you move around far away tiles will be freed and new ones initialized. Each tile creates an image (texture) based on it's location. (I admit I don't know if this is the most efficient way, I expected it would save time to have big textures ready that would only have to be clipped vs drawing everything on the fly). This causes a lot of switching between render targets, because for each tile SDL_RendererSetTarget is called to render directly to its texture and basically a lot of textures get 'pasted' on the bigger one (the tile's image). After this of course, the render target is changed back to the screen.

The rest of the render process is fairly simple:

  • SDL_RenderClear
  • Look up relevant tile
  • SDL_RenderCopy its image with a clip to get the right section on the screen and do the same for the adjacent tiles
  • Some more SDL_RenderCopys to put the player sprite and some other sprites (npcs) on the screen
  • SDL_RenderPresent
  • Wait a couple milliseconds with SDL_Delay

The final result seems valid because like I mentioned before, the very first call to SDL_RenderPresent displays everything just fine. However every subsequent call displays a screen with the drawing color, meaning ostensibly nothing happened anymore between the call to RenderClear and RenderPresent. So I think that after this first SDL_RenderPresent SDL_Rendercopy simply doesn't work anymore somehow. However the program doesn't crash either so it is almost like the textures all decide to become completely transparent for some reason, or maybe they are just rendered to limbo.

I honestly have no idea even in which area the problem could lie, but I have tried about everything I could think of, unfortunately to no avail yet. To make things worse all parts of the code I could isolate work fine on their own... So any suggestions or even suspicions of what the problem might be are more than welcome! Maybe I am looking at it the wrong way and using a hardware renderer for things like texture rendering is simply impossible? Also I have considered dropping SDL and learning OpenGL but since it would mean rewriting a lot of code I wanted to try asking here first to see if there is really no other solution. Finally here are some system specs, things I have tried, anything I could think of that might be relevant:

  • I have tried to create a "screen texture" as a middle man for the renderer where all RenderCopys are directed to before finally copying this one to the screen.
  • This is how I create my renderer (like in the Lazy Foo tutorial (https://lazyfoo.net/tutorials/SDL/43_render_to_texture/index.php) SDL_CreateRenderer( gWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC ); I also tried adding the SDL_RENDERER_TARGETTEXTURE flag. Never understood why that isn't done in the tutorial.
  • I have an AMD Radeon HD 8330 video card, Windows 8 OS
  • Calling SDL_GetRendererInfo reveals the hardware renderer is called direct3d and supported pixelformats are ARGB8888, YV12, and IYUV. Whenever I create a texture I use the source code in SDL_CreateTextureFromSurface to determine which format to use.
  • Because most of my bmps have an alpha channel I call SDL_SetTextureBlendMode with the SDL_BLENDMODE_BLEND flag on all textures. And also SDL_SetRenderDrawBlendMode with this flag on the renderer.
1
Edit in a minimal reproducible example. Which version of SDL are you using? Binaries from libsdl.org or self-compiled? Which compiler are you using? Are you doing something wonky like trying to use SDL_GetWindowSurface() with the renderer system?genpfault

1 Answers

1
votes

Turns out I was accidentally calling SDL_SetWindowSize in between frames due to checking a boolean pointer like this

if (boolean)

rather than

if (*boolean)

... Whoops!

Even though I set the size to the same values every time this invalidated all textures created through SDL_CreateTexture with the hardware renderer. Interestingly the ones created with SDL_CreateTextureFromSurface were unaffected. And like I said, textures created with a software renderer don't seem to mind a window resize at all. I'll leave this here in the hopes my stupidity might help someone else one day.