SDL: video: Add SDL_PremultiplySurfaceAlphaToARGB8888()

From 84808ea4bbd12ac212ff7a4ef82d426f6d771e99 Mon Sep 17 00:00:00 2001
From: David Gow <[EMAIL REDACTED]>
Date: Fri, 22 Oct 2021 17:48:32 +0800
Subject: [PATCH] video: Add SDL_PremultiplySurfaceAlphaToARGB8888()

A number of video backends need to get ARGB8888 formatted surfaces with
premultiplied alpha, typically for mouse cursors. Add a new function to
do this, based loosely on legacy_alpha_premultiply_ARGB8888() from the
KMSDRM backend.

The new function, SDL_PremultiplySurfaceAlphaToARGB8888() takes two
arguments:
- src: an SDL_Surface to be converted.
- dst: a buffer which is filled with premultiplied ARGB8888 data of the
  same size as the surface (assuming pitch = w).

This is not heavily optimised: it just repeatedly calls SDL_GetRGBA() to
do the conversion, but should do for now.
---
 src/video/SDL_pixels.c   | 30 ++++++++++++++++++++++++++++++
 src/video/SDL_pixels_c.h |  1 +
 2 files changed, 31 insertions(+)

diff --git a/src/video/SDL_pixels.c b/src/video/SDL_pixels.c
index ccb024dcb9..c7b4d32912 100644
--- a/src/video/SDL_pixels.c
+++ b/src/video/SDL_pixels.c
@@ -1227,4 +1227,34 @@ SDL_CalculateGammaRamp(float gamma, Uint16 * ramp)
     }
 }
 
+/* Creates a copy of an ARGB8888-format surface's pixels with premultiplied alpha */
+void
+SDL_PremultiplySurfaceAlphaToARGB8888(SDL_Surface *src, Uint32 *dst)
+{
+    Uint8 A, R, G, B;
+    int x, y;
+
+    if (SDL_MUSTLOCK(src))
+        SDL_LockSurface(src);
+
+    for (y = 0; y < src->h; ++y) {
+        Uint8 *src_px = (Uint8*)(src->pixels) + (y * src->pitch);
+        for (x = 0; x < src->w; ++x) {
+            /* Component bytes extraction. */
+            SDL_GetRGBA(*(Uint32*)src_px, src->format, &R, &G, &B, &A);
+            src_px += src->format->BytesPerPixel;
+
+            /* Alpha pre-multiplication of each component. */
+            R = (float)A * ((float)R /255);
+            G = (float)A * ((float)G /255);
+            B = (float)A * ((float)B /255);
+
+            /* ARGB8888 pixel recomposition. */
+            (*dst++) = (((Uint32)A << 24) | ((Uint32)R << 16) | ((Uint32)G << 8)) | ((Uint32)B << 0);
+        }
+    }
+    if (SDL_MUSTLOCK(src))
+        SDL_UnlockSurface(src);
+}
+
 /* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/video/SDL_pixels_c.h b/src/video/SDL_pixels_c.h
index 1974797fc5..91db5b446e 100644
--- a/src/video/SDL_pixels_c.h
+++ b/src/video/SDL_pixels_c.h
@@ -43,6 +43,7 @@ extern void SDL_InvalidateAllBlitMap(SDL_Surface *surface);
 extern void SDL_DitherColors(SDL_Color * colors, int bpp);
 extern Uint8 SDL_FindColor(SDL_Palette * pal, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
 extern void SDL_DetectPalette(SDL_Palette *pal, SDL_bool *is_opaque, SDL_bool *has_alpha_channel);
+extern void SDL_PremultiplySurfaceAlphaToARGB8888(SDL_Surface *src, Uint32 *dst);
 
 #endif /* SDL_pixels_c_h_ */