diff src/render/software/SDL_renderer_sw.c @ 5169:4d39eeaad00b

Added a way to get a framebuffer interface for a window, and also a way to create a software renderer for an arbitrary surface. The software renderer has been re-routed to use the framebuffer interface, which makes it possible to have software rendering available even on simple ports.
author Sam Lantinga <slouken@libsdl.org>
date Thu, 03 Feb 2011 15:49:37 -0800
parents d72793305335
children
line wrap: on
line diff
--- a/src/render/software/SDL_renderer_sw.c	Thu Feb 03 11:16:57 2011 -0800
+++ b/src/render/software/SDL_renderer_sw.c	Thu Feb 03 15:49:37 2011 -0800
@@ -69,7 +69,7 @@
     SW_CreateRenderer,
     {
      "software",
-     (SDL_RENDERER_PRESENTVSYNC),
+     0,
      8,
      {
       SDL_PIXELFORMAT_RGB555,
@@ -87,61 +87,19 @@
 
 typedef struct
 {
-    Uint32 format;
     SDL_bool updateSize;
-    SDL_Texture *texture;
-    SDL_Surface surface;
-    SDL_Renderer *renderer;
+    SDL_Surface *surface;
 } SW_RenderData;
 
-static SDL_Texture *
-CreateTexture(SDL_Renderer * renderer, Uint32 format, int w, int h)
-{
-    SDL_Texture *texture;
-
-    texture = (SDL_Texture *) SDL_calloc(1, sizeof(*texture));
-    if (!texture) {
-        SDL_OutOfMemory();
-        return NULL;
-    }
-
-    texture->format = format;
-    texture->access = SDL_TEXTUREACCESS_STREAMING;
-    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);
-}
 
 SDL_Renderer *
-SW_CreateRenderer(SDL_Window * window, Uint32 flags)
+SW_CreateRendererForSurface(SDL_Surface * surface)
 {
     SDL_Renderer *renderer;
     SW_RenderData *data;
-    int i;
-    int w, h;
-    Uint32 format;
-    int bpp;
-    Uint32 Rmask, Gmask, Bmask, Amask;
-    Uint32 renderer_flags;
-    const char *desired_driver;
 
-    format = SDL_GetWindowPixelFormat(window);
-    if (!SDL_PixelFormatEnumToMasks
-        (format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
-        SDL_SetError("Unknown display format");
+    if (!surface) {
+        SDL_SetError("Can't create renderer for NULL surface");
         return NULL;
     }
 
@@ -157,6 +115,8 @@
         SDL_OutOfMemory();
         return NULL;
     }
+    data->surface = surface;
+
     renderer->WindowEvent = SW_WindowEvent;
     renderer->CreateTexture = SW_CreateTexture;
     renderer->SetTextureColorMod = SW_SetTextureColorMod;
@@ -174,80 +134,34 @@
     renderer->RenderPresent = SW_RenderPresent;
     renderer->DestroyRenderer = SW_DestroyRenderer;
     renderer->info = SW_RenderDriver.info;
-    renderer->info.flags = 0;
-    renderer->window = window;
     renderer->driverdata = data;
 
-    data->format = format;
-
-    /* Find a render driver that we can use to display data */
-    renderer_flags = 0;
-    if (flags & SDL_RENDERER_PRESENTVSYNC) {
-        renderer_flags |= SDL_RENDERER_PRESENTVSYNC;
-    }
-    desired_driver = SDL_getenv("SDL_VIDEO_RENDERER_SWDRIVER");
-    for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) {
-        SDL_RendererInfo info;
-        SDL_GetRenderDriverInfo(i, &info);
-        if (SDL_strcmp(info.name, SW_RenderDriver.info.name) == 0) {
-            continue;
-        }
-        if (desired_driver
-            && SDL_strcasecmp(desired_driver, info.name) != 0) {
-            continue;
-        }
-        data->renderer = SDL_CreateRenderer(window, i, renderer_flags);
-        if (data->renderer) {
-            break;
-        }
-    }
-    if (i == SDL_GetNumRenderDrivers()) {
-        SW_DestroyRenderer(renderer);
-        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 */
-    SDL_GetWindowSize(window, &w, &h);
-    data->texture = CreateTexture(data->renderer, data->format, w, h);
-    if (!data->texture) {
-        SW_DestroyRenderer(renderer);
-        return NULL;
-    }
-
-    /* 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) {
-        SW_DestroyRenderer(renderer);
-        return NULL;
-    }
-
     return renderer;
 }
 
-static SDL_Texture *
+SDL_Renderer *
+SW_CreateRenderer(SDL_Window * window, Uint32 flags)
+{
+    SDL_Surface *surface;
+
+    surface = SDL_GetWindowSurface(window);
+    if (!surface) {
+        return NULL;
+    }
+    return SW_CreateRendererForSurface(surface);
+}
+
+static SDL_Surface *
 SW_ActivateRenderer(SDL_Renderer * renderer)
 {
     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
     SDL_Window *window = renderer->window;
 
     if (data->updateSize) {
-        /* Recreate the textures for the new window size */
-        int w, h;
-        if (data->texture) {
-            DestroyTexture(data->renderer, data->texture);
-        }
-        SDL_GetWindowSize(window, &w, &h);
-        data->texture = CreateTexture(data->renderer, data->format, w, h);
-        if (data->texture) {
-            data->updateSize = SDL_FALSE;
-        }
+        data->surface = SDL_GetWindowSurface(window);
+        data->updateSize = SDL_FALSE;
     }
-    return data->texture;
+    return data->surface;
 }
 
 static void
@@ -356,264 +270,130 @@
 SW_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points,
                     int count)
 {
-    SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
-    SDL_Texture *texture = SW_ActivateRenderer(renderer);
-    SDL_Rect rect;
-    int i;
-    int x, y;
-    int status = 0;
-
-    if (!texture) {
-        return -1;
-    }
+    SDL_Surface *surface = SW_ActivateRenderer(renderer);
 
-    /* Get the smallest rectangle that contains everything */
-    rect.x = 0;
-    rect.y = 0;
-    rect.w = texture->w;
-    rect.h = texture->h;
-    if (!SDL_EnclosePoints(points, count, &rect, &rect)) {
-        /* Nothing to draw */
-        return 0;
-    }
-
-    if (data->renderer->LockTexture(data->renderer, texture, &rect,
-                                    &data->surface.pixels,
-                                    &data->surface.pitch) < 0) {
+    if (!surface) {
         return -1;
     }
 
-    data->surface.clip_rect.w = data->surface.w = rect.w;
-    data->surface.clip_rect.h = data->surface.h = rect.h;
-
     /* Draw the points! */
     if (renderer->blendMode == SDL_BLENDMODE_NONE) {
-        Uint32 color = SDL_MapRGBA(data->surface.format,
+        Uint32 color = SDL_MapRGBA(surface->format,
                                    renderer->r, renderer->g, renderer->b,
                                    renderer->a);
 
-        for (i = 0; i < count; ++i) {
-            x = points[i].x - rect.x;
-            y = points[i].y - rect.y;
-
-            status = SDL_DrawPoint(&data->surface, x, y, color);
-        }
+        return SDL_DrawPoints(surface, points, count, color);
     } else {
-        for (i = 0; i < count; ++i) {
-            x = points[i].x - rect.x;
-            y = points[i].y - rect.y;
-
-            status = SDL_BlendPoint(&data->surface, x, y,
-                                    renderer->blendMode,
-                                    renderer->r, renderer->g, renderer->b,
-                                    renderer->a);
-        }
+        return SDL_BlendPoints(surface, points, count,
+                               renderer->blendMode,
+                               renderer->r, renderer->g, renderer->b,
+                               renderer->a);
     }
-
-    data->renderer->UnlockTexture(data->renderer, texture);
-
-    return status;
 }
 
 static int
 SW_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points,
                    int count)
 {
-    SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
-    SDL_Texture *texture = SW_ActivateRenderer(renderer);
-    SDL_Rect clip, rect;
-    int i;
-    int x1, y1, x2, y2;
-    int status = 0;
-
-    if (!texture) {
-        return -1;
-    }
+    SDL_Surface *surface = SW_ActivateRenderer(renderer);
 
-    /* Get the smallest rectangle that contains everything */
-    clip.x = 0;
-    clip.y = 0;
-    clip.w = texture->w;
-    clip.h = texture->h;
-    SDL_EnclosePoints(points, count, NULL, &rect);
-    if (!SDL_IntersectRect(&rect, &clip, &rect)) {
-        /* Nothing to draw */
-        return 0;
-    }
-
-    if (data->renderer->LockTexture(data->renderer, texture, &rect,
-                                    &data->surface.pixels,
-                                    &data->surface.pitch) < 0) {
+    if (!surface) {
         return -1;
     }
 
-    data->surface.clip_rect.w = data->surface.w = rect.w;
-    data->surface.clip_rect.h = data->surface.h = rect.h;
-
-    /* Draw the points! */
+    /* Draw the lines! */
     if (renderer->blendMode == SDL_BLENDMODE_NONE) {
-        Uint32 color = SDL_MapRGBA(data->surface.format,
+        Uint32 color = SDL_MapRGBA(surface->format,
                                    renderer->r, renderer->g, renderer->b,
                                    renderer->a);
 
-        for (i = 1; i < count; ++i) {
-            x1 = points[i-1].x - rect.x;
-            y1 = points[i-1].y - rect.y;
-            x2 = points[i].x - rect.x;
-            y2 = points[i].y - rect.y;
-
-            status = SDL_DrawLine(&data->surface, x1, y1, x2, y2, color);
-        }
+        return SDL_DrawLines(surface, points, count, color);
     } else {
-        for (i = 1; i < count; ++i) {
-            x1 = points[i-1].x - rect.x;
-            y1 = points[i-1].y - rect.y;
-            x2 = points[i].x - rect.x;
-            y2 = points[i].y - rect.y;
-
-            status = SDL_BlendLine(&data->surface, x1, y1, x2, y2,
-                                   renderer->blendMode,
-                                   renderer->r, renderer->g, renderer->b,
-                                   renderer->a);
-        }
+        return SDL_BlendLines(surface, points, count,
+                              renderer->blendMode,
+                              renderer->r, renderer->g, renderer->b,
+                              renderer->a);
     }
-
-    data->renderer->UnlockTexture(data->renderer, texture);
-
-    return status;
 }
 
 static int
 SW_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect ** rects,
                    int count)
 {
-    SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
-    SDL_Texture *texture = SW_ActivateRenderer(renderer);
-    SDL_Rect clip, rect;
-    Uint32 color = 0;
-    int i;
-    int status = 0;
+    SDL_Surface *surface = SW_ActivateRenderer(renderer);
 
-    if (!texture) {
+    if (!surface) {
         return -1;
     }
 
-    clip.x = 0;
-    clip.y = 0;
-    clip.w = texture->w;
-    clip.h = texture->h;
-
     if (renderer->blendMode == SDL_BLENDMODE_NONE) {
-        color = SDL_MapRGBA(data->surface.format,
-                            renderer->r, renderer->g, renderer->b,
-                            renderer->a);
+        Uint32 color = SDL_MapRGBA(surface->format,
+                                   renderer->r, renderer->g, renderer->b,
+                                   renderer->a);
+        return SDL_FillRects(surface, rects, count, color);
+    } else {
+        return SDL_BlendFillRects(surface, rects, count,
+                                     renderer->blendMode,
+                                     renderer->r, renderer->g, renderer->b,
+                                     renderer->a);
     }
-
-    for (i = 0; i < count; ++i) {
-        if (!SDL_IntersectRect(rects[i], &clip, &rect)) {
-            /* Nothing to draw */
-            continue;
-        }
-
-        if (data->renderer->LockTexture(data->renderer, texture, &rect,
-                                        &data->surface.pixels,
-                                        &data->surface.pitch) < 0) {
-            return -1;
-        }
-
-        data->surface.clip_rect.w = data->surface.w = rect.w;
-        data->surface.clip_rect.h = data->surface.h = rect.h;
-
-        if (renderer->blendMode == SDL_BLENDMODE_NONE) {
-            status = SDL_FillRect(&data->surface, NULL, color);
-        } else {
-            status = SDL_BlendFillRect(&data->surface, NULL,
-                                       renderer->blendMode,
-                                       renderer->r, renderer->g, renderer->b,
-                                       renderer->a);
-        }
-
-        data->renderer->UnlockTexture(data->renderer, texture);
-    }
-    return status;
 }
 
 static int
 SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
               const SDL_Rect * srcrect, const SDL_Rect * dstrect)
 {
-    SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
-    SDL_Surface *surface;
-    SDL_Rect real_srcrect;
-    SDL_Rect real_dstrect;
-    int status;
+    SDL_Surface *surface = SW_ActivateRenderer(renderer);
+    SDL_Surface *src = (SDL_Surface *) texture->driverdata;
+    SDL_Rect final_rect = *dstrect;
 
-    if (!SW_ActivateRenderer(renderer)) {
+    if (!surface) {
         return -1;
     }
-
-    if (data->renderer->LockTexture(data->renderer, data->texture, dstrect,
-                                    &data->surface.pixels,
-                                    &data->surface.pitch) < 0) {
-        return -1;
-    }
-
-    surface = (SDL_Surface *) texture->driverdata;
-    real_srcrect = *srcrect;
-
-    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;
-
-    status = SDL_LowerBlit(surface, &real_srcrect, &data->surface, &real_dstrect);
-    data->renderer->UnlockTexture(data->renderer, data->texture);
-    return status;
+    return SDL_BlitSurface(src, srcrect, surface, &final_rect);
 }
 
 static int
 SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
                     Uint32 format, void * pixels, int pitch)
 {
-    SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
+    SDL_Surface *surface = SW_ActivateRenderer(renderer);
+    Uint32 src_format;
+    void *src_pixels;
 
-    if (!SW_ActivateRenderer(renderer)) {
+    if (!surface) {
         return -1;
     }
 
-    if (data->renderer->LockTexture(data->renderer, data->texture, rect,
-                                    &data->surface.pixels,
-                                    &data->surface.pitch) < 0) {
+    if (rect->x < 0 || rect->x+rect->w > surface->w ||
+        rect->y < 0 || rect->y+rect->h > surface->h) {
+        SDL_SetError("Tried to read outside of surface bounds");
         return -1;
     }
 
-    SDL_ConvertPixels(rect->w, rect->h,
-                      data->format, data->surface.pixels, data->surface.pitch,
-                      format, pixels, pitch);
+    src_format = SDL_MasksToPixelFormatEnum(
+                    surface->format->BitsPerPixel,
+                    surface->format->Rmask, surface->format->Gmask,
+                    surface->format->Bmask, surface->format->Amask);
 
-    data->renderer->UnlockTexture(data->renderer, data->texture);
-    return 0;
+    src_pixels = (void*)((Uint8 *) surface->pixels +
+                    rect->y * surface->pitch +
+                    rect->x * surface->format->BytesPerPixel);
+
+    return SDL_ConvertPixels(rect->w, rect->h,
+                             src_format, src_pixels, surface->pitch,
+                             format, pixels, pitch);
 }
 
 static void
 SW_RenderPresent(SDL_Renderer * renderer)
 {
     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
-    SDL_Texture *texture = SW_ActivateRenderer(renderer);
-    SDL_Rect rect;
-
-    if (!texture) {
-        return;
-    }
+    SDL_Window *window = renderer->window;
 
-    /* Send the data to the display */
-    rect.x = 0;
-    rect.y = 0;
-    rect.w = texture->w;
-    rect.h = texture->h;
-    data->renderer->RenderCopy(data->renderer, texture, &rect, &rect);
-    data->renderer->RenderPresent(data->renderer);
+    if (window) {
+        SDL_UpdateWindowSurface(window);
+    }
 }
 
 static void
@@ -628,18 +408,8 @@
 SW_DestroyRenderer(SDL_Renderer * renderer)
 {
     SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
-    SDL_Window *window = renderer->window;
 
     if (data) {
-        if (data->texture) {
-            DestroyTexture(data->renderer, data->texture);
-        }
-        if (data->surface.format) {
-            SDL_FreeFormat(data->surface.format);
-        }
-        if (data->renderer) {
-            data->renderer->DestroyRenderer(data->renderer);
-        }
         SDL_free(data);
     }
     SDL_free(renderer);