SDL: Use SDL_Color for SDL_RenderGeometryRaw() and add SDL_RenderGeometryRawFloat()

From 3158342441afbdf0cb0bc7f8009adaa064bf1a92 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Tue, 6 Feb 2024 17:23:07 -0800
Subject: [PATCH] Use SDL_Color for SDL_RenderGeometryRaw() and add
 SDL_RenderGeometryRawFloat()

Eventually we can re-add a fast path for that data down to the individual renderers. Setting color scale would still require converting to float, and most hardware accelerated renderers prefer to consume colors as float, so this requires some thought and performance testing.

Fixes https://github.com/libsdl-org/SDL/issues/9009
---
 docs/README-migration.md          |  2 +-
 include/SDL3/SDL_render.h         | 36 ++++++++++++++++++++++++++++-
 src/dynapi/SDL_dynapi.sym         |  1 +
 src/dynapi/SDL_dynapi_overrides.h |  1 +
 src/dynapi/SDL_dynapi_procs.h     |  3 ++-
 src/render/SDL_render.c           | 38 +++++++++++++++++++++++++++++--
 test/testcolorspace.c             |  2 +-
 7 files changed, 77 insertions(+), 6 deletions(-)

diff --git a/docs/README-migration.md b/docs/README-migration.md
index 689fd1757f90..9642df3c01da 100644
--- a/docs/README-migration.md
+++ b/docs/README-migration.md
@@ -1051,7 +1051,7 @@ SDL_RenderWindowToLogical() and SDL_RenderLogicalToWindow() have been renamed SD
 
 The viewport, clipping state, and scale for render targets are now persistent and will remain set whenever they are active.
 
-SDL_RenderGeometryRaw() and SDL_Vertex have been changed to use floating point colors, in the range of [0..1] for SDR content.
+SDL_Vertex has been changed to use floating point colors, in the range of [0..1] for SDR content.
 
 SDL_RenderReadPixels() returns a surface instead of filling in preallocated memory.
 
