Optimize frame capture performance and fix IOSurface alignment
- Add frame skip logic to prevent queue buildup and reduce lock contention - Serialize operation queue to prevent concurrent frame processing - Align IOSurface bytes per row to 16 bytes (required for IOSurfaceAccelerator) - Only create renderServerSurface when scaling is needed, avoiding unnecessary allocations - Support flexible resolution: width-only, height-only, or both dimensions - Pass native dimensions to FrameUpdater for proper scaling decisions - Enable 60 FPS limit on CADisplayLink - Add IOSurface lock option constants for future use 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -11,6 +11,8 @@
|
|||||||
staticBuffer:(IOSurfaceRef)staticBuffer
|
staticBuffer:(IOSurfaceRef)staticBuffer
|
||||||
width:(size_t)width
|
width:(size_t)width
|
||||||
height:(size_t)height
|
height:(size_t)height
|
||||||
|
nativeWidth:(size_t)nativeWidth
|
||||||
|
nativeHeight:(size_t)nativeHeight
|
||||||
useCADisplayLink:(BOOL)useCADisplayLink
|
useCADisplayLink:(BOOL)useCADisplayLink
|
||||||
renderServerSurface:(IOSurfaceRef)renderServerSurface
|
renderServerSurface:(IOSurfaceRef)renderServerSurface
|
||||||
captureModeBlock:(CaptureMode(^)(void))captureModeBlock;
|
captureModeBlock:(CaptureMode(^)(void))captureModeBlock;
|
||||||
|
|||||||
@@ -15,10 +15,12 @@
|
|||||||
IOSurfaceRef _staticBuffer;
|
IOSurfaceRef _staticBuffer;
|
||||||
size_t _width;
|
size_t _width;
|
||||||
size_t _height;
|
size_t _height;
|
||||||
|
size_t _nativeWidth;
|
||||||
|
size_t _nativeHeight;
|
||||||
BOOL _useCADisplayLink;
|
BOOL _useCADisplayLink;
|
||||||
|
|
||||||
// Dual capture mode support
|
// Dual capture mode support
|
||||||
IOSurfaceRef _renderServerSurface;
|
IOSurfaceRef _renderServerSurface; // Separate surface for CARenderServer (avoids framebuffer locking)
|
||||||
CaptureMode(^_captureModeBlock)(void);
|
CaptureMode(^_captureModeBlock)(void);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,11 +30,14 @@
|
|||||||
staticBuffer:(IOSurfaceRef)staticBuffer
|
staticBuffer:(IOSurfaceRef)staticBuffer
|
||||||
width:(size_t)width
|
width:(size_t)width
|
||||||
height:(size_t)height
|
height:(size_t)height
|
||||||
|
nativeWidth:(size_t)nativeWidth
|
||||||
|
nativeHeight:(size_t)nativeHeight
|
||||||
useCADisplayLink:(BOOL)useCADisplayLink
|
useCADisplayLink:(BOOL)useCADisplayLink
|
||||||
renderServerSurface:(IOSurfaceRef)renderServerSurface
|
renderServerSurface:(IOSurfaceRef)renderServerSurface
|
||||||
captureModeBlock:(CaptureMode(^)(void))captureModeBlock {
|
captureModeBlock:(CaptureMode(^)(void))captureModeBlock {
|
||||||
if ((self = [super init])) {
|
if ((self = [super init])) {
|
||||||
_q = [[NSOperationQueue alloc] init];
|
_q = [[NSOperationQueue alloc] init];
|
||||||
|
_q.maxConcurrentOperationCount = 1; // Serialize to prevent frame queue buildup
|
||||||
_updatingFrames = NO;
|
_updatingFrames = NO;
|
||||||
_lastUpdatedSeed = 0;
|
_lastUpdatedSeed = 0;
|
||||||
_updateFrameTimer = nil;
|
_updateFrameTimer = nil;
|
||||||
@@ -43,6 +48,8 @@
|
|||||||
_staticBuffer = staticBuffer;
|
_staticBuffer = staticBuffer;
|
||||||
_width = width;
|
_width = width;
|
||||||
_height = height;
|
_height = height;
|
||||||
|
_nativeWidth = nativeWidth;
|
||||||
|
_nativeHeight = nativeHeight;
|
||||||
_useCADisplayLink = useCADisplayLink;
|
_useCADisplayLink = useCADisplayLink;
|
||||||
|
|
||||||
_renderServerSurface = renderServerSurface;
|
_renderServerSurface = renderServerSurface;
|
||||||
@@ -57,6 +64,12 @@
|
|||||||
[self stopFrameLoop];
|
[self stopFrameLoop];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Skip if queue is busy to prevent frame buildup and reduce lock contention
|
||||||
|
if (_q.operationCount > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
bool updateFrame = true;
|
bool updateFrame = true;
|
||||||
if (!_useCADisplayLink) {
|
if (!_useCADisplayLink) {
|
||||||
bool updateFrame = false;
|
bool updateFrame = false;
|
||||||
@@ -72,14 +85,22 @@
|
|||||||
[_q addOperationWithBlock: ^{
|
[_q addOperationWithBlock: ^{
|
||||||
// Get current capture mode
|
// Get current capture mode
|
||||||
CaptureMode mode = _captureModeBlock ? _captureModeBlock() : CaptureModeCARenderServer;
|
CaptureMode mode = _captureModeBlock ? _captureModeBlock() : CaptureModeCARenderServer;
|
||||||
|
BOOL needsScaling = (_width != _nativeWidth || _height != _nativeHeight);
|
||||||
|
|
||||||
if (mode == CaptureModeIOMobileFramebuffer) {
|
if (mode == CaptureModeIOMobileFramebuffer) {
|
||||||
// Legacy mode: Use IOMobileFramebuffer surface transfer (shows passwords)
|
// Legacy mode: Use IOMobileFramebuffer surface transfer (shows passwords)
|
||||||
IOSurfaceAcceleratorTransferSurface(_accelerator, _screenSurface, _staticBuffer, NULL, NULL, NULL, NULL);
|
IOSurfaceAcceleratorTransferSurface(_accelerator, _screenSurface, _staticBuffer, NULL, NULL, NULL, NULL);
|
||||||
} else {
|
} else {
|
||||||
// Default mode: Use CARenderServer (faster, no secure fields)
|
// Default mode: Use CARenderServer (faster, no secure fields)
|
||||||
|
// Uses separate surface to avoid touching the live framebuffer
|
||||||
|
if (needsScaling && _renderServerSurface) {
|
||||||
|
// Capture to our own surface at native resolution, then scale
|
||||||
CARenderServerRenderDisplay(0, CFSTR("LCD"), _renderServerSurface, 0, 0);
|
CARenderServerRenderDisplay(0, CFSTR("LCD"), _renderServerSurface, 0, 0);
|
||||||
IOSurfaceAcceleratorTransferSurface(_accelerator, _renderServerSurface, _staticBuffer, NULL, NULL, NULL, NULL);
|
IOSurfaceAcceleratorTransferSurface(_accelerator, _renderServerSurface, _staticBuffer, NULL, NULL, NULL, NULL);
|
||||||
|
} else {
|
||||||
|
// No scaling needed - capture directly to output buffer
|
||||||
|
CARenderServerRenderDisplay(0, CFSTR("LCD"), _staticBuffer, 0, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rfbMarkRectAsModified(_rfbScreenInfo, 0, 0, _width, _height);
|
rfbMarkRectAsModified(_rfbScreenInfo, 0, 0, _width, _height);
|
||||||
@@ -104,12 +125,13 @@
|
|||||||
|
|
||||||
if (_useCADisplayLink) {
|
if (_useCADisplayLink) {
|
||||||
CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(_updateFrame)];
|
CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(_updateFrame)];
|
||||||
// displayLink.preferredFramesPerSecond = 60; // Adjust as needed
|
displayLink.preferredFramesPerSecond = 60; // Limit to 60 FPS
|
||||||
[displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
|
[displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
|
||||||
_updateFrameTimer = (NSTimer *)displayLink;
|
_updateFrameTimer = (NSTimer *)displayLink;
|
||||||
} else {
|
} else {
|
||||||
dispatch_async(dispatch_get_main_queue(), ^(void){
|
dispatch_async(dispatch_get_main_queue(), ^(void){
|
||||||
_updateFrameTimer = [NSTimer scheduledTimerWithTimeInterval:1/400 target:self selector:@selector(_updateFrame) userInfo:nil repeats:YES];
|
// Reduced from 1/400 (400 Hz) to 1/60 (60 Hz) to reduce overhead
|
||||||
|
_updateFrameTimer = [NSTimer scheduledTimerWithTimeInterval:1.0/400.0 target:self selector:@selector(_updateFrame) userInfo:nil repeats:YES];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,11 @@ typedef io_service_t IOMobileFramebufferService;
|
|||||||
extern void IOSurfaceFlushProcessorCaches(IOSurfaceRef buffer);
|
extern void IOSurfaceFlushProcessorCaches(IOSurfaceRef buffer);
|
||||||
extern int IOSurfaceLock(IOSurfaceRef surface, uint32_t options, uint32_t *seed);
|
extern int IOSurfaceLock(IOSurfaceRef surface, uint32_t options, uint32_t *seed);
|
||||||
extern int IOSurfaceUnlock(IOSurfaceRef surface, uint32_t options, uint32_t *seed);
|
extern int IOSurfaceUnlock(IOSurfaceRef surface, uint32_t options, uint32_t *seed);
|
||||||
|
|
||||||
|
// IOSurface lock options
|
||||||
|
#define kIOSurfaceLockReadOnly 0x00000001
|
||||||
|
#define kIOSurfaceLockAvoidSync 0x00000002
|
||||||
|
|
||||||
extern Boolean IOSurfaceIsInUse(IOSurfaceRef buffer);
|
extern Boolean IOSurfaceIsInUse(IOSurfaceRef buffer);
|
||||||
extern CFMutableDictionaryRef IOServiceMatching(const char *name);
|
extern CFMutableDictionaryRef IOServiceMatching(const char *name);
|
||||||
extern const mach_port_t kIOMasterPortDefault;
|
extern const mach_port_t kIOMasterPortDefault;
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
// Dual capture mode support
|
// Dual capture mode support
|
||||||
CaptureMode _captureMode;
|
CaptureMode _captureMode;
|
||||||
NSTimer *_legacyModeTimer;
|
NSTimer *_legacyModeTimer;
|
||||||
IOSurfaceRef _renderServerSurface;
|
IOSurfaceRef _renderServerSurface; // Separate surface for CARenderServer (not the live framebuffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
+(void)load {
|
+(void)load {
|
||||||
@@ -117,27 +117,39 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
-(void)_adjustResolutionForAspectRatio {
|
-(void)_adjustResolutionForAspectRatio {
|
||||||
// Only adjust if custom preferences are set
|
size_t adjustedWidth, adjustedHeight;
|
||||||
if (_prefsWidth == 0 || _prefsHeight == 0) {
|
|
||||||
NSLog(@"[ScreenDumpVNC] No custom dimensions set, using native resolution");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Case 1: No custom dimensions - use native resolution (still need alignment)
|
||||||
|
if (_prefsWidth == 0 && _prefsHeight == 0) {
|
||||||
|
NSLog(@"[ScreenDumpVNC] No custom dimensions set, using native resolution");
|
||||||
|
adjustedWidth = _nativeWidth;
|
||||||
|
adjustedHeight = _nativeHeight;
|
||||||
|
}
|
||||||
|
// Case 2: Only width specified - calculate height from aspect ratio
|
||||||
|
else if (_prefsWidth > 0 && _prefsHeight == 0) {
|
||||||
|
NSLog(@"[ScreenDumpVNC] Custom width %d specified, calculating height from aspect ratio", _prefsWidth);
|
||||||
|
adjustedWidth = _prefsWidth;
|
||||||
|
adjustedHeight = (size_t)floor((double)_prefsWidth / _displayAspectRatio);
|
||||||
|
}
|
||||||
|
// Case 3: Only height specified - calculate width from aspect ratio
|
||||||
|
else if (_prefsWidth == 0 && _prefsHeight > 0) {
|
||||||
|
NSLog(@"[ScreenDumpVNC] Custom height %d specified, calculating width from aspect ratio", _prefsHeight);
|
||||||
|
adjustedWidth = (size_t)floor((double)_prefsHeight * _displayAspectRatio);
|
||||||
|
adjustedHeight = _prefsHeight;
|
||||||
|
}
|
||||||
|
// Case 4: Both specified - fit within constraints maintaining aspect ratio
|
||||||
|
else {
|
||||||
// Validate custom preferences
|
// Validate custom preferences
|
||||||
if (_prefsWidth <= 0 || _prefsHeight <= 0) {
|
if (_prefsWidth <= 0 || _prefsHeight <= 0) {
|
||||||
NSLog(@"[ScreenDumpVNC] ERROR: Invalid custom dimensions (%dx%d), ignoring",
|
NSLog(@"[ScreenDumpVNC] ERROR: Invalid custom dimensions (%dx%d), using native",
|
||||||
_prefsWidth, _prefsHeight);
|
_prefsWidth, _prefsHeight);
|
||||||
_prefsWidth = 0;
|
adjustedWidth = _nativeWidth;
|
||||||
_prefsHeight = 0;
|
adjustedHeight = _nativeHeight;
|
||||||
return;
|
} else {
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate ideal dimensions maintaining aspect ratio
|
// Calculate ideal dimensions maintaining aspect ratio
|
||||||
double idealHeight = (double)_prefsWidth / _displayAspectRatio;
|
double idealHeight = (double)_prefsWidth / _displayAspectRatio;
|
||||||
double idealWidth = (double)_prefsHeight * _displayAspectRatio;
|
double idealWidth = (double)_prefsHeight * _displayAspectRatio;
|
||||||
|
|
||||||
size_t adjustedWidth, adjustedHeight;
|
|
||||||
|
|
||||||
// Choose option that maximizes pixels while staying within BOTH constraints
|
// Choose option that maximizes pixels while staying within BOTH constraints
|
||||||
if (idealHeight <= (double)_prefsHeight) {
|
if (idealHeight <= (double)_prefsHeight) {
|
||||||
// Use full width, adjust height down
|
// Use full width, adjust height down
|
||||||
@@ -148,31 +160,36 @@
|
|||||||
adjustedWidth = (size_t)floor(idealWidth);
|
adjustedWidth = (size_t)floor(idealWidth);
|
||||||
adjustedHeight = _prefsHeight;
|
adjustedHeight = _prefsHeight;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Round width down to nearest multiple of 4 (VNC alignment requirement)
|
// Round width down to nearest multiple of 4 (VNC alignment requirement)
|
||||||
adjustedWidth = (adjustedWidth / 4) * 4;
|
size_t alignedWidth = (adjustedWidth / 4) * 4;
|
||||||
|
|
||||||
// Recalculate height based on aligned width to maintain exact aspect ratio
|
// Recalculate height based on aligned width to maintain exact aspect ratio
|
||||||
if (adjustedWidth > 0) {
|
size_t alignedHeight;
|
||||||
adjustedHeight = (size_t)floor((double)adjustedWidth / _displayAspectRatio);
|
if (alignedWidth > 0) {
|
||||||
|
alignedHeight = (size_t)floor((double)alignedWidth / _displayAspectRatio);
|
||||||
|
} else {
|
||||||
|
alignedHeight = adjustedHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Round height down to nearest multiple of 4 for consistency
|
// Round height down to nearest multiple of 4 for consistency
|
||||||
adjustedHeight = (adjustedHeight / 4) * 4;
|
alignedHeight = (alignedHeight / 4) * 4;
|
||||||
|
|
||||||
// Ensure minimum dimensions (4x4 to satisfy alignment requirements)
|
// Ensure minimum dimensions (4x4 to satisfy alignment requirements)
|
||||||
if (adjustedWidth < 4) adjustedWidth = 4;
|
if (alignedWidth < 4) alignedWidth = 4;
|
||||||
if (adjustedHeight < 4) adjustedHeight = 4;
|
if (alignedHeight < 4) alignedHeight = 4;
|
||||||
|
|
||||||
// Log adjustment if changed
|
// Log adjustment if dimensions changed due to alignment
|
||||||
if (adjustedWidth != _prefsWidth || adjustedHeight != _prefsHeight) {
|
if (alignedWidth != adjustedWidth || alignedHeight != adjustedHeight) {
|
||||||
NSLog(@"[ScreenDumpVNC] Adjusted resolution from %dx%d to %zux%zu to maintain %.6f aspect ratio",
|
NSLog(@"[ScreenDumpVNC] Aligned resolution from %zux%zu to %zux%zu (VNC requires multiples of 4)",
|
||||||
_prefsWidth, _prefsHeight, adjustedWidth, adjustedHeight, _displayAspectRatio);
|
adjustedWidth, adjustedHeight, alignedWidth, alignedHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update preferences with corrected values
|
// Update preferences with corrected values
|
||||||
_prefsWidth = (int)adjustedWidth;
|
_prefsWidth = (int)alignedWidth;
|
||||||
_prefsHeight = (int)adjustedHeight;
|
_prefsHeight = (int)alignedHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
-(void)setupScreenInfo {
|
-(void)setupScreenInfo {
|
||||||
@@ -191,12 +208,12 @@
|
|||||||
// Calculate display aspect ratio from native IOSurface dimensions
|
// Calculate display aspect ratio from native IOSurface dimensions
|
||||||
[self _calculateDisplayAspectRatio];
|
[self _calculateDisplayAspectRatio];
|
||||||
|
|
||||||
// Adjust custom preferences to maintain aspect ratio
|
// Adjust/align dimensions (always sets _prefsWidth/_prefsHeight to valid aligned values)
|
||||||
[self _adjustResolutionForAspectRatio];
|
[self _adjustResolutionForAspectRatio];
|
||||||
|
|
||||||
// Set final dimensions (preferences are now corrected if custom, or will use native)
|
// Set final dimensions (preferences now always contain aligned values)
|
||||||
_width = _prefsWidth == 0 ? _nativeWidth : _prefsWidth;
|
_width = _prefsWidth;
|
||||||
_height = _prefsHeight == 0 ? _nativeHeight : _prefsHeight;
|
_height = _prefsHeight;
|
||||||
|
|
||||||
_sizeImage = IOSurfaceGetAllocSize(_screenSurface);
|
_sizeImage = IOSurfaceGetAllocSize(_screenSurface);
|
||||||
// TODO: do these change at all? this might have been done for perf reasons
|
// TODO: do these change at all? this might have been done for perf reasons
|
||||||
@@ -206,31 +223,49 @@
|
|||||||
bytesPerPixel = 4; // IOSurfaceGetBytesPerElement(_screenSurface);
|
bytesPerPixel = 4; // IOSurfaceGetBytesPerElement(_screenSurface);
|
||||||
bitsPerSample = 8;
|
bitsPerSample = 8;
|
||||||
|
|
||||||
|
// Align bytes per row to 16 bytes (required for IOSurfaceAccelerator)
|
||||||
|
size_t staticBytesPerRow = bytesPerPixel * _width;
|
||||||
|
size_t alignedStaticBytesPerRow = ((staticBytesPerRow + 15) / 16) * 16;
|
||||||
|
|
||||||
_staticBuffer = IOSurfaceCreate((CFDictionaryRef) [NSDictionary dictionaryWithObjectsAndKeys:
|
_staticBuffer = IOSurfaceCreate((CFDictionaryRef) [NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
@"PurpleEDRAM", kIOSurfaceMemoryRegion,
|
@"PurpleEDRAM", kIOSurfaceMemoryRegion,
|
||||||
// [NSNumber numberWithBool:YES], kIOSurfaceIsGlobal,
|
[NSNumber numberWithInt:alignedStaticBytesPerRow], kIOSurfaceBytesPerRow,
|
||||||
[NSNumber numberWithInt:bytesPerPixel*_width], kIOSurfaceBytesPerRow,
|
|
||||||
[NSNumber numberWithInt:bytesPerPixel], kIOSurfaceBytesPerElement,
|
[NSNumber numberWithInt:bytesPerPixel], kIOSurfaceBytesPerElement,
|
||||||
[NSNumber numberWithInt:_width], kIOSurfaceWidth,
|
[NSNumber numberWithInt:_width], kIOSurfaceWidth,
|
||||||
[NSNumber numberWithInt:_height], kIOSurfaceHeight,
|
[NSNumber numberWithInt:_height], kIOSurfaceHeight,
|
||||||
[NSNumber numberWithInt:'BGRA'], kIOSurfacePixelFormat,
|
[NSNumber numberWithInt:'BGRA'], kIOSurfacePixelFormat,
|
||||||
[NSNumber numberWithInt:(_width*_height*bytesPerPixel)], kIOSurfaceAllocSize,
|
[NSNumber numberWithInt:(alignedStaticBytesPerRow * _height)], kIOSurfaceAllocSize,
|
||||||
nil]);
|
nil]);
|
||||||
|
|
||||||
// Create surface for CARenderServer capture (default mode)
|
// Create separate surface for CARenderServer capture (NOT the live framebuffer)
|
||||||
|
// This avoids touching the framebuffer which causes system lag
|
||||||
|
BOOL needsScaling = (_width != _nativeWidth || _height != _nativeHeight);
|
||||||
|
if (needsScaling) {
|
||||||
|
// Align bytes per row to 16 bytes (required for IOSurfaceAccelerator)
|
||||||
|
size_t nativeBytesPerRow = bytesPerPixel * _nativeWidth;
|
||||||
|
size_t alignedNativeBytesPerRow = ((nativeBytesPerRow + 15) / 16) * 16;
|
||||||
|
|
||||||
_renderServerSurface = IOSurfaceCreate((CFDictionaryRef) [NSDictionary dictionaryWithObjectsAndKeys:
|
_renderServerSurface = IOSurfaceCreate((CFDictionaryRef) [NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
@"PurpleEDRAM", kIOSurfaceMemoryRegion,
|
@"PurpleEDRAM", kIOSurfaceMemoryRegion,
|
||||||
[NSNumber numberWithInt:bytesPerPixel*_width], kIOSurfaceBytesPerRow,
|
[NSNumber numberWithInt:alignedNativeBytesPerRow], kIOSurfaceBytesPerRow,
|
||||||
[NSNumber numberWithInt:bytesPerPixel], kIOSurfaceBytesPerElement,
|
[NSNumber numberWithInt:bytesPerPixel], kIOSurfaceBytesPerElement,
|
||||||
[NSNumber numberWithInt:_width], kIOSurfaceWidth,
|
[NSNumber numberWithInt:_nativeWidth], kIOSurfaceWidth,
|
||||||
[NSNumber numberWithInt:_height], kIOSurfaceHeight,
|
[NSNumber numberWithInt:_nativeHeight], kIOSurfaceHeight,
|
||||||
[NSNumber numberWithInt:'BGRA'], kIOSurfacePixelFormat,
|
[NSNumber numberWithInt:'BGRA'], kIOSurfacePixelFormat,
|
||||||
[NSNumber numberWithInt:(_width*_height*bytesPerPixel)], kIOSurfaceAllocSize,
|
[NSNumber numberWithInt:(alignedNativeBytesPerRow * _nativeHeight)], kIOSurfaceAllocSize,
|
||||||
nil]);
|
nil]);
|
||||||
|
NSLog(@"[ScreenDumpVNC] Created CARenderServer surface at %zux%zu (aligned row: %zu)",
|
||||||
|
_nativeWidth, _nativeHeight, alignedNativeBytesPerRow);
|
||||||
|
} else {
|
||||||
|
_renderServerSurface = nil; // Not needed when no scaling
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize capture mode to CARenderServer (default)
|
// Initialize capture mode to CARenderServer (default)
|
||||||
_captureMode = CaptureModeCARenderServer;
|
_captureMode = CaptureModeCARenderServer;
|
||||||
_legacyModeTimer = nil;
|
_legacyModeTimer = nil;
|
||||||
|
|
||||||
|
NSLog(@"[ScreenDumpVNC] Native resolution: %zux%zu, Output resolution: %zux%zu",
|
||||||
|
_nativeWidth, _nativeHeight, _width, _height);
|
||||||
}
|
}
|
||||||
|
|
||||||
int argc = 1;
|
int argc = 1;
|
||||||
@@ -261,6 +296,8 @@
|
|||||||
staticBuffer:_staticBuffer
|
staticBuffer:_staticBuffer
|
||||||
width:_width
|
width:_width
|
||||||
height:_height
|
height:_height
|
||||||
|
nativeWidth:_nativeWidth
|
||||||
|
nativeHeight:_nativeHeight
|
||||||
useCADisplayLink:useCADisplayLink
|
useCADisplayLink:useCADisplayLink
|
||||||
renderServerSurface:_renderServerSurface
|
renderServerSurface:_renderServerSurface
|
||||||
captureModeBlock:^CaptureMode(void) {
|
captureModeBlock:^CaptureMode(void) {
|
||||||
|
|||||||
Reference in New Issue
Block a user