Skip to content

Conversation

ankith26
Copy link
Member

@ankith26 ankith26 commented Sep 1, 2025

  • A few abstractions were improved. PG_ConvertSurface now takes a surface as its second argument so it can copy the palette from it, to compat for the SDL2 path already doing it because there palette was part of the format. PG_GetSurfacePalette now creates a palette when the surface is indexed, SDL2 did it implicitly.
  • Added compat code for PG_BlitSurface because SDL3 doesn't modify dstrect anymore.

@ankith26 ankith26 requested a review from a team as a code owner September 1, 2025 14:20
Copy link
Contributor

coderabbitai bot commented Sep 1, 2025

📝 Walkthrough

Walkthrough

Replaces several surface-related macros with SDL-version-aware inline functions, unifies palette access via PG_GetSurfacePalette, changes conversion callsites to pass surfaces, adds PG_BlitSurface for SDL3-aware blitting, tweaks surface_fill error return, and corrects pgSurface_Blit docs.

Changes

Cohort / File(s) Change summary
Docs correction
docs/reST/c_api/surface.rst
Fixes pgSurface_Blit return semantics in docs: now states 0 on success and 1 on exception.
Core surface utilities (macros → inline)
src_c/_pygame.h
Replaces PG_ConvertSurface and PG_GetSurfacePalette macros with inline functions; adds palette-lazy creation for indexed formats; SDL2/SDL3-specific conversion implementations; updates PG_GetSurfaceDetails to use PG_GetSurfacePalette.
Blitting & SDL3 compatibility
src_c/surface.c
Adds PG_BlitSurface(...) wrapper for SDL3 clipping/dstrect semantics; refactors blit/conversion paths to pass surfaces rather than formats; uses SDL3 conversion APIs in SDL3 branches; adds declaration for PG_BlitSurface; minor error-return adjustments.
ConvertSurface callsite updates
src_c/draw.c, src_c/pixelarray_methods.c, src_c/surface.c
Call sites updated to pass destination SDL_Surface * instead of pixel-format pointers to PG_ConvertSurface; adjustments for SDL3 conversions where applicable.
Palette access unification
src_c/font.c, src_c/pixelcopy.c
Replaces conditional/versioned palette retrieval with uniform PG_GetSurfacePalette(surf) and adds null-safety checks before palette updates.
Surface fill error code
src_c/surface_fill.c
Default invalid-blend branch now calls SDL_SetError(...) and explicitly sets result = -1 (rather than assigning SDL_SetError’s return).
Tests
test/surface_test.py
Adds unittest.skipIf to two RLE-related tests for specific SDL version ranges that were briefly broken on SDL3/compat.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant App as Caller
  participant PB as PG_BlitSurface
  participant SDL as SDL

  App->>PB: PG_BlitSurface(src, srcrect, dst, dstrect)
  alt SDL3
    PB->>PB: adjust/clip dstrect (SDL3 semantics)
    PB->>SDL: SDL_BlitSurface(src, srcrect, dst, dstrect)
    SDL-->>PB: status
  else SDL2
    PB->>SDL: SDL_BlitSurface(src, srcrect, dst, dstrect)
    SDL-->>PB: status (may modify dstrect)
  end
  PB-->>App: 0 on success, non-zero on error
Loading
sequenceDiagram
  autonumber
  participant Call as Caller
  participant PC as PG_ConvertSurface
  participant SDL as SDL

  Call->>PC: PG_ConvertSurface(surface, dst_surface)
  alt SDL3
    PC->>SDL: SDL_ConvertSurfaceAndColorspace(surface, dst->format, dst->palette, dst->colorspace)
  else SDL2
    PC->>SDL: SDL_ConvertSurface(surface, dst->format, 0)
  end
  SDL-->>PC: converted_surface or NULL
  PC-->>Call: converted_surface or NULL
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

Surface, font, draw

Suggested reviewers

  • Starbuck5
  • MyreMylar
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch ankith26-sdl3-3

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
src_c/draw.c (1)

