Reorganized the render target code, moving the viewport handling to the general code and adding software implementation.
authorSam Lantinga <slouken@libsdl.org>
Sat, 21 Jan 2012 22:22:30 -0500
changeset 6246 c70ec935a4bb
parent 6245 9d15de67bff9
child 6247 b6212690f78d
Reorganized the render target code, moving the viewport handling to the general code and adding software implementation.
src/render/SDL_render.c
src/render/SDL_sysrender.h
src/render/direct3d/SDL_render_d3d.c
src/render/opengl/SDL_render_gl.c
src/render/opengles/SDL_render_gles.c
src/render/opengles2/SDL_render_gles2.c
src/render/software/SDL_render_sw.c
--- a/src/render/SDL_render.c	Sat Jan 21 22:14:38 2012 -0500
+++ b/src/render/SDL_render.c	Sat Jan 21 22:22:30 2012 -0500
@@ -106,11 +106,16 @@
                 SDL_Rect viewport;
 
                 SDL_GetWindowSize(window, &w, &h);
-                viewport.x = (w - renderer->viewport.w) / 2;
-                viewport.y = (h - renderer->viewport.h) / 2;
-                viewport.w = renderer->viewport.w;
-                viewport.h = renderer->viewport.h;
-                SDL_RenderSetViewport(renderer, &viewport);
+                if (renderer->target) {
+                    renderer->viewport_backup.x = (w - renderer->viewport_backup.w) / 2;
+                    renderer->viewport_backup.y = (h - renderer->viewport_backup.h) / 2;
+                } else {
+                    viewport.x = (w - renderer->viewport.w) / 2;
+                    viewport.y = (h - renderer->viewport.h) / 2;
+                    viewport.w = renderer->viewport.w;
+                    viewport.h = renderer->viewport.h;
+                    SDL_RenderSetViewport(renderer, &viewport);
+                }
             } else if (event->window.event == SDL_WINDOWEVENT_MINIMIZED) {
                 renderer->minimized = SDL_TRUE;
             } else if (event->window.event == SDL_WINDOWEVENT_RESTORED) {
@@ -796,6 +801,72 @@
     }
 }
 
+SDL_bool
+SDL_RenderTargetSupported(SDL_Renderer *renderer)
+{
+    if (!renderer || !renderer->SetTargetTexture) {
+        return SDL_FALSE;
+    }
+    return (renderer->info.flags & SDL_RENDERER_TARGETTEXTURE) != 0;
+}
+
+int
+SDL_SetTargetTexture(SDL_Renderer *renderer, SDL_Texture *texture)
+{
+    SDL_Rect viewport;
+
+    if (!SDL_RenderTargetSupported(renderer)) {
+        SDL_Unsupported();
+        return -1;
+    }
+    if (texture == renderer->target) {
+        /* Nothing to do! */
+        return 0;
+    }
+
+    /* texture == NULL is valid and means reset the target to the window */
+    if (texture) {
+        CHECK_TEXTURE_MAGIC(texture, -1);
+        if (renderer != texture->renderer) {
+            SDL_SetError("Texture was not created with this renderer");
+            return -1;
+        }
+        if (!(texture->access & SDL_TEXTUREACCESS_TARGET)) {
+            SDL_SetError("Texture not created with SDL_TEXTUREACCESS_TARGET");
+            return -1;
+        }
+        if (texture->native) {
+            /* Always render to the native texture */
+            texture = texture->native;
+        }
+    }
+
+    if (texture && !renderer->target) {
+        /* Make a backup of the viewport */
+        renderer->viewport_backup = renderer->viewport;
+    }
+    renderer->target = texture;
+
+    if (renderer->SetTargetTexture(renderer, texture) < 0) {
+        return -1;
+    }
+
+    if (texture) {
+        viewport.x = 0;
+        viewport.y = 0;
+        viewport.w = texture->w;
+        viewport.h = texture->h;
+    } else {
+        viewport = renderer->viewport_backup;
+    }
+    if (SDL_RenderSetViewport(renderer, &viewport) < 0) {
+        return -1;
+    }
+
+    /* All set! */
+    return 0;
+}
+
 int
 SDL_RenderSetViewport(SDL_Renderer * renderer, const SDL_Rect * rect)
 {
@@ -1150,35 +1221,6 @@
                                       format, pixels, pitch);
 }
 
