SDL: Implement fast 255 mult-div in SDL_blit_auto

From b34faf732d3a1d2340886a5ae26be343e514ebc0 Mon Sep 17 00:00:00 2001
From: Isaac Aronson <[EMAIL REDACTED]>
Date: Sun, 17 Dec 2023 07:55:49 -0600
Subject: [PATCH] Implement fast 255 mult-div in SDL_blit_auto

---
 src/video/SDL_blit.h      |    7 +
 src/video/SDL_blit_A.c    |    6 +-
 src/video/SDL_blit_auto.c | 2681 ++++++++++++++++++++++---------------
 src/video/SDL_blit_auto.h |    1 +
 src/video/sdlgenblit.pl   |   51 +-
 5 files changed, 1663 insertions(+), 1083 deletions(-)

diff --git a/src/video/SDL_blit.h b/src/video/SDL_blit.h
index 1d677cb7be268..a59c9a603c3e5 100644
--- a/src/video/SDL_blit.h
+++ b/src/video/SDL_blit.h
@@ -509,6 +509,13 @@ extern SDL_BlitFunc SDL_CalculateBlitA(SDL_Surface *surface);
         x += x >> 8;                                     \
         dC = x >> 8;                                     \
     } while (0)
+/* Perform a division by 255 after a multiplication of two 8-bit color channels */
+#define MULT_DIV_255(sC, dC, out) \
+    do {                          \
+        Uint16 x = sC * dC;       \
+        x += x >> 8;              \
+        out = x >> 8;             \
+    } while (0)
 /* Blend the RGB values of two pixels with an alpha value */
 #define ALPHA_BLEND_RGB(sR, sG, sB, A, dR, dG, dB)            \
     do {                                                      \
diff --git a/src/video/SDL_blit_A.c b/src/video/SDL_blit_A.c
index 43a1a09abb05a..b512056da58b1 100644
--- a/src/video/SDL_blit_A.c
+++ b/src/video/SDL_blit_A.c
@@ -1164,7 +1164,7 @@ static void BlitNtoNPixelAlpha(SDL_BlitInfo *info)
     }
 
     while (height--) {
-        if (srcbpp == 4 && dstbpp == 4 && dstfmt->Ashift == 24 && dstfmt->Rshift == 16 && dstfmt->Gshift == 8 &&
+        /* if (srcbpp == 4 && dstbpp == 4 && dstfmt->Ashift == 24 && dstfmt->Rshift == 16 && dstfmt->Gshift == 8 &&
             dstfmt->Bshift == 0) {
             DUFFS_LOOP4(
             {
@@ -1176,7 +1176,7 @@ static void BlitNtoNPixelAlpha(SDL_BlitInfo *info)
             dst += dstbpp;
             },
             width);
-        } else {
+        } else { */
             /* *INDENT-OFF* */ /* clang-format off */
             DUFFS_LOOP4(
             {
@@ -1193,7 +1193,7 @@ static void BlitNtoNPixelAlpha(SDL_BlitInfo *info)
             /* *INDENT-ON* */ /* clang-format on */
             src += srcskip;
             dst += dstskip;
-        }
+        // }
     }
     if (freeFormat) {
         SDL_DestroyPixelFormat(dstfmt);
diff --git a/src/video/SDL_blit_auto.c b/src/video/SDL_blit_auto.c
index 0d9f1a8d90f86..e3c50e0efe2ba 100644
--- a/src/video/SDL_blit_auto.c
+++ b/src/video/SDL_blit_auto.c
@@ -20,6 +20,7 @@
   3. This notice may not be removed or altered from any source distribution.
 */
 #include "SDL_internal.h"
+#include "SDL_blit.h"
 
 #if SDL_HAVE_BLIT_AUTO
 
@@ -86,14 +87,14 @@ static void SDL_Blit_XRGB8888_XRGB8888_Blend(SDL_BlitInfo *info)
                 dstB = srcB + dstB; if (dstB > 255) dstB = 255;
                 break;
             case SDL_COPY_MOD:
-                dstR = (srcR * dstR) / 255;
-                dstG = (srcG * dstG) / 255;
-                dstB = (srcB * dstB) / 255;
+                MULT_DIV_255(srcR, dstR, dstR);
+                MULT_DIV_255(srcG, dstG, dstG);
+                MULT_DIV_255(srcB, dstB, dstB);
                 break;
             case SDL_COPY_MUL:
-                dstR = (srcR * dstR) / 255;
-                dstG = (srcG * dstG) / 255;
-                dstB = (srcB * dstB) / 255;
+                MULT_DIV_255(srcR, dstR, dstR);
+                MULT_DIV_255(srcG, dstG, dstG);
+                MULT_DIV_255(srcB, dstB, dstB);
                 break;
             }
             dstpixel = (dstR << 16) | (dstG << 8) | dstB;
@@ -147,14 +148,14 @@ static void SDL_Blit_XRGB8888_XRGB8888_Blend_Scale(SDL_BlitInfo *info)
                 dstB = srcB + dstB; if (dstB > 255) dstB = 255;
                 break;
             case SDL_COPY_MOD:
-                dstR = (srcR * dstR) / 255;
-                dstG = (srcG * dstG) / 255;
-                dstB = (srcB * dstB) / 255;
+                MULT_DIV_255(srcR, dstR, dstR);
+                MULT_DIV_255(srcG, dstG, dstG);
+                MULT_DIV_255(srcB, dstB, dstB);
                 break;
             case SDL_COPY_MUL:
-                dstR = (srcR * dstR) / 255;
-                dstG = (srcG * dstG) / 255;
-                dstB = (srcB * dstB) / 255;
+                MULT_DIV_255(srcR, dstR, dstR);
+                MULT_DIV_255(srcG, dstG, dstG);
+                MULT_DIV_255(srcB, dstB, dstB);
                 break;
             }
             dstpixel = (dstR << 16) | (dstG << 8) | dstB;
@@ -184,9 +185,9 @@ static void SDL_Blit_XRGB8888_XRGB8888_Modulate(SDL_BlitInfo *info)
             pixel = *src;
             R = (Uint8)(pixel >> 16); G = (Uint8)(pixel >> 8); B = (Uint8)pixel;
             if (flags & SDL_COPY_MODULATE_COLOR) {
-                R = (R * modulateR) / 255;
-                G = (G * modulateG) / 255;
-                B = (B * modulateB) / 255;
+                MULT_DIV_255(R, modulateR, R);
+                MULT_DIV_255(G, modulateG, G);
+                MULT_DIV_255(B, modulateB, B);
             }
             pixel = (R << 16) | (G << 8) | B;
             *dst = pixel;
@@ -227,9 +228,9 @@ static void SDL_Blit_XRGB8888_XRGB8888_Modulate_Scale(SDL_BlitInfo *info)
             pixel = *src;
             R = (Uint8)(pixel >> 16); G = (Uint8)(pixel >> 8); B = (Uint8)pixel;
             if (flags & SDL_COPY_MODULATE_COLOR) {
-                R = (R * modulateR) / 255;
-                G = (G * modulateG) / 255;
-                B = (B * modulateB) / 255;
+                MULT_DIV_255(R, modulateR, R);
+                MULT_DIV_255(G, modulateG, G);
+                MULT_DIV_255(B, modulateB, B);
             }
             pixel = (R << 16) | (G << 8) | B;
             *dst = pixel;
@@ -264,23 +265,26 @@ static void SDL_Blit_XRGB8888_XRGB8888_Modulate_Blend(SDL_BlitInfo *info)
             dstpixel = *dst;
             dstR = (Uint8)(dstpixel >> 16); dstG = (Uint8)(dstpixel >> 8); dstB = (Uint8)dstpixel;
             if (flags & SDL_COPY_MODULATE_COLOR) {
-                srcR = (srcR * modulateR) / 255;
-                srcG = (srcG * modulateG) / 255;
-                srcB = (srcB * modulateB) / 255;
+                MULT_DIV_255(srcR, modulateR, srcR);
+                MULT_DIV_255(srcG, modulateG, srcG);
+                MULT_DIV_255(srcB, modulateB, srcB);
             }
             if (flags & (SDL_COPY_BLEND|SDL_COPY_ADD)) {
                 /* This goes away if we ever use premultiplied alpha */
                 if (srcA < 255) {
-                    srcR = (srcR * srcA) / 255;
-                    srcG = (srcG * srcA) / 255;
-                    srcB = (srcB * srcA) / 255;
+                    MULT_DIV_255(srcR, srcA, srcR);
+                    MULT_DIV_255(srcG, srcA, srcG);
+                    MULT_DIV_255(srcB, srcA, srcB);
                 }
             }
             switch (flags & (SDL_COPY_BLEND|SDL_COPY_ADD|SDL_COPY_MOD|SDL_COPY_MUL)) {
             case SDL_COPY_BLEND:
-                dstR = srcR + ((255 - srcA) * dstR) / 255;
-                dstG = srcG + ((255 - srcA) * dstG) / 255;
-                dstB = srcB + ((255 - srcA) * dstB) / 255;
+                MULT_DIV_255((255 - srcA), dstR, dstR);
+                dstR += srcR;
+                MULT_DIV_255((255 - srcA), dstG, dstG);
+                dstG += srcG;
+                MULT_DIV_255((255 - srcA), dstB, dstB);
+                dstB += srcB;
                 break;
             case SDL_COPY_ADD:
                 dstR = srcR + dstR; if (dstR > 255) dstR = 255;
@@ -288,14 +292,20 @@ static void SDL_Blit_XRGB8888_XRGB8888_Modulate_Blend(SDL_BlitInfo *info)
                 dstB = srcB + dstB; if (dstB > 255) dstB = 255;
                 break;
             case SDL_COPY_MOD:
-                dstR = (srcR * dstR) / 255;
-                dstG = (srcG * dstG) / 255;
-                dstB = (srcB * dstB) / 255;
+                MULT_DIV_255(srcR, dstR, dstR);
+                MULT_DIV_255(srcG, dstG, dstG);
+                MULT_DIV_255(srcB, dstB, dstB);
                 break;
             case SDL_COPY_MUL:
-                dstR = ((srcR * dstR) + (dstR * (255 - srcA))) / 255; if (dstR > 255) dstR = 255;
-                dstG = ((srcG * dstG) + (dstG * (255 - srcA))) / 255; if (dstG > 255) dstG = 255;
-                dstB = ((srcB * dstB) + (dstB * (255 - srcA))) / 255; if (dstB > 255) dstB = 255;
+                MULT_DIV_255(dstR, (255 - srcA), dstR);
+                dstR += (srcR * dstR);
+                if (dstR > 255) dstR = 255;
+                MULT_DIV_255(dstB, (255 - srcA), dstB);
+                dstB += (srcB * dstB);
+                if (dstB > 255) dstB = 255;
+                MULT_DIV_255(dstG, (255 - srcA), dstG);
+                dstG += (srcG * dstG);
+                if (dstG > 255) dstG = 255;
                 break;
             }
             dstpixel = (dstR << 16) | (dstG << 8) | dstB;
@@ -343,23 +353,26 @@ static void SDL_Blit_XRGB8888_XRGB8888_Modulate_Blend_Scale(SDL_BlitInfo *info)
             dstpixel = *dst;
             dstR = (Uint8)(dstpixel >> 16); dstG = (Uint8)(dstpixel >> 8); dstB = (Uint8)dstpixel;
             if (flags & SDL_COPY_MODULATE_COLOR) {
-                srcR = (srcR * modulateR) / 255;
-                srcG = (srcG * modulateG) / 255;
-                srcB = (srcB * modulateB) / 255;
+                MULT_DIV_255(srcR, modulateR, srcR);
+                MULT_DIV_255(srcG, modulateG, srcG);
+                MULT_DIV_255(srcB, modulateB, srcB);
             }
             if (flags & (SDL_COPY_BLEND|SDL_COPY_ADD)) {
                 /* This goes away if we ever use premultiplied alpha */
                 if (srcA < 255) {
-                    srcR = (srcR * srcA) / 255;
-                    srcG = (srcG * srcA) / 255;
-                    srcB = (srcB * srcA) / 255;
+                    MULT_DIV_255(srcR, srcA, srcR);
+                    MULT_DIV_255(srcG, srcA, srcG);
+                    MULT_DIV_255(srcB, srcA, srcB);
                 }
             }
             switch (flags & (SDL_COPY_BLEND|SDL_COPY_ADD|SDL_COPY_MOD|SDL_COPY_MUL)) {
             case SDL_COPY_BLEND:
-                dstR = srcR + ((255 - srcA) * dstR) / 255;
-                dstG = srcG + ((255 - srcA) * dstG) / 255;
-                dstB = srcB + ((255 - srcA) * dstB) / 255;
+                MULT_DIV_255((255 - srcA), dstR, dstR);
+                dstR += srcR;
+                MULT_DIV_255((255 - srcA), dstG, dstG);
+                dstG += srcG;
+                MULT_DIV_255((255 - srcA), dstB, dstB);
+                dstB += srcB;
                 break;
             case SDL_COPY_ADD:
                 dstR = srcR + dstR; if (dstR > 255) dstR = 255;
@@ -367,14 +380,20 @@ static void SDL_Blit_XRGB8888_XRGB8888_Modulate_Blend_Scale(SDL_BlitInfo *info)
                 dstB = srcB + dstB; if (dstB > 255) dstB = 255;
                 break;
             case SDL_COPY_MOD:
-                dstR = (srcR * dstR) / 255;
-                dstG = (srcG * dstG) / 255;
-                dstB = (srcB * dstB) / 255;
+                MULT_DIV_255(srcR, dstR, dstR);
+                MULT_DIV_255(srcG, dstG, dstG);
+                MULT_DIV_255(srcB, dstB, dstB);
                 break;
             case SDL_COPY_MUL:
-                dstR = ((srcR * dstR) + (dstR * (255 - srcA))) / 255; if (dstR > 255) dstR = 255;
-                dstG = ((srcG * dstG) + (dstG * (255 - srcA))) / 255; if (dstG > 255) dstG = 255;
-                dstB = ((srcB * dstB) + (dstB * (255 - srcA))) / 255; if (dstB > 255) dstB = 255;
+                MULT_DIV_255(dstR, (255 - srcA), dstR);
+                dstR += (srcR * dstR);
+                if (dstR > 255) dstR = 255;
+                MULT_DIV_255(dstB, (255 - srcA), dstB);
+                dstB += (srcB * dstB);
+                if (dstB > 255) dstB = 255;
+                MULT_DIV_255(dstG, (255 - srcA), dstG);
+                dstG += (srcG * dstG);
+                if (dstG > 255) dstG = 255;
                 break;
             }
             dstpixel = (dstR << 16) | (dstG << 8) | dstB;
@@ -450,14 +469,14 @@ static void SDL_Blit_XRGB8888_XBGR8888_Blend(SDL_BlitInfo *info)
                 dstB = srcB + dstB; if (dstB > 255) dstB = 255;
                 break;
             case SDL_COPY_MOD:
-                dstR = (srcR * dstR) / 255;
-                dstG = (srcG * dstG) / 255;
-                dstB = (srcB * dstB) / 255;
+                MULT_DIV_255(srcR, dstR, dstR);
+                MULT_DIV_255(srcG, dstG, dstG);
+                MULT_DIV_255(srcB, dstB, dstB);
                 break;
             case SDL_COPY_MUL:
-                dstR = (srcR * dstR) / 255;
-                dstG = (srcG * dstG) / 255;
-                dstB = (srcB * dstB) / 255;
+                MULT_DIV_255(srcR, dstR, dstR);
+                MULT_DIV_255(srcG, dstG, dstG);
+                MULT_DIV_255(srcB, dstB, dstB);
                 break;
             }
             dstpixel = (dstB << 16) | (dstG << 8) | dstR;
