Skip to content

Commit 14eafac

Browse files
committed
SDL3: surface+pixelarray+font+draw: runtime fixes
1 parent 1cd0093 commit 14eafac

File tree

9 files changed

+143
-66
lines changed

9 files changed

+143
-66
lines changed

docs/reST/c_api/surface.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,4 @@ Header file: src_c/include/pygame.h
5656
by the blit.
5757
5858
The C version of the :py:meth:`pygame.Surface.blit` method.
59-
Return ``1`` on success, ``0`` on an exception.
59+
Return ``0`` on success, ``1`` on an exception.

src_c/_pygame.h

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,17 @@
7676

7777
#define PG_CreateSurface SDL_CreateSurface
7878
#define PG_CreateSurfaceFrom SDL_CreateSurfaceFrom
79-
#define PG_ConvertSurface SDL_ConvertSurface
8079
#define PG_ConvertSurfaceFormat SDL_ConvertSurface
8180

81+
/* Convert surface using palette and format of dst */
82+
static inline SDL_Surface *
83+
PG_ConvertSurface(SDL_Surface *surface, SDL_Surface *dst)
84+
{
85+
return SDL_ConvertSurfaceAndColorspace(surface, dst->format,
86+
SDL_GetSurfacePalette(dst),
87+
SDL_GetSurfaceColorspace(dst), 0);
88+
}
89+
8290
#define PG_PixelFormatEnum SDL_PixelFormat
8391

8492
#define PG_SurfaceHasRLE SDL_SurfaceHasRLE
@@ -143,11 +151,23 @@ PG_SURF_BitsPerPixel(SDL_Surface *surf)
143151

144152
#define PG_PixelFormat const SDL_PixelFormatDetails
145153

154+
static inline SDL_Palette *
155+
PG_GetSurfacePalette(SDL_Surface *surf)
156+
{
157+
SDL_Palette *ret = SDL_GetSurfacePalette(surf);
158+
if (!ret && SDL_ISPIXELFORMAT_INDEXED(surf->format)) {
159+
/* Palette doesn't exist but is expected, so create it.
160+
* SDL will associate the newly created palette with the surface */
161+
ret = SDL_CreateSurfacePalette(surf);
162+
}
163+
return ret;
164+
}
165+
146166
static inline bool
147167
PG_GetSurfaceDetails(SDL_Surface *surf, PG_PixelFormat **format_p,
148168
SDL_Palette **palette_p)
149169
{
150-
*palette_p = SDL_GetSurfacePalette(surf);
170+
*palette_p = PG_GetSurfacePalette(surf);
151171
*format_p = SDL_GetPixelFormatDetails(surf->format);
152172
return *format_p != NULL;
153173
}
@@ -158,7 +178,6 @@ PG_GetSurfaceFormat(SDL_Surface *surf)
158178
return SDL_GetPixelFormatDetails(surf->format);
159179
}
160180

161-
#define PG_GetSurfacePalette SDL_GetSurfacePalette
162181
#define PG_SetPaletteColors SDL_SetPaletteColors
163182
#define PG_SetSurfacePalette SDL_SetSurfacePalette
164183
#define PG_SetSurfaceColorKey SDL_SetSurfaceColorKey
@@ -216,10 +235,15 @@ PG_GetSurfaceFormat(SDL_Surface *surf)
216235
SDL_CreateRGBSurfaceWithFormat(0, width, height, 0, format)
217236
#define PG_CreateSurfaceFrom(width, height, format, pixels, pitch) \
218237
SDL_CreateRGBSurfaceWithFormatFrom(pixels, width, height, 0, pitch, format)
219-
#define PG_ConvertSurface(src, fmt) SDL_ConvertSurface(src, fmt, 0)
220238
#define PG_ConvertSurfaceFormat(src, pixel_format) \
221239
SDL_ConvertSurfaceFormat(src, pixel_format, 0)
222240

241+
static inline SDL_Surface *
242+
PG_ConvertSurface(SDL_Surface *surface, SDL_Surface *dst)
243+
{
244+
return SDL_ConvertSurface(surface, dst->format, 0);
245+
}
246+
223247
#define PG_PixelFormatEnum SDL_PixelFormatEnum
224248

225249
#define PG_SoftStretchNearest(src, srcrect, dst, dstrect) \

src_c/draw.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1334,7 +1334,7 @@ flood_fill(PyObject *self, PyObject *arg, PyObject *kwargs)
13341334
if (pgSurface_Check(colorobj)) {
13351335
pat_surfobj = ((pgSurfaceObject *)colorobj);
13361336

1337-
pattern = PG_ConvertSurface(pat_surfobj->surf, surf->format);
1337+
pattern = PG_ConvertSurface(pat_surfobj->surf, surf);
13381338

13391339
if (pattern == NULL) {
13401340
return RAISE(PyExc_RuntimeError, "error converting pattern surf");

src_c/font.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -717,11 +717,7 @@ font_render(PyObject *self, PyObject *args, PyObject *kwds)
717717
resolve to Render_Solid, that needs to be explicitly handled. */
718718
if (surf != NULL && bg_rgba_obj != Py_None) {
719719
SDL_SetColorKey(surf, 0, 0);
720-
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
721-
SDL_Palette *palette = SDL_GetSurfacePalette(surf);
722-
#else
723-
SDL_Palette *palette = surf->format->palette;
724-
#endif
720+
SDL_Palette *palette = PG_GetSurfacePalette(surf);
725721
if (palette) {
726722
palette->colors[0].r = backg.r;
727723
palette->colors[0].g = backg.g;

src_c/pixelarray_methods.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ _make_surface(pgPixelArrayObject *array, PyObject *args)
137137
}
138138

139139
/* Ensure the new surface has the same format as the original */
140-
new_surf = PG_ConvertSurface(temp_surf, surf->format);
140+
new_surf = PG_ConvertSurface(temp_surf, surf);
141141
if (temp_surf != surf) {
142142
SDL_FreeSurface(temp_surf);
143143
}

src_c/pixelcopy.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1197,11 +1197,7 @@ make_surface(PyObject *self, PyObject *arg)
11971197
pgBuffer_Release(&pg_view);
11981198
return RAISE(pgExc_SDLError, SDL_GetError());
11991199
}
1200-
#if SDL_VERSION_ATLEAST(3, 0, 0)
1201-
SDL_Palette *palette = SDL_GetSurfacePalette(surf);
1202-
#else
1203-
SDL_Palette *palette = surf->format->palette;
1204-
#endif
1200+
SDL_Palette *palette = PG_GetSurfacePalette(surf);
12051201
if (SDL_ISPIXELFORMAT_INDEXED(PG_SURF_FORMATENUM(surf))) {
12061202
/* Give the surface something other than an all white palette.
12071203
* */

src_c/surface.c

Lines changed: 98 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1544,24 +1544,21 @@ surf_set_alpha(pgSurfaceObject *self, PyObject *args)
15441544
bool success =
15451545
PG_SetSurfaceRLE(surf, (flags & PGS_RLEACCEL) ? SDL_TRUE : SDL_FALSE);
15461546
/* HACK HACK HACK */
1547-
// TODO SDL3: figure out how to port this or if it's relevant to SDL3.
1548-
#if !SDL_VERSION_ATLEAST(3, 0, 0)
1549-
if ((surf->flags & SDL_RLEACCEL) && (!(flags & PGS_RLEACCEL))) {
1547+
if (SDL_MUSTLOCK(surf) && (!(flags & PGS_RLEACCEL))) {
15501548
/* hack to strip SDL_RLEACCEL flag off surface immediately when
15511549
it is not requested */
15521550
SDL_Rect sdlrect;
15531551
sdlrect.x = 0;
15541552
sdlrect.y = 0;
1555-
sdlrect.h = 0;
1556-
sdlrect.w = 0;
1553+
sdlrect.h = 1;
1554+
sdlrect.w = 1;
15571555

15581556
SDL_Surface *surface =
15591557
PG_CreateSurface(1, 1, PG_SURF_FORMATENUM(surf));
15601558

15611559
SDL_LowerBlit(surf, &sdlrect, surface, &sdlrect);
15621560
SDL_FreeSurface(surface);
15631561
}
1564-
#endif
15651562
/* HACK HACK HACK */
15661563
if (success) {
15671564
success = PG_SetSurfaceAlphaMod(surf, alpha);
@@ -1623,7 +1620,7 @@ surf_copy(pgSurfaceObject *self, PyObject *_null)
16231620
SURF_INIT_CHECK(surf)
16241621

16251622
pgSurface_Prep(self);
1626-
newsurf = PG_ConvertSurface(surf, surf->format);
1623+
newsurf = PG_ConvertSurface(surf, surf);
16271624
pgSurface_Unprep(self);
16281625

16291626
final = surf_subtype_new(Py_TYPE(self), newsurf, 1);
@@ -1683,7 +1680,7 @@ surf_convert(pgSurfaceObject *self, PyObject *args)
16831680
if (argobject) {
16841681
if (pgSurface_Check(argobject)) {
16851682
src = pgSurface_AsSurface(argobject);
1686-
newsurf = PG_ConvertSurface(surf, src->format);
1683+
newsurf = PG_ConvertSurface(surf, src);
16871684
}
16881685
else {
16891686
/* will be updated later, initialize to make static analyzer happy
@@ -1837,7 +1834,7 @@ surf_convert(pgSurfaceObject *self, PyObject *args)
18371834
if (argobject) {
18381835
if (pgSurface_Check(argobject)) {
18391836
src = pgSurface_AsSurface(argobject);
1840-
newsurf = PG_ConvertSurface(surf, src->format);
1837+
newsurf = PG_ConvertSurface(surf, src);
18411838
}
18421839
else {
18431840
/* will be updated later, initialize to make static analyzer happy
@@ -1961,7 +1958,7 @@ surf_convert(pgSurfaceObject *self, PyObject *args)
19611958
SDL_SetPixelFormatPalette(&format, palette);
19621959
}
19631960
}
1964-
newsurf = PG_ConvertSurface(surf, &format);
1961+
newsurf = SDL_ConvertSurface(surf, &format, 0);
19651962
SDL_SetSurfaceBlendMode(newsurf, SDL_BLENDMODE_NONE);
19661963
SDL_FreePalette(palette);
19671964
}
@@ -3016,20 +3013,15 @@ surf_get_flags(PyObject *self, PyObject *_null)
30163013
if (sdl_flags & SDL_PREALLOC) {
30173014
flags |= PGS_PREALLOC;
30183015
}
3016+
/* This checks if RLE was requested on the surface */
30193017
if (PG_SurfaceHasRLE(surf)) {
30203018
flags |= PGS_RLEACCELOK;
30213019
}
3022-
// TODO SDL3: figure out how to properly emulate SDL2 check/relevance
3023-
// Current implementation is just a placeholder.
3024-
#if SDL_VERSION_ATLEAST(3, 0, 0)
3025-
if (SDL_SurfaceHasRLE(surf)) {
3026-
flags |= PGS_RLEACCEL;
3027-
}
3028-
#else
3029-
if ((sdl_flags & SDL_RLEACCEL)) {
3020+
/* this checks if the surface actually has RLE.
3021+
* On SDL2: SDL_MUSTLOCK is (flags & SDL_RLEACCEL) */
3022+
if (SDL_MUSTLOCK(surf)) {
30303023
flags |= PGS_RLEACCEL;
30313024
}
3032-
#endif
30333025
if (is_window_surf) {
30343026
if (window_flags & PG_WINDOW_FULLSCREEN_INCLUSIVE) {
30353027
flags |= PGS_FULLSCREEN;
@@ -3767,7 +3759,7 @@ surf_premul_alpha(pgSurfaceObject *self, PyObject *_null)
37673759

37683760
pgSurface_Prep(self);
37693761
// Make a copy of the surface first
3770-
newsurf = PG_ConvertSurface(surf, surf->format);
3762+
newsurf = PG_ConvertSurface(surf, surf);
37713763

37723764
if ((surf->w > 0 && surf->h > 0)) {
37733765
// If the surface has no pixels we don't need to premul
@@ -4461,6 +4453,76 @@ surface_do_overlap(SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *dst,
44614453
return dstoffset < span || dstoffset > src->pitch - span;
44624454
}
44634455

4456+
int
4457+
PG_BlitSurface(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst,
4458+
SDL_Rect *dstrect)
4459+
{
4460+
#if SDL_VERSION_ATLEAST(3, 0, 0)
4461+
/* SDL3 doesn't modify dstrect, so compat for that.
4462+
* Below logic taken from SDL2 source with slight modifications */
4463+
SDL_Rect r_src, r_dst;
4464+
4465+
r_src.x = 0;
4466+
r_src.y = 0;
4467+
r_src.w = src->w;
4468+
r_src.h = src->h;
4469+
4470+
if (dstrect) {
4471+
r_dst.x = dstrect->x;
4472+
r_dst.y = dstrect->y;
4473+
}
4474+
else {
4475+
r_dst.x = 0;
4476+
r_dst.y = 0;
4477+
}
4478+
4479+
/* clip the source rectangle to the source surface */
4480+
if (srcrect) {
4481+
SDL_Rect tmp;
4482+
if (SDL_IntersectRect(srcrect, &r_src, &tmp) == SDL_FALSE) {
4483+
goto end;
4484+
}
4485+
4486+
/* Shift dstrect, if srcrect origin has changed */
4487+
r_dst.x += tmp.x - srcrect->x;
4488+
r_dst.y += tmp.y - srcrect->y;
4489+
4490+
/* Update srcrect */
4491+
r_src = tmp;
4492+
}
4493+
4494+
/* There're no dstrect.w/h parameters. It's the same as srcrect */
4495+
r_dst.w = r_src.w;
4496+
r_dst.h = r_src.h;
4497+
4498+
/* clip the destination rectangle against the clip rectangle */
4499+
{
4500+
SDL_Rect tmp, clip_rect;
4501+
SDL_GetSurfaceClipRect(dst, &clip_rect);
4502+
if (SDL_IntersectRect(&r_dst, &clip_rect, &tmp) == SDL_FALSE) {
4503+
goto end;
4504+
}
4505+
4506+
/* Update dstrect */
4507+
r_dst = tmp;
4508+
}
4509+
4510+
if (r_dst.w > 0 && r_dst.h > 0) {
4511+
if (dstrect) { /* update output parameter */
4512+
*dstrect = r_dst;
4513+
}
4514+
return SDL_BlitSurface(src, srcrect, dst, dstrect) ? 0 : -1;
4515+
}
4516+
end:
4517+
if (dstrect) {
4518+
dstrect->w = dstrect->h = 0;
4519+
}
4520+
return 0;
4521+
#else
4522+
return SDL_BlitSurface(src, srcrect, dst, dstrect);
4523+
#endif
4524+
}
4525+
44644526
/*this internal blit function is accessible through the C api*/
44654527
int
44664528
pgSurface_Blit(pgSurfaceObject *dstobj, pgSurfaceObject *srcobj,
@@ -4471,13 +4533,11 @@ pgSurface_Blit(pgSurfaceObject *dstobj, pgSurfaceObject *srcobj,
44714533
SDL_Surface *subsurface = NULL;
44724534
int result, suboffsetx = 0, suboffsety = 0;
44734535
SDL_Rect orig_clip, sub_clip, dstclip;
4474-
#if !SDL_VERSION_ATLEAST(3, 0, 0)
44754536
Uint8 alpha;
4476-
#endif
44774537

44784538
if (!PG_GetSurfaceClipRect(dst, &dstclip)) {
44794539
PyErr_SetString(pgExc_SDLError, SDL_GetError());
4480-
return 0;
4540+
return 1;
44814541
}
44824542

44834543
/* passthrough blits to the real surface */
@@ -4528,8 +4588,6 @@ pgSurface_Blit(pgSurfaceObject *dstobj, pgSurfaceObject *srcobj,
45284588
result = pygame_Blit(src, srcrect, dst, dstrect, blend_flags);
45294589
/* Py_END_ALLOW_THREADS */
45304590
}
4531-
// TODO SDL3: port the below bit of code. Skipping for initial surface port.
4532-
#if !SDL_VERSION_ATLEAST(3, 0, 0)
45334591
/* can't blit alpha to 8bit, crashes SDL */
45344592
else if (PG_SURF_BytesPerPixel(dst) == 1 &&
45354593
(SDL_ISPIXELFORMAT_ALPHA(PG_SURF_FORMATENUM(src)) ||
@@ -4539,17 +4597,22 @@ pgSurface_Blit(pgSurfaceObject *dstobj, pgSurfaceObject *srcobj,
45394597
result = pygame_Blit(src, srcrect, dst, dstrect, 0);
45404598
}
45414599
else {
4600+
#if SDL_VERSION_ATLEAST(3, 0, 0)
4601+
const SDL_PixelFormatDetails *fmt =
4602+
SDL_GetPixelFormatDetails(src->format);
4603+
src = fmt ? SDL_ConvertSurface(src,
4604+
SDL_GetPixelFormatForMasks(
4605+
fmt->bits_per_pixel, fmt->Rmask,
4606+
fmt->Gmask, fmt->Bmask, 0))
4607+
: NULL;
4608+
4609+
#else
45424610
SDL_PixelFormat *fmt = src->format;
45434611
SDL_PixelFormat newfmt;
45444612

45454613
newfmt.palette = 0; /* Set NULL (or SDL gets confused) */
4546-
#if SDL_VERSION_ATLEAST(3, 0, 0)
4547-
newfmt.bits_per_pixel = fmt->bits_per_pixel;
4548-
newfmt.bytes_per_pixel = fmt->bytes_per_pixel;
4549-
#else
45504614
newfmt.BitsPerPixel = fmt->BitsPerPixel;
45514615
newfmt.BytesPerPixel = fmt->BytesPerPixel;
4552-
#endif
45534616
newfmt.Amask = 0;
45544617
newfmt.Rmask = fmt->Rmask;
45554618
newfmt.Gmask = fmt->Gmask;
@@ -4562,13 +4625,10 @@ pgSurface_Blit(pgSurfaceObject *dstobj, pgSurfaceObject *srcobj,
45624625
newfmt.Rloss = fmt->Rloss;
45634626
newfmt.Gloss = fmt->Gloss;
45644627
newfmt.Bloss = fmt->Bloss;
4565-
src = PG_ConvertSurface(src, &newfmt);
4566-
if (src) {
4567-
#if SDL_VERSION_ATLEAST(3, 0, 0)
4568-
result = SDL_BlitSurface(src, srcrect, dst, dstrect) ? 0 : -1;
4569-
#else
4570-
result = SDL_BlitSurface(src, srcrect, dst, dstrect);
4628+
src = SDL_ConvertSurface(src, &newfmt, 0);
45714629
#endif
4630+
if (src) {
4631+
result = PG_BlitSurface(src, srcrect, dst, dstrect);
45724632
SDL_FreeSurface(src);
45734633
}
45744634
else {
@@ -4577,32 +4637,22 @@ pgSurface_Blit(pgSurfaceObject *dstobj, pgSurfaceObject *srcobj,
45774637
}
45784638
/* Py_END_ALLOW_THREADS */
45794639
}
4580-
#endif
45814640
else if (blend_flags != PYGAME_BLEND_ALPHA_SDL2 &&
45824641
!(pg_EnvShouldBlendAlphaSDL2()) && !SDL_HasColorKey(src) &&
45834642
(PG_SURF_BytesPerPixel(dst) == 4 ||
45844643
PG_SURF_BytesPerPixel(dst) == 2) &&
45854644
_PgSurface_SrcAlpha(src) &&
45864645
(SDL_ISPIXELFORMAT_ALPHA(PG_SURF_FORMATENUM(src))) &&
45874646
!PG_SurfaceHasRLE(src) && !PG_SurfaceHasRLE(dst) &&
4588-
#if SDL_VERSION_ATLEAST(3, 0, 0)
4589-
1
4590-
#else
4591-
!(src->flags & SDL_RLEACCEL) && !(dst->flags & SDL_RLEACCEL)
4592-
#endif
4593-
) {
4647+
!SDL_MUSTLOCK(src) && !SDL_MUSTLOCK(dst)) {
45944648
/* If we have a 32bit source surface with per pixel alpha
45954649
and no RLE we'll use pygame_Blit so we can mimic how SDL1
45964650
behaved */
45974651
result = pygame_Blit(src, srcrect, dst, dstrect, blend_flags);
45984652
}
45994653
else {
46004654
/* Py_BEGIN_ALLOW_THREADS */
4601-
#if SDL_VERSION_ATLEAST(3, 0, 0)
4602-
result = SDL_BlitSurface(src, srcrect, dst, dstrect) ? 0 : -1;
4603-
#else
4604-
result = SDL_BlitSurface(src, srcrect, dst, dstrect);
4605-
#endif
4655+
result = PG_BlitSurface(src, srcrect, dst, dstrect);
46064656
/* Py_END_ALLOW_THREADS */
46074657
}
46084658

0 commit comments

Comments
 (0)