Skip to content

Conversation

Starbuck5
Copy link
Member

@Starbuck5 Starbuck5 commented Aug 30, 2025

It's inconsistent between SDL2 and SDL3, and I see no way to fix it.

EDIT: looked into the source code and looked at how the pixelformat bpp gets populated, in both SDL2 and SDL3, and took the SDL3 implementation to implement here.

In SDL2, (surf->format->BitsPerPixel), the value means the number of bits each pixel occupies in total. For example, RGBX => 32.

In SDL3, (SDL_BITSPERPIXEL(surf->format)), the value means the number of pixels occupied by the pixel's data, not including padding. So RGBX => 24.

These changes reduce SDL3 unit test failures.

Before (w/o mixer tests):
Overall: FAILED (failures=39, errors=47)
Transform: FAILED (failures=4, errors=5)
Surface: FAILED (failures=12, errors=3, skipped=2)

After (still w/o mixer tests):
Overall: FAILED (failures=31, errors=46)
Transform: FAILED (errors=5)
Surface: FAILED (failures=11, errors=3, skipped=2)

@Starbuck5 Starbuck5 requested a review from a team as a code owner August 30, 2025 20:59
@Starbuck5 Starbuck5 added Surface pygame.Surface sdl3 labels Aug 30, 2025
Copy link
Contributor

coderabbitai bot commented Aug 30, 2025

📝 Walkthrough

Walkthrough

Replaced the SDL3-path PG_SURF_BitsPerPixel surface macro with a static inline function that computes bits-per-pixel with conditional handling for FourCC formats (YUY2/UYVY/YVYU → 32, other FourCC → 0) and byte-based fallbacks; other related macros unchanged.

Changes

Cohort / File(s) Summary
SDL3 surface BitsPerPixel computation
src_c/_pygame.h
Replaced PG_SURF_BitsPerPixel macro with a static inline int PG_SURF_BitsPerPixel(SDL_Surface *surf) that: returns 32 for YUY2/UYVY/YVYU FourCC, returns 0 for other FourCC, uses SDL_BITSPERPIXEL(surf->format) when SDL_BYTESPERPIXEL(surf->format) <= 2, else uses SDL_BYTESPERPIXEL(surf->format) * 8. Added explanatory comment referencing SDL pixel-format behavior. Other macros (PG_SURF_BytesPerPixel, PG_FORMAT_*) unchanged.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Caller as Code using surface
    participant Func as PG_SURF_BitsPerPixel(surf)
    participant Surf as SDL_Surface

    Caller->>Func: call with surf
    Func->>Surf: inspect surf->format (FourCC?)
    alt format is YUY2/UYVY/YVYU
        Func-->>Caller: return 32
    else format is other FourCC
        Func-->>Caller: return 0
    else not FourCC
        Func->>Surf: bytes = SDL_BYTESPERPIXEL(surf->format)
        alt bytes <= 2
            Func-->>Caller: return SDL_BITSPERPIXEL(surf->format)
        else bytes > 2
            Func-->>Caller: return bytes * 8
        end
    end
    note right of Func #EEF6FF: Inline function replaces prior macro for SDL3 path
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested labels

display

Suggested reviewers

  • ankith26
  • MyreMylar

📜 Recent 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 6da0210 and 833fd08.

