Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SDL_CreateRGBSurfaceWithFormatFrom silently failing when passed a sub-array of a bytes object #275

Open
TTimo opened this issue Feb 26, 2024 · 1 comment

Comments

@TTimo
Copy link

TTimo commented Feb 26, 2024

What doesn't work?

I'm finding that SDL_CreateRGBSurfaceWithFormatFrom either throws or fails to take in the pixel data (but creates a valid empty SDL_Surface) when passed in a sub-array of a bytes object directly. But it works if I setup an intermediate python object first.

How To Reproduce

This test case stems from difficulties I ran into when adding support for setting the application's window icon:

#!/usr/bin/env python

import sys
import sdl2

if __name__ == '__main__':
    sdl2.SDL_Init(sdl2.SDL_INIT_VIDEO)
    window = sdl2.SDL_CreateWindow(
        'test'.encode(),
        sdl2.SDL_WINDOWPOS_CENTERED,
        sdl2.SDL_WINDOWPOS_CENTERED,
        640,
        480,
        0
        )

    assert sys.byteorder == 'little'
    # A dummy 4 bytes header, followed by an little endian ARGB solid green fill
    # For instance, say we loaded a TGA file with 18 bytes worth of header
    w = h= 256
    pixels = b'\xff\xff\xff\xff' b'\x00\xff\x00\xff' * w * h

    # Arch Linux, Python 3.11.7:       pixels don't get through, yields a blank/fully transparent icon
    # Arch Linux, Python 3.12.2 (AUR): pixels don't get through, yields a blank/fully transparent icon
    # Windows, Python 3.11.8:          OSError: exception: access violation reading [..]
    # Windows, Python 3.12.2:          works fine!
    # (all with PySDL2 0.9.16, current atm and SDL 2.30.0)
    icon = sdl2.SDL_CreateRGBSurfaceWithFormatFrom(pixels[4:4+w*h*4], w, h, 32, w*4, sdl2.SDL_PIXELFORMAT_ARGB8888)
    assert icon is not None
    assert icon.contents.format.contents.format == sdl2.SDL_PIXELFORMAT_ARGB8888

    sdl2.SDL_SetWindowIcon(window, icon)

    import time
    time.sleep(4)

    # Workaround: this..
    pixels2 = pixels[4:4+w*h*4]
    icon = sdl2.SDL_CreateRGBSurfaceWithFormatFrom(pixels2, w, h, 32, w*4, sdl2.SDL_PIXELFORMAT_ARGB8888)
    assert icon is not None
    assert icon.contents.format.contents.format == sdl2.SDL_PIXELFORMAT_ARGB8888

    sdl2.SDL_SetWindowIcon(window, icon)

    import time
    time.sleep(4)

On Windows with Python 3.12 the first SDL_CreateRGBSurfaceWithFormatFrom call works. Elsewhere it'll either ignore the pixels and yield a transparent/empty surface, or throw an OSErrror.

The workaround is what bugs me the most .. just .. pixels2 = pixels[4:4+w*h*4] and all platforms work.

Platform:

  • OS: Windows 11 64-bit, Arch Linux (have not tested others)
  • Python Version: 3.11.7 3.11.8 3.12.2
  • SDL2 Version: 2.0.30
  • Using pysdl2-dll: Yes on Windows

Additional context
Add any other context about the problem here.

@TTimo
Copy link
Author

TTimo commented Feb 26, 2024

For a bit more context, this is the initial in-situ investigation of this problem. I only found the workaround later on when writing a test case: https://gitlab.steamos.cloud/devkit/steamos-devkit/-/commit/7e89557f692b7a1437ebbf4f51464a95d4f8f52f#f42379bd6d31600aba6eff88f0c3311df57ccea9

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

No branches or pull requests

1 participant