-SDL_bool
-SDL_RenderTargetSupported(SDL_Renderer *renderer)
-{
-    if (!renderer || !renderer->SetTargetTexture) {
-        return SDL_FALSE;
-    }
-    return (renderer->info.flags & SDL_RENDERER_TARGETTEXTURE) != 0;
-}
-
-int
-SDL_SetTargetTexture(SDL_Renderer *renderer, SDL_Texture *texture)
-{
-    
-    if(!renderer) {
-        return -1;
-    }
-    if (!renderer->SetTargetTexture) {
-        SDL_Unsupported();
-        return -1;
-    }
-    // Warning: texture==NULL is a valid parameter
-    if( texture ) {
-        CHECK_TEXTURE_MAGIC(texture, -1);
-        if(renderer != texture->renderer) return -1;
-    }
-    
-    return renderer->SetTargetTexture(renderer, texture);
-}
-
 void
 SDL_RenderPresent(SDL_Renderer * renderer)
 {
--- a/src/render/SDL_sysrender.h	Sat Jan 21 22:14:38 2012 -0500
+++ b/src/render/SDL_sysrender.h	Sat Jan 21 22:22:30 2012 -0500
@@ -77,6 +77,7 @@
     int (*LockTexture) (SDL_Renderer * renderer, SDL_Texture * texture,
                         const SDL_Rect * rect, void **pixels, int *pitch);
     void (*UnlockTexture) (SDL_Renderer * renderer, SDL_Texture * texture);
+    int (*SetTargetTexture) (SDL_Renderer * renderer, SDL_Texture * texture);
     int (*UpdateViewport) (SDL_Renderer * renderer);
     int (*RenderClear) (SDL_Renderer * renderer);
     int (*RenderDrawPoints) (SDL_Renderer * renderer, const SDL_Point * points,
@@ -87,7 +88,6 @@
                             int count);
     int (*RenderCopy) (SDL_Renderer * renderer, SDL_Texture * texture,
                        const SDL_Rect * srcrect, const SDL_Rect * dstrect);
-    int (*SetTargetTexture) (SDL_Renderer * renderer, SDL_Texture * texture);
     int (*RenderReadPixels) (SDL_Renderer * renderer, const SDL_Rect * rect,
                              Uint32 format, void * pixels, int pitch);
     void (*RenderPresent) (SDL_Renderer * renderer);
@@ -104,9 +104,11 @@
 
     /* The drawable area within the window */
     SDL_Rect viewport;
+    SDL_Rect viewport_backup;
 
     /* The list of textures */
     SDL_Texture *textures;
+    SDL_Texture *target;
 
     Uint8 r, g, b, a;                   /**< Color for drawing operations values */
     SDL_BlendMode blendMode;            /**< The drawing blend mode */
--- a/src/render/direct3d/SDL_render_d3d.c	Sat Jan 21 22:14:38 2012 -0500
+++ b/src/render/direct3d/SDL_render_d3d.c	Sat Jan 21 22:22:30 2012 -0500
@@ -99,6 +99,7 @@
 static int D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
                            const SDL_Rect * rect, void **pixels, int *pitch);
 static void D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
+static int D3D_SetTargetTexture(SDL_Renderer * renderer, SDL_Texture * texture);
 static int D3D_UpdateViewport(SDL_Renderer * renderer);
 static int D3D_RenderClear(SDL_Renderer * renderer);
 static int D3D_RenderDrawPoints(SDL_Renderer * renderer,
@@ -111,7 +112,6 @@
                           const SDL_Rect * srcrect, const SDL_Rect * dstrect);
 static int D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
                                 Uint32 format, void * pixels, int pitch);
-static int D3D_SetTargetTexture(SDL_Renderer * renderer, SDL_Texture * texture);
 static void D3D_RenderPresent(SDL_Renderer * renderer);
 static void D3D_DestroyTexture(SDL_Renderer * renderer,
                                SDL_Texture * texture);
@@ -141,10 +141,6 @@
     D3DTEXTUREFILTERTYPE scaleMode;
     IDirect3DSurface9 *defaultRenderTarget;
     IDirect3DSurface9 *currentRenderTarget;
-    SDL_bool renderTargetActive;
-    SDL_Rect viewport_copy;
-    
-    Uint32 NumSimultaneousRTs;
 } D3D_RenderData;
 
 typedef struct
@@ -392,6 +388,7 @@
     renderer->UpdateTexture = D3D_UpdateTexture;
     renderer->LockTexture = D3D_LockTexture;
     renderer->UnlockTexture = D3D_UnlockTexture;
+    renderer->SetTargetTexture = D3D_SetTargetTexture;
     renderer->UpdateViewport = D3D_UpdateViewport;
     renderer->RenderClear = D3D_RenderClear;
     renderer->RenderDrawPoints = D3D_RenderDrawPoints;
@@ -399,14 +396,13 @@
     renderer->RenderFillRects = D3D_RenderFillRects;
     renderer->RenderCopy = D3D_RenderCopy;
     renderer->RenderReadPixels = D3D_RenderReadPixels;
-    renderer->SetTargetTexture = D3D_SetTargetTexture;
     renderer->RenderPresent = D3D_RenderPresent;
     renderer->DestroyTexture = D3D_DestroyTexture;
     renderer->DestroyRenderer = D3D_DestroyRenderer;
     renderer->info = D3D_RenderDriver.info;
     renderer->driverdata = data;
 
-    renderer->info.flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE;
+    renderer->info.flags = SDL_RENDERER_ACCELERATED;
 
     SDL_VERSION(&windowinfo.version);
     SDL_GetWindowWMInfo(window, &windowinfo);
@@ -486,7 +482,9 @@
     IDirect3DDevice9_GetDeviceCaps(data->device, &caps);
     renderer->info.max_texture_width = caps.MaxTextureWidth;
     renderer->info.max_texture_height = caps.MaxTextureHeight;
-    data->NumSimultaneousRTs = caps.NumSimultaneousRTs;
+    if (caps.NumSimultaneousRTs >= 2) {
+        renderer->info.flags |= SDL_RENDERER_TARGETTEXTURE;
+    }
 
     /* Set up parameters for rendering */
     IDirect3DDevice9_SetVertexShader(data->device, NULL);
@@ -519,7 +517,6 @@
     /* Store the default render target */
     IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget );
     data->currentRenderTarget = NULL;
