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

dstrect of SDL_RenderCopy of SDL2 is broken on HTML5 #11926

Open
bottle2 opened this issue Jan 12, 2025 · 1 comment
Open

dstrect of SDL_RenderCopy of SDL2 is broken on HTML5 #11926

bottle2 opened this issue Jan 12, 2025 · 1 comment
Assignees
Milestone

Comments

@bottle2
Copy link

bottle2 commented Jan 12, 2025

hey pals

Documentation for parameter dstrect of SDL_RenderCopy in https://wiki.libsdl.org/SDL2/SDL_RenderCopy: "the destination SDL_Rect structure or NULL for the entire rendering target; the texture will be stretched to fill the given rectangle"

on Windows, it works appropriately. however, on HTML5, NULL yields strange results.

$ uname -a
MINGW64_NT-10.0-19045 DESKTOP-QIBT7ND 3.5.4-0bc1222b.x86_64 2024-12-05 09:27 UTC x86_64 Msys
$ emcc -v
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.74-git (1092ec30a3fb1d46b
1782ff1b4db5094d3d06ae5)
clang version 20.0.0git
Target: wasm32-unknown-emscripten
Thread model: posix
InstalledDir: C:/msys64/clang64/opt/emscripten-llvm/bin
$ pacman -Qi mingw-w64-clang-x86_64-SDL2
Name            : mingw-w64-clang-x86_64-SDL2
Version         : 2.30.11-1
Description     : A library for portable low-level access to a video framebuffer, audio output,
                  mouse, and keyboard (Version 2) (mingw-w64)
Architecture    : any
URL             : https://libsdl.org/
Licenses        : spdx:Zlib
Groups          : None
Provides        : None
Depends On      : mingw-w64-clang-x86_64-gcc-libs  mingw-w64-clang-x86_64-libiconv
                  mingw-w64-clang-x86_64-vulkan
Optional Deps   : None
Required By     : mingw-w64-clang-x86_64-SDL2_image  mingw-w64-clang-x86_64-SDL2_net
                  mingw-w64-clang-x86_64-SDL2_ttf  mingw-w64-clang-x86_64-ffmpeg
Optional For    : mingw-w64-clang-x86_64-libde265
Conflicts With  : None
Replaces        : None
Installed Size  : 7.73 MiB
Packager        : CI (msys2/msys2-autobuild/35ff0b71/12593557521)
Build Date      : Fri Jan 3 03:09:42 2025
Install Date    : Thu Jan 9 11:44:37 2025
Install Reason  : Explicitly installed
Install Script  : No
Validated By    : SHA-256 Sum  Signature

further disclaimer: I've run emcc --clear-cache before running the tests.

MRE:

#include <stdbool.h>
#include <stdio.h>

#include <SDL.h>

#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#define LOOP(ITER) emscripten_set_main_loop((ITER), 0, 1)
#define LOOP_END emscripten_cancel_main_loop(); return
#else
static bool is_playing = true;
#define LOOP(ITER) while (is_playing) (ITER)()
#define LOOP_END is_playing = false; return
#endif

#define TRY(IT) \
if ((IT)) { SDL_LogError(SDL_LOG_CATEGORY_ERROR, \
            __FILE__ ":%d: %s\n", __LINE__, SDL_GetError()); \
            exit(EXIT_FAILURE); } else (void)0

static SDL_threadID tid;
static SDL_Window *window;
static SDL_Renderer *renderer;
static SDL_Texture *texture;
static SDL_Rect rect = {0, 0, 800, 600};
static SDL_PixelFormat *pf = NULL;
static bool use_rect = false;
static uint32_t pixel_format;

static void resize(int width, int height)
{
    int w;
    int h;
    SDL_GetRendererOutputSize(renderer, &w, &h);
    SDL_Log("from event: %d %d from output: %d %d\n", width, height, w, h);

    if (rect.w != width || rect.h != height)
    {
        rect.w = width;
        rect.h = height;
    }
}

static void render(void)
{
    SDL_RenderClear(renderer);

    void *pixels;
    int pitch;
    TRY(SDL_LockTexture(texture, &rect, &pixels, &pitch));

    int x = rect.w / 2;
    int y = rect.h / 2;
    int radius = (rect.w < rect.h ? rect.w : rect.h) * 0.8 / 2;

    for (int j = 0; j < rect.h; j++)
        for (int i = 0; i < rect.w; i++)
        {
            uint8_t c = (j-y)*(j-y) + (i-x)*(i-x) < radius * radius ? 255 : 0;
            ((uint32_t *)(((unsigned char *)pixels) + j * pitch))[i]
                    = SDL_MapRGB(pf, c, c, c);
        }

    SDL_UnlockTexture(texture);
    SDL_RenderCopy(renderer, texture, &rect, use_rect ? &rect : NULL);

    SDL_RenderPresent(renderer);
}

