SDL: Select the best pixel formats for use in the software renderer

From 4ee4e49e4904d7472360188343744652167a150d Mon Sep 17 00:00:00 2001
From: Cameron Cawley <[EMAIL REDACTED]>
Date: Sat, 15 Oct 2022 12:36:07 +0100
Subject: [PATCH] Select the best pixel formats for use in the software
 renderer

---
 src/render/software/SDL_render_sw.c | 108 +++++++++++++++++++++++++---
 1 file changed, 99 insertions(+), 9 deletions(-)

diff --git a/src/render/software/SDL_render_sw.c b/src/render/software/SDL_render_sw.c
index 6ba77d46e5d5..6e54b67c68b7 100644
--- a/src/render/software/SDL_render_sw.c
+++ b/src/render/software/SDL_render_sw.c
@@ -1011,6 +1011,100 @@ SW_DestroyRenderer(SDL_Renderer * renderer)
     SDL_free(renderer);
 }
 
+static void
+SW_SelectBestFormats(SDL_Renderer *renderer, Uint32 format)
+{
+    /* Prefer the format used by the framebuffer by default. */
+    renderer->info.texture_formats[renderer->info.num_texture_formats++] = format;
+
+    switch (format) {
+    case SDL_PIXELFORMAT_XRGB4444:
+        renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_ARGB4444;
+        break;
+    case SDL_PIXELFORMAT_XBGR4444:
+        renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_ABGR4444;
+        break;
+    case SDL_PIXELFORMAT_ARGB4444:
+        renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_XRGB4444;
+        break;
+    case SDL_PIXELFORMAT_ABGR4444:
+        renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_XBGR4444;
+        break;
+
+    case SDL_PIXELFORMAT_XRGB1555:
+        renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_ARGB1555;
+        break;
+    case SDL_PIXELFORMAT_XBGR1555:
+        renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_ABGR1555;
+        break;
+    case SDL_PIXELFORMAT_ARGB1555:
+        renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_XRGB1555;
+        break;
+    case SDL_PIXELFORMAT_ABGR1555:
+        renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_XBGR1555;
+        break;
+
+    case SDL_PIXELFORMAT_XRGB8888:
+        renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_ARGB8888;
+        break;
+    case SDL_PIXELFORMAT_RGBX8888:
+        renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_RGBA8888;
+        break;
+    case SDL_PIXELFORMAT_XBGR8888:
+        renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_ABGR8888;
+        break;
+    case SDL_PIXELFORMAT_BGRX8888:
+        renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_BGRA8888;
+        break;
+    case SDL_PIXELFORMAT_ARGB8888:
+        renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_XRGB8888;
+        break;
+    case SDL_PIXELFORMAT_RGBA8888:
+        renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_RGBX8888;
+        break;
+    case SDL_PIXELFORMAT_ABGR8888:
+        renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_XBGR8888;
+        break;
+    case SDL_PIXELFORMAT_BGRA8888:
+        renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_BGRX8888;
+        break;
+    }
+
+    /* Ensure that we always have a SDL_PACKEDLAYOUT_8888 format. Having a matching component order increases the
+     * chances of getting a fast path for blitting.
+     */
+    if (SDL_ISPIXELFORMAT_PACKED(format)) {
+        if (SDL_PIXELLAYOUT(format) != SDL_PACKEDLAYOUT_8888) {
+            switch (SDL_PIXELORDER(format)) {
+            case SDL_PACKEDORDER_BGRX:
+            case SDL_PACKEDORDER_BGRA:
+                renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_BGRX8888;
+                renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_BGRA8888;
+                break;
+            case SDL_PACKEDORDER_RGBX:
+            case SDL_PACKEDORDER_RGBA:
+                renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_RGBX8888;
+                renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_RGBA8888;
+                break;
+            case SDL_PACKEDORDER_XBGR:
+            case SDL_PACKEDORDER_ABGR:
+                renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_XBGR8888;
+                renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_ABGR8888;
+                break;
+            case SDL_PACKEDORDER_XRGB:
+            case SDL_PACKEDORDER_ARGB:
+            default:
+                renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_XRGB8888;
+                renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_ARGB8888;
+                break;
+            }
+        }
+    } else {
+        renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_XRGB8888;
+        renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_ARGB8888;
+    }
+}
+
 SDL_Renderer *
 SW_CreateRendererForSurface(SDL_Surface * surface)
 {
@@ -1061,6 +1155,8 @@ SW_CreateRendererForSurface(SDL_Surface * surface)
     renderer->info = SW_RenderDriver.info;
     renderer->driverdata = data;
 
+    SW_SelectBestFormats(renderer, surface->format->format);
+
     SW_ActivateRenderer(renderer);
 
     return renderer;
@@ -1103,16 +1199,10 @@ SDL_RenderDriver SW_RenderDriver = {
     {
      "software",
      SDL_RENDERER_SOFTWARE | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE,
-     8,
+     0,
      {
-      SDL_PIXELFORMAT_ARGB8888,
-      SDL_PIXELFORMAT_ABGR8888,
-      SDL_PIXELFORMAT_RGBA8888,
-      SDL_PIXELFORMAT_BGRA8888,
-      SDL_PIXELFORMAT_RGB888,
-      SDL_PIXELFORMAT_BGR888,
-      SDL_PIXELFORMAT_RGB565,
-      SDL_PIXELFORMAT_RGB555
+      /* formats filled in later */
+      SDL_PIXELFORMAT_UNKNOWN
      },
      0,
      0}