-    data->renderTargetActive = SDL_FALSE;
 
     /* Set an identity world and view matrix */
     matrix.m[0][0] = 1.0f;
@@ -569,79 +566,6 @@
 }
 
 static int
-D3D_SetTargetTexture(SDL_Renderer * renderer, SDL_Texture * texture)
-{
-    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
-    D3D_TextureData *texturedata;
-    D3DMATRIX matrix;
-    HRESULT result;
-
-    D3D_ActivateRenderer(renderer);
-
-    if (data->NumSimultaneousRTs < 2) {
-        SDL_Unsupported();
-        return -1;
-    }
-
-    // Release the previous render target if it wasn't the default one
-    if (data->currentRenderTarget != NULL) {
-        IDirect3DSurface9_Release(data->currentRenderTarget);
-        data->currentRenderTarget = NULL;
-    }
-
-    /* Prepare an identity world and view matrix */
-    matrix.m[0][0] = 1.0f;
-    matrix.m[0][1] = 0.0f;
-    matrix.m[0][2] = 0.0f;
-    matrix.m[0][3] = 0.0f;
-    matrix.m[1][0] = 0.0f;
-    matrix.m[1][1] = 1.0f;
-    matrix.m[1][2] = 0.0f;
-    matrix.m[1][3] = 0.0f;
-    matrix.m[2][0] = 0.0f;
-    matrix.m[2][1] = 0.0f;
-    matrix.m[2][2] = 1.0f;
-    matrix.m[2][3] = 0.0f;
-    matrix.m[3][0] = 0.0f;
-    matrix.m[3][1] = 0.0f;
-    matrix.m[3][2] = 0.0f;
-    matrix.m[3][3] = 1.0f;
-
-    if (texture == NULL) {
-        if (data->renderTargetActive) {
-            data->renderTargetActive = SDL_FALSE;
-            IDirect3DDevice9_SetRenderTarget(data->device, 0, data->defaultRenderTarget );
-            renderer->viewport = data->viewport_copy;
-            D3D_UpdateViewport(renderer);
-        }
-        return 0;
-    }
-    if (renderer != texture->renderer) return -1;
-
-    if ( !data->renderTargetActive ) {
-        data->viewport_copy = renderer->viewport;
-    }
-
-    texturedata = (D3D_TextureData *) texture->driverdata;
-    result = IDirect3DTexture9_GetSurfaceLevel(texturedata->texture, 0, &data->currentRenderTarget );
-    if(FAILED(result)) {
-        return -1;
-    }
-    result = IDirect3DDevice9_SetRenderTarget(data->device, 0, data->currentRenderTarget );
-    if(FAILED(result)) {
-        return -1;
-    }
-
-    data->renderTargetActive = SDL_TRUE;
-    renderer->viewport.x = 0;
-    renderer->viewport.y = 0;
-    renderer->viewport.w = texture->w;
-    renderer->viewport.h = texture->h;
-    D3D_UpdateViewport(renderer);
-    return 0;
-}
-
-static int
 D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
 {
     D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata;
@@ -668,11 +592,10 @@
     } else
 #endif
     if (texture->access == SDL_TEXTUREACCESS_TARGET) {
-        pool = D3DPOOL_DEFAULT;         // D3DPOOL_MANAGED does not work with usage=D3DUSAGE_RENDERTARGET
+        /* D3DPOOL_MANAGED does not work with D3DUSAGE_RENDERTARGET */
+        pool = D3DPOOL_DEFAULT;
         usage = D3DUSAGE_RENDERTARGET;
-    }
-    else
-    {
+    } else {
         pool = D3DPOOL_MANAGED;
         usage = 0;
     }
@@ -811,6 +734,41 @@
 }
 
 static int
+D3D_SetTargetTexture(SDL_Renderer * renderer, SDL_Texture * texture)
+{
+    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
+    D3D_TextureData *texturedata;
+    HRESULT result;
+
+    D3D_ActivateRenderer(renderer);
+
+    /* Release the previous render target if it wasn't the default one */
+    if (data->currentRenderTarget != NULL) {
+        IDirect3DSurface9_Release(data->currentRenderTarget);
+        data->currentRenderTarget = NULL;
+    }
+
+    if (texture == NULL) {
+        IDirect3DDevice9_SetRenderTarget(data->device, 0, data->defaultRenderTarget);
+        return 0;
+    }
+
+    texturedata = (D3D_TextureData *) texture->driverdata;
+    result = IDirect3DTexture9_GetSurfaceLevel(texturedata->texture, 0, &data->currentRenderTarget);
+    if(FAILED(result)) {
+        D3D_SetError("GetSurfaceLevel()", result);
+        return -1;
+    }
+    result = IDirect3DDevice9_SetRenderTarget(data->device, 0, data->currentRenderTarget);
+    if(FAILED(result)) {
+        D3D_SetError("SetRenderTarget()", result);
+        return -1;
+    }
+
+    return 0;
+}
+
+static int
 D3D_RenderClear(SDL_Renderer * renderer)
 {
     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
--- a/src/render/opengl/SDL_render_gl.c	Sat Jan 21 22:14:38 2012 -0500
+++ b/src/render/opengl/SDL_render_gl.c	Sat Jan 21 22:22:30 2012 -0500
@@ -54,6 +54,7 @@
 static int GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
                           const SDL_Rect * rect, void **pixels, int *pitch);
 static void GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
