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

[core] Bad GetScreenWidth/GetScreenHeight values after resizing windows with FLAG_WINDOW_HIGHDPI #1982

Closed
3 tasks done
ArnaudValensi opened this issue Sep 9, 2021 · 9 comments

Comments

@ArnaudValensi
Copy link
Contributor

ArnaudValensi commented Sep 9, 2021

  • I tested it on latest raylib version from master branch
  • I checked there is no similar issue already reported
  • My code has no errors or misuse of raylib

Issue description

Hi,
When using FLAG_WINDOW_HIGHDPI, the GetScreenWidth/GetScreenHeight functions are giving bad values after a window resize. See the video below.
In this example, the GuiStatusBar disappears after a window resize.

Environment

  • Windows 10 pro
  • Resolution: 3840x2160 with 150% scaling

Issue Screenshot

8KBajZI0BV.mp4

Code Example

    SetConfigFlags(FLAG_WINDOW_RESIZABLE | FLAG_WINDOW_HIGHDPI);
    InitWindow(1280, 720, "Test");

    while (!WindowShouldClose()) {
        BeginDrawing();
        ClearBackground(DARKPURPLE);

        int width = GetScreenWidth();
        int height = GetScreenHeight();
        Vector2 scale = GetWindowScaleDPI();

        DrawText(TextFormat("screen size: %d, %d\n", width, height), 0, 0, 32, WHITE);
        DrawText(TextFormat("window scale dpi: %f, %f\n", scale.x, scale.y), 0, 40, 32, WHITE);

        GuiStatusBar(
            (Rectangle){0, GetScreenHeight() - 40, GetScreenWidth(), 40},
            "This is a status bar");

        EndDrawing();
    }

    CloseWindow();

You can reproduce by doing a make run in the following repo https://github.com/ArnaudValensi/raylib-highdpi-issue

@ArnaudValensi
Copy link
Contributor Author

ArnaudValensi commented Sep 9, 2021

When working with high dpi, we have the concept of physical size and logical size.
The logical size is the virtual size, independent of the dpi scale factor, it doesn't change when the dpi scale factor change.
The physical size is the real number of pixels used by the screen (logical size * dpi scale).

Here it is confusing if GetScreenWidth/GetScreenHeight are supposed to be the logical or the physical size, but since at startup they return the logical size, I guess it is supposed to also return the logical size after a window resize.

Maybe a less confusing API would be to have a different set of functions with explicit naming:

  • GetLogicalScreenWidth / GetLogicalScreenHeight
  • GetPhysicalScreenWidth / GetPhysicalScreenHeight

but of course, this would be a breaking change.

Here is an interesting resource from the documentation of glium, a library to use opengl api with rust programming language https://docs.rs/glium/0.22.0/glium/glutin/dpi/index.html

@ArnaudValensi
Copy link
Contributor Author

I have made more tests and the problem also exists on linux (manjaro), but everything works fine on macos.
On macos GetScreenWidth/GetScreenHeight are both always returning the logical size.

To summarize, on window and linux, there is a bug where GetScreenWidth/GetScreenHeight are returning the physical size instead of the logical size after a window resize.

@raysan5
Copy link
Owner

raysan5 commented Sep 10, 2021

Hi @ArnaudValensi, actually raylib had some issues managing HighDPI so GetWindowScaleDPI() was added to allow the users manage it, raylib just tries to scale the Window frame accordingly for the High DPI (also note that every OS manages it in a different way).

About logical and physical size, we can also add a virtual size, for example, in case we are using a RenderTexture of 320x240 to be displayed at 640x480 on a monitor of 1920x1080 + High DPI conversion rate.

Considering all the possibilities is not easy, there could be multiple side cases. Obviously there is a lot of room for improvement in raylib.

@ArnaudValensi
Copy link
Contributor Author

Hi @raysan5,

Thank you for your answer :)

I would be happy to help. As a first step, I can try to make GetScreenWidth / GetScreenHeight return consistent value before and after a screen resize.

Here is the current behavior:

MacOS:

Before resize: return the logical size.
After resize: return the logical size.

I think it is the expected behavior.

Windows and Linux:

Before resize: return the logical size.
After resize: return the physical size. <- here I can try to make it return the logical size instead.

What do you think?

@orcmid
Copy link
Contributor

orcmid commented Sep 10, 2021

@ArnaudValensi

Before resize: return the logical size.
After resize: return the logical size.

I think it is the expected behavior

Observing this, I suspect this is correct. My suspicion is that the information should be in terms of the simplest thing the application needs to know and does not require anything sophisticated to work with.

To know that rendering is at a higher resolution via stages of interpolations and/or vectoring is more demanding and also not clear what of that information is useful to the graphical application and under whose control.

This might mean more inside openGL than directly. It could be relevant with regard to font rendering perhaps. I am too ignorant to have any insight on the layering of abstractions that might work best. (Observing the complexity of Microsoft Terminal development, it seems I am not alone in that.)

@raysan5
Copy link
Owner

raysan5 commented Sep 10, 2021

@ArnaudValensi Thanks for reviewing this issue! The expected behaviour is:

Before resize: return the logical size.
After resize: return the logical size.

This way the user can manage HighDPI if required using GetWindowScaleDPI().

I took a look to the possible problem and it directed me to:

// GLFW3 WindowSize Callback, runs when window is resizedLastFrame
// NOTE: Window resizing not allowed by default
static void WindowSizeCallback(GLFWwindow *window, int width, int height)
{
    // Reset viewport and projection matrix for new size
    SetupViewport(width, height);

    CORE.Window.currentFbo.width = width;
    CORE.Window.currentFbo.height = height;
    CORE.Window.resizedLastFrame = true;

    if (IsWindowFullscreen()) return;

    // Set current screen size
    CORE.Window.screen.width = width;
    CORE.Window.screen.height = height;
    
    // NOTE: Postprocessing texture is not scaled to new size
}

It seems GLFW could be managing the width and height differently for macOS and other OSs.

The width returned by GetScreenWidth() is the actual size of the current framebuffer in use, CORE.Window.currentFbo.width.

@ArnaudValensi
Copy link
Contributor Author

@raysan5 I found an issue in this function, but also at the initialization. I fixed it here: #1987
I've tried the fix on Windows 10, Linux (Manjaro with kde desktop) and MacOS and it works fine with the simple example of the test repo I've created https://github.com/ArnaudValensi/raylib-highdpi-issue/blob/master/src/game/game.c

@raysan5
Copy link
Owner

raysan5 commented Oct 10, 2021

@ArnaudValensi thanks again for this great improvement!

@raysan5 raysan5 closed this as completed Oct 10, 2021
@ArnaudValensi
Copy link
Contributor Author

@raysan5 you're welcome :) Thank you for raylib ;)

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