📒 Files selected for processing (1)
  • src_c/_pygame.h (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src_c/_pygame.h
⏰ 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). (20)
  • GitHub Check: x86_64
  • GitHub Check: Debian (Bookworm - 12) [armv7]
  • GitHub Check: Debian (Bookworm - 12) [ppc64le]
  • GitHub Check: Debian (Bookworm - 12) [armv6]
  • GitHub Check: Debian (Bookworm - 12) [s390x]
  • GitHub Check: debug_coverage (ubuntu-24.04, 3.9.23)
  • GitHub Check: debug_coverage (ubuntu-24.04, 3.14.0rc1)
  • GitHub Check: debug_coverage (ubuntu-24.04, 3.13.5)
  • GitHub Check: build (ubuntu-22.04)
  • GitHub Check: x86_64
  • GitHub Check: i686
  • GitHub Check: aarch64
  • GitHub Check: msys2 (clang64, clang-x86_64)
  • GitHub Check: dev-check
  • GitHub Check: build (ubuntu-24.04)
  • GitHub Check: build (windows-latest)
  • GitHub Check: msys2 (ucrt64, ucrt-x86_64)
  • GitHub Check: msys2 (mingw64, x86_64)
  • GitHub Check: x86
  • GitHub Check: AMD64
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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: 1

Caution

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

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

959-963: Handle allocation/blit failures before calling rotozoomSurface

PG_CreateSurface or SDL_BlitSurface can fail; today these errors fall through and may crash or corrupt output. Check and bail with a clear error, freeing intermediates.

Apply this diff inside the else-branch:

-    Py_BEGIN_ALLOW_THREADS;
-    surf32 = PG_CreateSurface(surf->w, surf->h, SDL_PIXELFORMAT_ABGR8888);
-    SDL_BlitSurface(surf, NULL, surf32, NULL);
-    Py_END_ALLOW_THREADS;
+    Py_BEGIN_ALLOW_THREADS;
+    surf32 = PG_CreateSurface(surf->w, surf->h, SDL_PIXELFORMAT_ABGR8888);
+    int blit_rc = 0;
+#if SDL_VERSION_ATLEAST(3, 0, 0)
+    if (surf32) {
+        blit_rc = SDL_BlitSurface(surf, NULL, surf32, NULL) ? 0 : -1;
+    } else {
+        blit_rc = -1;
+    }
+#else
+    if (surf32) {
+        blit_rc = SDL_BlitSurface(surf, NULL, surf32, NULL);
+    } else {
+        blit_rc = -1;
+    }
+#endif
+    Py_END_ALLOW_THREADS;
+    if (!surf32 || blit_rc < 0) {
+        if (surf32) SDL_FreeSurface(surf32);
+        PyErr_SetString(pgExc_SDLError, SDL_GetError());
+        return NULL;
+    }
🧹 Nitpick comments (2)
src_c/surface.c (1)

3122-3128: get_bitsize now reflects “bits used” (not padding) — verify docs/tests

Returning PG_FORMAT_BitsPerPixel(fmt) matches SDL3’s semantics (e.g., RGBX => 24). Ensure DOC_SURFACE_GETBITSIZE and tests expect 24 (not 32) for padded 4-byte formats on SDL3 to avoid confusion.

I can update/add tests asserting (surface.get_bitsize(), surface.get_bytesize()) == (24, 4) for RGBX/XRGB on SDL3 and adjust docs accordingly. Want a patch?

src_c/rotozoom.c (1)

527-529: BytesPerPixel-based checks eliminate the SDL3 mismatch—good change.

Minor nit: compute once to avoid the second macro call and improve readability.