+static int GL_SetTargetTexture(SDL_Renderer * renderer, SDL_Texture * texture);
 static int GL_UpdateViewport(SDL_Renderer * renderer);
 static int GL_RenderClear(SDL_Renderer * renderer);
 static int GL_RenderDrawPoints(SDL_Renderer * renderer,
@@ -66,7 +67,6 @@
                          const SDL_Rect * srcrect, const SDL_Rect * dstrect);
 static int GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
                                Uint32 pixel_format, void * pixels, int pitch);
-static int GL_SetTargetTexture(SDL_Renderer * renderer, SDL_Texture * texture);
 static void GL_RenderPresent(SDL_Renderer * renderer);
 static void GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture);
 static void GL_DestroyRenderer(SDL_Renderer * renderer);
@@ -104,8 +104,6 @@
     
     SDL_bool GL_EXT_framebuffer_object_supported;
     GL_FBOList *framebuffers;
-    SDL_Texture *renderTarget;
-    SDL_Rect viewport_copy;
 
     /* OpenGL functions */
 #define SDL_PROC(ret,func,params) ret (APIENTRY *func) params;
@@ -309,19 +307,19 @@
     renderer->UpdateTexture = GL_UpdateTexture;
     renderer->LockTexture = GL_LockTexture;
     renderer->UnlockTexture = GL_UnlockTexture;
+    renderer->SetTargetTexture = GL_SetTargetTexture;
     renderer->UpdateViewport = GL_UpdateViewport;
     renderer->RenderClear = GL_RenderClear;
     renderer->RenderDrawPoints = GL_RenderDrawPoints;
     renderer->RenderDrawLines = GL_RenderDrawLines;
     renderer->RenderFillRects = GL_RenderFillRects;
     renderer->RenderCopy = GL_RenderCopy;
-    renderer->SetTargetTexture = GL_SetTargetTexture;
     renderer->RenderReadPixels = GL_RenderReadPixels;
     renderer->RenderPresent = GL_RenderPresent;
     renderer->DestroyTexture = GL_DestroyTexture;
     renderer->DestroyRenderer = GL_DestroyRenderer;
     renderer->info = GL_RenderDriver.info;
-    renderer->info.flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE;
+    renderer->info.flags = SDL_RENDERER_ACCELERATED;
     renderer->driverdata = data;
     renderer->window = window;
 
@@ -399,11 +397,11 @@
             SDL_GL_GetProcAddress("glFramebufferTexture2DEXT");
         data->glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)
             SDL_GL_GetProcAddress("glBindFramebufferEXT");
-       data->glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)
+        data->glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)
             SDL_GL_GetProcAddress("glCheckFramebufferStatusEXT");
+        renderer->info.flags |= SDL_RENDERER_TARGETTEXTURE;
     }
     data->framebuffers = NULL;
-    data->renderTarget = NULL;
 
     /* Set up parameters for rendering */
     GL_ResetState(renderer);
@@ -466,74 +464,6 @@
 }
 
 static int
-GL_SetTargetTexture(SDL_Renderer * renderer, SDL_Texture * texture)
-{
-    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;    
-    
-    GL_TextureData *texturedata;
-    GLenum status;
-
-    if (!renderer) return -1;
-    GL_ActivateRenderer(renderer);
-    
-    if (! data->GL_EXT_framebuffer_object_supported) {
-        SDL_Unsupported();
-        return -1;
-    }
-    
-    if (texture == NULL) {
-        if (data->renderTarget != NULL) {
-            data->renderTarget = NULL;
-            renderer->viewport = data->viewport_copy;
-            data->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
-            data->glMatrixMode(GL_PROJECTION);
-            data->glLoadIdentity();
-            data->glMatrixMode(GL_MODELVIEW);
-            data->glLoadIdentity();
-            data->glViewport(renderer->viewport.x, renderer->viewport.y, renderer->viewport.w, renderer->viewport.h);
-            data->glOrtho(0.0, (GLdouble) renderer->viewport.w, (GLdouble) renderer->viewport.h, 0.0, 0.0, 1.0);
-        }
-        return 0;
-    }
-    if (renderer != texture->renderer) return -1;
-    if (data->renderTarget==NULL) {
-        // Keep a copy of the default viewport to restore when texture==NULL
-        data->viewport_copy = renderer->viewport;
-    }
-    
-    
-    texturedata = (GL_TextureData *) texture->driverdata;
-    if (!texturedata) {
-        if (texture->native && texture->native->driverdata) {
-            texture = texture->native;
-            texturedata = texture->driverdata;
-        }
-        else return -1;
-    }
-    data->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, texturedata->fbo->FBO);
-    /* TODO: check if texture pixel format allows this operation */
-    data->glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, texturedata->type, texturedata->texture, 0);
-    /* Check FBO status */
-    status = data->glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
-    if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
-        return -1;
-    }
-
-    data->renderTarget = texture;
-    renderer->viewport.x = 0;
-    renderer->viewport.y = 0;
-    renderer->viewport.w = texture->w;
-    renderer->viewport.h = texture->h;
-    data->glMatrixMode(GL_PROJECTION);
-    data->glLoadIdentity();
-    data->glOrtho(0.0, (GLdouble) texture->w, 0.0, (GLdouble) texture->h, 0.0, 1.0);
-    data->glMatrixMode(GL_MODELVIEW);
-    data->glLoadIdentity();
-    data->glViewport(0, 0, texture->w, texture->h);    
-    return 0;
-}
-
-static int
 GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
 {
     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
@@ -777,6 +707,33 @@
 }
 
 static int
