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

Support high DPI displays on OS X #388

Closed
wants to merge 4 commits into
base: master
from

Conversation

Projects
None yet
7 participants
@mjbshaw

mjbshaw commented May 8, 2013

Fixes #353

Though the user must change their app's Info.plist to have:

<key>NSHighResolutionCapable</key>
<true/>

I don't know if there's a way for that to be set by default (perhaps using the SFML Xcode templates?).

@mantognini

This comment has been minimized.

Show comment
Hide comment
@mantognini

mantognini May 8, 2013

Member

Thanks for your PR

The official documentation doesn't specify since when this function is available.. do you have an idea ?

Regarding the templates, have a look at those lines.

Member

mantognini commented May 8, 2013

Thanks for your PR

The official documentation doesn't specify since when this function is available.. do you have an idea ?

Regarding the templates, have a look at those lines.

@mjbshaw

This comment has been minimized.

Show comment
Hide comment
@mjbshaw

mjbshaw May 8, 2013

The official documentation doesn't specify since when this function is available.. do you have an idea ?

It looks like it was added in the 10.7 API (also see here under "NSOpenGL and Resolution Independence"). Would you suggest using a macro to disable these changes if the OS X API is pre-10.7?

After reading that second link, I'm wondering if this paragraph might potentially be problematic:

To function correctly with wantsBestResolutionOpenGLSurface set to YES, a view must take care to perform correct conversions between view units and pixel units when needed. For example: The common practice of passing the width and height of [self bounds] to glViewport() will yield incorrect results (partial instead of complete coverage of the render surface) at backing scale factors other than 1.0, since the parameters to glViewport() must be expressed in pixels. Instead, use the dimensions of [self convertRectToBacking:[self bounds]], which are in appropriate (pixel) units.

I've also been experimenting a little, and while these changes so far do give a high-resolution window and OpenGL context, the window itself is still larger than it should be. For example, If I create a window with sf::RenderWindow window(sf::VideoMode(800, 600), "SFML window"); then I get a window with actual pixel size 1600x1200, but the OpenGL viewport is a 800x600 (actual pixels) and in the bottom left corner:

screen shot 2013-05-08 at 11 31 26 am
(The picture fills the entire viewport; trying to draw anything that is above or to the right of the picture results in it being clipped)

Obviously this needs fixing. I'll try and look into it more, but any directions you might have would be helpful!

Regarding the templates, have a look at those lines.

Thanks!

mjbshaw commented May 8, 2013

The official documentation doesn't specify since when this function is available.. do you have an idea ?

It looks like it was added in the 10.7 API (also see here under "NSOpenGL and Resolution Independence"). Would you suggest using a macro to disable these changes if the OS X API is pre-10.7?

After reading that second link, I'm wondering if this paragraph might potentially be problematic:

To function correctly with wantsBestResolutionOpenGLSurface set to YES, a view must take care to perform correct conversions between view units and pixel units when needed. For example: The common practice of passing the width and height of [self bounds] to glViewport() will yield incorrect results (partial instead of complete coverage of the render surface) at backing scale factors other than 1.0, since the parameters to glViewport() must be expressed in pixels. Instead, use the dimensions of [self convertRectToBacking:[self bounds]], which are in appropriate (pixel) units.

I've also been experimenting a little, and while these changes so far do give a high-resolution window and OpenGL context, the window itself is still larger than it should be. For example, If I create a window with sf::RenderWindow window(sf::VideoMode(800, 600), "SFML window"); then I get a window with actual pixel size 1600x1200, but the OpenGL viewport is a 800x600 (actual pixels) and in the bottom left corner:

screen shot 2013-05-08 at 11 31 26 am
(The picture fills the entire viewport; trying to draw anything that is above or to the right of the picture results in it being clipped)

Obviously this needs fixing. I'll try and look into it more, but any directions you might have would be helpful!

Regarding the templates, have a look at those lines.

Thanks!

@mantognini

This comment has been minimized.

Show comment
Hide comment
@mantognini

mantognini May 8, 2013

Member

Would you suggest using a macro to disable these changes if the OS X API is pre-10.7?

In this case, because it's a selector, using -[NSObject (BOOL)respondsToSelector:(SEL)aSelector] should be enough.

After reading that second link, I'm wondering if this paragraph might potentially be problematic:

Damn! This means that getting/setting the cursor position, etc... should be modified too.. :-/

Member

mantognini commented May 8, 2013

Would you suggest using a macro to disable these changes if the OS X API is pre-10.7?

In this case, because it's a selector, using -[NSObject (BOOL)respondsToSelector:(SEL)aSelector] should be enough.

After reading that second link, I'm wondering if this paragraph might potentially be problematic:

Damn! This means that getting/setting the cursor position, etc... should be modified too.. :-/

@mjbshaw

This comment has been minimized.

Show comment
Hide comment
@mjbshaw

mjbshaw May 9, 2013

Alright, Marco, I could really use your feedback on this idea:

So I've been playing around with things, and things seem to be working with the following diff:

diff --git a/src/SFML/Window/OSX/SFViewController.mm b/src/SFML/Window/OSX/SFViewController.mm
index e2ce3eb..1f8629c 100644
--- a/src/SFML/Window/OSX/SFViewController.mm
+++ b/src/SFML/Window/OSX/SFViewController.mm
@@ -147,7 +147,7 @@
 ////////////////////////////////////////////////////////////
 -(NSSize)size
 {
-    return [m_oglView frame].size;
+    return [m_oglView convertRectToBacking:[m_oglView frame]].size;//return [m_oglView frame].size;
 }


diff --git a/src/SFML/Window/OSX/SFWindowController.mm b/src/SFML/Window/OSX/SFWindowController.mm
index c572a24..3e96b69 100644
--- a/src/SFML/Window/OSX/SFWindowController.mm
+++ b/src/SFML/Window/OSX/SFWindowController.mm
@@ -293,8 +293,8 @@
 -(NSPoint)position
 {
     // First, get the top left corner of the view in its own base system
-    NSPoint const origin = [m_oglView frame].origin;
-    NSSize  const size = [m_oglView frame].size;
+    NSPoint const origin = [m_oglView convertRectToBacking:[m_oglView frame]].origin;
+    NSSize  const size = [m_oglView convertRectToBacking:[m_oglView frame]].size;
     NSPoint const topLeftCornerOfView = NSMakePoint(origin.x, origin.y + size.height);
     NSPoint const positionInView = [m_oglView convertPointToBase:topLeftCornerOfView];

@@ -331,7 +331,7 @@
 -(NSSize)size
 {
     if (*m_fullscreenMode == sf::VideoMode()) {
-        return [m_oglView frame].size;
+        return [m_oglView convertRectToBacking:[m_oglView frame]].size;
     } else {
         return NSMakeSize(m_fullscreenMode->width, m_fullscreenMode->height);
     }

I've tested this with my Retina MBP connected to an external display device, and have it working on both my high DPI retina display as well as my low-DPI external monitor, and can drag the window between the two screens and resize the window, and it all works.

I have no documentation to back this up, but I have doubts that window sizes and cursor positions are allowed to be specified on a native-pixel basis. That is, in my attempts to resize a window or move the mouse a single pixel on a Retina display, I seem to be unable to do so (testing with non-SFML, high resolution apps). I think that window sizes and mouse positions are always done with logical pixels instead of physical pixels (and these logical pixels are 2x2 physical pixels on my retina display). Again, I have nothing (in terms of documentation) to back that up, but that's what I am concluding from some of my testing. If that really is the case, then I don't think we need to modify getting/setting the cursor position.

If that is indeed the case, that would be a nice thing, in my opinion, as the user creates an 800x600 window and whether it's on a retina display or not, it's the same physical size (so on the retina display, it's 1600x1200). In other words, they just continue as normal creating an 800x600 window, and if it's on a retina screen it will be high res 1600x1200, and if it's not on a retina screen it's an 800x600 window (so they don't have to worry about the window being small on a retina screen).

With the diff in this comment applied, the window was created with sf::RenderWindow window(sf::VideoMode(800, 600), "SFML window"); and a 1600x1200 physical-pixel window was created with a high resolution OpenGL context. Mouse positions and window sizes (from sf::Event::Resized events) were still reported as if the window was 800x600, but the graphics were rendered on a 1600x1200 canvas so they looked sharp and crisp. While I think this behavior might be convenient, I'm not sure how you feel about a 1600x1200 window reporting itself as 800x600 to SFML users.

However, window.getViewport(window.getView()) reported a width and height of 1600x1200, despite the window reporting a size of 800x600. This meant that despite the window not being small (because it was 1600x1200 actual pixels), sprites were small (because they were living in native pixels, not logical pixels like the window size). I don't know if you consider this problematic or not, but I'd like your feedback on it before I proceed and try to put together another commit.

Sorry for being long winded!

mjbshaw commented May 9, 2013

Alright, Marco, I could really use your feedback on this idea:

So I've been playing around with things, and things seem to be working with the following diff:

diff --git a/src/SFML/Window/OSX/SFViewController.mm b/src/SFML/Window/OSX/SFViewController.mm
index e2ce3eb..1f8629c 100644
--- a/src/SFML/Window/OSX/SFViewController.mm
+++ b/src/SFML/Window/OSX/SFViewController.mm
@@ -147,7 +147,7 @@
 ////////////////////////////////////////////////////////////
 -(NSSize)size
 {
-    return [m_oglView frame].size;
+    return [m_oglView convertRectToBacking:[m_oglView frame]].size;//return [m_oglView frame].size;
 }


diff --git a/src/SFML/Window/OSX/SFWindowController.mm b/src/SFML/Window/OSX/SFWindowController.mm
index c572a24..3e96b69 100644
--- a/src/SFML/Window/OSX/SFWindowController.mm
+++ b/src/SFML/Window/OSX/SFWindowController.mm
@@ -293,8 +293,8 @@
 -(NSPoint)position
 {
     // First, get the top left corner of the view in its own base system
-    NSPoint const origin = [m_oglView frame].origin;
-    NSSize  const size = [m_oglView frame].size;
+    NSPoint const origin = [m_oglView convertRectToBacking:[m_oglView frame]].origin;
+    NSSize  const size = [m_oglView convertRectToBacking:[m_oglView frame]].size;
     NSPoint const topLeftCornerOfView = NSMakePoint(origin.x, origin.y + size.height);
     NSPoint const positionInView = [m_oglView convertPointToBase:topLeftCornerOfView];

@@ -331,7 +331,7 @@
 -(NSSize)size
 {
     if (*m_fullscreenMode == sf::VideoMode()) {
-        return [m_oglView frame].size;
+        return [m_oglView convertRectToBacking:[m_oglView frame]].size;
     } else {
         return NSMakeSize(m_fullscreenMode->width, m_fullscreenMode->height);
     }

I've tested this with my Retina MBP connected to an external display device, and have it working on both my high DPI retina display as well as my low-DPI external monitor, and can drag the window between the two screens and resize the window, and it all works.

I have no documentation to back this up, but I have doubts that window sizes and cursor positions are allowed to be specified on a native-pixel basis. That is, in my attempts to resize a window or move the mouse a single pixel on a Retina display, I seem to be unable to do so (testing with non-SFML, high resolution apps). I think that window sizes and mouse positions are always done with logical pixels instead of physical pixels (and these logical pixels are 2x2 physical pixels on my retina display). Again, I have nothing (in terms of documentation) to back that up, but that's what I am concluding from some of my testing. If that really is the case, then I don't think we need to modify getting/setting the cursor position.

If that is indeed the case, that would be a nice thing, in my opinion, as the user creates an 800x600 window and whether it's on a retina display or not, it's the same physical size (so on the retina display, it's 1600x1200). In other words, they just continue as normal creating an 800x600 window, and if it's on a retina screen it will be high res 1600x1200, and if it's not on a retina screen it's an 800x600 window (so they don't have to worry about the window being small on a retina screen).

With the diff in this comment applied, the window was created with sf::RenderWindow window(sf::VideoMode(800, 600), "SFML window"); and a 1600x1200 physical-pixel window was created with a high resolution OpenGL context. Mouse positions and window sizes (from sf::Event::Resized events) were still reported as if the window was 800x600, but the graphics were rendered on a 1600x1200 canvas so they looked sharp and crisp. While I think this behavior might be convenient, I'm not sure how you feel about a 1600x1200 window reporting itself as 800x600 to SFML users.

However, window.getViewport(window.getView()) reported a width and height of 1600x1200, despite the window reporting a size of 800x600. This meant that despite the window not being small (because it was 1600x1200 actual pixels), sprites were small (because they were living in native pixels, not logical pixels like the window size). I don't know if you consider this problematic or not, but I'd like your feedback on it before I proceed and try to put together another commit.

Sorry for being long winded!

@ghost ghost assigned mantognini May 9, 2013

@mantognini

This comment has been minimized.

Show comment
Hide comment
@mantognini

mantognini May 9, 2013

Member

Thanks again for your work, this is awesome ! 👍

Unfortunately I don't have time to test or dig into the subject right now. So I can't really help much more.

I only found those two articles that might give more insight on the topic :

Member

mantognini commented May 9, 2013

Thanks again for your work, this is awesome ! 👍

Unfortunately I don't have time to test or dig into the subject right now. So I can't really help much more.

I only found those two articles that might give more insight on the topic :

@mjbshaw

This comment has been minimized.

Show comment
Hide comment
@mjbshaw

mjbshaw May 11, 2013

I just want to leave a note that I'm also looking into supporting high DPI displays on Windows too. I've got Windows on my Mac with a 200% scaling factor and currently the graphics are naively scaled up (i.e. not rendered in high res). I'm focusing on OS X for now but want to keep Windows in my mind. If anyone has any experience working with high DPI screens on Windows and has any tips or suggestions or insights, that'd be appreciated.

mjbshaw commented May 11, 2013

I just want to leave a note that I'm also looking into supporting high DPI displays on Windows too. I've got Windows on my Mac with a 200% scaling factor and currently the graphics are naively scaled up (i.e. not rendered in high res). I'm focusing on OS X for now but want to keep Windows in my mind. If anyone has any experience working with high DPI screens on Windows and has any tips or suggestions or insights, that'd be appreciated.

@MarioLiebisch

This comment has been minimized.

Show comment
Hide comment
@MarioLiebisch

MarioLiebisch May 11, 2013

Member

Haven't heard of any such thing for Windows. As far as I know windows are always limited by the desktop resolution and their own window size. That's just how the desktop composition works (i.e. all windows are rendered on textures and then drawn on screen). Unless I misunderstood the whole thing.

Member

MarioLiebisch commented May 11, 2013

Haven't heard of any such thing for Windows. As far as I know windows are always limited by the desktop resolution and their own window size. That's just how the desktop composition works (i.e. all windows are rendered on textures and then drawn on screen). Unless I misunderstood the whole thing.

@mjbshaw

This comment has been minimized.

Show comment
Hide comment
@mjbshaw

mjbshaw May 11, 2013

Windows 8 (and possibly Windows 7?) added more support for resolution independence. WPF programs have auto-resolution independence, but OpenGL is all pixel based, and I don't have experience on Windows dealing with high DPI screens beyond WPF. I think this might be what I'm looking for, but if others have insights that would be helpful.

mjbshaw commented May 11, 2013

Windows 8 (and possibly Windows 7?) added more support for resolution independence. WPF programs have auto-resolution independence, but OpenGL is all pixel based, and I don't have experience on Windows dealing with high DPI screens beyond WPF. I think this might be what I'm looking for, but if others have insights that would be helpful.

@MarioLiebisch

This comment has been minimized.

Show comment
Hide comment
@MarioLiebisch

MarioLiebisch May 11, 2013

Member

Ah, this is different I think. WPF ist still limited to desktop resolution, but you can define your stuff using percentages, points, etc. similar to web pages. Different DPI resolutions are something that screwed with font and UI Rendering since Windows 95 (or maybe even longer). It's not exactly the same as retina display stuff.

Member

MarioLiebisch commented May 11, 2013

Ah, this is different I think. WPF ist still limited to desktop resolution, but you can define your stuff using percentages, points, etc. similar to web pages. Different DPI resolutions are something that screwed with font and UI Rendering since Windows 95 (or maybe even longer). It's not exactly the same as retina display stuff.

@mantognini

This comment has been minimized.

Show comment
Hide comment
@mantognini

mantognini Jun 28, 2013

Member

I was hoping to roll retina support with SFML 2.1 but there is another issue: convertRectToBacking: exists only from 10.7. I would like to keep 10.5 support for SFML 2.1 since it would be a release mostly about fixes. With SFML 2.2 I think it would be okay to drop 10.5 & 10.6 support because 10.9 will be there and we will already be supporting 4 versions of the operating system.

At that point, integrating your work will be easier. Hopefully!

Member

mantognini commented Jun 28, 2013

I was hoping to roll retina support with SFML 2.1 but there is another issue: convertRectToBacking: exists only from 10.7. I would like to keep 10.5 support for SFML 2.1 since it would be a release mostly about fixes. With SFML 2.2 I think it would be okay to drop 10.5 & 10.6 support because 10.9 will be there and we will already be supporting 4 versions of the operating system.

At that point, integrating your work will be easier. Hopefully!

@LaurentGomila

This comment has been minimized.

Show comment
Hide comment
@LaurentGomila

LaurentGomila Jun 28, 2013

Member

If the feature is not available in older versions of the SDK, can't you enable it conditionnally in source code? I guess that if it was introduced in OS X 10.7, it means that older versions don't handle retina displays anyway.

Member

LaurentGomila commented Jun 28, 2013

If the feature is not available in older versions of the SDK, can't you enable it conditionnally in source code? I guess that if it was introduced in OS X 10.7, it means that older versions don't handle retina displays anyway.

@mantognini

This comment has been minimized.

Show comment
Hide comment
@mantognini

mantognini Jun 28, 2013

Member

Maybe, yes. But it might require conditional #if in many places – I don't know exactly how mouse events, for example, will be handled.

There is also the case of fullscreen that might be different.. It would be easier to use newer API available from 10.7 (if I remember correctly) and solve #343.

It's probably my lazy side that's talking now, but since 10.5 users are less than 10% of all Mac users it might be a reasonably good idea to spare some time and drop it.

Anyway, I won't put this task on the top of the list but, still, I'll try to find a good solution one of these days. :-)

Member

mantognini commented Jun 28, 2013

Maybe, yes. But it might require conditional #if in many places – I don't know exactly how mouse events, for example, will be handled.

There is also the case of fullscreen that might be different.. It would be easier to use newer API available from 10.7 (if I remember correctly) and solve #343.

It's probably my lazy side that's talking now, but since 10.5 users are less than 10% of all Mac users it might be a reasonably good idea to spare some time and drop it.

Anyway, I won't put this task on the top of the list but, still, I'll try to find a good solution one of these days. :-)

@vonj

This comment has been minimized.

Show comment
Hide comment
@vonj

vonj Jun 28, 2013

No... 10.5 is ancient. Really. And you have no legacy projects on SFML 2.1. Keeping 10.5 support is just too much. It is not like Windows XP which still represent a large audience.

Marco Antognini notifications@github.com skrev:

I was hoping to roll retina support with SFML 2.1 but there is another issue: convertRectToBacking: exists only from 10.7. I would like to keep 10.5 support for SFML 2.1 since it would be a release mostly about fixes. With SFML 2.2 I think it would be okay to drop 10.5 & 10.6 support because 10.9 will be there and we will already be supporting 4 versions of the operating system.

At that point, integrating your work will be easier. Hopefully!


Reply to this email directly or view it on GitHub:
#388 (comment)

vonj commented Jun 28, 2013

No... 10.5 is ancient. Really. And you have no legacy projects on SFML 2.1. Keeping 10.5 support is just too much. It is not like Windows XP which still represent a large audience.

Marco Antognini notifications@github.com skrev:

I was hoping to roll retina support with SFML 2.1 but there is another issue: convertRectToBacking: exists only from 10.7. I would like to keep 10.5 support for SFML 2.1 since it would be a release mostly about fixes. With SFML 2.2 I think it would be okay to drop 10.5 & 10.6 support because 10.9 will be there and we will already be supporting 4 versions of the operating system.

At that point, integrating your work will be easier. Hopefully!


Reply to this email directly or view it on GitHub:
#388 (comment)

@mjbshaw

This comment has been minimized.

Show comment
Hide comment
@mjbshaw

mjbshaw Jun 28, 2013

Yeah, things would be much simpler if 10.5 and 10.6 were dropped.

Mouse events and window sizes are the most annoying in this issue, because they're not reported in native resolution. I didn't deal with them in my changes because it seemed to just keep getting messier and messier.

I haven't tried fullscreen testing. I'll test it sometime.

mjbshaw commented Jun 28, 2013

Yeah, things would be much simpler if 10.5 and 10.6 were dropped.

Mouse events and window sizes are the most annoying in this issue, because they're not reported in native resolution. I didn't deal with them in my changes because it seemed to just keep getting messier and messier.

I haven't tried fullscreen testing. I'll test it sometime.

@arjun-menon

This comment has been minimized.

Show comment
Hide comment
@arjun-menon

arjun-menon Dec 6, 2013

I just want to add that, in fullscreen, SFML is capable of rendering at the full resolution without any sort of tweaking. I have a 13-inch Retina MBP, and a fullscreen window has a resolution of 2560x1600. However in windowed mode, the problem persists. It seems like the discussion on this issue has fallen silent. Are there plans to fix this anytime in the near future?

Note: I'm creating a RenderWindow as shown below:

sf::VideoMode mode = sf::VideoMode::getFullscreenModes()[0];
sf::RenderWindow *renderWindow = new sf::RenderWindow(mode, "WindowTitle", sf::Style::Fullscreen);

arjun-menon commented Dec 6, 2013

I just want to add that, in fullscreen, SFML is capable of rendering at the full resolution without any sort of tweaking. I have a 13-inch Retina MBP, and a fullscreen window has a resolution of 2560x1600. However in windowed mode, the problem persists. It seems like the discussion on this issue has fallen silent. Are there plans to fix this anytime in the near future?

Note: I'm creating a RenderWindow as shown below:

sf::VideoMode mode = sf::VideoMode::getFullscreenModes()[0];
sf::RenderWindow *renderWindow = new sf::RenderWindow(mode, "WindowTitle", sf::Style::Fullscreen);
@LaurentGomila

This comment has been minimized.

Show comment
Hide comment
@LaurentGomila

LaurentGomila Dec 6, 2013

Member

Yes, there are plans (and already ideas) to solve this problem, since high-dpi displays will become more and more common. This is even more important now that we have the iOS and Android ports.

Member

LaurentGomila commented Dec 6, 2013

Yes, there are plans (and already ideas) to solve this problem, since high-dpi displays will become more and more common. This is even more important now that we have the iOS and Android ports.

mantognini added a commit that referenced this pull request Apr 21, 2014

Add support for retina displays (close #353)
Based on PR #388 by Michael Bradshaw

Convert size to match the size requested by the user.
@mantognini

This comment has been minimized.

Show comment
Hide comment
@mantognini

mantognini Apr 21, 2014

Member

@mjbshaw thanks for the PR, it helped me a lot!

Member

mantognini commented Apr 21, 2014

@mjbshaw thanks for the PR, it helped me a lot!

@mantognini mantognini closed this Apr 21, 2014

@mjbshaw

This comment has been minimized.

Show comment
Hide comment
@mjbshaw

mjbshaw Apr 21, 2014

@mantognini Glad I could help in some way!

mjbshaw commented Apr 21, 2014

@mantognini Glad I could help in some way!

@mantognini mantognini modified the milestones: 2.2, 2.x Apr 21, 2014

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment