Skip to content

Commit de289b4

Browse files
committed
SDL3: surface+pixelarray+font: runtime fixes
1 parent 3a17519 commit de289b4

File tree

7 files changed

+135
-45
lines changed

7 files changed

+135
-45
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: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,17 @@
7777

7878
#define PG_CreateSurface SDL_CreateSurface
7979
#define PG_CreateSurfaceFrom SDL_CreateSurfaceFrom
80-
#define PG_ConvertSurface SDL_ConvertSurface
8180
#define PG_ConvertSurfaceFormat SDL_ConvertSurface
8281

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

8593
#define PG_SurfaceHasRLE SDL_SurfaceHasRLE
@@ -106,7 +114,17 @@ PG_UnlockMutex(SDL_mutex *mutex)
106114
return 0;
107115
}
108116

109-
#define PG_SURF_BitsPerPixel(surf) SDL_BITSPERPIXEL(surf->format)
117+
static inline int
118+
PG_SURF_BitsPerPixel(SDL_Surface *surf)
119+
{
120+
if (SDL_BYTESPERPIXEL(surf->format) == 4) {
121+
/* Compat with SDL2: for 24-bit images SDL3 returns 24 when SDL2
122+
* returned 32 */
123+
return 32;
124+
}
125+
return SDL_BITSPERPIXEL(surf->format);
126+
}
127+
110128
#define PG_SURF_BytesPerPixel(surf) SDL_BYTESPERPIXEL(surf->format)
111129
#define PG_FORMAT_BitsPerPixel(format) format->bits_per_pixel
112130
#define PG_FORMAT_BytesPerPixel(format) format->bytes_per_pixel
@@ -119,11 +137,23 @@ PG_UnlockMutex(SDL_mutex *mutex)
119137

120138
#define PG_PixelFormat const SDL_PixelFormatDetails
121139

140+
static inline SDL_Palette *
141+
PG_GetSurfacePalette(SDL_Surface *surf)
142+
{
143+
SDL_Palette *ret = SDL_GetSurfacePalette(surf);
144+
if (!ret && SDL_ISPIXELFORMAT_INDEXED(surf->format)) {
145+
/* Palette doesn't exist but is expected, so create it.
146+
* SDL will associate the newly created palette with the surface */
147+
ret = SDL_CreateSurfacePalette(surf);
148+
}
149+
return ret;
150+
}
151+
122152
static inline bool
123153
PG_GetSurfaceDetails(SDL_Surface *surf, PG_PixelFormat **format_p,
124154
SDL_Palette **palette_p)
125155
{
126-
*palette_p = SDL_GetSurfacePalette(surf);
156+
*palette_p = PG_GetSurfacePalette(surf);
127157
*format_p = SDL_GetPixelFormatDetails(surf->format);
128158
return *format_p != NULL;
129159
}
@@ -134,7 +164,6 @@ PG_GetSurfaceFormat(SDL_Surface *surf)
134164
return SDL_GetPixelFormatDetails(surf->format);
135165
}
136166

137-
#define PG_GetSurfacePalette SDL_GetSurfacePalette
138167
#define PG_SetPaletteColors SDL_SetPaletteColors
139168
#define PG_SetSurfacePalette SDL_SetSurfacePalette
140169
#define PG_SetSurfaceColorKey SDL_SetSurfaceColorKey
@@ -188,10 +217,15 @@ PG_GetSurfaceFormat(SDL_Surface *surf)
188217
SDL_CreateRGBSurfaceWithFormat(0, width, height, 0, format)
189218
#define PG_CreateSurfaceFrom(width, height, format, pixels, pitch) \
190219
SDL_CreateRGBSurfaceWithFormatFrom(pixels, width, height, 0, pitch, format)
191-
#define PG_ConvertSurface(src, fmt) SDL_ConvertSurface(src, fmt, 0)
192220
#define PG_ConvertSurfaceFormat(src, pixel_format) \
193221
SDL_ConvertSurfaceFormat(src, pixel_format, 0)
194222

223+
static inline SDL_Surface *
224+
PG_ConvertSurface(SDL_Surface *surface, SDL_Surface *dst)
225+
{
226+
return SDL_ConvertSurface(surface, dst->format, 0);
227+
}
228+
195229
#define PG_PixelFormatEnum SDL_PixelFormatEnum
196230

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

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: 90 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1623,7 +1623,7 @@ surf_copy(pgSurfaceObject *self, PyObject *_null)
16231623
SURF_INIT_CHECK(surf)
16241624

16251625
pgSurface_Prep(self);
1626-
newsurf = PG_ConvertSurface(surf, surf->format);
1626+
newsurf = PG_ConvertSurface(surf, surf);
16271627
pgSurface_Unprep(self);
16281628

16291629
final = surf_subtype_new(Py_TYPE(self), newsurf, 1);
@@ -1683,7 +1683,7 @@ surf_convert(pgSurfaceObject *self, PyObject *args)
16831683
if (argobject) {
16841684
if (pgSurface_Check(argobject)) {
16851685
src = pgSurface_AsSurface(argobject);
1686-
newsurf = PG_ConvertSurface(surf, src->format);
1686+
newsurf = PG_ConvertSurface(surf, src);
16871687
}
16881688
else {
16891689
/* will be updated later, initialize to make static analyzer happy
@@ -1837,7 +1837,7 @@ surf_convert(pgSurfaceObject *self, PyObject *args)
18371837
if (argobject) {
18381838
if (pgSurface_Check(argobject)) {
18391839
src = pgSurface_AsSurface(argobject);
1840-
newsurf = PG_ConvertSurface(surf, src->format);
1840+
newsurf = PG_ConvertSurface(surf, src);
18411841
}
18421842
else {
18431843
/* will be updated later, initialize to make static analyzer happy
@@ -1961,7 +1961,7 @@ surf_convert(pgSurfaceObject *self, PyObject *args)
19611961
SDL_SetPixelFormatPalette(&format, palette);
19621962
}
19631963
}
1964-
newsurf = PG_ConvertSurface(surf, &format);
1964+
newsurf = SDL_ConvertSurface(surf, &format, 0);
19651965
SDL_SetSurfaceBlendMode(newsurf, SDL_BLENDMODE_NONE);
19661966
SDL_FreePalette(palette);
19671967
}
@@ -3767,7 +3767,7 @@ surf_premul_alpha(pgSurfaceObject *self, PyObject *_null)
37673767

37683768
pgSurface_Prep(self);
37693769
// Make a copy of the surface first
3770-
newsurf = PG_ConvertSurface(surf, surf->format);
3770+
newsurf = PG_ConvertSurface(surf, surf);
37713771

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

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

44784546
if (!PG_GetSurfaceClipRect(dst, &dstclip)) {
44794547
PyErr_SetString(pgExc_SDLError, SDL_GetError());
4480-
return 0;
4548+
return 1;
44814549
}
44824550

44834551
/* passthrough blits to the real surface */
@@ -4528,8 +4596,6 @@ pgSurface_Blit(pgSurfaceObject *dstobj, pgSurfaceObject *srcobj,
45284596
result = pygame_Blit(src, srcrect, dst, dstrect, blend_flags);
45294597
/* Py_END_ALLOW_THREADS */
45304598
}
4531-
// TODO SDL3: port the below bit of code. Skipping for initial surface port.
4532-
#if !SDL_VERSION_ATLEAST(3, 0, 0)
45334599
/* can't blit alpha to 8bit, crashes SDL */
45344600
else if (PG_SURF_BytesPerPixel(dst) == 1 &&
45354601
(SDL_ISPIXELFORMAT_ALPHA(PG_SURF_FORMATENUM(src)) ||
@@ -4539,17 +4605,22 @@ pgSurface_Blit(pgSurfaceObject *dstobj, pgSurfaceObject *srcobj,
45394605
result = pygame_Blit(src, srcrect, dst, dstrect, 0);
45404606
}
45414607
else {
4608+
#if SDL_VERSION_ATLEAST(3, 0, 0)
4609+
const SDL_PixelFormatDetails *fmt =
4610+
SDL_GetPixelFormatDetails(src->format);
4611+
src = fmt ? SDL_ConvertSurface(src,
4612+
SDL_GetPixelFormatForMasks(
4613+
fmt->bits_per_pixel, fmt->Rmask,
4614+
fmt->Gmask, fmt->Bmask, 0))
4615+
: NULL;
4616+
4617+
#else
45424618
SDL_PixelFormat *fmt = src->format;
45434619
SDL_PixelFormat newfmt;
45444620

45454621
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
45504622
newfmt.BitsPerPixel = fmt->BitsPerPixel;
45514623
newfmt.BytesPerPixel = fmt->BytesPerPixel;
4552-
#endif
45534624
newfmt.Amask = 0;
45544625
newfmt.Rmask = fmt->Rmask;
45554626
newfmt.Gmask = fmt->Gmask;
@@ -4562,13 +4633,10 @@ pgSurface_Blit(pgSurfaceObject *dstobj, pgSurfaceObject *srcobj,
45624633
newfmt.Rloss = fmt->Rloss;
45634634
newfmt.Gloss = fmt->Gloss;
45644635
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);
4636+
src = SDL_ConvertSurface(src, &newfmt, 0);
45714637
#endif
4638+
if (src) {
4639+
result = PG_BlitSurface(src, srcrect, dst, dstrect);
45724640
SDL_FreeSurface(src);
45734641
}
45744642
else {
@@ -4577,7 +4645,6 @@ pgSurface_Blit(pgSurfaceObject *dstobj, pgSurfaceObject *srcobj,
45774645
}
45784646
/* Py_END_ALLOW_THREADS */
45794647
}
4580-
#endif
45814648
else if (blend_flags != PYGAME_BLEND_ALPHA_SDL2 &&
45824649
!(pg_EnvShouldBlendAlphaSDL2()) && !SDL_HasColorKey(src) &&
45834650
(PG_SURF_BytesPerPixel(dst) == 4 ||
@@ -4598,11 +4665,7 @@ pgSurface_Blit(pgSurfaceObject *dstobj, pgSurfaceObject *srcobj,
45984665
}
45994666
else {
46004667
/* 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
4668+
result = PG_BlitSurface(src, srcrect, dst, dstrect);
46064669
/* Py_END_ALLOW_THREADS */
46074670
}
46084671

src_c/surface_fill.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1143,7 +1143,8 @@ surface_fill_blend(SDL_Surface *surface, SDL_Rect *rect, Uint32 color,
11431143
}
11441144

11451145
default: {
1146-
result = SDL_SetError("invalid blend flag for this operation");
1146+
SDL_SetError("invalid blend flag for this operation");
1147+
result = -1;
11471148
break;
11481149
}
11491150
}

0 commit comments

Comments
 (0)