Fixed bug 4469 - make SDL_CreateTextureFromSurface pick a more appropriate format

Sylvain

Currently SDL_CreateTextureFromSurface picks first valid format, and do a conversion.

    format = renderer->info.texture_formats[0];
    for (i = 0; i < renderer->info.num_texture_formats; ++i) {
        if (!SDL_ISPIXELFORMAT_FOURCC(renderer->info.texture_formats[i]) &&
            SDL_ISPIXELFORMAT_ALPHA(renderer->info.texture_formats[i]) == needAlpha) {
            format = renderer->info.texture_formats[i];
            break;

It could try to find a better format, for instance :

 if SDL_Surface has no Amask, but a colorkey :
   if surface fmt is RGB888, try to pick ARGB8888 renderer fmt
   if surface fmt is BGR888, try to pick ABGR8888 renderer fmt
 else
   try to pick the same renderer format as surface fmt

if no format has been picked, use the fallback.


I think it goes with bug 4290 fastpath BlitNtoN
when you expand a surface with pixel format of size 24 to 32, there is a fast path possible.


So with this issue:

- if you have a surface with colorkey (RGB or BGR, not palette), it takes a renderer format where the conversion is faster.
  (it avoids, if possible, RGB -> ABGR which means switching RGB to BGR)

- if you have a surface ABGR format, it try to take the ABGR from the renderer.
  (it avoids, if possible, ABGR -> ARGB, which means switch RGB to BGR)
diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c
index 81f9296..faca9fe 100644
--- a/src/render/SDL_render.c
+++ b/src/render/SDL_render.c
@@ -1189,7 +1189,7 @@
     SDL_bool needAlpha;
     SDL_bool direct_update;
     int i;
-    Uint32 format;
+    Uint32 format = SDL_PIXELFORMAT_UNKNOWN;
     SDL_Texture *texture;
 
     CHECK_RENDERER_MAGIC(renderer, NULL);
@@ -1218,12 +1218,43 @@
         }
     }
 
-    format = renderer->info.texture_formats[0];
-    for (i = 0; i < (int)renderer->info.num_texture_formats; ++i) {
-        if (!SDL_ISPIXELFORMAT_FOURCC(renderer->info.texture_formats[i]) &&
-            SDL_ISPIXELFORMAT_ALPHA(renderer->info.texture_formats[i]) == needAlpha) {
-            format = renderer->info.texture_formats[i];
-            break;
+    /* Try to have the best pixel format for the texture */
+    /* No alpha, but a colorkey => promote to alpha */
+    if (!fmt->Amask && SDL_HasColorKey(surface)) {
+        if (fmt->format == SDL_PIXELFORMAT_RGB888) {
+            for (i = 0; i < renderer->info.num_texture_formats; ++i) {
+                if (renderer->info.texture_formats[i] == SDL_PIXELFORMAT_ARGB8888) {
+                    format = SDL_PIXELFORMAT_ARGB8888;
+                    break;
+                }
+            }
+        } else if (fmt->format == SDL_PIXELFORMAT_BGR888) {
+            for (i = 0; i < renderer->info.num_texture_formats; ++i) {
+                if (renderer->info.texture_formats[i] == SDL_PIXELFORMAT_ABGR8888) {
+                    format = SDL_PIXELFORMAT_ABGR8888;
+                    break;
+                }
+            }
+        }
+    } else {
+        /* Exact match would be fine */
+        for (i = 0; i < renderer->info.num_texture_formats; ++i) {
+            if (renderer->info.texture_formats[i] == fmt->format) {
+                format = fmt->format;
+                break;
+            }
+        }
+    }
+
+    /* Fallback, choose a valid pixel format */
+    if (format == SDL_PIXELFORMAT_UNKNOWN) {
+        format = renderer->info.texture_formats[0];
+        for (i = 0; i < renderer->info.num_texture_formats; ++i) {
+            if (!SDL_ISPIXELFORMAT_FOURCC(renderer->info.texture_formats[i]) &&
+                    SDL_ISPIXELFORMAT_ALPHA(renderer->info.texture_formats[i]) == needAlpha) {
+                format = renderer->info.texture_formats[i];
+                break;
+            }
         }
     }