kmsdrm: Use SDL_PremultiplySurfaceAlphaToARGB8888() for cursor surface

Instead of taking a direct copy of the mouse cursor surface, and then
premultiplying on every BO upload (using the custom
legacy_alpha_premultiply_ARGB8888 function), use the new
SDL_PremultiplySurfaceAlphaToARGB8888() function, which converts a whole
surface at a time, once and save the result.

The already-premultiplied data is then copied from that to the BO on
each upload, adjusting for the stride (which the previous implementation
required to be equal to the width), thereby making the extra copy
slightly useful..

This also adds support for non-SDL_PIXELFORMAT_ARGB8888 surfaces.
main
David Gow 2021-10-22 19:04:32 +08:00 committed by Sam Lantinga
parent b528d48446
commit a76b73dd2c
1 changed files with 16 additions and 57 deletions

View File

@ -30,6 +30,8 @@
#include "../../events/SDL_mouse_c.h"
#include "../../events/default_cursor.h"
#include "../SDL_pixels_c.h"
static SDL_Cursor *KMSDRM_CreateDefaultCursor(void);
static SDL_Cursor *KMSDRM_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y);
static int KMSDRM_ShowCursor(SDL_Cursor * cursor);
@ -59,30 +61,6 @@ KMSDRM_CreateDefaultCursor(void)
return SDL_CreateCursor(default_cdata, default_cmask, DEFAULT_CWIDTH, DEFAULT_CHEIGHT, DEFAULT_CHOTX, DEFAULT_CHOTY);
}
/* Converts a pixel from straight-alpha [AA, RR, GG, BB], which the SDL cursor surface has,
to premultiplied-alpha [AA. AA*RR, AA*GG, AA*BB].
These multiplications have to be done with floats instead of uint32_t's,
and the resulting values have to be converted to be relative to the 0-255 interval,
where 255 is 1.00 and anything between 0 and 255 is 0.xx. */
void legacy_alpha_premultiply_ARGB8888 (uint32_t *pixel) {
uint32_t A, R, G, B;
/* Component bytes extraction. */
A = (*pixel >> (3 << 3)) & 0xFF;
R = (*pixel >> (2 << 3)) & 0xFF;
G = (*pixel >> (1 << 3)) & 0xFF;
B = (*pixel >> (0 << 3)) & 0xFF;
/* 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. */
(*pixel) = (((uint32_t)A << 24) | ((uint32_t)R << 16) | ((uint32_t)G << 8)) | ((uint32_t)B << 0);
}
/* Given a display's driverdata, destroy the cursor BO for it.
To be called from KMSDRM_DestroyWindow(), as that's where we
destroy the driverdata for the window's display. */
@ -171,10 +149,10 @@ KMSDRM_DumpCursorToBO(SDL_VideoDisplay *display, SDL_Cursor *cursor)
uint32_t bo_handle;
size_t bo_stride;
size_t bufsize;
uint32_t *ready_buffer = NULL;
uint32_t pixel;
uint8_t *ready_buffer = NULL;
uint8_t *src_row;
int i,j;
int i;
int ret;
if (!curdata || !dispdata->cursor_bo) {
@ -186,21 +164,17 @@ KMSDRM_DumpCursorToBO(SDL_VideoDisplay *display, SDL_Cursor *cursor)
bo_stride = KMSDRM_gbm_bo_get_stride(dispdata->cursor_bo);
bufsize = bo_stride * dispdata->cursor_h;
ready_buffer = (uint32_t*)SDL_calloc(1, bufsize);
ready_buffer = (uint8_t*)SDL_calloc(1, bufsize);
if (!ready_buffer) {
ret = SDL_OutOfMemory();
goto cleanup;
}
/* Copy from the cursor buffer to a buffer that we can dump to the GBM BO,
pre-multiplying by alpha each pixel as we go. */
/* Copy from the cursor buffer to a buffer that we can dump to the GBM BO. */
for (i = 0; i < curdata->h; i++) {
for (j = 0; j < curdata->w; j++) {
pixel = ((uint32_t*)curdata->buffer)[i * curdata->w + j];
legacy_alpha_premultiply_ARGB8888 (&pixel);
SDL_memcpy(ready_buffer + (i * dispdata->cursor_w) + j, &pixel, 4);
}
src_row = &((uint8_t*)curdata->buffer)[i * curdata->w * 4];
SDL_memcpy(ready_buffer + (i * bo_stride), src_row, 4 * curdata->w);
}
/* Dump the cursor buffer to our GBM BO. */
@ -271,13 +245,6 @@ KMSDRM_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y)
curdata = NULL;
ret = NULL;
/* All code below assumes ARGB8888 format for the cursor surface,
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_assert(surface->format->format == SDL_PIXELFORMAT_ARGB8888);
SDL_assert(surface->pitch == surface->w * 4);
cursor = (SDL_Cursor *) SDL_calloc(1, sizeof(*cursor));
if (!cursor) {
SDL_OutOfMemory();
@ -298,8 +265,8 @@ KMSDRM_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y)
/* Configure the cursor buffer info.
This buffer has the original size of the cursor surface we are given. */
curdata->buffer_pitch = surface->pitch;
curdata->buffer_size = surface->pitch * surface->h;
curdata->buffer_pitch = surface->w;
curdata->buffer_size = surface->w * surface->h * 4;
curdata->buffer = (uint32_t*)SDL_malloc(curdata->buffer_size);
if (!curdata->buffer) {
@ -307,19 +274,11 @@ KMSDRM_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y)
goto cleanup;
}
if (SDL_MUSTLOCK(surface)) {
if (SDL_LockSurface(surface) < 0) {
/* Could not lock surface */
goto cleanup;
}
}
/* Copy the surface pixels to the cursor buffer, for future use in ShowCursor() */
SDL_memcpy(curdata->buffer, surface->pixels, curdata->buffer_size);
if (SDL_MUSTLOCK(surface)) {
SDL_UnlockSurface(surface);
}
/* All code below assumes ARGB8888 format for the cursor surface,
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);
cursor->driverdata = curdata;