// https://discourse.libsdl.org/t/is-it-thread-safe-to-render-inside-event-watcher/49409
static int filter(void *userdata, SDL_Event *event)
{
    (void)userdata;

    if (SDL_WINDOWEVENT == event->type)
    {
        switch (event->window.event)
        {
            case SDL_WINDOWEVENT_EXPOSED:
                SDL_assert(SDL_GetThreadID(NULL) == tid);
                render();
                return 0;
            break;
            case SDL_WINDOWEVENT_RESIZED: // Fall through.
            case SDL_WINDOWEVENT_SIZE_CHANGED:
                if (SDL_GetThreadID(NULL) == tid)
                {
                    resize(event->window.data1, event->window.data2);
                    return 0;
                }
            break;
            default:
                // Do nothing.
            break;
        }
    }

    return 1;
}

void iter(void)
{
    for (SDL_Event event; SDL_PollEvent(&event); )
    {
        if (SDL_QUIT == event.type)
        {
            SDL_DestroyTexture(texture);
            SDL_DestroyRenderer(renderer);
            SDL_DestroyWindow(window);
            SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_EVENTS);
            LOOP_END;
        }
        else if (SDL_WINDOWEVENT == event.type &&
                (SDL_WINDOWEVENT_RESIZED == event.window.event ||
                 SDL_WINDOWEVENT_SIZE_CHANGED == event.window.event))
        {
            resize(event.window.data1, event.window.data2);
        }
	else if (SDL_KEYDOWN == event.type && 'u' == event.key.keysym.sym)
        {
            use_rect = !use_rect;
        }
    }

    render();
}

int main(int argc, char *argv[])
{
    (void)argc;
    (void)argv;

    atexit(SDL_Quit);

    TRY(SDL_InitSubSystem(SDL_INIT_VIDEO | SDL_INIT_EVENTS));

    tid = SDL_GetThreadID(NULL);

    TRY(!(window = SDL_CreateWindow(
        "Resize, texture and render test",
        SDL_WINDOWPOS_UNDEFINED,
        SDL_WINDOWPOS_UNDEFINED,
        800, 600,
        SDL_WINDOW_RESIZABLE
    )));

    TRY(!(renderer = SDL_CreateRenderer(window, -1, 0)));

    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 1);

    {
        SDL_RendererInfo info = {0};
        TRY(SDL_GetRendererInfo(renderer, &info));
        SDL_assert(info.num_texture_formats > 0);
        pixel_format = info.texture_formats[0];
        TRY(!(pf = SDL_AllocFormat(pixel_format)));
        SDL_assert(32 == pf->BitsPerPixel);
    }

    TRY(!(texture = SDL_CreateTexture(renderer,
                    pixel_format, SDL_TEXTUREACCESS_STREAMING,
                    5000, 5000)));

    SDL_SetEventFilter(filter, NULL);

    LOOP(iter);

    return 0;
}

commands used to compile the native Windows and HTML5 version:

$ cc -std=c99 $(pkg-config --cflags SDL2) -o simple simple.c $(pkg-config --libs SDL2)
$ emcc -std=c99 -Oz -flto -sINITIAL_MEMORY=655360000 -std=c18 simple.c --use-port=sdl2 -o index.html --shell-file=shell.html

file shell.html comes from here: https://github.com/floooh/sokol-samples/blob/3e746d86cd87f634f4f7793c2e8d0ef71a2067ca/webpage/shell.html

visual evidence of it behaving properly on Windows:

image

HTML5 just after running emrun index.html:

image

after resizing windows:

image

after pressing U:

image

again, after opening for the first time and pressing U without resizing:

image

pressing U makes the code use some SDL_Rect for parameter dstrect of SDL_RenderCopy. as I write, I now noticed that I never called SDL_GetWindowSize nor SDL_GetRendererOutputSize after window creation. but oh well, this is a different problem.

@slouken slouken added this to the 3.2.0 milestone Jan 12, 2025
@slouken slouken assigned icculus and unassigned icculus Jan 12, 2025
@slouken slouken modified the milestone: 3.2.0 Jan 12, 2025
@icculus
Copy link
Collaborator

icculus commented Jan 12, 2025

If someone could confirm this happens on SDL3 also, I'd appreciate it. I'm crunching on 3.2.0 and can't look at it this week if it isn't.

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

3 participants