Skip to content

Commit 697c4c9

Browse files
committed
SDL3: surface+pixelarray+font+draw: runtime fixes
1 parent 4d809d9 commit 697c4c9

File tree

9 files changed

+148
-69
lines changed

9 files changed

+148
-69
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: 103 additions & 51 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
@@ -1954,7 +1951,7 @@ surf_convert(pgSurfaceObject *self, PyObject *args)
19541951
SDL_SetPixelFormatPalette(format, palette);
19551952
}
19561953
}
1957-
newsurf = PG_ConvertSurface(surf, format);
1954+
newsurf = SDL_ConvertSurface(surf, format, 0);
19581955
SDL_SetSurfaceBlendMode(newsurf, SDL_BLENDMODE_NONE);
19591956
SDL_FreeFormat(format);
19601957
SDL_FreePalette(palette);
@@ -3010,20 +3007,15 @@ surf_get_flags(PyObject *self, PyObject *_null)
30103007
if (sdl_flags & SDL_PREALLOC) {
30113008
flags |= PGS_PREALLOC;
30123009
}
3010+
/* This checks if RLE was requested on the surface */
30133011
if (PG_SurfaceHasRLE(surf)) {
30143012
flags |= PGS_RLEACCELOK;
30153013
}
3016-
// TODO SDL3: figure out how to properly emulate SDL2 check/relevance
3017-
// Current implementation is just a placeholder.
3018-
#if SDL_VERSION_ATLEAST(3, 0, 0)
3019-
if (SDL_SurfaceHasRLE(surf)) {
3020-
flags |= PGS_RLEACCEL;
3021-
}
3022-
#else
3023-
if ((sdl_flags & SDL_RLEACCEL)) {
3014+
/* this checks if the surface actually has RLE.
3015+
* On SDL2: SDL_MUSTLOCK is (flags & SDL_RLEACCEL) */
3016+
if (SDL_MUSTLOCK(surf)) {
30243017
flags |= PGS_RLEACCEL;
30253018
}
3026-
#endif
30273019
if (is_window_surf) {
30283020
if (window_flags & PG_WINDOW_FULLSCREEN_INCLUSIVE) {
30293021
flags |= PGS_FULLSCREEN;
@@ -3761,7 +3753,7 @@ surf_premul_alpha(pgSurfaceObject *self, PyObject *_null)
37613753

37623754
pgSurface_Prep(self);
37633755
// Make a copy of the surface first
3764-
newsurf = PG_ConvertSurface(surf, surf->format);
3756+
newsurf = PG_ConvertSurface(surf, surf);
37653757

37663758
if ((surf->w > 0 && surf->h > 0)) {
37673759
// If the surface has no pixels we don't need to premul
@@ -4455,6 +4447,76 @@ surface_do_overlap(SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *dst,
44554447
return dstoffset < span || dstoffset > src->pitch - span;
44564448
}
44574449

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

44724532
if (!PG_GetSurfaceClipRect(dst, &dstclip)) {
44734533
PyErr_SetString(pgExc_SDLError, SDL_GetError());
4474-
return 0;
4534+
return 1;
44754535
}
44764536

44774537
/* passthrough blits to the real surface */
@@ -4522,8 +4582,6 @@ pgSurface_Blit(pgSurfaceObject *dstobj, pgSurfaceObject *srcobj,
45224582
result = pygame_Blit(src, srcrect, dst, dstrect, blend_flags);
45234583
/* Py_END_ALLOW_THREADS */
45244584
}
4525-
// TODO SDL3: port the below bit of code. Skipping for initial surface port.
4526-
#if !SDL_VERSION_ATLEAST(3, 0, 0)
45274585
/* can't blit alpha to 8bit, crashes SDL */
45284586
else if (PG_SURF_BytesPerPixel(dst) == 1 &&
45294587
(SDL_ISPIXELFORMAT_ALPHA(PG_SURF_FORMATENUM(src)) ||
@@ -4533,59 +4591,53 @@ pgSurface_Blit(pgSurfaceObject *dstobj, pgSurfaceObject *srcobj,
45334591
result = pygame_Blit(src, srcrect, dst, dstrect, 0);
45344592
}
45354593
else {
4594+
#if SDL_VERSION_ATLEAST(3, 0, 0)
4595+
const SDL_PixelFormatDetails *fmt =
4596+
SDL_GetPixelFormatDetails(src->format);
4597+
src = fmt ? SDL_ConvertSurface(src,
4598+
SDL_GetPixelFormatForMasks(
4599+
fmt->bits_per_pixel, fmt->Rmask,
4600+
fmt->Gmask, fmt->Bmask, 0))
4601+
: NULL;
4602+
#else
45364603
SDL_PixelFormat *fmt = src->format;
45374604
SDL_PixelFormat *newfmt =
45384605
SDL_AllocFormat(SDL_MasksToPixelFormatEnum(
45394606
fmt->BitsPerPixel, fmt->Rmask, fmt->Gmask, fmt->Bmask, 0));
45404607
if (!newfmt) {
4541-
result = -1;
4608+
src = NULL;
45424609
}
45434610
else {
4544-
src = PG_ConvertSurface(src, newfmt);
4545-
4611+
src = SDL_ConvertSurface(src, newfmt, 0);
45464612
SDL_FreeFormat(newfmt);
4547-
if (src) {
4548-
#if SDL_VERSION_ATLEAST(3, 0, 0)
4549-
result =
4550-
SDL_BlitSurface(src, srcrect, dst, dstrect) ? 0 : -1;
4551-
#else
4552-
result = SDL_BlitSurface(src, srcrect, dst, dstrect);
4613+
}
45534614
#endif
4554-
SDL_FreeSurface(src);
4555-
}
4556-
else {
4557-
result = -1;
4558-
}
4615+
if (src) {
4616+
result = PG_BlitSurface(src, srcrect, dst, dstrect);
4617+
SDL_FreeSurface(src);
4618+
}
4619+
else {
4620+
result = -1;
45594621
}
45604622
}
45614623
/* Py_END_ALLOW_THREADS */
45624624
}
4563-
#endif
45644625
else if (blend_flags != PYGAME_BLEND_ALPHA_SDL2 &&
45654626
!(pg_EnvShouldBlendAlphaSDL2()) && !SDL_HasColorKey(src) &&
45664627
(PG_SURF_BytesPerPixel(dst) == 4 ||
45674628
PG_SURF_BytesPerPixel(dst) == 2) &&
45684629
_PgSurface_SrcAlpha(src) &&
45694630
(SDL_ISPIXELFORMAT_ALPHA(PG_SURF_FORMATENUM(src))) &&
45704631
!PG_SurfaceHasRLE(src) && !PG_SurfaceHasRLE(dst) &&
4571-
#if SDL_VERSION_ATLEAST(3, 0, 0)
4572-
1
4573-
#else
4574-
!(src->flags & SDL_RLEACCEL) && !(dst->flags & SDL_RLEACCEL)
4575-
#endif
4576-
) {
4632+
!SDL_MUSTLOCK(src) && !SDL_MUSTLOCK(dst)) {
45774633
/* If we have a 32bit source surface with per pixel alpha
45784634
and no RLE we'll use pygame_Blit so we can mimic how SDL1
45794635
behaved */
45804636
result = pygame_Blit(src, srcrect, dst, dstrect, blend_flags);
45814637
}
45824638
else {
45834639
/* Py_BEGIN_ALLOW_THREADS */
4584-
#if SDL_VERSION_ATLEAST(3, 0, 0)
4585-
result = SDL_BlitSurface(src, srcrect, dst, dstrect) ? 0 : -1;
4586-
#else
4587-
result = SDL_BlitSurface(src, srcrect, dst, dstrect);
4588-
#endif
4640+
result = PG_BlitSurface(src, srcrect, dst, dstrect);
45894641
/* Py_END_ALLOW_THREADS */
45904642
}
45914643

0 commit comments

Comments
 (0)