@@ -511,14 +530,14 @@ static void SDL_Blit_XRGB8888_XBGR8888_Blend_Scale(SDL_BlitInfo *info)
                 dstB = srcB + dstB; if (dstB > 255) dstB = 255;
                 break;
             case SDL_COPY_MOD:
-                dstR = (srcR * dstR) / 255;
-                dstG = (srcG * dstG) / 255;
-                dstB = (srcB * dstB) / 255;
+                MULT_DIV_255(srcR, dstR, dstR);
+                MULT_DIV_255(srcG, dstG, dstG);
+                MULT_DIV_255(srcB, dstB, dstB);
                 break;
             case SDL_COPY_MUL:
-                dstR = (srcR * dstR) / 255;
-                dstG = (srcG * dstG) / 255;
-                dstB = (srcB * dstB) / 255;
+                MULT_DIV_255(srcR, dstR, dstR);
+                MULT_DIV_255(srcG, dstG, dstG);
+                MULT_DIV_255(srcB, dstB, dstB);
                 break;
             }
             dstpixel = (dstB << 16) | (dstG << 8) | dstR;
@@ -548,9 +567,9 @@ static void SDL_Blit_XRGB8888_XBGR8888_Modulate(SDL_BlitInfo *info)
             pixel = *src;
             R = (Uint8)(pixel >> 16); G = (Uint8)(pixel >> 8); B = (Uint8)pixel;
             if (flags & SDL_COPY_MODULATE_COLOR) {
-                R = (R * modulateR) / 255;
-                G = (G * modulateG) / 255;
-                B = (B * modulateB) / 255;
+                MULT_DIV_255(R, modulateR, R);
+                MULT_DIV_255(G, modulateG, G);
+                MULT_DIV_255(B, modulateB, B);
             }
             pixel = (B << 16) | (G << 8) | R;
             *dst = pixel;
