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] HighDPI not considered while using RenderTexture #1086

Closed
raysan5 opened this issue Jan 29, 2020 · 20 comments
Closed

[core] HighDPI not considered while using RenderTexture #1086

raysan5 opened this issue Jan 29, 2020 · 20 comments
Labels
bug This is a bug

Comments

@raysan5
Copy link
Owner

raysan5 commented Jan 29, 2020

This issue is directly related to #837.

When creating a RenderTexture on a HighDPI application:

// Create a RenderTexture2D to be used for render to texture
RenderTexture2D target = LoadRenderTexture(GetScreenWidth(), GetScreenHeight());

GetScreenWidth() and GetScreenHeight() actually return the original screen size requested by the user, despite that everything drawn is scaled to match HighDPI. So, we end up with a RenderTexture smaller than the actual render size.

One possible solution would be to consider the scaleFactor directly on GetScreenWidth() and GetScreenHeight() but if those calls are used in game logic for some maths it will lend to logic errors, because scaling is done automatically only on drawing.

Another solution would be directly exposing the HighDPI scaleFactor and let the user manage everything.

Feedback is welcome!

@jozanza
Copy link

jozanza commented Feb 4, 2020

I love the idea of exposing the DPI to the user. I ran into this issue, and am working off a fork that exposes this info via

float GetWindowDPI(void).

I found it necessary for recreating the render texture when the window is moved to a new monitor with a different DPI or when the window is resized.

@raysan5
Copy link
Owner Author

raysan5 commented Mar 3, 2020

Just for reference, glfwGetMonitorContentScale() is the related function.

@ismyhc
Copy link

ismyhc commented Apr 23, 2020

@raysan5 Im very interested in this feature. I agree with @jozanza . Exposing the dpi seems like a good solution. Im about to do this locally now.

@ismyhc
Copy link

ismyhc commented Apr 24, 2020

Hmmm. I was going to try and do this, but I'm getting an error. Here is what I have done to try and expose the dpi.

core.c

Vector2 GetWindowDPI(void)
{

#if defined(PLATFORM_DESKTOP)
    float xdpi;
    float ydpi;
    glfwGetMonitorContentScale(CORE.Window.handle, &xdpi, &ydpi);
    return (Vector2){ xdpi, ydpi };
#endif
    return (Vector2){ 1.0f, 1.0f };
}

And here is the error I get when calling the function from my code.

WARNING: GLFW: Error: 65544 Description: Cocoa: Failed to find a screen for monitor

Any ideas?

@jozanza would you mind sharing your implementation in your fork?

@ismyhc
Copy link

ismyhc commented Apr 24, 2020

Success! Sorry I figured it out. I was passing the window handle. The glfwGetMonitorContentScale() actually was expecting a monitor pointer.

Heres my final code which is working:

Vector2 GetWindowDPI(void)
{
#if defined(PLATFORM_DESKTOP)
    GLFWmonitor *monitor = glfwGetPrimaryMonitor();
    if (!monitor)
    {
        TRACELOG(LOG_WARNING, "GLFW: Failed to get primary monitor");
        return (Vector2){ 1.0f, 1.0f };
    }
    float xdpi;
    float ydpi;
    glfwGetMonitorContentScale(monitor, &xdpi, &ydpi);
    return (Vector2){ xdpi, ydpi };
#endif
    return (Vector2){ 1.0f, 1.0f };
}

@Miha-ha
Copy link

Miha-ha commented Apr 24, 2020

I think it is better:

Vector2 GetWindowDPI(void)
{
    float xdpi = 1.0;
    float ydpi = 1.0;

#if defined(PLATFORM_DESKTOP)
    GLFWmonitor *monitor = glfwGetPrimaryMonitor();
    if (!monitor)
    {
        TRACELOG(LOG_WARNING, "GLFW: Failed to get primary monitor");
        return (Vector2){ xdpi, ydpi };
    }
    glfwGetMonitorContentScale(monitor, &xdpi, &ydpi);
#endif
     return (Vector2){ xdpi, ydpi };
}

@raysan5
Copy link
Owner Author

raysan5 commented Apr 24, 2020

@ismyhc @Miha-ha Added GetWindowScaleDPI() on commit 8e59ecb.

Still need to think about the issue a bit more... but this is a solution for now...

@ismyhc
Copy link

ismyhc commented Apr 24, 2020

@raysan5 thanks for this! Ive been toying around with both Raylib and SDL2. What I'm trying to accomplish is actually handled in one line in SDL2.

SDL_RenderSetLogicalSize(SDL_Renderer * renderer, int w, int h)

Im not sure how it would translate to Raylib, but below you can see description of the function which explains what Id like to do.


/**
 *  \brief Set device independent resolution for rendering
 *
 *  \param renderer The renderer for which resolution should be set.
 *  \param w      The width of the logical resolution
 *  \param h      The height of the logical resolution
 *
 *  This function uses the viewport and scaling functionality to allow a fixed logical
 *  resolution for rendering, regardless of the actual output resolution.  If the actual
 *  output resolution doesn't have the same aspect ratio the output rendering will be
 *  centered within the output display.
 *
 *  If the output display is a window, mouse events in the window will be filtered
 *  and scaled so they seem to arrive within the logical resolution.
 *
 *  \note If this function results in scaling or subpixel drawing by the
 *        rendering backend, it will be handled using the appropriate
 *        quality hints.
 *
 *  \sa SDL_RenderGetLogicalSize()
 *  \sa SDL_RenderSetScale()
 *  \sa SDL_RenderSetViewport()
 */
extern DECLSPEC int SDLCALL SDL_RenderSetLogicalSize(SDL_Renderer * renderer, int w, int h);

@raysan5
Copy link
Owner Author

raysan5 commented Apr 24, 2020

@ismyhc it seems similar to example core_window_letterbox

@TakUnderhand
Copy link

TakUnderhand commented Jul 19, 2020

Hey @raysan5.

I had an issue that may be related.

First I turned off the following in libs/raylib/src/core.c:
//#define SUPPORT_HIGH_DPI // Force HighDPI support on macOS

With this removed, I get the following behaviour:

  1. App loads and behaves normally

  2. Resizing the app leads to the following:
    a) Screen image is 1/2 size and positioned in the bottom left corner:

Screenshot 2020-07-19 at 10 25 04

b) Buttons still work as though the screen is full size.

c) Moving the window sets everything back right again!

I fixed this issue by messing with glfw:

In libs/raylib/src/external/glfw/src/cocoa_window.m
I modified windowDidResize(), adding the following two lines from the windowDidMove() function at the end of windowDidResize():

if (window->context.client != GLFW_NO_API)
    [window->context.nsgl.object update];

@raysan5
Copy link
Owner Author

raysan5 commented Jul 20, 2020

@TakUnderhand Thanks for reporting! I'm afraid behaviour could be dependant of macOS version as well as retina display... but, in any case, your solution points to GLFW library, maybe that issue could also be asked on their repo to make it available for all the users.

Also, note that current GLFW version used in raylib is about 4 month old, maybe something changed on GLFW side on that time.

@TakUnderhand
Copy link

Thanks :)
I took GLFW 3.3.2 from their repo, combined it into Raylib, just to see if that latest version would have any fix for this issue. (It didn't).
If I get chance, I'll put a simple test case together, to raise an issue on the GLFW team.

@raysan5
Copy link
Owner Author

raysan5 commented Jul 20, 2020

@TakUnderhand Thank you very much for your time an effort! This issue has been open for some time, it would be great to find a proper fix! :)

@mattj1
Copy link

mattj1 commented Oct 28, 2020

Not sure how helpful this is, but I wrote a hack to allow me to drag a window between monitors that "mostly" works:

https://gist.github.com/mattj1/606a94527badb6ffa7d22245c9b745b1

(I'm on a Mac, btw)

Note: GLFW is required, and you have to specify your viewport size to rlViewport.

@raysan5
Copy link
Owner Author

raysan5 commented Oct 29, 2020

hi @mattj1! Thank you very much for the git! I'm reviewing it!

raysan5 added a commit that referenced this issue Oct 29, 2020
@raysan5 raysan5 added the bug This is a bug label Nov 1, 2020
@raysan5 raysan5 added this to the raylib 3.5 milestone Dec 4, 2020
@raysan5 raysan5 removed this from the raylib 3.5 milestone Dec 14, 2020
@saikyun
Copy link
Contributor

saikyun commented Jan 3, 2021

Not sure how helpful this is, but I wrote a hack to allow me to drag a window between monitors that "mostly" works:

https://gist.github.com/mattj1/606a94527badb6ffa7d22245c9b745b1

(I'm on a Mac, btw)

Note: GLFW is required, and you have to specify your viewport size to rlViewport.

Cheers, this helped me a lot. Thanks!

@default-writer
Copy link
Contributor

I love the idea of exposing the DPI to the user. I ran into this issue, and am working off a fork that exposes this info via

float GetWindowDPI(void).

I found it necessary for recreating the render texture when the window is moved to a new monitor with a different DPI or when the window is resized.

i use another approach, i send this flag directly, i will send code in my fork soon

@default-writer
Copy link
Contributor

Hey @raysan5.

I had an issue that may be related.

First I turned off the following in libs/raylib/src/core.c:
//#define SUPPORT_HIGH_DPI // Force HighDPI support on macOS

With this removed, I get the following behaviour:

  1. App loads and behaves normally
  2. Resizing the app leads to the following:
    a) Screen image is 1/2 size and positioned in the bottom left corner:
Screenshot 2020-07-19 at 10 25 04

b) Buttons still work as though the screen is full size.

c) Moving the window sets everything back right again!

I fixed this issue by messing with glfw:

In libs/raylib/src/external/glfw/src/cocoa_window.m
I modified windowDidResize(), adding the following two lines from the windowDidMove() function at the end of windowDidResize():

if (window->context.client != GLFW_NO_API)
    [window->context.nsgl.object update];

this is because of call SetViewport with incorrect screen widths and heights, on HiDPI systems, render width is often not equals to screen width, so GetWindowScaleDPI willl return {2.0f, 2.0f} not {1.0f, 1.0f}

@redthing1
Copy link
Contributor

Hey @raysan5.
I had an issue that may be related.
First I turned off the following in libs/raylib/src/core.c:
//#define SUPPORT_HIGH_DPI // Force HighDPI support on macOS
With this removed, I get the following behaviour:

  1. App loads and behaves normally
  2. Resizing the app leads to the following:
    a) Screen image is 1/2 size and positioned in the bottom left corner:
Screenshot 2020-07-19 at 10 25 04 b) Buttons still work as though the screen is full size. c) Moving the window sets everything back right again! I fixed this issue by messing with glfw: In libs/raylib/src/external/glfw/src/cocoa_window.m I modified windowDidResize(), adding the following two lines from the windowDidMove() function at the end of windowDidResize(): ``` if (window->context.client != GLFW_NO_API) [window->context.nsgl.object update]; ```

this is because of call SetViewport with incorrect screen widths and heights, on HiDPI systems, render width is often not equals to screen width, so GetWindowScaleDPI willl return {2.0f, 2.0f} not {1.0f, 1.0f}

I am seeing something like this too, but on Linux on a hidpi screen

@raysan5
Copy link
Owner Author

raysan5 commented Mar 20, 2021

Finally I opt for the option of letting the user manage the RenderTexture scaling on HighDPI.

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

No branches or pull requests

9 participants