1 /* 2 * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #import "GlassLayer3D.h" 27 28 #import "GlassMacros.h" 29 #import "RemoteLayerSupport.h" 30 #import "GlassScreen.h" 31 32 //#define VERBOSE 33 #ifndef VERBOSE 34 #define LOG(MSG, ...) 35 #else 36 #define LOG(MSG, ...) GLASS_LOG(MSG, ## __VA_ARGS__); 37 #endif 38 39 @implementation GlassLayer3D 40 41 static NSArray *allModes = nil; 42 43 - (void)_connectToRemoteServer:(NSString*)serverName 44 { 45 // SAK: Note that RemoteLayerGetServerPort can return 0/MACH_PORT_NULL. This is 46 // not an error, and means that JRSRenderServer is tracking the port for us. 47 // Yes, this is odd, and I've asked Apple to clarify it for us. 48 self->_serverPort = RemoteLayerGetServerPort(serverName); 49 self->_remoteLayer = RemoteLayerGetRemoteFromLocal(self->_serverPort, self); 50 if (self->_remoteLayer != nil) 51 { 52 self->_remoteLayerID = RemoteLayerGetIdForRemote(self->_remoteLayer); 53 if (self->_remoteLayerID != 0) 54 { 55 [self->_remoteLayer retain]; 56 } 57 else 58 { 59 NSLog(@"RemoteLayer ERROR: 0 _remoteLayerID for serverName:%@", serverName); 60 } 61 } 62 else 63 { 64 NSLog(@"RemoteLayer ERROR: nil remoteLayer for serverName:%@", serverName); 65 } 66 } 67 68 - (id)initWithSharedContext:(CGLContextObj)ctx 69 andClientContext:(CGLContextObj)clCtx 70 withHiDPIAware:(BOOL)HiDPIAware 71 withIsSwPipe:(BOOL)isSwPipe 72 { 73 LOG("GlassLayer3D initWithSharedContext]"); 74 self = [super init]; 75 if (self != nil) 76 { 77 self->_serverPort = MACH_PORT_NULL; 78 self->_remoteLayer = nil; 79 self->_remoteLayerID = 0; 80 81 self->_painterOffscreen = [[GlassOffscreen alloc] initWithContext:clCtx andIsSwPipe:isSwPipe]; 82 self->_glassOffscreen = [[GlassOffscreen alloc] initWithContext:ctx andIsSwPipe:isSwPipe]; 83 [self->_glassOffscreen setLayer:self]; 84 LOG(" GlassLayer3D context: %p", ctx); 85 86 self->isHiDPIAware = HiDPIAware; 87 88 [self setAsynchronous:NO]; 89 [self setAutoresizingMask:(kCALayerWidthSizable|kCALayerHeightSizable)]; 90 [self setContentsGravity:kCAGravityTopLeft]; 91 92 // Initially the view is not in any window yet, so using the 93 // screens[0]'s scale is a good starting point (this is most probably 94 // the notebook's main LCD display which is HiDPI-capable). 95 // Note that mainScreen is the screen with the current app bar focus 96 // in Mavericks and later OS so it will likely not match the screen 97 // we initially show windows on if an app is started from an external 98 // monitor. 99 [self notifyScaleFactorChanged:GetScreenScaleFactor([[NSScreen screens] objectAtIndex:0])]; 100 101 [self setMasksToBounds:YES]; 102 [self setNeedsDisplayOnBoundsChange:YES]; 103 [self setAnchorPoint:CGPointMake(0.0f, 0.0f)]; 104 105 if (allModes == nil) { 106 allModes = [[NSArray arrayWithObjects:NSDefaultRunLoopMode, 107 NSEventTrackingRunLoopMode, 108 NSModalPanelRunLoopMode, nil] retain]; 109 } 110 } 111 return self; 112 } 113 114 - (void)dealloc 115 { 116 [self->_glassOffscreen release]; 117 self->_glassOffscreen = nil; 118 119 [self->_painterOffscreen release]; 120 self->_painterOffscreen = nil; 121 122 [self->_remoteLayer dealloc]; 123 self->_remoteLayer = nil; 124 125 [super dealloc]; 126 } 127 128 - (void)notifyScaleFactorChanged:(CGFloat)scale 129 { 130 if (self->isHiDPIAware) { 131 if ([self respondsToSelector:@selector(setContentsScale:)]) { 132 [self setContentsScale: scale]; 133 } 134 } 135 } 136 137 //- (void)setBounds:(CGRect)bounds 138 //{ 139 // LOG("GlassLayer3D setBounds:%s", [NSStringFromRect(NSRectFromCGRect(bounds)) UTF8String]); 140 // [super setBounds:bounds]; 141 //} 142 143 - (BOOL)canDrawInCGLContext:(CGLContextObj)glContext pixelFormat:(CGLPixelFormatObj)pixelFormat forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp 144 { 145 return [self->_glassOffscreen isDirty]; 146 } 147 148 - (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat 149 { 150 return CGLRetainContext([self->_glassOffscreen getContext]); 151 } 152 153 - (CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask 154 { 155 return CGLRetainPixelFormat(CGLGetPixelFormat([self->_glassOffscreen getContext])); 156 } 157 158 - (void)drawInCGLContext:(CGLContextObj)glContext pixelFormat:(CGLPixelFormatObj)pixelFormat forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp 159 { 160 // glContext is already set as current by now and locked by Quartz internaly 161 LOG("GlassLayer3D drawInCGLContext]"); 162 LOG(" current context: %p", CGLGetCurrentContext()); 163 #ifdef VERBOSE 164 { 165 GLint fbo = 0; // default to screen 166 glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, (GLint*)&fbo); 167 LOG(" fbo: %d", fbo); 168 } 169 #endif 170 // the viewport is already set for us here, so just blit 171 172 #if 0 173 // this will stretch the offscreen to cover all the surface 174 // ie., live resizing "appears" better, but the blit area is not at 1:1 scale 175 [self->_glassOffscreen blit]; 176 #else 177 // we blit only in the area we rendered in 178 GLint params[] = { 0, 0, 0, 0 }; 179 glGetIntegerv(GL_VIEWPORT, params); 180 if ((params[2] > 0) && ((params[3] > 0))) 181 { 182 [self->_glassOffscreen blitForWidth:(GLuint)params[2] andHeight:(GLuint)params[3]]; 183 } 184 #endif 185 186 // the default implementation of the method flushes the context. 187 [super drawInCGLContext:glContext pixelFormat:pixelFormat forLayerTime:timeInterval displayTime:timeStamp]; 188 LOG("\n"); 189 } 190 191 - (void)flush 192 { 193 [(GlassOffscreen*)_glassOffscreen blitFromOffscreen:(GlassOffscreen*)_painterOffscreen]; 194 if ([NSThread isMainThread]) { 195 [[self->_glassOffscreen getLayer] setNeedsDisplay]; 196 } else { 197 [[self->_glassOffscreen getLayer] performSelectorOnMainThread:@selector(setNeedsDisplay) 198 withObject:nil 199 waitUntilDone:NO 200 modes:allModes]; 201 } 202 } 203 204 - (uint32_t)getRemoteLayerIdForServer:(NSString*)serverName 205 { 206 if (self->_remoteLayerID == 0) 207 { 208 Class JRSRemoteLayer_class = objc_getClass("JRSRenderServer"); 209 if (JRSRemoteLayer_class != nil) 210 { 211 [self _connectToRemoteServer:serverName]; 212 } 213 else 214 { 215 NSLog(@"GlassLayer3D: no remote CALayer server support detected!"); 216 // we're running on JDK without remote CALayer server (JRSRemoteLayer.h) support 217 } 218 } 219 return self->_remoteLayerID; 220 } 221 222 - (void)hostRemoteLayerId:(uint32_t)layerId 223 { 224 if (layerId > 0) 225 { 226 RemoteLayerHostRemoteIdInLocal(layerId, self); 227 } 228 else 229 { 230 NSLog(@"GlassLayer3D: invalid remote layer id!"); 231 } 232 } 233 234 - (GlassOffscreen*)getPainterOffscreen 235 { 236 return self->_painterOffscreen; 237 } 238 239 - (GlassOffscreen*)getGlassOffscreen 240 { 241 return self->_glassOffscreen; 242 } 243 244 - (void)hostOffscreen:(GlassOffscreen*)offscreen 245 { 246 [self->_glassOffscreen release]; 247 self->_glassOffscreen = [offscreen retain]; 248 [self->_glassOffscreen setLayer:self]; 249 } 250 251 @end