SDL: Clamp HDR colors to the SDR range for SDR renderers

From aa8f609ff3ae2235281a59ee4870df18342f1577 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Fri, 2 Feb 2024 12:18:32 -0800
Subject: [PATCH] Clamp HDR colors to the SDR range for SDR renderers

---
 src/render/ps2/SDL_render_ps2.c     | 16 ++++++------
 src/render/psp/SDL_render_psp.c     | 32 +++++++++++------------
 src/render/software/SDL_render_sw.c | 40 ++++++++++++++---------------
 3 files changed, 44 insertions(+), 44 deletions(-)

diff --git a/src/render/ps2/SDL_render_ps2.c b/src/render/ps2/SDL_render_ps2.c
index 0440be4e7b95..54c208106fa0 100644
--- a/src/render/ps2/SDL_render_ps2.c
+++ b/src/render/ps2/SDL_render_ps2.c
@@ -105,20 +105,20 @@ static int PixelFormatToPS2PSM(Uint32 format)
 
 static gs_rgbaq float_color_to_RGBAQ(const SDL_FColor *color)
 {
-    uint8_t colorR = (uint8_t)SDL_roundf(color->r * 255.0f);
-    uint8_t colorG = (uint8_t)SDL_roundf(color->g * 255.0f);
-    uint8_t colorB = (uint8_t)SDL_roundf(color->b * 255.0f);
-    uint8_t colorA = (uint8_t)SDL_roundf(color->a * 255.0f);
+    uint8_t colorR = (uint8_t)SDL_roundf(SDL_clamp(color->r, 0.0f, 1.0f) * 255.0f);
+    uint8_t colorG = (uint8_t)SDL_roundf(SDL_clamp(color->g, 0.0f, 1.0f) * 255.0f);
+    uint8_t colorB = (uint8_t)SDL_roundf(SDL_clamp(color->b, 0.0f, 1.0f) * 255.0f);
+    uint8_t colorA = (uint8_t)SDL_roundf(SDL_clamp(color->a, 0.0f, 1.0f) * 255.0f);
 
     return color_to_RGBAQ(colorR, colorG, colorB, colorA, 0x00);
 }
 
 static uint64_t float_GS_SETREG_RGBAQ(const SDL_FColor *color)
 {
-    uint8_t colorR = (uint8_t)SDL_roundf(color->r * 255.0f);
-    uint8_t colorG = (uint8_t)SDL_roundf(color->g * 255.0f);
-    uint8_t colorB = (uint8_t)SDL_roundf(color->b * 255.0f);
-    uint8_t colorA = (uint8_t)SDL_roundf(color->a * 255.0f);
+    uint8_t colorR = (uint8_t)SDL_roundf(SDL_clamp(color->r, 0.0f, 1.0f) * 255.0f);
+    uint8_t colorG = (uint8_t)SDL_roundf(SDL_clamp(color->g, 0.0f, 1.0f) * 255.0f);
+    uint8_t colorB = (uint8_t)SDL_roundf(SDL_clamp(color->b, 0.0f, 1.0f) * 255.0f);
+    uint8_t colorA = (uint8_t)SDL_roundf(SDL_clamp(color->a, 0.0f, 1.0f) * 255.0f);
 
     return GS_SETREG_RGBAQ(colorR, colorG, colorB, colorA, 0x00);
 }
diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c
index e8db7e664a1a..2f95e8a35ab7 100644
--- a/src/render/psp/SDL_render_psp.c
+++ b/src/render/psp/SDL_render_psp.c
@@ -688,10 +688,10 @@ static int PSP_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL
             verts->y = xy_[1] * scale_y;
             verts->z = 0;
 
-            verts->col.r = (Uint8)SDL_roundf(col_->r * 255.0f);
-            verts->col.g = (Uint8)SDL_roundf(col_->g * 255.0f);
-            verts->col.b = (Uint8)SDL_roundf(col_->b * 255.0f);
-            verts->col.a = (Uint8)SDL_roundf(col_->a * 255.0f);
+            verts->col.r = (Uint8)SDL_roundf(SDL_clamp(col_->r, 0.0f, 1.0f) * 255.0f);
+            verts->col.g = (Uint8)SDL_roundf(SDL_clamp(col_->g, 0.0f, 1.0f) * 255.0f);
+            verts->col.b = (Uint8)SDL_roundf(SDL_clamp(col_->b, 0.0f, 1.0f) * 255.0f);
+            verts->col.a = (Uint8)SDL_roundf(SDL_clamp(col_->a, 0.0f, 1.0f) * 255.0f);
 
             verts++;
         }
@@ -727,10 +727,10 @@ static int PSP_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL
             verts->y = xy_[1] * scale_y;
             verts->z = 0;
 
-            verts->col.r = (Uint8)SDL_roundf(col_->r * 255.0f);
-            verts->col.g = (Uint8)SDL_roundf(col_->g * 255.0f);
-            verts->col.b = (Uint8)SDL_roundf(col_->b * 255.0f);
-            verts->col.a = (Uint8)SDL_roundf(col_->a * 255.0f);
+            verts->col.r = (Uint8)SDL_roundf(SDL_clamp(col_->r, 0.0f, 1.0f) * 255.0f);
+            verts->col.g = (Uint8)SDL_roundf(SDL_clamp(col_->g, 0.0f, 1.0f) * 255.0f);
+            verts->col.b = (Uint8)SDL_roundf(SDL_clamp(col_->b, 0.0f, 1.0f) * 255.0f);
+            verts->col.a = (Uint8)SDL_roundf(SDL_clamp(col_->a, 0.0f, 1.0f) * 255.0f);
 
             verts->u = uv_[0] * psp_texture->textureWidth;
             verts->v = uv_[1] * psp_texture->textureHeight;
@@ -1063,10 +1063,10 @@ static int PSP_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, v
         switch (cmd->command) {
         case SDL_RENDERCMD_SETDRAWCOLOR:
         {
-            const Uint8 r = (Uint8)SDL_roundf(cmd->data.color.color.r * 255.0f);
-            const Uint8 g = (Uint8)SDL_roundf(cmd->data.color.color.g * 255.0f);
-            const Uint8 b = (Uint8)SDL_roundf(cmd->data.color.color.b * 255.0f);
-            const Uint8 a = (Uint8)SDL_roundf(cmd->data.color.color.a * 255.0f);
+            const Uint8 r = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.r, 0.0f, 1.0f) * 255.0f);
+            const Uint8 g = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.g, 0.0f, 1.0f) * 255.0f);
+            const Uint8 b = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.b, 0.0f, 1.0f) * 255.0f);
+            const Uint8 a = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.a, 0.0f, 1.0f) * 255.0f);
             drawstate.color = GU_RGBA(r, g, b, a);
             break;
         }
@@ -1094,10 +1094,10 @@ static int PSP_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, v
 
         case SDL_RENDERCMD_CLEAR:
         {
-            const Uint8 r = (Uint8)SDL_roundf(cmd->data.color.color.r * 255.0f);
-            const Uint8 g = (Uint8)SDL_roundf(cmd->data.color.color.g * 255.0f);
-            const Uint8 b = (Uint8)SDL_roundf(cmd->data.color.color.b * 255.0f);
-            const Uint8 a = (Uint8)SDL_roundf(cmd->data.color.color.a * 255.0f);
+            const Uint8 r = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.r, 0.0f, 1.0f) * 255.0f);
+            const Uint8 g = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.g, 0.0f, 1.0f) * 255.0f);
+            const Uint8 b = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.b, 0.0f, 1.0f) * 255.0f);
+            const Uint8 a = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.a, 0.0f, 1.0f) * 255.0f);
             sceGuClearColor(GU_RGBA(r, g, b, a));
             sceGuClearStencil(a);
             sceGuClear(GU_COLOR_BUFFER_BIT | GU_STENCIL_BUFFER_BIT);
diff --git a/src/render/software/SDL_render_sw.c b/src/render/software/SDL_render_sw.c
index a4832af70a62..2d406fe3c010 100644
--- a/src/render/software/SDL_render_sw.c
+++ b/src/render/software/SDL_render_sw.c
@@ -107,10 +107,10 @@ static int SW_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_Pr
         return SDL_SetError("Cannot create surface");
     }
     texture->driverdata = surface;
-    r = (Uint8)SDL_roundf(texture->color.r * 255.0f);
-    g = (Uint8)SDL_roundf(texture->color.g * 255.0f);
-    b = (Uint8)SDL_roundf(texture->color.b * 255.0f);
-    a = (Uint8)SDL_roundf(texture->color.a * 255.0f);
+    r = (Uint8)SDL_roundf(SDL_clamp(texture->color.r, 0.0f, 1.0f) * 255.0f);
+    g = (Uint8)SDL_roundf(SDL_clamp(texture->color.g, 0.0f, 1.0f) * 255.0f);
+    b = (Uint8)SDL_roundf(SDL_clamp(texture->color.b, 0.0f, 1.0f) * 255.0f);
+    a = (Uint8)SDL_roundf(SDL_clamp(texture->color.a, 0.0f, 1.0f) * 255.0f);
     SDL_SetSurfaceColorMod(texture->driverdata, r, g, b);
     SDL_SetSurfaceAlphaMod(texture->driverdata, a);
     SDL_SetSurfaceBlendMode(texture->driverdata, texture->blendMode);