diff --git a/include/SDL3/SDL_render.h b/include/SDL3/SDL_render.h
index a796589b64f8..026f966e253b 100644
--- a/include/SDL3/SDL_render.h
+++ b/include/SDL3/SDL_render.h
@@ -1751,7 +1751,7 @@ extern DECLSPEC int SDLCALL SDL_RenderGeometry(SDL_Renderer *renderer,
  * \param texture (optional) The SDL texture to use.
  * \param xy Vertex positions
  * \param xy_stride Byte size to move from one element to the next element
- * \param color Vertex colors (as SDL_FColor)
+ * \param color Vertex colors (as SDL_Color)
  * \param color_stride Byte size to move from one element to the next element
  * \param uv Vertex normalized texture coordinates
  * \param uv_stride Byte size to move from one element to the next element
@@ -1769,6 +1769,40 @@ extern DECLSPEC int SDLCALL SDL_RenderGeometry(SDL_Renderer *renderer,
  * \sa SDL_Vertex
  */
 extern DECLSPEC int SDLCALL SDL_RenderGeometryRaw(SDL_Renderer *renderer,
+                                               SDL_Texture *texture,
+                                               const float *xy, int xy_stride,
+                                               const SDL_Color *color, int color_stride,
+                                               const float *uv, int uv_stride,
+                                               int num_vertices,
+                                               const void *indices, int num_indices, int size_indices);
+
+/**
+ * Render a list of triangles, optionally using a texture and indices into the
+ * vertex arrays Color and alpha modulation is done per vertex
+ * (SDL_SetTextureColorMod and SDL_SetTextureAlphaMod are ignored).
+ *
+ * \param renderer The rendering context.
+ * \param texture (optional) The SDL texture to use.
+ * \param xy Vertex positions
+ * \param xy_stride Byte size to move from one element to the next element
+ * \param color Vertex colors (as SDL_FColor)
+ * \param color_stride Byte size to move from one element to the next element
+ * \param uv Vertex normalized texture coordinates
+ * \param uv_stride Byte size to move from one element to the next element
+ * \param num_vertices Number of vertices.
+ * \param indices (optional) An array of indices into the 'vertices' arrays,
+ *                if NULL all vertices will be rendered in sequential order.
+ * \param num_indices Number of indices.
+ * \param size_indices Index size: 1 (byte), 2 (short), 4 (int)
+ * \returns 0 on success or a negative error code on failure; call
+ *          SDL_GetError() for more information.
+ *
+ * \since This function is available since SDL 3.0.0.
+ *
+ * \sa SDL_RenderGeometry
+ * \sa SDL_Vertex
+ */
+extern DECLSPEC int SDLCALL SDL_RenderGeometryRawFloat(SDL_Renderer *renderer,
                                                SDL_Texture *texture,
                                                const float *xy, int xy_stride,
                                                const SDL_FColor *color, int color_stride,
diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym
index c196aee418b9..20ee328d9bb0 100644
--- a/src/dynapi/SDL_dynapi.sym
+++ b/src/dynapi/SDL_dynapi.sym
@@ -969,6 +969,7 @@ SDL3_0.0.0 {
     SDL_CopyProperties;
     SDL_SetRenderColorScale;
     SDL_GetRenderColorScale;
+    SDL_RenderGeometryRawFloat;
     # extra symbols go here (don't modify this line)
   local: *;
 };
diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h
index 2aa25f12be95..64939646e3c8 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -994,3 +994,4 @@
 #define SDL_CopyProperties SDL_CopyProperties_REAL
 #define SDL_SetRenderColorScale SDL_SetRenderColorScale_REAL
 #define SDL_GetRenderColorScale SDL_GetRenderColorScale_REAL
+#define SDL_RenderGeometryRawFloat SDL_RenderGeometryRawFloat_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index 6f93f2ff1185..2a32ddf5ece0 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -562,7 +562,7 @@ SDL_DYNAPI_PROC(int,SDL_RenderCoordinatesToWindow,(SDL_Renderer *a, float b, flo
 SDL_DYNAPI_PROC(int,SDL_RenderFillRect,(SDL_Renderer *a, const SDL_FRect *b),(a,b),return)
 SDL_DYNAPI_PROC(int,SDL_RenderFillRects,(SDL_Renderer *a, const SDL_FRect *b, int c),(a,b,c),return)
 SDL_DYNAPI_PROC(int,SDL_RenderGeometry,(SDL_Renderer *a, SDL_Texture *b, const SDL_Vertex *c, int d, const int *e, int f),(a,b,c,d,e,f),return)
-SDL_DYNAPI_PROC(int,SDL_RenderGeometryRaw,(SDL_Renderer *a, SDL_Texture *b, const float *c, int d, const SDL_FColor *e, int f, const float *g, int h, int i, const void *j, int k, int l),(a,b,c,d,e,f,g,h,i,j,k,l),return)
+SDL_DYNAPI_PROC(int,SDL_RenderGeometryRaw,(SDL_Renderer *a, SDL_Texture *b, const float *c, int d, const SDL_Color *e, int f, const float *g, int h, int i, const void *j, int k, int l),(a,b,c,d,e,f,g,h,i,j,k,l),return)
 SDL_DYNAPI_PROC(int,SDL_RenderLine,(SDL_Renderer *a, float b, float c, float d, float e),(a,b,c,d,e),return)
 SDL_DYNAPI_PROC(int,SDL_RenderLines,(SDL_Renderer *a, const SDL_FPoint *b, int c),(a,b,c),return)
 SDL_DYNAPI_PROC(int,SDL_RenderPoint,(SDL_Renderer *a, float b, float c),(a,b,c),return)
@@ -1019,3 +1019,4 @@ SDL_DYNAPI_PROC(SDL_Surface*,SDL_ConvertSurfaceFormatAndColorspace,(SDL_Surface
 SDL_DYNAPI_PROC(int,SDL_CopyProperties,(SDL_PropertiesID a, SDL_PropertiesID b),(a,b),return)
 SDL_DYNAPI_PROC(int,SDL_SetRenderColorScale,(SDL_Renderer *a, float b),(a,b),return)
 SDL_DYNAPI_PROC(int,SDL_GetRenderColorScale,(SDL_Renderer *a, float *b),(a,b),return)
+SDL_DYNAPI_PROC(int,SDL_RenderGeometryRawFloat,(SDL_Renderer *a, SDL_Texture *b, const float *c, int d, const SDL_FColor *e, int f, const float *g, int h, int i, const void *j, int k, int l),(a,b,c,d,e,f,g,h,i,j,k,l),return)
diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c
index 6b3d05a790a9..09101e328a9c 100644
--- a/src/render/SDL_render.c
+++ b/src/render/SDL_render.c
@@ -3704,7 +3704,7 @@ int SDL_RenderGeometry(SDL_Renderer *renderer,
         const float *uv = &vertices->tex_coord.x;
         int uv_stride = sizeof(SDL_Vertex);
         int size_indices = 4;
-        return SDL_RenderGeometryRaw(renderer, texture, xy, xy_stride, color, color_stride, uv, uv_stride, num_vertices, indices, num_indices, size_indices);
+        return SDL_RenderGeometryRawFloat(renderer, texture, xy, xy_stride, color, color_stride, uv, uv_stride, num_vertices, indices, num_indices, size_indices);
     } else {
         return SDL_InvalidParamError("vertices");
     }
@@ -4079,7 +4079,7 @@ static int SDLCALL SDL_SW_RenderGeometryRaw(SDL_Renderer *renderer,
     return retval;
 }
 
-int SDL_RenderGeometryRaw(SDL_Renderer *renderer,
+int SDL_RenderGeometryRawFloat(SDL_Renderer *renderer,
                           SDL_Texture *texture,
                           const float *xy, int xy_stride,
                           const SDL_FColor *color, int color_stride,
@@ -4189,6 +4189,40 @@ int SDL_RenderGeometryRaw(SDL_Renderer *renderer,
                               renderer->view->scale.y);
 }
 
+int SDL_RenderGeometryRaw(SDL_Renderer *renderer, SDL_Texture *texture, const float *xy, int xy_stride, const SDL_Color *color, int color_stride, const float *uv, int uv_stride, int num_vertices, const void *indices, int num_indices, int size_indices)
+{
+    int i, retval, isstack;
+    const Uint8 *color2 = (const Uint8 *)color;
+    SDL_FColor *color3;
+
+    if (num_vertices <= 0) {
+        return SDL_InvalidParamError("num_vertices");
+    }
+    if (!color) {
+        return SDL_InvalidParamError("color");
+    }
+
+    color3 = (SDL_FColor *)SDL_small_alloc(SDL_FColor, num_vertices, &isstack);
+    if (!color3) {
+        return -1;
+    }
+
+    for (i = 0; i < num_vertices; ++i) {
+        color3[i].r = color->r / 255.0f;
+        color3[i].g = color->g / 255.0f;
+        color3[i].b = color->b / 255.0f;
+        color3[i].a = color->a / 255.0f;
+        color2 += color_stride;
+        color = (const SDL_Color *)color2;
+    }
+
+    retval = SDL_RenderGeometryRawFloat(renderer, texture, xy, xy_stride, color3, sizeof(*color3), uv, uv_stride, num_vertices, indices, num_indices, size_indices);
+
+    SDL_small_free(color3, isstack);
+
+    return retval;
+}
+
 SDL_Surface *SDL_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect)
 {
     SDL_Rect real_rect;
diff --git a/test/testcolorspace.c b/test/testcolorspace.c
index 8448257fb8cb..f3b6b3a9b127 100644
--- a/test/testcolorspace.c
+++ b/test/testcolorspace.c
@@ -457,7 +457,7 @@ static void DrawGradient(float x, float y, float width, float height, float star
     color[2] = max_color;
     color[3] = min_color;
 
-    SDL_RenderGeometryRaw(renderer, NULL, xy, xy_stride, color, color_stride, NULL, 0, num_vertices, indices, num_indices, size_indices);
+    SDL_RenderGeometryRawFloat(renderer, NULL, xy, xy_stride, color, color_stride, NULL, 0, num_vertices, indices, num_indices, size_indices);
 }
 
 static float scRGBtoNits(float v)