+GL_SetTargetTexture(SDL_Renderer * renderer, SDL_Texture * texture)
+{
+    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;    
+    GL_TextureData *texturedata;
+    GLenum status;
+
+    GL_ActivateRenderer(renderer);
+    
+    if (texture == NULL) {
+        data->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+        return 0;
+    }
+
+    texturedata = (GL_TextureData *) texture->driverdata;
+    data->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, texturedata->fbo->FBO);
+    /* TODO: check if texture pixel format allows this operation */
+    data->glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, texturedata->type, texturedata->texture, 0);
+    /* Check FBO status */
+    status = data->glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+    if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
+        SDL_SetError("glFramebufferTexture2DEXT() failed");
+        return -1;
+    }
+    return 0;
+}
+
+static int
 GL_UpdateViewport(SDL_Renderer * renderer)
 {
     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
@@ -791,10 +748,19 @@
 
     data->glMatrixMode(GL_PROJECTION);
     data->glLoadIdentity();
-    data->glOrtho((GLdouble) 0,
-                  (GLdouble) renderer->viewport.w,
-                  (GLdouble) renderer->viewport.h,
-                  (GLdouble) 0, 0.0, 1.0);
+    if (renderer->target) {
+        data->glOrtho((GLdouble) 0,
+                      (GLdouble) renderer->viewport.w,
+                      (GLdouble) 0,
+                      (GLdouble) renderer->viewport.h,
+                       0.0, 1.0);
+    } else {
+        data->glOrtho((GLdouble) 0,
+                      (GLdouble) renderer->viewport.w,
+                      (GLdouble) renderer->viewport.h,
+                      (GLdouble) 0,
+                       0.0, 1.0);
+    }
     return 0;
 }
 
--- a/src/render/opengles/SDL_render_gles.c	Sat Jan 21 22:14:38 2012 -0500
+++ b/src/render/opengles/SDL_render_gles.c	Sat Jan 21 22:22:30 2012 -0500
@@ -56,6 +56,8 @@
                             const SDL_Rect * rect, void **pixels, int *pitch);
 static void GLES_UnlockTexture(SDL_Renderer * renderer,
                                SDL_Texture * texture);
+static int GLES_SetTargetTexture(SDL_Renderer * renderer,
+                                 SDL_Texture * texture);
 static int GLES_UpdateViewport(SDL_Renderer * renderer);
 static int GLES_RenderClear(SDL_Renderer * renderer);
 static int GLES_RenderDrawPoints(SDL_Renderer * renderer,
@@ -73,7 +75,6 @@
 static void GLES_DestroyTexture(SDL_Renderer * renderer,
                                 SDL_Texture * texture);
 static void GLES_DestroyRenderer(SDL_Renderer * renderer);
-static int GLES_SetTargetTexture(SDL_Renderer * renderer, SDL_Texture * texture);
 
 typedef struct GLES_FBOList GLES_FBOList;
 
@@ -110,8 +111,6 @@
 #undef SDL_PROC
     SDL_bool GL_OES_framebuffer_object_supported;
     GLES_FBOList *framebuffers;
-    SDL_Texture *renderTarget;
-    SDL_Rect viewport_copy;
 
     SDL_bool useDrawTexture;
     SDL_bool GL_OES_draw_texture_supported;
@@ -257,71 +256,6 @@
     data->glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 }
 