@@ -591,9 +610,9 @@ static void SDL_Blit_XRGB8888_XBGR8888_Modulate_Scale(SDL_BlitInfo *info)
             pixel = *src;
             R = (Uint8)(pixel >> 16); G = (Uint8)(pixel >> 8); B = (Uint8)pixel;
             if (flags & SDL_COPY_MODULATE_COLOR) {
-                R = (R * modulateR) / 255;
-                G = (G * modulateG) / 255;
-                B = (B * modulateB) / 255;
+                MULT_DIV_255(R, modulateR, R);
+                MULT_DIV_255(G, modulateG, G);
+                MULT_DIV_255(B, modulateB, B);
             }
             pixel = (B << 16) | (G << 8) | R;
             *dst = pixel;
@@ -628,23 +647,26 @@ static void SDL_Blit_XRGB8888_XBGR8888_Modulate_Blend(SDL_BlitInfo *info)
             dstpixel = *dst;
             dstB = (Uint8)(dstpixel >> 16); dstG = (Uint8)(dstpixel >> 8); dstR = (Uint8)dstpixel;
             if (flags & SDL_COPY_MODULATE_COLOR) {
-                srcR = (srcR * modulateR) / 255;
-                srcG = (srcG * modulateG) / 255;
-                srcB = (srcB * modulateB) / 255;
+                MULT_DIV_255(srcR, modulateR, srcR);
+                MULT_DIV_255(srcG, modulateG, srcG);
+                MULT_DIV_255(srcB, modulateB, srcB);
             }
             if (flags & (SDL_COPY_BLEND|SDL_COPY_ADD)) {
                 /* This goes away if we ever use premultiplied alpha */
                 if (srcA < 255) {
-                    srcR = (srcR * srcA) / 255;
-                    srcG = (srcG * srcA) / 255;
-                    srcB = (srcB * srcA) / 255;
+                    MULT_DIV_255(srcR, srcA, srcR);
+                    MULT_DIV_255(srcG, srcA, srcG);
+                    MULT_DIV_255(srcB, srcA, srcB);
                 }
             }
             switch (flags & (SDL_COPY_BLEND|SDL_COPY_ADD|SDL_COPY_MOD|SDL_COPY_MUL)) {
             case SDL_COPY_BLEND:
-                dstR = srcR + ((255 - srcA) * dstR) / 255;
-                dstG = srcG + ((255 - srcA) * dstG) / 255;
-                dstB = srcB + ((255 - srcA) * dstB) / 255;
+                MULT_DIV_255((255 - srcA), dstR, dstR);
+                dstR += srcR;
+                MULT_DIV_255((255 - srcA), dstG, dstG);
+                dstG += srcG;
+                MULT_DIV_255((255 - srcA), dstB, dstB);
+                dstB += srcB;
                 break;
             case SDL_COPY_ADD:
                 dstR = srcR + dstR; if (dstR > 255) dstR = 255;
@@ -652,14 +674,20 @@ static void SDL_Blit_XRGB8888_XBGR8888_Modulate_Blend(SDL_BlitInfo *info)
                 dstB = srcB + dstB; if (dstB > 255) dstB = 255;
                 break;
             case SDL_COPY_MOD:
-                dstR = (srcR * dstR) / 255;
-                dstG = (srcG * dstG) / 255;
-                dstB = (srcB * dstB) / 255;
+                MULT_DIV_255(srcR, dstR, dstR);
+                MULT_DIV_255(srcG, dstG, dstG);
+                MULT_DIV_255(srcB, dstB, dstB);
                 break;
             case SDL_COPY_MUL:
-                dstR = ((srcR * dstR) + (dstR * (255 - srcA))) / 255; if (dstR > 255) dstR = 255;
-                dstG = ((srcG * dstG) + (dstG * (255 - srcA))) / 255; if (dstG > 255) dstG = 255;
-                dstB = ((srcB * dstB) + (dstB * (255 - srcA))) / 255; if (dstB > 255) dstB = 255;
+                MULT_DIV_255(dstR, (255 - srcA), dstR);
+                dstR += (srcR * dstR);
+                if (dstR > 255) dstR = 255;
+                MULT_DIV_255(dstB, (255 - srcA), dstB);
+                dstB += (srcB * dstB);
+                if (dstB > 255) dstB = 255;
+                MULT_DIV_255(dstG, (255 - srcA), dstG);
+                dstG += (srcG * dstG);
+                if (dstG > 255) dstG = 255;
                 break;
             }
             dstpixel = (dstB << 16) | (dstG << 8) | dstR;
