diff --git a/pip.xcodeproj/project.pbxproj b/pip.xcodeproj/project.pbxproj index 32cebbc..e5875fd 100644 --- a/pip.xcodeproj/project.pbxproj +++ b/pip.xcodeproj/project.pbxproj @@ -813,7 +813,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CODE_SIGN_STYLE = Automatic; EXECUTABLE_PREFIX = lib; - MACOSX_DEPLOYMENT_TARGET = 12.1; + MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -829,7 +829,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CODE_SIGN_STYLE = Automatic; EXECUTABLE_PREFIX = lib; - MACOSX_DEPLOYMENT_TARGET = 12.1; + MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_FAST_MATH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; diff --git a/pip/imageRenderer.h b/pip/imageRenderer.h index 348e3f0..20ef98e 100644 --- a/pip/imageRenderer.h +++ b/pip/imageRenderer.h @@ -19,7 +19,7 @@ @property (nonatomic,strong) CIContext *context; @property (nonatomic,strong,readonly) NSView *view; @property (nonatomic,strong) id delegate; -- (instancetype)init; +- (instancetype)init:(BOOL)hidpi; - (NSRect)cropRect; - (void)setScale:(float) scale; - (void)setCropRect:(NSRect) rect; diff --git a/pip/info.plist b/pip/info.plist index 03df198..21bb164 100644 --- a/pip/info.plist +++ b/pip/info.plist @@ -5,9 +5,9 @@ Icon file AppIcon CFBundleVersion - 18 + 19 CFBundleShortVersionString - 2.41 + 2.50 CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier diff --git a/pip/metalRenderer.m b/pip/metalRenderer.m index 82e24c4..0d56621 100644 --- a/pip/metalRenderer.m +++ b/pip/metalRenderer.m @@ -28,7 +28,7 @@ @implementation MetalRenderer{ @synthesize context; @synthesize delegate; -- (instancetype)init{ +- (instancetype)init:(BOOL)hidpi{ self = [super init]; self.image = nil; self.device = MTLCreateSystemDefaultDevice(); @@ -36,10 +36,11 @@ - (instancetype)init{ self.view.clearColor = MTLClearColorMake(0, 0, 0, 0); self.view.delegate = self; self.view.framebufferOnly = NO; - self.view.autoResizeDrawable = YES; + self.view.autoResizeDrawable = true; self.view.enableSetNeedsDisplay = YES; + self.view.wantsBestResolutionOpenGLSurface = hidpi; colorspace = CGColorSpaceCreateDeviceRGB(); - self.context = [CIContext contextWithMTLDevice:self.device options:@{kCIContextWorkingColorSpace: (__bridge id)colorspace}]; + self.context = [CIContext contextWithMTLDevice:self.device options:@{kCIContextWorkingColorSpace: (__bridge id)colorspace,}]; self.commandQueue = [self.device newCommandQueue]; imageScale = 0; @@ -53,18 +54,8 @@ - (void)dealloc{ - (void)setCropRect:(NSRect) rect{ if(!self.image) return; - NSSize frameSize = self.view.frame.size; - NSSize imageSize = self.image.extent.size; - float scale = frameSize.width / imageSize.width; - - if(rect.size.width * rect.size.height <= 1) goto end; - rect = NSMakeRect(rect.origin.x / scale, rect.origin.y / scale, rect.size.width / scale, rect.size.height / scale); - if(rect.size.width * rect.size.height <= 1) goto end; - cropRect = rect; - return; - - end: - cropRect = CGRectZero; + float scale = self.image.extent.size.width / self.view.frame.size.width; + cropRect = CGRectApplyAffineTransform(rect, CGAffineTransformMakeScale(scale, scale)); } - (void)drawInMTKView:(MTKView *)view { @@ -74,10 +65,14 @@ - (void)drawInMTKView:(MTKView *)view { CIImage* image = self.image; - if(cropRect.size.width * cropRect.size.height != 0) image = [image imageByCroppingToRect:cropRect]; - + NSRect bounds = {.size = image.extent.size}; NSSize frameSize = self.view.frame.size; - NSSize imageSize = image.extent.size; + float hidpi_scale = self.view.wantsBestResolutionOpenGLSurface ? self.view.window.backingScaleFactor : 1; + + if(cropRect.size.width * cropRect.size.height != 0) bounds = cropRect; + bounds = CGRectApplyAffineTransform(bounds, CGAffineTransformMakeScale(1.0/hidpi_scale, 1.0/hidpi_scale)); + + NSSize imageSize = bounds.size; NSSize availSize = self.view.window.screen.visibleFrame.size; float frameAspectRatio = frameSize.width / frameSize.height; @@ -103,12 +98,19 @@ - (void)drawInMTKView:(MTKView *)view { if(arr < 0.99 || arr > 1.01) [self.delegate onResize:targetSize andAspectRatio:targetSize]; - float scale = targetSize.width / imageSize.width; - image = (scale < 0.99 || scale > 1.01) ? [image imageByApplyingTransform:CGAffineTransformMakeScale(scale, scale)] : image; + float scale = targetSize.width / (imageSize.width / hidpi_scale); + + self.view.drawableSize = CGSizeApplyAffineTransform(bounds.size, CGAffineTransformMakeScale(hidpi_scale, hidpi_scale)); + bounds = CGRectApplyAffineTransform(bounds, CGAffineTransformMakeScale(scale, scale)); + + // if(targetSize.width < imageSize.width){ + scale /= hidpi_scale; + image = [image imageByApplyingTransform:CGAffineTransformMakeScale(scale, scale)]; + self.view.drawableSize = bounds.size; + // } - self.view.drawableSize = targetSize; id commandBuffer = [self.commandQueue commandBuffer]; - [self.context render:image toMTLTexture:outputTexture commandBuffer:commandBuffer bounds:image.extent colorSpace:colorspace]; + [self.context render:image toMTLTexture:outputTexture commandBuffer:commandBuffer bounds:bounds colorSpace:colorspace]; [commandBuffer presentDrawable:self.view.currentDrawable]; [commandBuffer commit]; } diff --git a/pip/openGLRenderer.m b/pip/openGLRenderer.m index 0eaa167..75eb747 100644 --- a/pip/openGLRenderer.m +++ b/pip/openGLRenderer.m @@ -55,25 +55,22 @@ @implementation OpenGLRenderer{ @synthesize context; @synthesize delegate; -- (instancetype)init{ +- (instancetype)init:(BOOL)hidpi{ self = [super init]; cropRect = CGRectZero; GLView *openGLView = [[GLView alloc] initWithFrame:CGRectZero pixelFormat:[NSOpenGLView defaultPixelFormat]]; openGLView.renderDelegate = self; self.view = openGLView; self.view.openGLContext = getGLContext(); - self.view.wantsBestResolutionOpenGLSurface = NO; + self.view.wantsBestResolutionOpenGLSurface = hidpi; self.context = getCIContext(); return self; } - (void)setCropRect:(NSRect) rect{ if(!self.image) return; - NSSize frameSize = self.view.frame.size; - NSSize imageSize = self.image.extent.size; - float scale = frameSize.width / imageSize.width; - rect = NSMakeRect(rect.origin.x / scale, rect.origin.y / scale, rect.size.width / scale, rect.size.height / scale); - cropRect = rect; + float scale = self.image.extent.size.width / self.view.frame.size.width; + cropRect = CGRectApplyAffineTransform(rect, CGAffineTransformMakeScale(scale, scale)); } - (void)openGLView:(GLView *)view drawRect:(CGRect)rect { @@ -81,7 +78,11 @@ - (void)openGLView:(GLView *)view drawRect:(CGRect)rect { NSSize frameSize = self.view.frame.size; NSSize targetSize = frameSize; - NSSize imageSize = cropRect.size.width * cropRect.size.height == 0 ? self.image.extent.size : cropRect.size; + float hidpi_scale = self.view.wantsBestResolutionOpenGLSurface ? self.view.window.backingScaleFactor : 1; + + NSSize imageSize = CGSizeZero; + if(cropRect.size.width * cropRect.size.height != 0) imageSize = CGSizeApplyAffineTransform(cropRect.size, CGAffineTransformMakeScale(1.0/hidpi_scale, 1.0/hidpi_scale)); + else imageSize = CGSizeApplyAffineTransform(self.image.extent.size, CGAffineTransformMakeScale(1.0/hidpi_scale, 1.0/hidpi_scale)); NSSize availSize = self.view.window.screen.visibleFrame.size; float frameAspectRatio = frameSize.width / frameSize.height; @@ -106,15 +107,14 @@ - (void)openGLView:(GLView *)view drawRect:(CGRect)rect { if(arr < 0.99 || arr > 1.01) [self.delegate onResize:targetSize andAspectRatio:targetSize]; - NSRect fromRect = cropRect.size.width * cropRect.size.height == 0 ? self.image.extent : cropRect; + NSRect fromRect = cropRect.size.width * cropRect.size.height == 0 ? (NSRect){.size = self.image.extent.size} : cropRect; - NSRect inRect = CGRectZero; - inRect.size = targetSize; + NSRect inRect = {.size = targetSize}; glMatrixMode(GL_PROJECTION); glLoadIdentity(); - glViewport(0, 0, targetSize.width, targetSize.height); + glViewport(0, 0, targetSize.width * hidpi_scale, targetSize.height * hidpi_scale); glOrtho(0, targetSize.width, 0, targetSize.height, -1, 1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); diff --git a/pip/preferences.m b/pip/preferences.m index 6aed71c..ea0db95 100644 --- a/pip/preferences.m +++ b/pip/preferences.m @@ -23,6 +23,7 @@ static NSArray* getPrefsArray(void){ return @[ + OPTION(hidpi, "Use HiDPI mode", CheckBox, [NSNull null], @0, @"on supported displays"), OPTION(renderer, "Display Renderer", Select, (@[@"Metal", @"Opengl"]), [NSNumber numberWithInt:DisplayRendererTypeOpenGL], [NSNull null]), #ifndef NO_AIRPLAY OPTION(airplay, "AirPlay Receiver", CheckBox, [NSNull null], @1, @"Use PiP as Airplay receiver"), @@ -60,7 +61,7 @@ @implementation Preferences{ -(id)init{ self = [super - initWithContentRect:NSMakeRect(0, 0, 450, 200) + initWithContentRect:NSMakeRect(0, 0, 450, 210) styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskNonactivatingPanel backing:NSBackingStoreBuffered defer:YES ]; diff --git a/pip/window.m b/pip/window.m index 5998819..1c70b9d 100644 --- a/pip/window.m +++ b/pip/window.m @@ -211,10 +211,13 @@ static void request_permission(const char* perm_string){ [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"x-apple.systempreferences:com.apple.preference.security?Privacy_%s", perm_string]]]; } -static CGImageRef CaptureWindow(CGWindowID wid){ +static CGImageRef CaptureWindow(CGWindowID wid, bool hidpi){ CGImageRef window_image = NULL; CFArrayRef window_image_arr = NULL; - window_image_arr = CGSHWCaptureWindowList(CGSMainConnectionID(), &wid, 1, kCGSCaptureIgnoreGlobalClipShape | kCGSWindowCaptureNominalResolution); + window_image_arr = CGSHWCaptureWindowList(CGSMainConnectionID(), &wid, 1, 0 + | kCGSCaptureIgnoreGlobalClipShape + | (hidpi ? 0 : kCGSWindowCaptureNominalResolution) + ); if(window_image_arr) window_image = (CGImageRef)CFArrayGetValueAtIndex(window_image_arr, 0); if(!window_image) window_image = CGWindowListCreateImage(CGRectNull, kCGWindowListOptionIncludingWindow, wid, kCGWindowImageNominalResolution | kCGWindowImageBoundsIgnoreFraming); return window_image; @@ -398,6 +401,7 @@ @implementation Window{ VButton* playbutt; float contentAR; int refreshRate; + bool is_hidpi; bool shouldClose; bool isWinClosing; bool isPipCLosing; @@ -441,6 +445,7 @@ - (id) initWithAirplay:(bool)enable andTitle:(NSString*)title{ display_stream = NULL; shouldEnableFullScreen = is_playing = is_airplay_session = enable; + is_hidpi = [(NSNumber*)getPref(@"hidpi") intValue] > 0 && !is_airplay_session; self = [super initWithContentRect:kStartRect styleMask:kWindowMask backing:NSBackingStoreBuffered defer:YES]; @@ -502,7 +507,7 @@ - (id) initWithAirplay:(bool)enable andTitle:(NSString*)title{ rootView.autoresizingMask = NSViewHeightSizable | NSViewWidthSizable | NSViewMinXMargin | NSViewMaxXMargin | NSViewMinYMargin | NSViewMaxYMargin; imageView = [[ImageView alloc] initWithFrame:kStartRect]; - imageView.renderer = [(NSNumber*)getPref(@"renderer") intValue] == DisplayRendererTypeOpenGL ? [[OpenGLRenderer alloc] init] : [[MetalRenderer alloc] init]; + imageView.renderer = [(NSNumber*)getPref(@"renderer") intValue] == DisplayRendererTypeOpenGL ? [[OpenGLRenderer alloc] init:is_hidpi] : [[MetalRenderer alloc] init:is_hidpi]; imageView.renderer.delegate = self; imageView.hidden = !is_airplay_session; @@ -817,7 +822,7 @@ - (void) renderH264:(uint8_t*) data withLength:(size_t) length{ } - (void)capture{ - CGImageRef window_image = window_id >= 0 ? CaptureWindow(window_id) : (display_id >= 0 ? CGDisplayCreateImage(display_id) : NULL); + CGImageRef window_image = window_id >= 0 ? CaptureWindow(window_id, is_hidpi) : (display_id >= 0 ? CGDisplayCreateImage(display_id) : NULL); if(window_image != NULL){ CIImage* ciimage = [CIImage imageWithCGImage:window_image]; CGRect imageRect = [ciimage extent]; @@ -962,7 +967,7 @@ - (void)rightMouseDown:(NSEvent *)theEvent { } } else{ - CGImageRef window_image = CaptureWindow(windowId); + CGImageRef window_image = CaptureWindow(windowId, false); if(window_image == NULL) continue; isFaulty = CGImageGetHeight(window_image) * CGImageGetWidth(window_image) <= 1; CGImageRelease(window_image); @@ -1101,6 +1106,7 @@ - (void)changeWindow:(id)sender{ else if(display_id >= 0){ size_t width = CGDisplayPixelsWide(display_id); size_t height = CGDisplayPixelsHigh(display_id); + if(is_hidpi) width *= self.backingScaleFactor, height *= self.backingScaleFactor; NSDictionary* opts = @{ (__bridge NSString *)kCGDisplayStreamMinimumFrameTime : @(1.0f / refreshRate),