-static int
-GLES_SetTargetTexture(SDL_Renderer * renderer, SDL_Texture * texture)
-{
-    GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
-    int w, h;
-    GLES_TextureData *texturedata = NULL;
-    GLenum status;
-
-    if (!renderer) return -1;
-    GLES_ActivateRenderer(renderer);
-    if (! data->GL_OES_framebuffer_object_supported) {
-        SDL_Unsupported();
-        return -1;
-    }
-
-    if (texture == NULL) {
-        if (data->renderTarget != NULL) {
-            data->renderTarget = NULL;
-            renderer->viewport = data->viewport_copy;
-            data->glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
-            data->glMatrixMode(GL_PROJECTION);
-            data->glLoadIdentity();
-            data->glMatrixMode(GL_MODELVIEW);
-            data->glLoadIdentity();
-            data->glViewport(renderer->viewport.x, renderer->viewport.y, renderer->viewport.w, renderer->viewport.h);
-            data->glOrthof(0.0, (GLfloat) renderer->viewport.w, (GLfloat) renderer->viewport.h, 0.0, 0.0, 1.0);
-        }
-        return 0;
-    }
-
-    if (renderer != texture->renderer) return -1;
-    if (data->renderTarget==NULL) {
-        // Keep a copy of the default viewport to restore when texture==NULL
-        data->viewport_copy = renderer->viewport;
-    }
-    texturedata = (GLES_TextureData *) texture->driverdata;
-    if (!texturedata) {
-        if (texture->native && texture->native->driverdata) {
-            texture = texture->native;
-            texturedata = texture->driverdata;
-        }
-        else return -1;
-    }
-    data->glBindFramebufferOES(GL_FRAMEBUFFER_OES, texturedata->fbo->FBO);
-    /* TODO: check if texture pixel format allows this operation */
-    data->glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, texturedata->type, texturedata->texture, 0);
-    /* Check FBO status */
-    status = data->glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
-    if (status != GL_FRAMEBUFFER_COMPLETE_OES) {
-        return -1;
-    }
-    data->renderTarget = texture;
-    renderer->viewport.x = 0;
-    renderer->viewport.y = 0;
-    renderer->viewport.w = texture->w;
-    renderer->viewport.h = texture->h;
-    data->glMatrixMode(GL_PROJECTION);
-    data->glLoadIdentity();
-    data->glOrthof(0.0, (GLfloat) texture->w, 0.0, (GLfloat) texture->h, 0.0, 1.0);
-    data->glMatrixMode(GL_MODELVIEW);
-    data->glLoadIdentity();
-    data->glViewport(0, 0, texture->w, texture->h);
-    return 0;
-}
-
 SDL_Renderer *
 GLES_CreateRenderer(SDL_Window * window, Uint32 flags)
 {
@@ -361,6 +295,7 @@
     renderer->UpdateTexture = GLES_UpdateTexture;
     renderer->LockTexture = GLES_LockTexture;
     renderer->UnlockTexture = GLES_UnlockTexture;
+    renderer->SetTargetTexture = GLES_SetTargetTexture;
     renderer->UpdateViewport = GLES_UpdateViewport;
     renderer->RenderClear = GLES_RenderClear;
     renderer->RenderDrawPoints = GLES_RenderDrawPoints;
@@ -372,10 +307,9 @@
     renderer->DestroyTexture = GLES_DestroyTexture;
     renderer->DestroyRenderer = GLES_DestroyRenderer;
     renderer->info = GLES_RenderDriver.info;
-    renderer->info.flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE;
+    renderer->info.flags = SDL_RENDERER_ACCELERATED;
     renderer->driverdata = data;
     renderer->window = window;
-    renderer->SetTargetTexture = GLES_SetTargetTexture;
 
     data->context = SDL_GL_CreateContext(window);
     if (!data->context) {
@@ -421,9 +355,9 @@
 
     if (SDL_GL_ExtensionSupported("GL_OES_framebuffer_object")) {
         data->GL_OES_framebuffer_object_supported = SDL_TRUE;
+        renderer->info.flags |= SDL_RENDERER_TARGETTEXTURE;
     }
     data->framebuffers = NULL;
-    data->renderTarget = NULL;
 
     /* Set up parameters for rendering */
     GLES_ResetState(renderer);
@@ -641,6 +575,33 @@
 }
 
 static int
+GLES_SetTargetTexture(SDL_Renderer * renderer, SDL_Texture * texture)
+{
+    GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
+    GLES_TextureData *texturedata = NULL;
+    GLenum status;
+
+    GLES_ActivateRenderer(renderer);
+
+    if (texture == NULL) {
+        data->glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
+        return 0;
+    }
+
+    texturedata = (GLES_TextureData *) texture->driverdata;
+    data->glBindFramebufferOES(GL_FRAMEBUFFER_OES, texturedata->fbo->FBO);
+    /* TODO: check if texture pixel format allows this operation */
+    data->glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, texturedata->type, texturedata->texture, 0);
+    /* Check FBO status */
+    status = data->glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
+    if (status != GL_FRAMEBUFFER_COMPLETE_OES) {
+        SDL_SetError("glFramebufferTexture2DOES() failed");
+        return -1;
+    }
+    return 0;
+}
+
+static int
 GLES_UpdateViewport(SDL_Renderer * renderer)
 {
     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
@@ -870,7 +831,7 @@
         SDL_Window *window = renderer->window;
 
         SDL_GetWindowSize(window, &w, &h);
-        if (data->renderTarget != NULL) {
+        if (renderer->target) {
             cropRect[0] = srcrect->x;
             cropRect[1] = srcrect->y;
             cropRect[2] = srcrect->w;
--- a/src/render/opengles2/SDL_render_gles2.c	Sat Jan 21 22:14:38 2012 -0500
+++ b/src/render/opengles2/SDL_render_gles2.c	Sat Jan 21 22:22:30 2012 -0500
@@ -145,8 +145,6 @@
 #include "SDL_gles2funcs.h"
 #undef SDL_PROC
     GLES2_FBOList *framebuffers;
-    SDL_Texture *renderTarget;
-    SDL_Rect viewport_copy;
 
     int shader_format_count;
     GLenum *shader_formats;
@@ -166,8 +164,8 @@
                               const SDL_WindowEvent *event);
 static int GLES2_UpdateViewport(SDL_Renderer * renderer);
 static void GLES2_DestroyRenderer(SDL_Renderer *renderer);
+static int GLES2_SetOrthographicProjection(SDL_Renderer *renderer);
 
-static int GLES2_SetTargetTexture(SDL_Renderer * renderer, SDL_Texture * texture);
 
 static SDL_GLContext SDL_CurrentContext = NULL;
 
@@ -329,6 +327,7 @@
 static void GLES2_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture);
 static int GLES2_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect,
                                const void *pixels, int pitch);
+static int GLES2_SetTargetTexture(SDL_Renderer * renderer, SDL_Texture * texture);
 
 static GLenum
 GetScaleQuality(void)
