All Downloads are FREE. Search and download functionalities are using the official Maven repository.

native-glass.mac.GlassLayer3D.m Maven / Gradle / Ivy

/*
 * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

#import "GlassLayer3D.h"

#import "GlassMacros.h"
#import "RemoteLayerSupport.h"
#import "GlassScreen.h"

//#define VERBOSE
#ifndef VERBOSE
    #define LOG(MSG, ...)
#else
    #define LOG(MSG, ...) GLASS_LOG(MSG, ## __VA_ARGS__);
#endif

@implementation GlassLayer3D

- (void)_connectToRemoteServer:(NSString*)serverName
{
    // SAK: Note that RemoteLayerGetServerPort can return 0/MACH_PORT_NULL. This is
    // not an error, and means that JRSRenderServer is tracking the port for us.
    // Yes, this is odd, and I've asked Apple to clarify it for us.
    self->_serverPort = RemoteLayerGetServerPort(serverName);
    self->_remoteLayer = RemoteLayerGetRemoteFromLocal(self->_serverPort, self);
    if (self->_remoteLayer != nil)
    {
        self->_remoteLayerID = RemoteLayerGetIdForRemote(self->_remoteLayer);
        if (self->_remoteLayerID != 0)
        {
            [self->_remoteLayer retain];
        }
        else
        {
            NSLog(@"RemoteLayer ERROR: 0 _remoteLayerID for serverName:%@", serverName);
        }
    }
    else
    {
        NSLog(@"RemoteLayer ERROR: nil remoteLayer for serverName:%@", serverName);
    }
}
- (CGLPixelFormatObj)_createPixelFormat
{
    CGLPixelFormatObj pix = NULL;
    {
        const CGLPixelFormatAttribute attributes[] =
        {
            kCGLPFAAccelerated,
            kCGLPFAColorSize, 32,
            (CGLPixelFormatAttribute)0
        };
        GLint npix = 0;
        CGLError err = CGLChoosePixelFormat(attributes, &pix, &npix);
        if (err != kCGLNoError)
        {
            NSLog(@"CGLChoosePixelFormat error: %d", err);
        }
    }
    return pix;
}

- (CGLContextObj)_createContextWithShared:(CGLContextObj)share withFormat:(CGLPixelFormatObj)format
{
    CGLContextObj ctx = NULL;
    {
        //NSLog(@"ALLOC");
        CGLError err = CGLCreateContext(format, share, &ctx);
        if (err != kCGLNoError)
        {
            NSLog(@"CGLCreateContext error: %d", err);
        }
    }
    return ctx;
}

- (id)initWithSharedContext:(CGLContextObj)ctx withHiDPIAware:(BOOL)HiDPIAware
{
    LOG("GlassLayer3D initWithSharedContext]");
    self = [super init];
    if (self != nil)
    {
        self->_serverPort = MACH_PORT_NULL;
        self->_remoteLayer = nil;
        self->_remoteLayerID = 0;

        self->_format = [self _createPixelFormat];
        self->_ctx = [self _createContextWithShared:ctx withFormat:self->_format];
        self->_offscreen = nil;
        LOG("   GlassLayer3D context: %p", self->_ctx);

        self->isHiDPIAware = HiDPIAware;

        [self setAsynchronous:YES]; // allow the layer to check for dirty flag and repaint if needed
        [self setAutoresizingMask:(kCALayerWidthSizable|kCALayerHeightSizable)];
        [self setContentsGravity:kCAGravityTopLeft];

        // Initially the view is not in any window yet, so using the
        // mainScreen's scale is a good starting point (this is most probably
        // the notebook's main LCD display which is HiDPI-capable).
        [self notifyScaleFactorChanged:GetScreenScaleFactor([NSScreen mainScreen])];

        [self setMasksToBounds:YES];
        [self setNeedsDisplayOnBoundsChange:YES];
        [self setAnchorPoint:CGPointMake(0.0f, 0.0f)];
    }
    return self;
}

- (void)dealloc
{
    //NSLog(@"FREE");
    CGLDestroyContext( self->_ctx );
    self->_ctx = NULL;

    [self->_offscreen dealloc];
    self->_offscreen = nil;

    [self->_remoteLayer dealloc];
    self->_remoteLayer = nil;

    [super dealloc];
}

- (void)notifyScaleFactorChanged:(CGFloat)scale
{
    if (self->isHiDPIAware) {
        if ([self respondsToSelector:@selector(setContentsScale:)]) {
            [self setContentsScale: scale];
        }
    }
}

//- (void)setBounds:(CGRect)bounds
//{
//    LOG("GlassLayer3D setBounds:%s", [NSStringFromRect(NSRectFromCGRect(bounds)) UTF8String]);
//    [super setBounds:bounds];
//}

- (BOOL)canDrawInCGLContext:(CGLContextObj)glContext pixelFormat:(CGLPixelFormatObj)pixelFormat forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp
{
    //return YES;
    return (([self needsDisplay] == YES) || ([self->_offscreen isDirty] == YES));
}

- (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat
{
    return CGLRetainContext(self->_ctx);
}

- (CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask
{
    return CGLRetainPixelFormat(self->_format);
}

- (void)drawInCGLContext:(CGLContextObj)glContext pixelFormat:(CGLPixelFormatObj)pixelFormat forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp
{
    [self->_offscreen lock];
    {
        LOG("GlassLayer3D drawInCGLContext]");
        LOG("   current context: %p", CGLGetCurrentContext());
#ifdef VERBOSE
        {
            GLint fbo = 0; // default to screen
            glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, (GLint*)&fbo);
            LOG("   fbo: %d", fbo);
        }
#endif
        // the viewport is already set for us here, so just blit
        
#if 0
        // this will stretch the offscreen to cover all the surface
        // ie., live resizing "appears" better, but the blit area is not at 1:1 scale
        [self->_offscreen blit];
#else
        // we blit only in the area we rendered in
        GLint params[] = { 0, 0, 0, 0 };
        glGetIntegerv(GL_VIEWPORT, params);
        if ((params[2] > 0) && ((params[3] > 0)))
        {
            [self->_offscreen blitForWidth:(GLuint)params[2] andHeight:(GLuint)params[3]];
        }
#endif
        
        // the default implementation of the method flushes the context.
        [super drawInCGLContext:glContext pixelFormat:pixelFormat forLayerTime:timeInterval displayTime:timeStamp];
        LOG("\n");
    }
    [self->_offscreen unlock];
}

- (uint32_t)getRemoteLayerIdForServer:(NSString*)serverName
{
    if (self->_remoteLayerID == 0)
    {
        Class JRSRemoteLayer_class = objc_getClass("JRSRenderServer");
        if (JRSRemoteLayer_class != nil)
        {
            [self _connectToRemoteServer:serverName];
        }
        else
        {
            NSLog(@"GlassLayer3D: no remote CALayer server support detected!");
            // we're running on JDK without remote CALayer server (JRSRemoteLayer.h) support
        }
    }
    return self->_remoteLayerID;
}

- (void)hostRemoteLayerId:(uint32_t)layerId
{
    if (layerId > 0)
    {
        RemoteLayerHostRemoteIdInLocal(layerId, self);
    }
    else
    {
        NSLog(@"GlassLayer3D: invalid remote layer id!");
    }
}

- (GlassOffscreen*)getOffscreen
{
    return self->_offscreen;
}

- (void)hostOffscreen:(GlassOffscreen*)offscreen
{
    [self->_offscreen release];
    self->_offscreen = nil;
    self->_offscreen = [offscreen retain];
}

@end




© 2015 - 2024 Weber Informatics LLC | Privacy Policy