@@ -707,23 +735,26 @@ static void SDL_Blit_XRGB8888_XBGR8888_Modulate_Blend_Scale(SDL_BlitInfo *info)
             dstpixel = *dst;
             dstB = (Uint8)(dstpixel >> 16); dstG = (Uint8)(dstpixel >> 8); dstR = (Uint8)dstpixel;
             if (flags & SDL_COPY_MODULATE_COLOR) {
-                srcR = (srcR * modulateR) / 255;
-                srcG = (srcG * modulateG) / 255;
-                srcB = (srcB * modulateB) / 255;
+                MULT_DIV_255(srcR, modulateR, srcR);
+                MULT_DIV_255(srcG, modulateG, srcG);
+                MULT_DIV_255(srcB, modulateB, srcB);
             }
             if (flags & (SDL_COPY_BLEND|SDL_COPY_ADD)) {
                 /* This goes away if we ever use premultiplied alpha */
                 if (srcA < 255) {
-                    srcR = (srcR * srcA) / 255;
-                    srcG = (srcG * srcA) / 255;
-                    srcB = (srcB * srcA) / 255;
+                    MULT_DIV_255(srcR, srcA, srcR);
+                    MULT_DIV_255(srcG, srcA, srcG);
+                    MULT_DIV_255(srcB, srcA, srcB);
                 }
             }
             switch (flags & (SDL_COPY_BLEND|SDL_COPY_ADD|SDL_COPY_MOD|SDL_COPY_MUL)) {
             case SDL_COPY_BLEND:
-                dstR = srcR + ((255 - srcA) * dstR) / 255;
-                dstG = srcG + ((255 - srcA) * dstG) / 255;
-                dstB = srcB + ((255 - srcA) * dstB) / 255;
+                MULT_DIV_255((255 - srcA), dstR, dstR);
+                dstR += srcR;
+                MULT_DIV_255((255 - srcA), dstG, dstG);
+                dstG += srcG;
+                MULT_DIV_255((255 - srcA), dstB, dstB);
+                dstB += srcB;
                 break;
             case SDL_COPY_ADD:
                 dstR = srcR + dstR; if (dstR > 255) dstR = 255;
@@ -731,14 +762,20 @@ static void SDL_Blit_XRGB8888_XBGR8888_Modulate_Blend_Scale(SDL_BlitInfo *info)
                 dstB = srcB + dstB; if (dstB > 255) dstB = 255;
                 break;
             case SDL_COPY_MOD:
-                dstR = (srcR * dstR) / 255;
-                dstG = (srcG * dstG) / 255;
-                dstB = (srcB * dstB) / 255;
+                MULT_DIV_255(srcR, dstR, dstR);
+                MULT_DIV_255(srcG, dstG, dstG);
+                MULT_DIV_255(srcB, dstB, dstB);
                 break;
             case SDL_COPY_MUL:
-                dstR = ((srcR * dstR) + (dstR * (255 - srcA))) / 255; if (dstR > 255) dstR = 255;
-                dstG = ((srcG * dstG) + (dstG * (255 - srcA))) / 255; if (dstG > 255) dstG = 255;
-                dstB = ((srcB * dstB) + (dstB * (255 - srcA))) / 255; if (dstB > 255) dstB = 255;
+                MULT_DIV_255(dstR, (255 - srcA), dstR);
+                dstR += (srcR * dstR);
+                if (dstR > 255) dstR = 255;
+                MULT_DIV_255(dstB, (255 - srcA), dstB);
+                dstB += (srcB * dstB);
+                if (dstB > 255) dstB = 255;
+                MULT_DIV_255(dstG, (255 - srcA), dstG);
+                dstG += (srcG * dstG);
+                if (dstG > 255) dstG = 255;
                 break;
             }
             dstpixel = (dstB << 16) | (dstG << 8) | dstR;