@@ -533,6 +532,33 @@
     return 0;
 }
 
+static int
+GLES2_SetTargetTexture(SDL_Renderer * renderer, SDL_Texture * texture)
+{
+    GLES2_DriverContext *data = (GLES2_DriverContext *) renderer->driverdata;
+    GLES2_TextureData *texturedata = NULL;
+    GLenum status;
+
+    if (texture == NULL) {
+        data->glBindFramebuffer(GL_FRAMEBUFFER, 0);
+    } else {
+        texturedata = (GLES2_TextureData *) texture->driverdata;
+        data->glBindFramebuffer(GL_FRAMEBUFFER, texturedata->fbo->FBO);
+        /* TODO: check if texture pixel format allows this operation */
+        data->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texturedata->texture_type, texturedata->texture, 0);
+        /* Check FBO status */
+        status = data->glCheckFramebufferStatus(GL_FRAMEBUFFER);
+        if (status != GL_FRAMEBUFFER_COMPLETE) {
+            SDL_SetError("glFramebufferTexture2D() failed");
+            return -1;
+        }
+    }
+    if (data->current_program) {
+        GLES2_SetOrthographicProjection(renderer);
+    }
+    return 0;
+}
+
 /*************************************************************************************************
  * Shader management functions                                                                   *
  *************************************************************************************************/
@@ -546,7 +572,6 @@
                                                    SDL_BlendMode blendMode);
 static int GLES2_SelectProgram(SDL_Renderer *renderer, GLES2_ImageSource source,
                                SDL_BlendMode blendMode);