1334-1346: Fix memory leak and lock the converted pattern surface correctly

  • pattern is a newly allocated surface from PG_ConvertSurface and is never freed.
  • The lock/unlock uses pgSurface_Lock/Unlock on pat_surfobj, which does not lock pattern. Use SDL_LockSurface/SDL_UnlockSurface on pattern instead.

Apply:

@@
-        pattern = PG_ConvertSurface(pat_surfobj->surf, surf);
+        pattern = PG_ConvertSurface(pat_surfobj->surf, surf);
@@
-        SDL_SetSurfaceRLE(pattern, SDL_FALSE);
+        SDL_SetSurfaceRLE(pattern, SDL_FALSE);
@@
-    if (pattern && SDL_MUSTLOCK(pattern)) {
-        did_lock_pat = SDL_TRUE;
-        if (!pgSurface_Lock(pat_surfobj)) {
-            if (did_lock_surf) {
-                pgSurface_Unlock(surfobj);
-            }
-            return RAISE(PyExc_RuntimeError, "error locking pattern surface");
-        }
-    }
+    if (pattern && SDL_MUSTLOCK(pattern)) {
+        did_lock_pat = SDL_TRUE;
+        if (SDL_LockSurface(pattern) != 0) {
+            if (did_lock_surf) {
+                pgSurface_Unlock(surfobj);
+            }
+            SDL_FreeSurface(pattern);
+            return RAISE(PyExc_RuntimeError, "error locking pattern surface");
+        }
+    }
@@
-    /* no allocated pattern surface to free */
-
-    if (did_lock_pat) {
-        if (!pgSurface_Unlock(pat_surfobj)) {
-            if (did_lock_surf) {
-                pgSurface_Unlock(surfobj);
-            }
-            return RAISE(PyExc_RuntimeError,
-                         "error unlocking pattern surface");
-        }
-    }
+    if (did_lock_pat) {
+        SDL_UnlockSurface(pattern);
+    }
     if (did_lock_surf) {
-        if (!pgSurface_Unlock(surfobj)) {
-            return RAISE(PyExc_RuntimeError, "error unlocking surface");
-        }
+        if (!pgSurface_Unlock(surfobj)) {
+            if (pattern) {
+                SDL_FreeSurface(pattern);
+            }
+            return RAISE(PyExc_RuntimeError, "error unlocking surface");
+        }
     }
 