@@ -814,14 +851,14 @@ static void SDL_Blit_XRGB8888_ARGB8888_Blend(SDL_BlitInfo *info)
                 dstB = srcB + dstB; if (dstB > 255) dstB = 255;
                 break;
             case SDL_COPY_MOD:
-                dstR = (srcR * dstR) / 255;
-                dstG = (srcG * dstG) / 255;
-                dstB = (srcB * dstB) / 255;
+                MULT_DIV_255(srcR, dstR, dstR);
+                MULT_DIV_255(srcG, dstG, dstG);
+                MULT_DIV_255(srcB, dstB, dstB);
                 break;
             case SDL_COPY_MUL:
-                dstR = (srcR * dstR) / 255;
-                dstG = (srcG * dstG) / 255;
-                dstB = (srcB * dstB) / 255;
+                MULT_DIV_255(srcR, dstR, dstR);
+                MULT_DIV_255(srcG, dstG, dstG);
+                MULT_DIV_255(srcB, dstB, dstB);
                 break;
             }
             dstpixel = (dstA << 24) | (dstR << 16) | (dstG << 8) | dstB;
@@ -876,14 +913,14 @@ static void SDL_Blit_XRGB8888_ARGB8888_Blend_Scale(SDL_BlitInfo *info)
                 dstB = srcB + dstB; if (dstB > 255) dstB = 255;
                 break;
             case SDL_COPY_MOD:
-                dstR = (srcR * dstR) / 255;
-                dstG = (srcG * dstG) / 255;
-                dstB = (srcB * dstB) / 255;
+                MULT_DIV_255(srcR, dstR, dstR);
+                MULT_DIV_255(srcG, dstG, dstG);
+                MULT_DIV_255(srcB, dstB, dstB);
                 break;
             case SDL_COPY_MUL:
-                dstR = (srcR * dstR) / 255;
-                dstG = (srcG * dstG) / 255;
-                dstB = (srcB * dstB) / 255;
+                MULT_DIV_255(srcR, dstR, dstR);
+                MULT_DIV_255(srcG, dstG, dstG);
+                MULT_DIV_255(srcB, dstB, dstB);
                 break;
             }
             dstpixel = (dstA << 24) | (dstR << 16) | (dstG << 8) | dstB;
@@ -915,9 +952,9 @@ static void SDL_Blit_XRGB8888_ARGB8888_Modulate(SDL_BlitInfo *info)
             pixel = *src;
             R = (Uint8)(pixel >> 16); G = (Uint8)(pixel >> 8); B = (Uint8)pixel;
             if (flags & SDL_COPY_MODULATE_COLOR) {
-                R = (R * modulateR) / 255;
-                G = (G * modulateG) / 255;
-                B = (B * modulateB) / 255;
+                MULT_DIV_255(R, modulateR, R);
+                MULT_DIV_255(G, modulateG, G);
+                MULT_DIV_255(B, modulateB, B);
             }
             pixel = (A << 24) | (R << 16) | (G << 8) | B;
             *dst = pixel;
