Added SDL_PremultiplyAlpha() to premultiply alpha on a block of SDL_PIXELFORMAT_ARGB8888 pixels
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
diff --git a/WhatsNew.txt b/WhatsNew.txt
index 732f1a5..5b22900 100644
--- a/WhatsNew.txt
+++ b/WhatsNew.txt
@@ -5,6 +5,9 @@ This is a list of major changes in SDL's version history.
2.0.18:
---------------------------------------------------------------------------
+General:
+* Added SDL_PremultiplyAlpha() to premultiply alpha on a block of SDL_PIXELFORMAT_ARGB8888 pixels
+
Linux:
* Added the hint SDL_HINT_LINUX_JOYSTICK_CLASSIC to control whether /dev/input/js* or /dev/input/event* are used as joystick devices
* Added the hint SDL_HINT_JOYSTICK_DEVICE to allow the user to specify devices that will be opened in addition to the normal joystick detection
diff --git a/include/SDL_surface.h b/include/SDL_surface.h
index 29ebfb6..0b18fa0 100644
--- a/include/SDL_surface.h
+++ b/include/SDL_surface.h
@@ -705,7 +705,7 @@ extern DECLSPEC SDL_Surface *SDLCALL SDL_ConvertSurfaceFormat
* \param height the height of the block to copy, in pixels
* \param src_format an SDL_PixelFormatEnum value of the `src` pixels format
* \param src a pointer to the source pixels
- * \param src_pitch the pitch of the block to copy, in bytes
+ * \param src_pitch the pitch of the source pixels, in bytes
* \param dst_format an SDL_PixelFormatEnum value of the `dst` pixels format
* \param dst a pointer to be filled in with new pixel data
* \param dst_pitch the pitch of the destination pixels, in bytes
@@ -721,6 +721,32 @@ extern DECLSPEC int SDLCALL SDL_ConvertPixels(int width, int height,
void * dst, int dst_pitch);
/**
+ * Premultiply the alpha on a block of pixels.
+ *
+ * This is safe to use with src == dst, but not for other overlapping areas.
+ *
+ * This function is currently only implemented for SDL_PIXELFORMAT_ARGB8888.
+ *
+ * \param width the width of the block to convert, in pixels
+ * \param height the height of the block to convert, in pixels
+ * \param src_format an SDL_PixelFormatEnum value of the `src` pixels format
+ * \param src a pointer to the source pixels
+ * \param src_pitch the pitch of the source pixels, in bytes
+ * \param dst_format an SDL_PixelFormatEnum value of the `dst` pixels format
+ * \param dst a pointer to be filled in with premultiplied pixel data
+ * \param dst_pitch the pitch of the destination pixels, in bytes
+ * \returns 0 on success or a negative error code on failure; call
+ * SDL_GetError() for more information.
+ *
+ * \since This function is available since SDL 2.0.18.
+ */
+extern DECLSPEC int SDLCALL SDL_PremultiplyAlpha(int width, int height,
+ Uint32 src_format,
+ const void * src, int src_pitch,
+ Uint32 dst_format,
+ void * dst, int dst_pitch);
+
+/**
* Perform a fast fill of a rectangle with a specific color.
*
* `color` should be a pixel of the format used by the surface, and can be
diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h
index 62364c3..6c0de51 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -854,3 +854,4 @@
#define SDL_GameControllerHasRumble SDL_GameControllerHasRumble_REAL
#define SDL_GameControllerHasRumbleTriggers SDL_GameControllerHasRumbleTriggers_REAL
#define SDL_hid_ble_scan SDL_hid_ble_scan_REAL
+#define SDL_PremultiplyAlpha SDL_PremultiplyAlpha_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index 4953f29..d110e31 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -923,3 +923,4 @@ SDL_DYNAPI_PROC(SDL_bool,SDL_JoystickHasRumbleTriggers,(SDL_Joystick *a),(a),ret
SDL_DYNAPI_PROC(SDL_bool,SDL_GameControllerHasRumble,(SDL_GameController *a),(a),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_GameControllerHasRumbleTriggers,(SDL_GameController *a),(a),return)
SDL_DYNAPI_PROC(void,SDL_hid_ble_scan,(SDL_bool a),(a),)
+SDL_DYNAPI_PROC(int,SDL_PremultiplyAlpha,(int a, int b, Uint32 c, const void *d, int e, Uint32 f, void *g, int h),(a,b,c,d,e,f,g,h),return)
diff --git a/src/video/SDL_pixels.c b/src/video/SDL_pixels.c
index 1402167..eff0c94 100644
--- a/src/video/SDL_pixels.c
+++ b/src/video/SDL_pixels.c
@@ -1227,33 +1227,4 @@ 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) {
- Uint32 *src_px = (Uint32*)((Uint8 *)src->pixels + (y * src->pitch));
- for (x = 0; x < src->w; ++x) {
- /* Component bytes extraction. */
- SDL_GetRGBA(*src_px++, src->format, &R, &G, &B, &A);
-
- /* Alpha pre-multiplication of each component. */
- R = ((Uint32)A * R) / 255;
- G = ((Uint32)A * G) / 255;
- B = ((Uint32)A * B) / 255;
-
- /* ARGB8888 pixel recomposition. */
- *dst++ = (((Uint32)A << 24) | ((Uint32)R << 16) | ((Uint32)G << 8) | (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 91db5b4..1974797 100644
--- a/src/video/SDL_pixels_c.h
+++ b/src/video/SDL_pixels_c.h
@@ -43,7 +43,6 @@ 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_ */
diff --git a/src/video/SDL_surface.c b/src/video/SDL_surface.c
index bb2e532..45a64c9 100644
--- a/src/video/SDL_surface.c
+++ b/src/video/SDL_surface.c
@@ -1381,7 +1381,12 @@ int SDL_ConvertPixels(int width, int height,
void *nonconst_src = (void *) src;
int ret;
- /* Check to make sure we are blitting somewhere, so we don't crash */
+ if (!src) {
+ return SDL_InvalidParamError("src");
+ }
+ if (!src_pitch) {
+ return SDL_InvalidParamError("src_pitch");
+ }
if (!dst) {
return SDL_InvalidParamError("dst");
}
@@ -1441,6 +1446,68 @@ int SDL_ConvertPixels(int width, int height,
}
/*
+ * Premultiply the alpha on a block of pixels
+ *
+ * This is currently only implemented for SDL_PIXELFORMAT_ARGB8888
+ *
+ * Here are some ideas for optimization:
+ * https://github.com/Wizermil/premultiply_alpha/tree/master/premultiply_alpha
+ * https://developer.arm.com/documentation/101964/0201/Pre-multiplied-alpha-channel-data
+ */
+int SDL_PremultiplyAlpha(int width, int height,
+ Uint32 src_format, const void * src, int src_pitch,
+ Uint32 dst_format, void * dst, int dst_pitch)
+{
+ int c;
+ Uint32 srcpixel;
+ Uint32 srcR, srcG, srcB, srcA;
+ Uint32 dstpixel;
+ Uint32 dstR, dstG, dstB, dstA;
+
+ if (!src) {
+ return SDL_InvalidParamError("src");
+ }
+ if (!src_pitch) {
+ return SDL_InvalidParamError("src_pitch");
+ }
+ if (!dst) {
+ return SDL_InvalidParamError("dst");
+ }
+ if (!dst_pitch) {
+ return SDL_InvalidParamError("dst_pitch");
+ }
+ if (src_format != SDL_PIXELFORMAT_ARGB8888) {
+ return SDL_InvalidParamError("src_format");
+ }
+ if (dst_format != SDL_PIXELFORMAT_ARGB8888) {
+ return SDL_InvalidParamError("dst_format");
+ }
+
+ while (height--) {
+ const Uint32 *src_px = (const Uint32 *)src;
+ Uint32 *dst_px = (Uint32 *)dst;
+ for (c = width; c; --c) {
+ /* Component bytes extraction. */
+ srcpixel = *src_px++;
+ RGBA_FROM_ARGB8888(srcpixel, srcR, srcG, srcB, srcA);
+
+ /* Alpha pre-multiplication of each component. */
+ dstA = srcA;
+ dstR = (srcA * srcR) / 255;
+ dstG = (srcA * srcG) / 255;
+ dstB = (srcA * srcB) / 255;
+
+ /* ARGB8888 pixel recomposition. */
+ ARGB8888_FROM_RGBA(dstpixel, dstR, dstG, dstB, dstA);
+ *dst_px++ = dstpixel;
+ }
+ src = (const Uint8 *)src + src_pitch;
+ dst = (Uint8 *)dst + dst_pitch;
+ }
+ return 0;
+}
+
+/*
* Free a surface created by the above function.
*/
void
diff --git a/src/video/kmsdrm/SDL_kmsdrmmouse.c b/src/video/kmsdrm/SDL_kmsdrmmouse.c
index 2d0795e..08e51ae 100644
--- a/src/video/kmsdrm/SDL_kmsdrmmouse.c
+++ b/src/video/kmsdrm/SDL_kmsdrmmouse.c
@@ -278,7 +278,9 @@ KMSDRM_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y)
like other backends do. Also, the GBM BO pixels have to be
alpha-premultiplied, but the SDL surface we receive has
straight-alpha pixels, so we always have to convert. */
- SDL_PremultiplySurfaceAlphaToARGB8888(surface, curdata->buffer);
+ SDL_PremultiplyAlpha(surface->w, surface->h,
+ surface->format->format, surface->pixels, surface->pitch,
+ SDL_PIXELFORMAT_ARGB8888, curdata->buffer, surface->w * 4);
cursor->driverdata = curdata;
diff --git a/src/video/wayland/SDL_waylandmouse.c b/src/video/wayland/SDL_waylandmouse.c
index 19a439f..67ab721 100644
--- a/src/video/wayland/SDL_waylandmouse.c
+++ b/src/video/wayland/SDL_waylandmouse.c
@@ -280,7 +280,9 @@ Wayland_CreateCursor(SDL_Surface *surface, int hot_x, int hot_y)
}
/* Wayland requires premultiplied alpha for its surfaces. */
- SDL_PremultiplySurfaceAlphaToARGB8888(surface, data->shm_data);
+ SDL_PremultiplyAlpha(surface->w, surface->h,
+ surface->format->format, surface->pixels, surface->pitch,
+ SDL_PIXELFORMAT_ARGB8888, data->shm_data, surface->w * 4);
data->surface = wl_compositor_create_surface(wd->compositor);
wl_surface_set_user_data(data->surface, NULL);
@@ -447,4 +449,7 @@ Wayland_FiniMouse(SDL_VideoData *data)
}
SDL_free(data->cursor_themes);
}
+
#endif /* SDL_VIDEO_DRIVER_WAYLAND */
+
+/* vi: set ts=4 sw=4 expandtab: */