+    /* free the temporary converted pattern surface */
+    if (pattern) {
+        SDL_FreeSurface(pattern);
+        pattern = NULL;
+    }
@@
-    if (flood_fill_result == -1) {
+    if (flood_fill_result == -1) {
         return NULL; /* error already set by flood_fill_inner */
     }

Also applies to: 1361-1369, 1376-1384, 1385-1389, 1391-1394

src_c/pixelarray_methods.c (1)

161-168: Locking logic inverted: pixels may be written without required lock

new_surf pixels are accessed below, but the code locks when SDL_MUSTLOCK(new_surf) == 0 and skips locking when it’s required. This is a pre-existing issue, not introduced here, but it can cause undefined behavior on RLE-accelerated surfaces.

Apply:

-    /* Acquire a temporary lock. */
-    if (SDL_MUSTLOCK(new_surf) == 0) {
-        SDL_LockSurface(new_surf);
-    }
+    /* Acquire a temporary lock if required. */
+    if (SDL_MUSTLOCK(new_surf)) {
+        SDL_LockSurface(new_surf);
+    }
@@
-    if (SDL_MUSTLOCK(new_surf) == 0) {
-        SDL_UnlockSurface(new_surf);
-    }
+    if (SDL_MUSTLOCK(new_surf)) {
+        SDL_UnlockSurface(new_surf);
+    }

Given the PR’s SDL3-compat scope, feel free to land this in a follow-up if you prefer to keep this diff minimal.

Also applies to: 240-243

src_c/surface.c (1)

1793-1804: Prevent NULL deref when conversion fails.

SDL_ConvertSurfaceAndColorspace may fail; SDL_SetSurfaceBlendMode(newsurf, …) is called unconditionally and can crash.

Apply:

-            SDL_SetSurfaceBlendMode(newsurf, SDL_BLENDMODE_NONE);
+            if (newsurf) {
+                SDL_SetSurfaceBlendMode(newsurf, SDL_BLENDMODE_NONE);
+            }
🧹 Nitpick comments (2)
src_c/_pygame.h (1)

116-126: Clarify the comment to avoid confusion about “24-bit images.”

The intent is to preserve SDL2’s 32 bpp reporting for formats stored in 4 bytes per pixel. Suggest wording-only tweak.

-        /* Compat with SDL2: for 24-bit images SDL3 returns 24 when SDL2
-         * returned 32 */
+        /* Compat with SDL2: some 24-bit formats are stored in 4 bytes/pixel
+         * (e.g., RGB888). SDL3 reports 24 bits for these, whereas SDL2
+         * reported 32. Preserve SDL2 behavior when BytesPerPixel == 4. */
src_c/draw.c (1)

1361-1369: Optional: remove did_lock_pat entirely if RLE is disabled

Since SDL_SetSurfaceRLE(pattern, SDL_FALSE) guarantees SDL_MUSTLOCK(pattern) is false, the extra lock branch is redundant. You can simplify by dropping it. Your call.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between c7e9c15 and 9ad82e8.

📒 Files selected for processing (8)
  • docs/reST/c_api/surface.rst (1 hunks)
  • src_c/_pygame.h (4 hunks)
  • src_c/draw.c (1 hunks)
  • src_c/font.c (1 hunks)
  • src_c/pixelarray_methods.c (1 hunks)
  • src_c/pixelcopy.c (1 hunks)
  • src_c/surface.c (10 hunks)
  • src_c/surface_fill.c (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: Starbuck5
PR: pygame-community/pygame-ce#3573
File: src_c/_camera.c:129-131
Timestamp: 2025-08-30T21:11:00.196Z
Learning: When doing SDL2 to SDL3 compatibility changes, Starbuck5 prefers to maintain exact existing behaviors even when other improvements could be made, focusing solely on the compatibility aspect rather than mixing in behavioral fixes.
🧬 Code graph analysis (5)
src_c/pixelarray_methods.c (1)
src_c/_pygame.h (2)
  • PG_ConvertSurface (82-88)
  • PG_ConvertSurface (226-230)
src_c/font.c (1)
src_c/_pygame.h (2)
  • PG_GetSurfacePalette (139-149)
  • PG_GetSurfacePalette (283-287)
src_c/pixelcopy.c (1)
src_c/_pygame.h (2)
  • PG_GetSurfacePalette (139-149)
  • PG_GetSurfacePalette (283-287)
src_c/draw.c (1)
src_c/_pygame.h (2)
  • PG_ConvertSurface (82-88)
  • PG_ConvertSurface (226-230)
src_c/surface.c (1)
src_c/_pygame.h (2)
  • PG_ConvertSurface (82-88)
  • PG_ConvertSurface (226-230)
🔇 Additional comments (16)
docs/reST/c_api/surface.rst (1)

59-60: Ensure pgSurface_Blit only returns 0 or 1
All branches in the C API’s pgSurface_Blit implementation (src_c/surface.c around its definition) must return 0 on success and 1 on exception. Manually inspect every return in that function to confirm there are no stray -1 or SDL error codes leaking through.

src_c/surface_fill.c (1)

1146-1148: Good: don’t rely on SDL_SetError’s return value.

Explicitly setting result = -1 is clearer and avoids potential API drift. LGTM.

src_c/_pygame.h (4)

139-150: LGTM: lazy palette creation matches SDL2-era expectations.

Creating a palette for indexed formats when missing restores implicit SDL2 behavior and should reduce surprises at call sites.


226-231: LGTM: SDL2 wrapper keeps prior behavior.

Passing dst->format into SDL_ConvertSurface maintains the old conversion semantics on SDL2.


155-158: Audit callers of PG_GetSurfaceDetails for null-palette handling. PG_GetSurfaceDetails may return true with *palette_p == NULL (e.g. non-indexed formats or allocation failure)—ensure no caller dereferences SDL_Palette *palette without first checking for NULL.


81-89: SDL3 API names and parameter order are correct
The wrapper matches SDL3’s signatures—SDL_ConvertSurfaceAndColorspace takes (SDL_Surface*, SDL_PixelFormat, SDL_Palette*, SDL_Colorspace, SDL_PropertiesID), and the getter is correctly named SDL_GetSurfaceColorspace(SDL_Surface*). No changes needed.

src_c/pixelcopy.c (1)

1200-1210: Unify palette access via PG_GetSurfacePalette — looks good

The switch to PG_GetSurfacePalette(surf) matches the new SDL3-compatible helper and keeps behavior for indexed formats. Safe under both SDL2 and SDL3.

src_c/font.c (1)

718-726: Use PG_GetSurfacePalette for SDL2/SDL3 parity — good change

Centralizes palette access and allows lazy creation on indexed surfaces; guarded by a null check before writes. No behavioral regressions expected.

src_c/pixelarray_methods.c (2)

139-147: Correct PG_ConvertSurface call site — destination is the surface, not its format

Matches the new inline API and ensures colorspace/palette are taken from the destination surface.


139-147: No lingering PG_ConvertSurface(...->format) call sites. All existing calls now pass SDL_Surface pointers only—no instances of the old ->format signature remain.

src_c/surface.c (6)

1626-1626: LGTM: copy via PG_ConvertSurface(surf, surf).

Passing the dest surface to copy palette/format is correct for SDL3.


1683-1688: LGTM: convert-to-surface path uses PG_ConvertSurface.

Using the destination surface to derive format/palette matches the new helper.

Also applies to: 1840-1841


1965-1965: LGTM: SDL2 branch calls SDL_ConvertSurface with flags=0.


3771-3771: LGTM: premul path copies via PG_ConvertSurface before modifying.


4546-4549: Return-path change acknowledged.

Returning 1 on PG_GetSurfaceClipRect failure matches the function’s “non-zero error” convention.

Please confirm downstream callers don’t rely on distinguishing -1 vs 1 here.


4639-4641: LGTM contingent on PG_BlitSurface fix.

Switching to PG_BlitSurface is correct for SDL3 as long as the wrapper passes the adjusted rects and return code.

Once the wrapper fix lands, please run a quick blit test to ensure dstrect returned from Surface.blit reflects clipping like SDL2 did.

Also applies to: 4668-4669

@Starbuck5 Starbuck5 added the sdl3 label Sep 1, 2025
@ankith26 ankith26 marked this pull request as draft September 3, 2025 15:54
@ankith26 ankith26 marked this pull request as ready for review September 3, 2025 16:32
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (3)
src_c/surface.c (2)

4456-4524: Fix PG_BlitSurface (SDL3): wrong return code, wrong rects, missing src adjust on dst clip

  • Inverts SDL_BlitSurface return (success reported as -1).
  • Calls SDL_BlitSurface with original srcrect/dstrect instead of computed r_src/r_dst.
  • Doesn’t adjust r_src when r_dst is clipped.
 int
 PG_BlitSurface(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst,
                SDL_Rect *dstrect)
 {
 #if SDL_VERSION_ATLEAST(3, 0, 0)
-    /* SDL3 doesn't modify dstrect, so compat for that.
-     * Below logic taken from SDL2 source with slight modifications */
-    SDL_Rect r_src, r_dst;
-
-    r_src.x = 0;
-    r_src.y = 0;
-    r_src.w = src->w;
-    r_src.h = src->h;
-
-    if (dstrect) {
-        r_dst.x = dstrect->x;
-        r_dst.y = dstrect->y;
-    }
-    else {
-        r_dst.x = 0;
-        r_dst.y = 0;
-    }
-
-    /* clip the source rectangle to the source surface */
-    if (srcrect) {
-        SDL_Rect tmp;
-        if (SDL_IntersectRect(srcrect, &r_src, &tmp) == SDL_FALSE) {
-            goto end;
-        }
-
-        /* Shift dstrect, if srcrect origin has changed */
-        r_dst.x += tmp.x - srcrect->x;
-        r_dst.y += tmp.y - srcrect->y;
-
-        /* Update srcrect */
-        r_src = tmp;
-    }
-
-    /* There're no dstrect.w/h parameters. It's the same as srcrect */
-    r_dst.w = r_src.w;
-    r_dst.h = r_src.h;
-
-    /* clip the destination rectangle against the clip rectangle */
-    {
-        SDL_Rect tmp, clip_rect;
-        SDL_GetSurfaceClipRect(dst, &clip_rect);
-        if (SDL_IntersectRect(&r_dst, &clip_rect, &tmp) == SDL_FALSE) {
-            goto end;
-        }
-
-        /* Update dstrect */
-        r_dst = tmp;
-    }
-
-    if (r_dst.w > 0 && r_dst.h > 0) {
-        if (dstrect) { /* update output parameter */
-            *dstrect = r_dst;
-        }
-        return SDL_BlitSurface(src, srcrect, dst, dstrect) ? 0 : -1;
-    }
-end:
-    if (dstrect) {
-        dstrect->w = dstrect->h = 0;
-    }
-    return 0;
+    /* SDL3 doesn't modify dstrect; emulate SDL2 behavior. */
+    SDL_Rect r_src = {0, 0, src->w, src->h};
+    SDL_Rect r_dst = {0, 0, 0, 0};
+    SDL_Rect tmp, clip_rect;
+    int old_dst_x, old_dst_y;
+
+    if (dstrect) {
+        r_dst.x = dstrect->x;
+        r_dst.y = dstrect->y;
+    }
+    /* Clip source to source surface if srcrect provided */
+    if (srcrect) {
+        if (SDL_IntersectRect(srcrect, &r_src, &tmp) == SDL_FALSE) {
+            goto end_zero;
+        }
+        /* Shift dst if srcrect origin changed */
+        r_dst.x += tmp.x - srcrect->x;
+        r_dst.y += tmp.y - srcrect->y;
+        r_src = tmp;
+    }
+    /* dst size follows source size */
+    r_dst.w = r_src.w;
+    r_dst.h = r_src.h;
+
+    /* Clip destination to its clip rect and adjust source accordingly */
+    SDL_GetSurfaceClipRect(dst, &clip_rect);
+    old_dst_x = r_dst.x;
+    old_dst_y = r_dst.y;
+    if (SDL_IntersectRect(&r_dst, &clip_rect, &tmp) == SDL_FALSE) {
+        goto end_zero;
+    }
+    /* Adjust source by how much destination was moved */
+    r_src.x += tmp.x - old_dst_x;
+    r_src.y += tmp.y - old_dst_y;
+    r_src.w = tmp.w;
+    r_src.h = tmp.h;
+    r_dst = tmp;
+
+    /* Perform blit; propagate final dstrect to caller */
+    {
+        int rc = SDL_BlitSurface(src, &r_src, dst, &r_dst);
+        if (dstrect) {
+            *dstrect = r_dst;
+        }
+        return rc;  /* 0 on success, -1 on error */
+    }
+end_zero:
+    if (dstrect) {
+        dstrect->w = 0;
+        dstrect->h = 0;
+    }
+    return 0;
 #else
     return SDL_BlitSurface(src, srcrect, dst, dstrect);
 #endif
 }

4601-4609: SDL3 SDL_ConvertSurface missing flags argument

Pass the third flags parameter (0) to match SDL3 signature.

-            src = fmt ? SDL_ConvertSurface(src,
-                                           SDL_GetPixelFormatForMasks(
-                                               fmt->bits_per_pixel, fmt->Rmask,
-                                               fmt->Gmask, fmt->Bmask, 0))
+            src = fmt ? SDL_ConvertSurface(
+                           src,
+                           SDL_GetPixelFormatForMasks(fmt->bits_per_pixel,
+                                                      fmt->Rmask, fmt->Gmask,
+                                                      fmt->Bmask, 0),
+                           0)
                        : NULL;
test/surface_test.py (1)

412-416: Apply the same version-gating helper here

Mirror the change made above to avoid duplicating the tuple ranges.

-    @unittest.skipIf(
-        (2, 32, 50) <= pygame.version.SDL <= (2, 32, 56)
-        or (3, 0, 0) <= pygame.version.SDL <= (3, 2, 22),
-        "This test was briefly broken on SDL3 (and sdl2-compat) but got fixed.",
-    )
+    @unittest.skipIf(
+        _is_rle_regression_sdl(),
+        "Skip due to SDL RLE regression: affected SDL versions 2.32.50–2.32.56 and 3.0.0–3.2.22.",
+    )
🧹 Nitpick comments (2)
src_c/surface.c (1)

1547-1555: RLE strip hack looks fine

Rect init order is unconventional (h before w) but harmless. No functional concerns.

test/surface_test.py (1)

379-383: Consolidate SDL version gating and clarify range in skip message

Tuple comparisons are fine, but inlining the ranges twice is brittle. Factor the predicate into a small helper and reuse it. Also make the skip reason state the exact affected ranges for CI clarity.

Apply this diff to the decorator:

-    @unittest.skipIf(
-        (2, 32, 50) <= pygame.version.SDL <= (2, 32, 56)
-        or (3, 0, 0) <= pygame.version.SDL <= (3, 2, 22),
-        "This test was briefly broken on SDL3 (and sdl2-compat) but got fixed.",
-    )
+    @unittest.skipIf(
+        _is_rle_regression_sdl(),
+        "Skip due to SDL RLE regression: affected SDL versions 2.32.50–2.32.56 and 3.0.0–3.2.22.",
+    )

Add this helper near the imports (module scope):

def _is_rle_regression_sdl() -> bool:
    v = pygame.version.SDL
    return ((2, 32, 50) <= v <= (2, 32, 56)) or ((3, 0, 0) <= v <= (3, 2, 22))
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 9ad82e8 and 14eafac.

📒 Files selected for processing (9)
  • docs/reST/c_api/surface.rst (1 hunks)
  • src_c/_pygame.h (3 hunks)
  • src_c/draw.c (1 hunks)
  • src_c/font.c (1 hunks)
  • src_c/pixelarray_methods.c (1 hunks)
  • src_c/pixelcopy.c (1 hunks)
  • src_c/surface.c (12 hunks)
  • src_c/surface_fill.c (1 hunks)
  • test/surface_test.py (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • src_c/pixelarray_methods.c
  • src_c/font.c
  • docs/reST/c_api/surface.rst
  • src_c/draw.c
  • src_c/surface_fill.c
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: Starbuck5
PR: pygame-community/pygame-ce#3573
File: src_c/_pygame.h:108-133
Timestamp: 2025-09-01T20:18:57.470Z
Learning: In pygame-ce PR #3573, PG_SURF_BitsPerPixel was changed from a simple macro to a static inline function to handle SDL2/SDL3 differences. SDL2's BitsPerPixel includes padding bits (e.g., RGBX => 32) while SDL3's SDL_BITSPERPIXEL excludes padding (e.g., RGBX => 24). The new implementation bridges this gap rather than removing the helper entirely.
Learnt from: Starbuck5
PR: pygame-community/pygame-ce#3573
File: src_c/_pygame.h:115-126
Timestamp: 2025-09-01T20:22:30.959Z
Learning: In pygame-ce PR #3573, the PG_SURF_BitsPerPixel function implementation uses hardcoded return values of 32 for YUY2/UYVY/YVYU FOURCC formats because it's copying the exact logic from SDL's internal SDL_GetMasksForPixelFormat function. This ensures perfect compatibility between SDL2 and SDL3 behaviors rather than using the technically more accurate values that might be returned by SDL_GetPixelFormatDetails.
📚 Learning: 2025-09-01T20:18:57.470Z
Learnt from: Starbuck5
PR: pygame-community/pygame-ce#3573
File: src_c/_pygame.h:108-133
Timestamp: 2025-09-01T20:18:57.470Z
Learning: In pygame-ce PR #3573, PG_SURF_BitsPerPixel was changed from a simple macro to a static inline function to handle SDL2/SDL3 differences. SDL2's BitsPerPixel includes padding bits (e.g., RGBX => 32) while SDL3's SDL_BITSPERPIXEL excludes padding (e.g., RGBX => 24). The new implementation bridges this gap rather than removing the helper entirely.

Applied to files:

  • src_c/pixelcopy.c
  • test/surface_test.py
  • src_c/surface.c
  • src_c/_pygame.h
📚 Learning: 2025-09-01T20:22:30.959Z
Learnt from: Starbuck5
PR: pygame-community/pygame-ce#3573
File: src_c/_pygame.h:115-126
Timestamp: 2025-09-01T20:22:30.959Z
Learning: In pygame-ce PR #3573, the PG_SURF_BitsPerPixel function implementation uses hardcoded return values of 32 for YUY2/UYVY/YVYU FOURCC formats because it's copying the exact logic from SDL's internal SDL_GetMasksForPixelFormat function. This ensures perfect compatibility between SDL2 and SDL3 behaviors rather than using the technically more accurate values that might be returned by SDL_GetPixelFormatDetails.

Applied to files:

  • src_c/pixelcopy.c
  • src_c/surface.c
  • src_c/_pygame.h
📚 Learning: 2025-08-30T21:11:00.196Z
Learnt from: Starbuck5
PR: pygame-community/pygame-ce#3573
File: src_c/_camera.c:129-131
Timestamp: 2025-08-30T21:11:00.196Z
Learning: When doing SDL2 to SDL3 compatibility changes, Starbuck5 prefers to maintain exact existing behaviors even when other improvements could be made, focusing solely on the compatibility aspect rather than mixing in behavioral fixes.

Applied to files:

  • src_c/surface.c
🧬 Code graph analysis (2)
src_c/pixelcopy.c (1)
src_c/_pygame.h (2)
  • PG_GetSurfacePalette (154-164)
  • PG_GetSurfacePalette (298-302)
src_c/surface.c (2)
src_c/_pygame.h (2)
  • PG_ConvertSurface (82-88)
  • PG_ConvertSurface (241-245)
src_c/alphablit.c (1)
  • pygame_Blit (1582-1687)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: debug_coverage (ubuntu-24.04, 3.14.0rc1)
  • GitHub Check: build (ubuntu-22.04)
  • GitHub Check: x86
  • GitHub Check: Debian (Bookworm - 12) [armv7]
  • GitHub Check: dev-check
🔇 Additional comments (11)
src_c/_pygame.h (3)

154-165: Lazy palette creation for indexed surfaces: LGTM

Creates a palette on-demand for indexed formats, aligning SDL3 with SDL2 expectations.


166-173: Use new PG_GetSurfacePalette in details helper: LGTM

Ensures callers consistently obtain a palette where applicable.


241-246: SDL2 inline PG_ConvertSurface wrapper: LGTM

Correct flags usage and format sourcing.

src_c/surface.c (7)

1623-1624: Copy via PG_ConvertSurface: LGTM

Copies format/palette/colorspace from source surface as intended.


1684-1684: Convert-to-surface signature: LGTM

Passing the destination surface to copy its format/palette is correct.


1837-1838: SDL2 convert-to-surface path: LGTM

Keeps parity with SDL3 surface-based conversion.


1962-1962: SDL2 newfmt convert: LGTM

Includes required flags argument (0); OK.


2200-2206: Normalize SDL2/SDL3 fill return to -1/0

Subtracting 1 standardizes error to -1. Verify PG_FillSurfaceRect returns 1/0 across both versions in all build configs.


3017-3024: RLE flags reporting across SDL2/SDL3

PG_SurfaceHasRLE indicates requested RLE; SDL_MUSTLOCK is used here to infer active RLE. Double-check SDL3’s SDL_MUSTLOCK semantics so PGS_RLEACCEL isn’t set spuriously on non-RLE surfaces.


4647-4656: Fast-path pygame_Blit vs PG_BlitSurface split: LGTM (after PG_BlitSurface fix)

Once PG_BlitSurface is corrected, these paths will produce correct rects and errors.

src_c/pixelcopy.c (1)

1201-1210: Unified palette access in make_surface: LGTM

PG_GetSurfacePalette ensures an attached palette for INDEX8, matching the new helper’s contract.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants