BradLarson / GPUImage2

GPUImage 2 is a BSD-licensed Swift framework for GPU-accelerated video and image processing.
BSD 3-Clause "New" or "Revised" License
4.85k stars 605 forks source link

macOS — HiDPI only allows for one processImage pass #251

Open rorz opened 6 years ago

rorz commented 6 years ago

Hi there

I'm really enjoying writing custom filters and retro-fitting them into the 'SimpleImageFilter' example project to get going with GPUImage2 on macOS.

However, one thing irking me early on was the lack of retina / HiDPI output from the RenderView. According to RenderView's parent class, NSOpenGLView, you can set this directly via wantsBestResolutionOpenGLSurface to true. I've since assumed that's the same as checking this box:

screen shot 2018-06-25 at 22 14 29

When I run the application, the pictureInput --> (filter x, y, z) --> pipeline renders perfectly to the RenderView output, in x2 resolution. Unfortunately, subsequent calls to processImage, such as after changing filter inputs, causes the image to shrink down to occupy the bottom-left 1/4 of the view.

In fact, if I take all the filters away and reduce the pipeline down to just pictureInput --> renderView, the first processImage call loads it up on the screen fine, while the second (and all subsequent calls), shrinks it down again.

This is best illustrated by running it on the 'SimpleImageFilter' example, as vanilla as possible, and only checking the 'best resolution' box in IB.

Initial pass:

screen shot 2018-06-25 at 22 21 39

Subsequent passes:

screen shot 2018-06-25 at 22 21 43

I've so far tried a number of things, including:

I do feel as though the fact this fails to work on the example project either illustrates that I'm doing something wrong, or that it's not a simple one-liner.

FYI, this is in Xcode 9 / 10, and macOS 13. Thanks!

rorz commented 6 years ago

Found the source of the issue: RenderView class needs to implement re-scaled backing bounds, as outlined in the OpenGL spec here. It turns out that setting wantsBestResolutionOpenGLSurface alone isn't enough.

I will look at getting a PR going to implement this, but if you're in the same position as me, you can implement this really easily by modifying the RenderView source to the following:

let backingBounds = self.convertToBacking(self.bounds) // <-- magic line
let viewSize = GLSize(width:GLint(round(backingBounds.size.width)), height:GLint(round(backingBounds.size.height)))