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 { 72 LOG("GlassLayer3D initWithSharedContext]"); 73 self = [super init]; 74 if (self != nil) 75 { 76 self->_serverPort = MACH_PORT_NULL; 77 self->_remoteLayer = nil; 78 self->_remoteLayerID = 0; 79 80 self->_painterOffscreen = [[GlassOffscreen alloc] initWithContext:clCtx]; 81 self->_glassOffscreen = [[GlassOffscreen alloc] initWithContext:ctx]; 82 [self->_glassOffscreen setLayer:self]; 83 LOG(" GlassLayer3D context: %p", ctx); 84 85 self->isHiDPIAware = HiDPIAware; 86 87 [self setAsynchronous:NO]; 88 [self setAutoresizingMask:(kCALayerWidthSizable|kCALayerHeightSizable)]; 89 [self setContentsGravity:kCAGravityTopLeft]; 90 91 // Initially the view is not in any window yet, so using the 92 // screens[0]'s scale is a good starting point (this is most probably 93 // the notebook's main LCD display which is HiDPI-capable). 94 // Note that mainScreen is the screen with the current app bar focus 95 // in Mavericks and later OS so it will likely not match the screen 96 // we initially show windows on if an app is started from an external 97 // monitor. 98 [self notifyScaleFactorChanged:GetScreenScaleFactor([[NSScreen screens] objectAtIndex:0])]; 99 100 [self setMasksToBounds:YES]; 101 [self setNeedsDisplayOnBoundsChange:YES]; 102 [self setAnchorPoint:CGPointMake(0.0f, 0.0f)]; 103 104 if (allModes == nil) { 105 allModes = [[NSArray arrayWithObjects:NSDefaultRunLoopMode, 106 NSEventTrackingRunLoopMode, 107 NSModalPanelRunLoopMode, nil] retain]; 108 } 109 } 110 return self; 111 } 112 113 - (void)dealloc 114 { 115 [self->_glassOffscreen release]; 116 self->_glassOffscreen = nil; 117 118 [self->_painterOffscreen release]; 119 self->_painterOffscreen = nil; 120 121 [self->_remoteLayer dealloc]; 122 self->_remoteLayer = nil; 123 124 [super dealloc]; 125 } 126 127 - (void)notifyScaleFactorChanged:(CGFloat)scale 128 { 129 if (self->isHiDPIAware) { 130 if ([self respondsToSelector:@selector(setContentsScale:)]) { 131 [self setContentsScale: scale]; 132 } 133 } 134 } 135 136 //- (void)setBounds:(CGRect)bounds 137 //{ 138 // LOG("GlassLayer3D setBounds:%s", [NSStringFromRect(NSRectFromCGRect(bounds)) UTF8String]); 139 // [super setBounds:bounds]; 140 //} 141 142 - (BOOL)canDrawInCGLContext:(CGLContextObj)glContext pixelFormat:(CGLPixelFormatObj)pixelFormat forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp 143 { 144 return [self->_glassOffscreen isDirty]; 145 } 146 147 - (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat 148 { 149 return CGLRetainContext([self->_glassOffscreen getContext]); 150 } 151 152 - (CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask 153 { 154 return CGLRetainPixelFormat(CGLGetPixelFormat([self->_glassOffscreen getContext])); 155 } 156 157 - (void)drawInCGLContext:(CGLContextObj)glContext pixelFormat:(CGLPixelFormatObj)pixelFormat forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp 158 { 159 // glContext is already set as current by now and locked by Quartz internaly 160 LOG("GlassLayer3D drawInCGLContext]"); 161 LOG(" current context: %p", CGLGetCurrentContext()); 162 #ifdef VERBOSE 163 { 164 GLint fbo = 0; // default to screen 165 glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, (GLint*)&fbo); 166 LOG(" fbo: %d", fbo); 167 } 168 #endif 169 // the viewport is already set for us here, so just blit 170 171 #if 0 172 // this will stretch the offscreen to cover all the surface 173 // ie., live resizing "appears" better, but the blit area is not at 1:1 scale 174 [self->_glassOffscreen blit]; 175 #else 176 // we blit only in the area we rendered in 177 GLint params[] = { 0, 0, 0, 0 }; 178 glGetIntegerv(GL_VIEWPORT, params); 179 if ((params[2] > 0) && ((params[3] > 0))) 180 { 181 [self->_glassOffscreen blitForWidth:(GLuint)params[2] andHeight:(GLuint)params[3]]; 182 } 183 #endif 184 185 // the default implementation of the method flushes the context. 186 [super drawInCGLContext:glContext pixelFormat:pixelFormat forLayerTime:timeInterval displayTime:timeStamp]; 187 LOG("\n"); 188 } 189 190 - (void)flush 191 { 192 [(GlassOffscreen*)_glassOffscreen blitFromOffscreen:(GlassOffscreen*)_painterOffscreen]; 193 if ([NSThread isMainThread]) { 194 [[self->_glassOffscreen getLayer] setNeedsDisplay]; 195 } else { 196 [[self->_glassOffscreen getLayer] performSelectorOnMainThread:@selector(setNeedsDisplay) 197 withObject:nil 198 waitUntilDone:NO 199 modes:allModes]; 200 } 201 } 202 203 - (uint32_t)getRemoteLayerIdForServer:(NSString*)serverName 204 { 205 if (self->_remoteLayerID == 0) 206 { 207 Class JRSRemoteLayer_class = objc_getClass("JRSRenderServer"); 208 if (JRSRemoteLayer_class != nil) 209 { 210 [self _connectToRemoteServer:serverName]; 211 } 212 else 213 { 214 NSLog(@"GlassLayer3D: no remote CALayer server support detected!"); 215 // we're running on JDK without remote CALayer server (JRSRemoteLayer.h) support 216 } 217 } 218 return self->_remoteLayerID; 219 } 220 221 - (void)hostRemoteLayerId:(uint32_t)layerId 222 { 223 if (layerId > 0) 224 { 225 RemoteLayerHostRemoteIdInLocal(layerId, self); 226 } 227 else 228 { 229 NSLog(@"GlassLayer3D: invalid remote layer id!"); 230 } 231 } 232 233 - (GlassOffscreen*)getPainterOffscreen 234 { 235 return self->_painterOffscreen; 236 } 237 238 - (GlassOffscreen*)getGlassOffscreen 239 { 240 return self->_glassOffscreen; 241 } 242 243 - (void)hostOffscreen:(GlassOffscreen*)offscreen 244 { 245 [self->_glassOffscreen release]; 246 self->_glassOffscreen = [offscreen retain]; 247 [self->_glassOffscreen setLayer:self]; 248 } 249 250 @end