@@ -583,10 +583,10 @@ static int SW_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_
             ptr->dst.y = (int)(xy_[1] * scale_y);
             trianglepoint_2_fixedpoint(&ptr->dst);
 
-            ptr->color.r = (Uint8)SDL_roundf(col_.r * 255.0f);
-            ptr->color.g = (Uint8)SDL_roundf(col_.g * 255.0f);
-            ptr->color.b = (Uint8)SDL_roundf(col_.b * 255.0f);
-            ptr->color.a = (Uint8)SDL_roundf(col_.a * 255.0f);
+            ptr->color.r = (Uint8)SDL_roundf(SDL_clamp(col_.r, 0.0f, 1.0f) * 255.0f);
+            ptr->color.g = (Uint8)SDL_roundf(SDL_clamp(col_.g, 0.0f, 1.0f) * 255.0f);
+            ptr->color.b = (Uint8)SDL_roundf(SDL_clamp(col_.b, 0.0f, 1.0f) * 255.0f);
+            ptr->color.a = (Uint8)SDL_roundf(SDL_clamp(col_.a, 0.0f, 1.0f) * 255.0f);
 
             ptr++;
         }
@@ -614,10 +614,10 @@ static int SW_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_
             ptr->dst.y = (int)(xy_[1] * scale_y);
             trianglepoint_2_fixedpoint(&ptr->dst);
 
-            ptr->color.r = (Uint8)SDL_roundf(col_.r * 255.0f);
-            ptr->color.g = (Uint8)SDL_roundf(col_.g * 255.0f);
-            ptr->color.b = (Uint8)SDL_roundf(col_.b * 255.0f);
-            ptr->color.a = (Uint8)SDL_roundf(col_.a * 255.0f);
+            ptr->color.r = (Uint8)SDL_roundf(SDL_clamp(col_.r, 0.0f, 1.0f) * 255.0f);
+            ptr->color.g = (Uint8)SDL_roundf(SDL_clamp(col_.g, 0.0f, 1.0f) * 255.0f);
+            ptr->color.b = (Uint8)SDL_roundf(SDL_clamp(col_.b, 0.0f, 1.0f) * 255.0f);
+            ptr->color.a = (Uint8)SDL_roundf(SDL_clamp(col_.a, 0.0f, 1.0f) * 255.0f);
 
             ptr++;
         }
@@ -697,10 +697,10 @@ static int SW_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, vo
         switch (cmd->command) {
         case SDL_RENDERCMD_SETDRAWCOLOR:
         {
-            drawstate.color.r = (Uint8)SDL_roundf(cmd->data.color.color.r * 255.0f);
-            drawstate.color.g = (Uint8)SDL_roundf(cmd->data.color.color.g * 255.0f);
-            drawstate.color.b = (Uint8)SDL_roundf(cmd->data.color.color.b * 255.0f);
-            drawstate.color.a = (Uint8)SDL_roundf(cmd->data.color.color.a * 255.0f);
+            drawstate.color.r = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.r, 0.0f, 1.0f) * 255.0f);
+            drawstate.color.g = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.g, 0.0f, 1.0f) * 255.0f);
+            drawstate.color.b = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.b, 0.0f, 1.0f) * 255.0f);
+            drawstate.color.a = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.a, 0.0f, 1.0f) * 255.0f);
             break;
         }
 
@@ -720,10 +720,10 @@ static int SW_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, vo
 
         case SDL_RENDERCMD_CLEAR:
         {
-            const Uint8 r = (Uint8)SDL_roundf(cmd->data.color.color.r * 255.0f);
-            const Uint8 g = (Uint8)SDL_roundf(cmd->data.color.color.g * 255.0f);
-            const Uint8 b = (Uint8)SDL_roundf(cmd->data.color.color.b * 255.0f);
-            const Uint8 a = (Uint8)SDL_roundf(cmd->data.color.color.a * 255.0f);
+            const Uint8 r = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.r, 0.0f, 1.0f) * 255.0f);
+            const Uint8 g = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.g, 0.0f, 1.0f) * 255.0f);
+            const Uint8 b = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.b, 0.0f, 1.0f) * 255.0f);
+            const Uint8 a = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.a, 0.0f, 1.0f) * 255.0f);
             /* By definition the clear ignores the clip rect */
             SDL_SetSurfaceClipRect(surface, NULL);
             SDL_FillSurfaceRect(surface, NULL, SDL_MapRGBA(surface->format, r, g, b, a));