-static int GLES2_SetOrthographicProjection(SDL_Renderer *renderer);
 
 static GLES2_ProgramCacheEntry *
 GLES2_CacheProgram(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *vertex,
@@ -1128,13 +1153,13 @@
 
     /* Activate an appropriate shader and set the projection matrix */
     blendMode = texture->blendMode;
-    if (rdata->renderTarget!=NULL) {
+    if (renderer->target) {
         /* Check if we need to do color mapping between the source and render target textures */
-        if (rdata->renderTarget->format != texture->format) {
+        if (renderer->target->format != texture->format) {
             switch (texture->format)
             {
             case SDL_PIXELFORMAT_ABGR8888:
-                switch (rdata->renderTarget->format)
+                switch (renderer->target->format)
                 {
                     case SDL_PIXELFORMAT_ARGB8888:
                     case SDL_PIXELFORMAT_RGB888:
@@ -1146,7 +1171,7 @@
                 }
                 break;
             case SDL_PIXELFORMAT_ARGB8888:
-                switch (rdata->renderTarget->format)
+                switch (renderer->target->format)
                 {
                     case SDL_PIXELFORMAT_ABGR8888:
                     case SDL_PIXELFORMAT_BGR888:
@@ -1158,7 +1183,7 @@
                 }
                 break;
             case SDL_PIXELFORMAT_BGR888:
-                switch (rdata->renderTarget->format)
+                switch (renderer->target->format)
                 {
                     case SDL_PIXELFORMAT_ABGR8888:
                         sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR;
@@ -1172,7 +1197,7 @@
                 }
                 break;
             case SDL_PIXELFORMAT_RGB888:
-                switch (rdata->renderTarget->format)
+                switch (renderer->target->format)
                 {
                     case SDL_PIXELFORMAT_ABGR8888:
                         sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
@@ -1230,7 +1255,7 @@
     GLES2_SetTexCoords(rdata, SDL_TRUE);
 
     /* Emit the textured quad */
-    if (rdata->renderTarget!=NULL) {
+    if (renderer->target) {
         // Flip the texture vertically to compensate for the inversion it'll be subjected to later when it's rendered to the screen
         vertices[0] = (GLfloat)dstrect->x;
         vertices[1] = (GLfloat)renderer->viewport.h-dstrect->y;
@@ -1356,60 +1381,6 @@
     rdata->glDisableVertexAttribArray(GLES2_ATTRIBUTE_TEXCOORD);
 }
 
-static int
-GLES2_SetTargetTexture(SDL_Renderer * renderer, SDL_Texture * texture)
-{
-    GLES2_DriverContext *data = (GLES2_DriverContext *) renderer->driverdata;
-    GLES2_TextureData *texturedata = NULL;
-    GLenum status;
-    SDL_BlendMode blendMode;
-
-    if (!renderer) return -1;
-
-    blendMode = texture->blendMode;
-    if (texture == NULL) {
-        if (data->renderTarget!=NULL) {
-            data->glBindFramebuffer(GL_FRAMEBUFFER, 0);
-            renderer->viewport = data->viewport_copy;
-            data->renderTarget = NULL;
-            data->glViewport(renderer->viewport.x, renderer->viewport.y, renderer->viewport.w, renderer->viewport.h);
-            if(data->current_program) GLES2_SetOrthographicProjection(renderer);
-        }
-        return 0;
-    }
-    if (renderer != texture->renderer) return -1;
-    if (data->renderTarget==NULL) {
-        // Keep a copy of the default viewport to restore when texture==NULL
-        data->viewport_copy = renderer->viewport;
-    }
-
-    texturedata = (GLES2_TextureData *) texture->driverdata;
-    if (!texturedata) {
-        if (texture->native && texture->native->driverdata) {
-            texture = texture->native;
-            texturedata = texture->driverdata;
-        }
-        else return -1;
-    }
-    data->glBindFramebuffer(GL_FRAMEBUFFER, texturedata->fbo->FBO);
-    /* TODO: check if texture pixel format allows this operation */
-    data->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texturedata->texture_type, texturedata->texture, 0);
-    /* Check FBO status */
-    status = data->glCheckFramebufferStatus(GL_FRAMEBUFFER);
-    if (status != GL_FRAMEBUFFER_COMPLETE) {
-        return -1;
-    }
-    
-    renderer->viewport.x = 0;
-    renderer->viewport.y = 0;
-    renderer->viewport.w = texture->w;
-    renderer->viewport.h = texture->h;
-    data->renderTarget = texture;
-    data->glViewport(0, 0, texture->w, texture->h);
-    if(data->current_program) GLES2_SetOrthographicProjection(renderer);
-    return 0;
-}
-
 static SDL_Renderer *
 GLES2_CreateRenderer(SDL_Window *window, Uint32 flags)
 {
@@ -1511,7 +1482,6 @@
 #endif /* ZUNE_HD */
 
     rdata->framebuffers = NULL;
-    rdata->renderTarget = NULL;
 
     /* Populate the function pointers for the module */
     renderer->WindowEvent         = &GLES2_WindowEvent;
@@ -1519,6 +1489,7 @@
     renderer->UpdateTexture       = &GLES2_UpdateTexture;
     renderer->LockTexture         = &GLES2_LockTexture;
     renderer->UnlockTexture       = &GLES2_UnlockTexture;
+    renderer->SetTargetTexture    = &GLES2_SetTargetTexture;
     renderer->UpdateViewport      = &GLES2_UpdateViewport;
     renderer->RenderClear         = &GLES2_RenderClear;
     renderer->RenderDrawPoints    = &GLES2_RenderDrawPoints;
@@ -1529,7 +1500,6 @@
     renderer->RenderPresent       = &GLES2_RenderPresent;
     renderer->DestroyTexture      = &GLES2_DestroyTexture;
     renderer->DestroyRenderer     = &GLES2_DestroyRenderer;
-    renderer->SetTargetTexture    = &GLES2_SetTargetTexture;
 
     GLES2_ResetState(renderer);
 
--- a/src/render/software/SDL_render_sw.c	Sat Jan 21 22:14:38 2012 -0500
+++ b/src/render/software/SDL_render_sw.c	Sat Jan 21 22:22:30 2012 -0500
@@ -51,6 +51,7 @@
 static int SW_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
                           const SDL_Rect * rect, void **pixels, int *pitch);
 static void SW_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
+static int SW_SetTargetTexture(SDL_Renderer * renderer, SDL_Texture * texture);
 static int SW_UpdateViewport(SDL_Renderer * renderer);
 static int SW_RenderClear(SDL_Renderer * renderer);
 static int SW_RenderDrawPoints(SDL_Renderer * renderer,
@@ -72,7 +73,7 @@
     SW_CreateRenderer,
     {
      "software",
-     SDL_RENDERER_SOFTWARE,
+     SDL_RENDERER_SOFTWARE | SDL_RENDERER_TARGETTEXTURE,
      8,
      {
       SDL_PIXELFORMAT_RGB555,
@@ -91,6 +92,7 @@
 typedef struct
 {
     SDL_Surface *surface;
+    SDL_Surface *window;
 } SW_RenderData;
 
 
@@ -100,7 +102,10 @@
     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
 
     if (!data->surface) {
-        data->surface = SDL_GetWindowSurface(renderer->window);
+        data->surface = data->window;
+    }
+    if (!data->surface) {
+        data->surface = data->window = SDL_GetWindowSurface(renderer->window);
 
         SW_UpdateViewport(renderer);
     }
@@ -140,8 +145,8 @@
     renderer->UpdateTexture = SW_UpdateTexture;
     renderer->LockTexture = SW_LockTexture;
     renderer->UnlockTexture = SW_UnlockTexture;
+    renderer->SetTargetTexture = SW_SetTargetTexture;
     renderer->UpdateViewport = SW_UpdateViewport;
-    renderer->DestroyTexture = SW_DestroyTexture;
     renderer->RenderClear = SW_RenderClear;
     renderer->RenderDrawPoints = SW_RenderDrawPoints;
     renderer->RenderDrawLines = SW_RenderDrawLines;
@@ -149,6 +154,7 @@
     renderer->RenderCopy = SW_RenderCopy;
     renderer->RenderReadPixels = SW_RenderReadPixels;
     renderer->RenderPresent = SW_RenderPresent;
+    renderer->DestroyTexture = SW_DestroyTexture;
     renderer->DestroyRenderer = SW_DestroyRenderer;
     renderer->info = SW_RenderDriver.info;
     renderer->driverdata = data;
@@ -277,6 +283,19 @@
 }
 
 static int
+SW_SetTargetTexture(SDL_Renderer * renderer, SDL_Texture * texture)
+{
+    SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
+
+    if (texture ) {
+        data->surface = (SDL_Surface *) texture->driverdata;
+    } else {
+        data->surface = data->window;
+    }
+    return 0;
+}
+
+static int
 SW_UpdateViewport(SDL_Renderer * renderer)
 {
     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;