@@ -960,9 +997,9 @@ static void SDL_Blit_XRGB8888_ARGB8888_Modulate_Scale(SDL_BlitInfo *info)
             pixel = *src;
             R = (Uint8)(pixel >> 16); G = (Uint8)(pixel >> 8); B = (Uint8)pixel;
             if (flags & SDL_COPY_MODULATE_COLOR) {
-                R = (R * modulateR) / 255;
-                G = (G * modulateG) / 255;
-                B = (B * modulateB) / 255;
+                MULT_DIV_255(R, modulateR, R);
+                MULT_DIV_255(G, modulateG, G);
+                MULT_DIV_255(B, modulateB, B);
             }
             pixel = (A << 24) | (R << 16) | (G << 8) | B;
             *dst = pixel;
@@ -997,24 +1034,28 @@ static void SDL_Blit_XRGB8888_ARGB8888_Modulate_Blend(SDL_BlitInfo *info)
             dstpixel = *dst;
             dstR = (Uint8)(dstpixel >> 16); dstG = (Uint8)(dstpixel >> 8); dstB = (Uint8)dstpixel; dstA = (Uint8)(dstpixel >> 24);
             if (flags & SDL_COPY_MODULATE_COLOR) {
-                srcR = (srcR * modulateR) / 255;
-                srcG = (srcG * modulateG) / 255;
-                srcB = (srcB * modulateB) / 255;
+                MULT_DIV_255(srcR, modulateR, srcR);
+                MULT_DIV_255(srcG, modulateG, srcG);
+                MULT_DIV_255(srcB, modulateB, srcB);
             }
             if (flags & (SDL_COPY_BLEND|SDL_COPY_ADD)) {
                 /* This goes away if we ever use premultiplied alpha */
                 if (srcA < 255) {
-                    srcR = (srcR * srcA) / 255;
-                    srcG = (srcG * srcA) / 255;
-                    srcB = (srcB * srcA) / 255;
+                    MULT_DIV_255(srcR, srcA, srcR);
+                    MULT_DIV_255(srcG, srcA, srcG);
+                    MULT_DIV_255(srcB, srcA, srcB);
                 }
             }
             switch (flags & (SDL_COPY_BLEND|SDL_COPY_ADD|SDL_COPY_MOD|SDL_COPY_MUL)) {
             case SDL_COPY_BLEND:
-                dstR = srcR + ((255 - srcA) * dstR) / 255;
-                dstG = srcG + ((255 - srcA) * dstG) / 255;
-                dstB = srcB + ((255 - srcA) * dstB) / 255;
-                dstA = srcA + ((255 - srcA) * dstA) / 255;
+                MULT_DIV_255((255 - srcA), dstR, dstR);
+                dstR += srcR;
+                MULT_DIV_255((255 - srcA), dstG, dstG);
+                dstG += srcG;
+                MULT_DIV_255((255 - srcA), dstB, dstB);
+                dstB += srcB;
+                MULT_DIV_255((255 - srcA), dstA, dstA);
+                dstA += srcA;
                 break;
             case SDL_COPY_ADD:
                 dstR = srcR + dstR; if (dstR > 255) dstR = 255;
@@ -1022,14 +1063,20 @@ static void SDL_Blit_XRGB8888_ARGB8888_Modulate_Blend(SDL_BlitInfo *info)
                 dstB = srcB + dstB; if (dstB > 255) dstB = 255;
                 break;
             case SDL_COPY_MOD:
-                dstR = (srcR * dstR) / 255;
-                dstG = (srcG * dstG) / 255;
-                dstB = (srcB * dstB) / 255;
+                MULT_DIV_255(srcR, dstR, dstR);
+                MULT_DIV_255(srcG, dstG, dstG);
+                MULT_DIV_255(srcB, dstB, dstB);
                 break;
             case SDL_COPY_MUL:
-                dstR = ((srcR * dstR) + (dstR * (255 - srcA))) / 255; if (dstR > 255) dstR = 255;
-                dstG = ((srcG * dstG) + (dstG * (255 - srcA))) / 255; if (dstG > 255) dstG = 255;
-                dstB = ((srcB * dstB) + (dstB * (255 - srcA))) / 255; if (dstB > 255) dstB = 255;
+                MULT_DIV_255(dstR, (255 - srcA), dstR);
+                dstR += (srcR * dstR);
+                if (dstR > 255) dstR = 255;
+                MULT_DIV_255(dstB, (255 - srcA), dstB);
+                dstB += (srcB * dstB);
+                if (dstB > 255) dstB = 255;
+                MULT_DIV_255(dstG, (255 - srcA), dstG);
+                dstG += (srcG * dstG);
+                if (dstG > 255) dstG = 255;
                 break;
             }
             dstpixel = (dstA << 24) | (dstR << 16) | (dstG << 8) | dstB;
@@ -1077,24 +1124,28 @@ static void SDL_Blit_XRGB8888_ARGB8888_Modulate_Blend_Scale(SDL_BlitInfo *info)
             dstpixel = *dst;
             dstR = (Uint8)(dstpixel >> 16); dstG = (Uint8)(dstpixel >> 8); dstB = (Uint8)dstpixel; dstA = (Uint8)(dstpixel >> 24);
             if (flags & SDL_COPY_MODULATE_COLOR) {
-                srcR = (srcR * modulateR) / 255;
-                srcG = (srcG * modulateG) / 255;
-                srcB = (srcB * modulateB) / 255;
+                MULT_DIV_255(srcR, modulateR, srcR);
+                MULT_DIV_255(srcG, modulateG, srcG);
+                MULT_DIV_255(srcB, modulateB, srcB);
             }
             if (flags & (SDL_COPY_BLEND|SDL_COPY_ADD)) {
                 /* This goes away if we ever use premultiplied alpha */
                 if (srcA < 255) {
-                    srcR = (srcR * srcA) / 255;
-                    srcG = (srcG * srcA) / 255;
-                    srcB = (srcB * srcA) / 255;
+                    MULT_DIV_255(srcR, srcA, srcR);
+                    MULT_DIV_255(srcG, srcA, srcG);
+                    MULT_DIV_255(srcB, srcA, srcB);
                 }
             }
             switch (flags & (SDL_COPY_BLEND|SDL_COPY_ADD|SDL_COPY_MOD|SDL_COPY_MUL)) {
             case SDL_COPY_BLEND:
-                dstR = srcR + ((255 - srcA) * dstR) / 255;
-                dstG = srcG + ((255 - srcA) * dstG) / 255;
-                dstB = srcB + ((255 - srcA) * dstB) / 255;
-                dstA = srcA + ((255 - srcA) * dstA) / 255;
+                MULT_DIV_255((255 - srcA), dstR, dstR);
+                dstR += srcR;
+                MULT_DIV_255((255 - srcA), dstG, dstG);
+                dstG += srcG;
+                MULT_DIV_255((255 - srcA), dstB, dstB);
+                dstB += srcB;
+                MULT_DIV_255((255 - srcA), dstA, dstA);
+                dstA += srcA;
                 break;
             case SDL_COPY_ADD:
                 dstR = srcR + dstR; if (dstR > 255) dstR = 255;
@@ -1102,14 +1153,20 @@ static void SDL_Blit_XRGB8888_ARGB8888_Modulate_Blend_Scale(SDL_BlitInfo *info)
                 dstB = srcB + dstB; if (dstB > 255) dstB = 255;
                 break;
             case SDL_COPY_MOD:
-                dstR = (srcR * dstR) / 255;
-                dstG = (srcG * dstG) / 255;
-                dstB = (srcB * dstB) / 255;
+                MULT_DIV_255(srcR, dstR, dstR);
+                MULT_DIV_255(srcG, dstG, dstG);
+                MULT_DIV_255(srcB, dstB, dstB);
                 break;
             case SDL_COPY_MUL:
-                dstR = ((srcR * dstR) + (dstR * (255 - srcA))) / 255; if (dstR > 255) dstR = 255;
-                dstG = ((srcG * dstG) + (dstG * (255 - srcA))) / 255; if (dstG > 255) dstG = 255;
-                dstB = ((srcB * dstB) + (dstB * (255 - srcA))) / 255; if (dstB > 255) dstB = 255;
+                MULT_DIV_255(dstR, (255 - srcA), dstR);
+                dstR += (srcR * dstR);
+                if (dstR > 255) dstR = 255;
+                MULT_DIV_255(dstB, (255 - srcA), dstB);
+                dstB += (srcB * dstB);
+                if (dstB > 255) dstB = 255;
+                MULT_DIV_255(dstG, (255 - srcA), dstG);
+                dstG += (srcG * dstG);
+                if (dstG > 255) dstG = 255;
                 break;
             }
             dstpixel = (dstA << 24) | (dstR << 16) | (dstG << 8) | dstB;
@@ -1185,14 +1242,14 @@ static void SDL_Blit_XBGR8888_XRGB8888_Blend(SDL_BlitInfo *info)
                 dstB = srcB + dst

(Patch may be truncated, please check the link at the top of this post.)