-    is32bit = (PG_SURF_BytesPerPixel(src) == 4);
-    if ((is32bit) || (PG_SURF_BytesPerPixel(src) == 1)) {
+    int src_bpp_bytes = PG_SURF_BytesPerPixel(src);
+    is32bit = (src_bpp_bytes == 4);
+    if (is32bit || src_bpp_bytes == 1) {
📜 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 83d395f and 1276caa.

📒 Files selected for processing (7)
  • src_c/_camera.c (1 hunks)
  • src_c/_pygame.h (0 hunks)
  • src_c/display.c (1 hunks)
  • src_c/image.c (1 hunks)
  • src_c/rotozoom.c (1 hunks)
  • src_c/surface.c (3 hunks)
  • src_c/transform.c (1 hunks)
💤 Files with no reviewable changes (1)
  • src_c/_pygame.h
🧰 Additional context used
🧬 Code graph analysis (1)
src_c/surface.c (1)
src_c/_pygame.h (2)
  • PG_GetSurfaceFormat (129-133)
  • PG_GetSurfaceFormat (241-245)
⏰ 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). (20)
  • GitHub Check: x86_64
  • GitHub Check: msys2 (mingw64, x86_64)
  • GitHub Check: build
  • GitHub Check: msys2 (ucrt64, ucrt-x86_64)
  • GitHub Check: msys2 (clang64, clang-x86_64)
  • GitHub Check: debug_coverage (ubuntu-24.04, 3.9.23)
  • GitHub Check: debug_coverage (ubuntu-24.04, 3.14.0rc1)
  • GitHub Check: debug_coverage (ubuntu-24.04, 3.13.5)
  • GitHub Check: Debian (Bookworm - 12) [ppc64le]
  • GitHub Check: Debian (Bookworm - 12) [armv6]
  • GitHub Check: Debian (Bookworm - 12) [s390x]
  • GitHub Check: Debian (Bookworm - 12) [armv7]
  • GitHub Check: AMD64
  • GitHub Check: x86
  • GitHub Check: build (ubuntu-22.04)
  • GitHub Check: dev-check
  • GitHub Check: aarch64
  • GitHub Check: i686
  • GitHub Check: x86_64
  • GitHub Check: build (ubuntu-24.04)
🔇 Additional comments (4)
src_c/display.c (1)

1808-1814: Depth check switch to BytesPerPixel is correct for SDL3 semantics.

Using PG_SURF_BytesPerPixel(surface->surf) * 8 avoids the SDL3 BitsPerPixel ambiguity (e.g., XRGB8888: 32 vs 24 used-bits). Change looks good.

src_c/transform.c (1)

954-957: Correct switch to BytesPerPixel for SDL3 semantics

Using PG_SURF_BytesPerPixel(surf) == 4 correctly handles RGBX/XRGB (24bpp with 4-byte stride) on SDL3, fixing false negatives from BitsPerPixel==32 checks. Good call.

src_c/surface.c (1)

444-448: Use format details to compute bit size (SDL3-safe)

  • Fetching the pixel format via PG_GetSurfaceFormat with NULL-check is correct.
  • Switching to PG_FORMAT_BitsPerPixel(fmt) in surface_str keeps the repr accurate under SDL3.

Also applies to: 473-474

src_c/image.c (1)

1711-1713: Approve: switch to PG_SURF_BytesPerPixel*8 is correct and SDL3-safe
Verified no remaining PG_SURF_BitsPerPixel calls in src_c. LGTM.

@Starbuck5 Starbuck5 changed the title Get rid of PG_SURF_BitsPerPixel Fix PG_SURF_BitsPerPixel SDL3 Sep 1, 2025
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

🧹 Nitpick comments (4)
src_c/_pygame.h (4)

108-112: Clarify the intent of this helper and its SDL2/SDL3 semantics.

The current comment suggests this is an “implementation from SDL_GetMasksForPixelFormat”, but the function re-derives BPP with extra heuristics and special-cases. Please tighten the doc to state the exact contract (SDL2-style total bits vs SDL3 “significant bits”), and why the heuristics exist.

Apply:

-// Implementation from SDL_GetMasksForPixelFormat, which is used by
-// SDL_InitPixelFormatDetails in SDL_pixels.c
-// Created to match surf->format->BitsPerPixel in SDL2,
-// details->bits_per_pixel in SDL3.
+// Helper to produce SDL2-style “total bits per pixel” from an SDL3 surface.
+// SDL3's SDL_BITSPERPIXEL() may exclude pad bits on some formats (e.g., RGBX),
+// so we re-derive a value consistent with SDL2's surf->format->BitsPerPixel.
+// See SDL_InitPixelFormatDetails / SDL_PixelFormatDetails for reference.

128-132: Avoid heuristic threshold; use PixelFormatDetails to prevent drift.

The “<= 2 bytes use BITSPERPIXEL else bytes*8” rule is brittle (e.g., 12/15 bpp corner cases, future formats). Prefer SDL_PixelFormatDetails as the single source of truth and only fall back if unavailable.

-static inline int
-PG_SURF_BitsPerPixel(SDL_Surface *surf)
-{
-    if (SDL_ISPIXELFORMAT_FOURCC(surf->format)) {
-        // however, some of these are packed formats, and can legit declare
-        // bits-per-pixel!
-        switch (surf->format) {
-            case SDL_PIXELFORMAT_YUY2:
-            case SDL_PIXELFORMAT_UYVY:
-            case SDL_PIXELFORMAT_YVYU:
-                return 32;
-            default:
-                return 0;  // oh well.
-        }
-    }
-
-    if (SDL_BYTESPERPIXEL(surf->format) <= 2) {
-        return SDL_BITSPERPIXEL(surf->format);
-    }
-    return SDL_BYTESPERPIXEL(surf->format) * 8;
-}
+static inline int
+PG_SURF_BitsPerPixel(const SDL_Surface *surf)
+{
+    const SDL_PixelFormatDetails *d = SDL_GetPixelFormatDetails(surf->format);
+    if (d) {
+        // SDL2-style “total bits”: prefer bytes_per_pixel*8 for wide formats,
+        // otherwise use details->bits_per_pixel.
+        return (d->bytes_per_pixel > 2) ? (int)(d->bytes_per_pixel * 8)
+                                        : (int)d->bits_per_pixel;
+    }
+    return 0;
+}

112-114: Minor signature tweak: accept const SDL_Surface.*

Function does not mutate the surface; const improves call-site flexibility and communicates intent.

-static inline int
-PG_SURF_BitsPerPixel(SDL_Surface *surf)
+static inline int
+PG_SURF_BitsPerPixel(const SDL_Surface *surf)

108-133: Add tests covering representative formats across SDL2/SDL3.

Lock in behavior with a small matrix: INDEX8, RGB565, RGB24, RGBX8888/XRGB8888, RGBA8888, YUY2/UYVY/YVYU, and a 64bpp format. Assert consistency with the intended “total bits” semantics.

📜 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 1276caa and 6da0210.

📒 Files selected for processing (1)
  • src_c/_pygame.h (1 hunks)
⏰ 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). (19)
  • GitHub Check: arm64
  • GitHub Check: x86_64
  • GitHub Check: aarch64
  • GitHub Check: AMD64
  • GitHub Check: x86
  • GitHub Check: debug_coverage (ubuntu-24.04, 3.14.0rc1)
  • GitHub Check: x86_64
  • GitHub Check: dev-check
  • GitHub Check: debug_coverage (ubuntu-24.04, 3.9.23)
  • GitHub Check: i686
  • GitHub Check: msys2 (ucrt64, ucrt-x86_64)
  • GitHub Check: msys2 (mingw64, x86_64)
  • GitHub Check: msys2 (clang64, clang-x86_64)
  • GitHub Check: Debian (Bookworm - 12) [armv6]
  • GitHub Check: Debian (Bookworm - 12) [ppc64le]
  • GitHub Check: build (ubuntu-22.04)
  • GitHub Check: Debian (Bookworm - 12) [s390x]
  • GitHub Check: Debian (Bookworm - 12) [armv7]
  • GitHub Check: build (ubuntu-24.04)

@Starbuck5
Copy link
Member Author

Starbuck5 commented Sep 1, 2025

@ankith26 You gave feedback on the first pass of this PR that you were uneasy about changing SDL2 codepaths. I've reworked this PR to fix the macro instead of removing it, after doing a bit more research (I didn't think it could be fixed initially). This PR now is highly correct and also doesn't change the SDL2 path at all.

EDIT: Had to force push again because I misnamed the commit

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

Successfully merging this pull request may close these issues.

1 participant