2

As modern macOS devices choose to use a scaled HiDPI resolution by default, bitmap images get blurred on screen. Is there a way to render a bitmap pixel by pixel to the true native physical pixels of the display screen? Any CoreGraphics, OpenGL, or metal API that would allow this without change the display mode of the screen?

If you are thinking of those convertXXXXToBacking and friends, stop. Here is the explanation for you. A typical 13 in MacBook pro now has native 2560x1600 pixel resolution. The default recommended screen resolution is 1440x900 after fresh macOS install. The user can change it to 1680x1050 via System Preferences. In either 1440x900 or 1680x1050 case, the backingScaleFactor is exactly 2. The typical rendering route would render anything first to the unphysical 2880x1800 or 3360x2100 resolution and the OS/GPU did the final resampling with an unknown method.

jxy
  • 784
  • 7
  • 16

2 Answers2

2

Your best bet is probably Metal. MTKView's drawableSize claims that the default is the view's size "in native pixels". I'm not certain if that means device pixels or backing store pixels. If the latter, you could turn off autoResizeDrawable and set drawableSize directly.

To obtain the display's physical pixel count, you can use my answer here.

You can also try using Core Graphics with a CGImage of that size drawn to a rect of the screen size in backing store pixels. It's possible that all of the scaling will be internally cancelled out.

Ken Thomases
  • 88,520
  • 7
  • 116
  • 154
  • Your answer to that question (display's physical pixel count) did not really work, and that was why I supplied my answer. – jxy Dec 03 '18 at 21:32
  • MTKView's drawableSize can be set to anything, but the OS ends up scaling up to the "native pixel" size, and then down to the actual physical pixels, which makes any bitmap images blurry. I had wished all the internal scaling would cancel out, but that was not possible in my experiments. I guess there is really no such reversible pixel scaling algorithm. – jxy Dec 03 '18 at 21:38
  • My physical-pixel-count answer "did not really work" in what way? I saw your answer but didn't realize this question and that answer were by the same person. :) In my testing on a Retina iMac, no display mode has `kDisplayModeNativeFlag` set in its IOFlags. Also, is your `MTKView` full-screen? There may be optimizations for full-screen that aren't otherwise available. – Ken Thomases Dec 03 '18 at 22:51
  • Coincidentally, I reused that answer I linked on [another question](https://stackoverflow.com/questions/53595111/how-to-get-the-physical-display-resolution-on-macos) where it was generously accepted even though it didn't quite work. They ended up discovering your technique on their own. But your technique does not work for me, as mentioned. On a lark, would you perhaps test setting the `drawableSize` based on the largest 1x mode? – Ken Thomases Dec 03 '18 at 23:34
-1

If these are resource images, use asset catalogs to provide x2 and x3 resolution version of your images, icons, etc. Classes like NSImageView will automatically select the best version for the display resolution.

If you just have some random image and you want it draw at the resolution of the display, get the backingScaleFactor of the view's window. If it's 2.0 then drawing a 200 x 200 pixel image into a 100 x 100 coordinate point rectangle will draw it at 1:1 native resolution. Similarly, if the scale factor is 3.0, a 300 x 300 pixel image will draw into a 100 x 100 coordinate point rectangle.

Not surprisingly, Apple has an extensive guide on this subject: High Resolution Guidelines for OS X

James Bucanek
  • 3,299
  • 3
  • 14
  • 30
  • 1
    A typical 13 in MacBook pro now has native 2560x1600 pixel resolution. The default recommended screen resolution is 1440x900 after fresh macOS install. The user can change it to 1680x1050 via System Preferences. In either 1440x900 or 1680x1050 case, the `backingScaleFactor` is exactly 2. None of what you said here would render to the screen's native pixels exactly. All would render to the unphysical 2880x1800 or 3360x2100 resolution and the OS/GPU did the final resampling. – jxy Nov 30 '18 at 15:22
  • You really didn't explain what you were trying to do in the original question. If this is your question, the answer is "you can't". Drawing software can only draw into the "logical" display buffer (say, 1440x900); the back end video drivers/hardware will translate that to the physical pixels of the device (assuming it has physical pixels). There's no magic way of writing 1.78 pixels of image into 1.0 pixel of display buffer. – James Bucanek Nov 30 '18 at 17:30