diff src/video/SDL_renderer_sw.c @ 1907:06c27a737b7a

Streamlined the API a bit and optimized the software renderer.
author Sam Lantinga <slouken@libsdl.org>
date Sat, 15 Jul 2006 09:46:36 +0000
parents c2a27da60b18
children 092bd3a019c5
line wrap: on
line diff
--- a/src/video/SDL_renderer_sw.c	Fri Jul 14 08:24:43 2006 +0000
+++ b/src/video/SDL_renderer_sw.c	Sat Jul 15 09:46:36 2006 +0000
@@ -23,6 +23,7 @@
 
 #include "SDL_video.h"
 #include "SDL_sysvideo.h"
+#include "SDL_pixels_c.h"
 #include "SDL_rect_c.h"
 #include "SDL_yuv_sw_c.h"
 
@@ -53,20 +54,12 @@
 static void SDL_SW_DirtyTexture(SDL_Renderer * renderer,
                                 SDL_Texture * texture, int numrects,
                                 const SDL_Rect * rects);
-static void SDL_SW_SelectRenderTexture(SDL_Renderer * renderer,
-                                       SDL_Texture * texture);
 static int SDL_SW_RenderFill(SDL_Renderer * renderer, const SDL_Rect * rect,
                              Uint32 color);
 static int SDL_SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
                              const SDL_Rect * srcrect,
                              const SDL_Rect * dstrect, int blendMode,
                              int scaleMode);
-static int SDL_SW_RenderReadPixels(SDL_Renderer * renderer,
-                                   const SDL_Rect * rect, void *pixels,
-                                   int pitch);
-static int SDL_SW_RenderWritePixels(SDL_Renderer * renderer,
-                                    const SDL_Rect * rect, const void *pixels,
-                                    int pitch);
 static void SDL_SW_RenderPresent(SDL_Renderer * renderer);
 static void SDL_SW_DestroyTexture(SDL_Renderer * renderer,
                                   SDL_Texture * texture);
@@ -79,7 +72,7 @@
      "software",
      (SDL_Renderer_SingleBuffer | SDL_Renderer_PresentCopy |
       SDL_Renderer_PresentFlip2 | SDL_Renderer_PresentFlip3 |
-      SDL_Renderer_PresentDiscard | SDL_Renderer_RenderTarget),
+      SDL_Renderer_PresentDiscard | SDL_Renderer_PresentVSync),
      (SDL_TextureBlendMode_None | SDL_TextureBlendMode_Mask |
       SDL_TextureBlendMode_Blend),
      (SDL_TextureScaleMode_None | SDL_TextureScaleMode_Fast),
@@ -102,14 +95,63 @@
 
 typedef struct
 {
-    int current_screen;
-    SDL_Surface *screens[3];
-    SDL_Surface *target;
+    Uint32 format;
+    int current_texture;
+    SDL_Texture *texture[3];
+    SDL_Surface surface;
     SDL_Renderer *renderer;
     SDL_DirtyRectList dirty;
-    SDL_bool makedirty;
 } SDL_SW_RenderData;
 
+static SDL_Texture *
+CreateTexture(SDL_Renderer * renderer, Uint32 format, int w, int h)
+{
+    SDL_Texture *texture;
+
+    texture = (SDL_Texture *) SDL_malloc(sizeof(*texture));
+    if (!texture) {
+        SDL_OutOfMemory();
+        return NULL;
+    }
+
+    SDL_zerop(texture);
+    texture->format = format;
+    texture->access = SDL_TextureAccess_Local;
+    texture->w = w;
+    texture->h = h;
+    texture->renderer = renderer;
+
+    if (renderer->CreateTexture(renderer, texture) < 0) {
+        SDL_free(texture);
+        return NULL;
+    }
+    return texture;
+}
+
+static void
+DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
+{
+    renderer->DestroyTexture(renderer, texture);
+    SDL_free(texture);
+}
+
+static int
+DisplayPaletteChanged(void *userdata, SDL_Palette * palette)
+{
+    SDL_SW_RenderData *data = (SDL_SW_RenderData *) userdata;
+    int i;
+
+    for (i = 0; i < SDL_arraysize(data->texture); ++i) {
+        if (data->texture[i] && data->renderer->SetTexturePalette) {
+            data->renderer->SetTexturePalette(data->renderer,
+                                              data->texture[i],
+                                              palette->colors, 0,
+                                              palette->ncolors);
+        }
+    }
+    return 0;
+}
+
 SDL_Renderer *
 SDL_SW_CreateRenderer(SDL_Window * window, Uint32 flags)
 {
@@ -120,6 +162,7 @@
     int i, n;
     int bpp;
     Uint32 Rmask, Gmask, Bmask, Amask;
+    Uint32 renderer_flags;
 
     if (!SDL_PixelFormatEnumToMasks
         (displayMode->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
@@ -149,11 +192,8 @@
     renderer->LockTexture = SDL_SW_LockTexture;
     renderer->UnlockTexture = SDL_SW_UnlockTexture;
     renderer->DirtyTexture = SDL_SW_DirtyTexture;
-    renderer->SelectRenderTexture = SDL_SW_SelectRenderTexture;
     renderer->RenderFill = SDL_SW_RenderFill;
     renderer->RenderCopy = SDL_SW_RenderCopy;
-    renderer->RenderReadPixels = SDL_SW_RenderReadPixels;
-    renderer->RenderWritePixels = SDL_SW_RenderWritePixels;
     renderer->RenderPresent = SDL_SW_RenderPresent;
     renderer->DestroyTexture = SDL_SW_DestroyTexture;
     renderer->DestroyRenderer = SDL_SW_DestroyRenderer;
@@ -161,7 +201,7 @@
     renderer->window = window->id;
     renderer->driverdata = data;
 
-    renderer->info.flags = SDL_Renderer_RenderTarget;
+    renderer->info.flags = 0;
 
     if (flags & SDL_Renderer_PresentFlip2) {
         renderer->info.flags |= SDL_Renderer_PresentFlip2;
@@ -173,28 +213,18 @@
         renderer->info.flags |= SDL_Renderer_PresentCopy;
         n = 1;
     }
-    for (i = 0; i < n; ++i) {
-        data->screens[i] =
-            SDL_CreateRGBSurface(0, window->w, window->h, bpp, Rmask, Gmask,
-                                 Bmask, Amask);
-        if (!data->screens[i]) {
-            SDL_SW_DestroyRenderer(renderer);
-            return NULL;
-        }
-        SDL_SetSurfacePalette(data->screens[i], display->palette);
-    }
-    data->current_screen = 0;
-    data->target = data->screens[0];
-    data->makedirty = SDL_TRUE;
+    data->format = displayMode->format;
 
     /* Find a render driver that we can use to display data */
+    renderer_flags = (SDL_Renderer_SingleBuffer |
+                      SDL_Renderer_PresentDiscard);
+    if (flags & SDL_Renderer_PresentVSync) {
+        renderer_flags |= SDL_Renderer_PresentVSync;
+    }
     for (i = 0; i < display->num_render_drivers; ++i) {
         SDL_RenderDriver *driver = &display->render_drivers[i];
         if (driver->info.name != SDL_SW_RenderDriver.info.name) {
-            data->renderer =
-                driver->CreateRenderer(window,
-                                       (SDL_Renderer_SingleBuffer |
-                                        SDL_Renderer_PresentDiscard));
+            data->renderer = driver->CreateRenderer(window, renderer_flags);
             if (data->renderer) {
                 break;
             }
@@ -205,6 +235,35 @@
         SDL_SetError("Couldn't find display render driver");
         return NULL;
     }
+    if (data->renderer->info.flags & SDL_Renderer_PresentVSync) {
+        renderer->info.flags |= SDL_Renderer_PresentVSync;
+    }
+
+    /* Create the textures we'll use for display */
+    for (i = 0; i < n; ++i) {
+        data->texture[i] =
+            CreateTexture(data->renderer, data->format, window->w, window->h);
+        if (!data->texture[i]) {
+            SDL_SW_DestroyRenderer(renderer);
+            return NULL;
+        }
+    }
+    data->current_texture = 0;
+
+    /* Create a surface we'll use for rendering */
+    data->surface.flags = SDL_PREALLOC;
+    data->surface.format = SDL_AllocFormat(bpp, Rmask, Gmask, Bmask, Amask);
+    if (!data->surface.format) {
+        SDL_SW_DestroyRenderer(renderer);
+        return NULL;
+    }
+    SDL_SetSurfacePalette(&data->surface, display->palette);
+
+    /* Set up a palette watch on the display palette */
+    if (display->palette) {
+        SDL_AddPaletteWatch(display->palette, DisplayPaletteChanged, data);
+    }
+
     return renderer;
 }
 
@@ -212,10 +271,6 @@
 SDL_SW_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
 {
     if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
-        if (texture->access == SDL_TextureAccess_Render) {
-            SDL_SetError("Rendering to YUV format textures is not supported");
-            return -1;
-        }
         texture->driverdata = SDL_SW_CreateYUVTexture(texture);
     } else {
         int bpp;
@@ -347,29 +402,18 @@
 {
 }
 
-static void
-SDL_SW_SelectRenderTexture(SDL_Renderer * renderer, SDL_Texture * texture)
-{
-    SDL_SW_RenderData *data = (SDL_SW_RenderData *) renderer->driverdata;
-
-    if (texture) {
-        data->target = (SDL_Surface *) texture->driverdata;
-        data->makedirty = SDL_FALSE;
-    } else {
-        data->target = data->screens[data->current_screen];
-        data->makedirty = SDL_TRUE;
-    }
-}
-
 static int
 SDL_SW_RenderFill(SDL_Renderer * renderer, const SDL_Rect * rect,
                   Uint32 color)
 {
     SDL_SW_RenderData *data = (SDL_SW_RenderData *) renderer->driverdata;
-    SDL_Rect real_rect = *rect;
     Uint8 r, g, b, a;
+    void *pixels;
+    int pitch;
+    SDL_Rect real_rect;
+    int status;
 
-    if (data->makedirty) {
+    if (data->renderer->info.flags & SDL_Renderer_PresentCopy) {
         SDL_AddDirtyRect(&data->dirty, rect);
     }
 
@@ -377,9 +421,25 @@
     r = (Uint8) ((color >> 16) & 0xFF);
     g = (Uint8) ((color >> 8) & 0xFF);
     b = (Uint8) (color & 0xFF);
-    color = SDL_MapRGBA(data->target->format, r, g, b, a);
+    color = SDL_MapRGBA(data->surface.format, r, g, b, a);
 
-    return SDL_FillRect(data->target, &real_rect, color);
+    if (data->renderer->
+        LockTexture(data->renderer, data->texture[data->current_texture],
+                    rect, 1, &data->surface.pixels,
+                    &data->surface.pitch) < 0) {
+        return -1;
+    }
+    data->surface.w = rect->w;
+    data->surface.h = rect->h;
+    data->surface.clip_rect.w = rect->w;
+    data->surface.clip_rect.h = rect->h;
+    real_rect = data->surface.clip_rect;
+
+    status = SDL_FillRect(&data->surface, &real_rect, color);
+
+    data->renderer->UnlockTexture(data->renderer,
+                                  data->texture[data->current_texture]);
+    return status;
 }
 
 static int
@@ -389,25 +449,34 @@
 {
     SDL_SW_RenderData *data = (SDL_SW_RenderData *) renderer->driverdata;
     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
-    SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
+    int status;
+
+    if (data->renderer->info.flags & SDL_Renderer_PresentCopy) {
+        SDL_AddDirtyRect(&data->dirty, dstrect);
+    }
 
-    if (data->makedirty) {
-        SDL_AddDirtyRect(&data->dirty, dstrect);
+    if (data->renderer->
+        LockTexture(data->renderer, data->texture[data->current_texture],
+                    dstrect, 1, &data->surface.pixels,
+                    &data->surface.pitch) < 0) {
+        return -1;
     }
 
     if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
-        SDL_Surface *target = data->target;
-        void *pixels =
-            (Uint8 *) target->pixels + dstrect->y * target->pitch +
-            dstrect->x * target->format->BytesPerPixel;
-        return SDL_SW_CopyYUVToRGB((SDL_SW_YUVTexture *) texture->driverdata,
-                                   srcrect, display->current_mode.format,
-                                   dstrect->w, dstrect->h, pixels,
-                                   target->pitch);
+        status =
+            SDL_SW_CopyYUVToRGB((SDL_SW_YUVTexture *) texture->driverdata,
+                                srcrect, data->format, dstrect->w, dstrect->h,
+                                data->surface.pixels, data->surface.pitch);
     } else {
         SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
         SDL_Rect real_srcrect = *srcrect;
-        SDL_Rect real_dstrect = *dstrect;
+        SDL_Rect real_dstrect;
+
+        data->surface.w = dstrect->w;
+        data->surface.h = dstrect->h;
+        data->surface.clip_rect.w = dstrect->w;
+        data->surface.clip_rect.h = dstrect->h;
+        real_dstrect = data->surface.clip_rect;
 
         if (blendMode &
             (SDL_TextureBlendMode_Mask | SDL_TextureBlendMode_Blend)) {
@@ -417,91 +486,53 @@
         }
         if (scaleMode != SDL_TextureScaleMode_None &&
             (srcrect->w != dstrect->w || srcrect->h != dstrect->h)) {
-            return SDL_SoftStretch(surface, &real_srcrect, data->target,
-                                   &real_dstrect);
+            status =
+                SDL_SoftStretch(surface, &real_srcrect, &data->surface,
+                                &real_dstrect);
         } else {
-            return SDL_LowerBlit(surface, &real_srcrect, data->target,
-                                 &real_dstrect);
+            status =
+                SDL_LowerBlit(surface, &real_srcrect, &data->surface,
+                              &real_dstrect);
         }
     }
-}
-
-static int
-SDL_SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
-                        void *pixels, int pitch)
-{
-    SDL_SW_RenderData *data = (SDL_SW_RenderData *) renderer->driverdata;
-    SDL_Surface *surface = data->target;
-    Uint8 *src, *dst;
-    int row;
-    size_t length;
-
-    src =
-        (Uint8 *) surface->pixels + rect->y * surface->pitch +
-        rect->x * surface->format->BytesPerPixel;
-    dst = (Uint8 *) pixels;
-    length = rect->w * surface->format->BytesPerPixel;
-    for (row = 0; row < rect->h; ++row) {
-        SDL_memcpy(dst, src, length);
-        src += surface->pitch;
-        dst += pitch;
-    }
-    return 0;
-}
-
-static int
-SDL_SW_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect,
-                         const void *pixels, int pitch)
-{
-    SDL_SW_RenderData *data = (SDL_SW_RenderData *) renderer->driverdata;
-    SDL_Surface *surface = data->target;
-    Uint8 *src, *dst;
-    int row;
-    size_t length;
-
-    if (data->makedirty) {
-        SDL_AddDirtyRect(&data->dirty, rect);
-    }
-
-    src = (Uint8 *) pixels;
-    dst =
-        (Uint8 *) surface->pixels + rect->y * surface->pitch +
-        rect->x * surface->format->BytesPerPixel;
-    length = rect->w * surface->format->BytesPerPixel;
-    for (row = 0; row < rect->h; ++row) {
-        SDL_memcpy(dst, src, length);
-        src += pitch;
-        dst += surface->pitch;
-    }
-    return 0;
+    data->renderer->UnlockTexture(data->renderer,
+                                  data->texture[data->current_texture]);
+    return status;
 }
 
 static void
 SDL_SW_RenderPresent(SDL_Renderer * renderer)
 {
     SDL_SW_RenderData *data = (SDL_SW_RenderData *) renderer->driverdata;
-    SDL_Surface *surface = data->screens[data->current_screen];
-    SDL_DirtyRect *dirty;
+    SDL_Texture *texture = data->texture[data->current_texture];
 
     /* Send the data to the display */
-    for (dirty = data->dirty.list; dirty; dirty = dirty->next) {
-        void *pixels =
-            (void *) ((Uint8 *) surface->pixels +
-                      dirty->rect.y * surface->pitch +
-                      dirty->rect.x * surface->format->BytesPerPixel);
-        data->renderer->RenderWritePixels(data->renderer, &dirty->rect,
-                                          pixels, surface->pitch);
+    if (data->renderer->info.flags & SDL_Renderer_PresentCopy) {
+        SDL_DirtyRect *dirty;
+        for (dirty = data->dirty.list; dirty; dirty = dirty->next) {
+            data->renderer->RenderCopy(data->renderer, texture, &dirty->rect,
+                                       &dirty->rect,
+                                       SDL_TextureBlendMode_None,
+                                       SDL_TextureScaleMode_None);
+        }
+        SDL_ClearDirtyRects(&data->dirty);
+    } else {
+        SDL_Rect rect;
+        rect.x = 0;
+        rect.y = 0;
+        rect.w = texture->w;
+        rect.h = texture->h;
+        data->renderer->RenderCopy(data->renderer, texture, &rect, &rect,
+                                   SDL_TextureBlendMode_None,
+                                   SDL_TextureScaleMode_None);
     }
-    SDL_ClearDirtyRects(&data->dirty);
     data->renderer->RenderPresent(data->renderer);
 
     /* Update the flipping chain, if any */
     if (renderer->info.flags & SDL_Renderer_PresentFlip2) {
-        data->current_screen = (data->current_screen + 1) % 2;
-        data->target = data->screens[data->current_screen];
+        data->current_texture = (data->current_texture + 1) % 2;
     } else if (renderer->info.flags & SDL_Renderer_PresentFlip3) {
-        data->current_screen = (data->current_screen + 1) % 3;
-        data->target = data->screens[data->current_screen];
+        data->current_texture = (data->current_texture + 1) % 3;
     }
 }
 
@@ -521,14 +552,27 @@
 SDL_SW_DestroyRenderer(SDL_Renderer * renderer)
 {
     SDL_SW_RenderData *data = (SDL_SW_RenderData *) renderer->driverdata;
+    SDL_Window *window = SDL_GetWindowFromID(renderer->window);
+    SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
     int i;
 
     if (data) {
-        for (i = 0; i < SDL_arraysize(data->screens); ++i) {
-            if (data->screens[i]) {
-                SDL_FreeSurface(data->screens[i]);
+        for (i = 0; i < SDL_arraysize(data->texture); ++i) {
+            if (data->texture[i]) {
+                DestroyTexture(data->renderer, data->texture[i]);
             }
         }
+        if (data->surface.format) {
+            SDL_SetSurfacePalette(&data->surface, NULL);
+            SDL_FreeFormat(data->surface.format);
+        }
+        if (display->palette) {
+            SDL_DelPaletteWatch(display->palette, DisplayPaletteChanged,
+                                data);
+        }
+        if (data->renderer) {
+            data->renderer->DestroyRenderer(data->renderer);
+        }
         SDL_FreeDirtyRects(&data->dirty);
         SDL_free(data);
     }