We are currently migrating Bugzilla to GitHub issues.
Any changes made to the bug tracker now will be lost, so please do not post new bugs or make changes to them.
When we're done, all bug URLs will redirect to their equivalent location on the new bug tracker.

Bug 3150

Summary: Software renderer default render target does not get set correctly after using target texture
Product: SDL Reporter: Alex Robinson <aprobinsong>
Component: renderAssignee: Sam Lantinga <slouken>
Status: RESOLVED FIXED QA Contact: Sam Lantinga <slouken>
Severity: normal    
Priority: P2 CC: sezeroz, sylvain.becker
Version: 2.0.3   
Hardware: x86_64   
OS: Linux   
Attachments: SDL_render_sw.c patch file

Description Alex Robinson 2015-10-12 19:00:22 UTC
Created attachment 2286 [details]
SDL_render_sw.c patch file

The software renderer uses the SW_RenderData struct, which has two fields: SDL_Surface* surface and SDL_Surface* window. From what I can see (based on the implementation of SW_SetRenderTarget at line 319 in SDL_render_sw.c), the surface field is treated as the current rendering target while the window field is treated as the default rendering target. To set the rendering target to a texture created with access method SDL_TEXTUREACCESS_TARGET, one would call SDL_SetRenderTarget with the texture of interest. To set the rendering target back to the default target, one would call SDL_SetRenderTarget will a NULL pointer. At line 326 in SDL_render_sw.c, the surface field gets set to the window field when a NULL pointer is passed in to the SW_SetRenderTarget method. After doing a quick search in SDL_render_sw.c I noticed that the window field never actually gets initialized anywhere (i.e. not in SW_ActivateRenderer or SW_CreateRendererForSurface). 

With the code in its current state I get the following error after running the following block of code:

'
int bits_per_pixel;
Uint32 rmask, gmask, bmask, amask;

SDL_PixelFormatEnumToMask( SDL_PIXELFORMAT_ARGB888, &bits_per_pixel, &rmask, &gmask, &bmask, &amask );

SDL_Surface* surface = SDL_CreateRGBSurface( 0, 800, 600, bits_per_pixel, rmask, gmask, bmask, amask );

SDL_Renderer* sw_renderer = SDL_CreateSoftwareRenderer( surface );

SDL_Texture* texture = SDL_CreateTexture( sw_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, 800, 600 );

SDL_SetRenderTarget( sw_renderer, texture );

SDL_SetRenderDrawColor( sw_renderer, 0xFF, 0, 0, 0xFF );
SDL_RenderClear( sw_renderer );
SDL_RenderPresent( sw_renderer );

SDL_SetRenderTarget( sw_renderer, NULL );

int return_value = SDL_RenderCopy( sw_renderer, texture, NULL, NULL );

if( return_value != 0 )
  printf( "The texture could not be rendered! SDL_Error: %s\n", SDL_GetError() );
`

Output: "The texture could not be rendered! SDL error: Invalid window"

Potential Fix: By initializing the window field of the SDL_RendererData object to the input surface in the SW_CreateRendererForSurface method the default target surface will be cached and subsequent calls to SW_SetRenderTarget with a NULL texture pointer will correctly restore the default surface target. See the attached patch file for SDL_render_sw.c
Comment 1 Sam Lantinga 2016-10-01 20:54:11 UTC
I think this is fixed, but it's hard to tell since your patch has no context.

Can you try the latest SDL snapshot?
http://www.libsdl.org/tmp/SDL-2.0.zip

Thanks!
Comment 2 Sylvain 2016-11-12 18:53:16 UTC
I tried it and this is fixed from this commit:
https://hg.libsdl.org/SDL/diff/f061a86fbb08/src/render/software/SDL_render_sw.c
Comment 3 Sam Lantinga 2016-11-13 08:11:58 UTC
Thanks for confirming!