Esempio n. 1
0
void StimulusDisplay::addContext(int _context_id){
	context_ids.push_back(_context_id);
    int contextIndex = context_ids.size() - 1;
    
    OpenGLContextLock ctxLock = opengl_context_manager->setCurrent(_context_id);
    getCurrentViewportSize(bufferWidths[contextIndex], bufferHeights[contextIndex]);
    
    CVDisplayLinkRef dl;
    
    if (kCVReturnSuccess != CVDisplayLinkCreateWithActiveCGDisplays(&dl)) {
        throw SimpleException("Unable to create display link");
    }
    
    displayLinks.push_back(dl);
    displayLinkContexts.emplace_back(new DisplayLinkContext(this, contextIndex));
    
    if (kCVReturnSuccess != CVDisplayLinkSetOutputCallback(dl,
                                                           &StimulusDisplay::displayLinkCallback,
                                                           displayLinkContexts.back().get()))
    {
        throw SimpleException("Unable to set display link output callback");
    }
    
    if (kCVReturnSuccess != opengl_context_manager->prepareDisplayLinkForContext(dl, _context_id)) {
        throw SimpleException("Unable to associate display link with OpenGL context");
    }
    
    if (0 == contextIndex) {
        setMainDisplayRefreshRate();
        allocateBufferStorage();
    }
}
bool DisplayRefreshMonitorMac::requestRefreshCallback()
{
    if (!isActive())
        return false;

    if (!m_displayLink) {
        setIsActive(false);
        CVReturn error = CVDisplayLinkCreateWithCGDisplay(displayID(), &m_displayLink);
        if (error)
            return false;

        error = CVDisplayLinkSetOutputCallback(m_displayLink, displayLinkCallback, this);
        if (error)
            return false;

        error = CVDisplayLinkStart(m_displayLink);
        if (error)
            return false;

        setIsActive(true);
    }

    LockHolder lock(mutex());
    setIsScheduled(true);
    return true;
}
Esempio n. 3
0
BEGIN_NAMESPACE_MW



/**********************************************************************
 *                  StimulusDisplay Methods
 **********************************************************************/
StimulusDisplay::StimulusDisplay(bool drawEveryFrame, bool announceIndividualStimuli) :
    current_context_index(-1),
    mainDisplayRefreshRate(0.0),
    currentOutputTimeUS(-1),
    announceIndividualStimuli(announceIndividualStimuli),
    announceStimuliOnImplicitUpdates(true),
    drawEveryFrame(drawEveryFrame)
{
    // defer creation of the display chain until after the stimulus display has been created
    display_stack = shared_ptr< LinkedList<StimulusNode> >(new LinkedList<StimulusNode>());
    
	setDisplayBounds();
    setBackgroundColor(0.5, 0.5, 0.5);

    opengl_context_manager = OpenGLContextManager::instance();
    clock = Clock::instance();

    waitingForRefresh = false;
    needDraw = false;
    
    if (kCVReturnSuccess != CVDisplayLinkCreateWithActiveCGDisplays(&displayLink) ||
        kCVReturnSuccess != CVDisplayLinkSetOutputCallback(displayLink,
                                                           &StimulusDisplay::displayLinkCallback,
                                                           this))
    {
        throw SimpleException("Unable to create display link");
    }
        
    stateSystemNotification = shared_ptr<VariableCallbackNotification>(new VariableCallbackNotification(boost::bind(&StimulusDisplay::stateSystemCallback, this, _1, _2)));
    state_system_mode->addNotification(stateSystemNotification);
}
Esempio n. 4
0
static void p1_display_video_clock_start(P1Plugin *pel)
{
    P1Object *obj = (P1Object *) pel;
    P1DisplayVideoClock *dvclock = (P1DisplayVideoClock *) pel;
    CVReturn ret;

    dvclock->display_id = dvclock->cfg_display_id;
    dvclock->divisor = dvclock->cfg_divisor;
    dvclock->skip_counter = 0;

    ret = CVDisplayLinkCreateWithCGDisplay(dvclock->display_id, &dvclock->display_link);
    if (ret != kCVReturnSuccess)
        goto halt;

    ret = CVDisplayLinkSetOutputCallback(dvclock->display_link, p1_display_video_clock_callback, dvclock);
    if (ret != kCVReturnSuccess)
        goto halt;

    // Async, final state change happens in the callback.
    ret = CVDisplayLinkStart(dvclock->display_link);
    if (ret != kCVReturnSuccess)
        goto halt;

    obj->state.current = P1_STATE_STARTING;
    p1_object_notify(obj);

    return;

halt:
    p1_log(obj, P1_LOG_ERROR, "Failed to start display link: Core Video error %d", ret);

    p1_display_video_clock_kill_session(dvclock);

    obj->state.current = P1_STATE_IDLE;
    obj->state.flags |= P1_FLAG_ERROR;
    p1_object_notify(obj);
}
/*
    PsychOSOpenOnscreenWindow()
    
    Creates the CGL pixel format and the CGL context objects and then instantiates the context onto the screen.
    
    -The pixel format and the context are stored in the target specific field of the window recored.  Close
    should clean up by destroying both the pixel format and the context.
    
    -We mantain the context because it must be be made the current context by drawing functions to draw into 
    the specified window.
    
    -We maintain the pixel format object because there seems to be now way to retrieve that from the context.
    
    -To tell the caller to clean up PsychOSOpenOnscreenWindow returns FALSE if we fail to open the window. It 
    would be better to just issue an PsychErrorExit() and have that clean up everything allocated outside of
    PsychOpenOnscreenWindow().
    
    MK: The new option 'stereomode' allows selection of stereo display instead of mono display:
    0 (default) ==  Old behaviour -> Monoscopic rendering context.
    >0          ==  Stereo display, where the number defines the type of stereo algorithm to use.
    =1          ==  Use OpenGL built-in stereo by creating a context/window with left- and right backbuffer. This is
                    the only mode of interest here, as it requires use of a stereo capable OpenGL pixelformat. All other
                    stereo modes are implemented by PTB itself in a platform independent manner on top of a standard mono
                    context.
*/
psych_bool PsychOSOpenOnscreenWindow(PsychScreenSettingsType *screenSettings, PsychWindowRecordType *windowRecord, int numBuffers, int stereomode, int conserveVRAM)
{
    CGOpenGLDisplayMask             displayMask;
    CGLError                        error;
    CGDirectDisplayID               cgDisplayID;
    CGLPixelFormatAttribute         attribs[40];
    int                             attribcount;
    GLint                           numVirtualScreens;
    GLenum                          glerr;
    PsychRectType                   screenrect;
    int                             i;
    int                             windowLevel;
    long                            scw, sch;
    void*                           cocoaWindow = NULL;

    // Map screen number to physical display handle cgDisplayID:
    PsychGetCGDisplayIDFromScreenNumber(&cgDisplayID, screenSettings->screenNumber);
    displayMask = CGDisplayIDToOpenGLDisplayMask(cgDisplayID);

    // NULL-out Cocoa window handle, so this is well-defined in case of error:
    windowRecord->targetSpecific.windowHandle = NULL;

    // Retrieve windowLevel, an indicator of where non-CGL / non-fullscreen windows should
    // be located wrt. to other windows. -2 = Allow regular window manager control of stacking
    // order, visibility etc., -1 = Invisible/hidden, 0 = Behind everything else, occluded by
    // everything else. 1 - 999 = At layer 'windowLevel' -> Occludes stuff on layers "below" it.
    // 1000 - 1999 = At highest level, but partially translucent / alpha channel allows to make
    // regions transparent. Range 1000 - 1499 = transparent for mouse and keyboard, alpha 0-99.99%,
    // 1500-1599 = opaque for mouse and keyboard, alpha 0-99.99%, 2000 or higher: Above everything,
    // fully opaque, occludes everything, a typical fullscreen onscreen window. 2000 is the default.
    windowLevel = PsychPrefStateGet_WindowShieldingLevel();

    // Window rect provided which has same size as screen?
    // We do not use windowed mode if the provided window rectangle either
    // matches the target screens rectangle (and therefore its exact size)
    // or its screens global rectangle. In such cases we use CGL for better
    // low level control and to exclude the desktop compositor from interfering:
    PsychGetScreenRect(screenSettings->screenNumber, screenrect);
    if (PsychMatchRect(screenrect, windowRecord->rect)) windowRecord->specialflags |= kPsychIsFullscreenWindow;

    PsychGetGlobalScreenRect(screenSettings->screenNumber, screenrect);
    if (PsychMatchRect(screenrect, windowRecord->rect)) windowRecord->specialflags |= kPsychIsFullscreenWindow;

    if ((windowRecord->specialflags & kPsychIsFullscreenWindow) && (PsychPrefStateGet_Verbosity() > 3)) {
        printf("PTB-INFO: Always using Cocoa for fullscreen windows to work around graphics driver bugs in OSX.\n");
        printf("PTB-INFO: Presentation timing precision is not yet known for this configuration on most machines. Check your results.\n");
    }

    // Display for fullscreen window not captured? Timing precision is unclear in this mode. In theory the compositor should disable
    // itself for fullscreen windows on modern OSX versions. If it really does that, who knows?
    if ((windowRecord->specialflags & kPsychIsFullscreenWindow) && (PsychPrefStateGet_ConserveVRAM() & kPsychUseAGLCompositorForFullscreenWindows)) {
        // Force a window rectangle that matches the global screen rectangle for that windows screen:
        PsychCopyRect(windowRecord->rect, screenrect);

        // Warn user about what's going on:
        if (PsychPrefStateGet_Verbosity()>1) printf("PTB-INFO: No display capture / compositor lockout for fullscreen window. Timing precision is unknown.\n");
    }

    if ((windowRecord->specialflags & kPsychGUIWindow) && (PsychPrefStateGet_Verbosity() > 3)) {
        printf("PTB-INFO: Onscreen window is configured as regular GUI window.\n");
    }

    // Create onscreen Cocoa window of requested position and size:
    if (PsychCocoaCreateWindow(windowRecord, windowLevel, &cocoaWindow)) {
        printf("\nPTB-ERROR[CreateNewWindow failed]: Failed to open Cocoa onscreen window\n\n");
        return(FALSE);
    }

    // Transparent window requested?
    if ((windowLevel >= 1000) && (windowLevel < 2000)) {
        // Setup of global window alpha value for transparency. This is premultiplied to
        // the individual per-pixel alpha values if transparency is enabled by Cocoa code.
        //
        // Levels 1000 - 1499 and 1500 to 1999 map to a master opacity level of 0.0 - 1.0:
        PsychCocoaSetWindowAlpha(cocoaWindow, ((float) (windowLevel % 500)) / 499.0);
    }

    // Show it! Unless a windowLevel of -1 requests hiding the window:
    if (windowLevel != -1) PsychCocoaShowWindow(cocoaWindow);

    // If usercode wants a black startup screen then we add a pause of 0.5 seconds here
    // before proceeding. This will avoid a white flash at window open time, which might
    // be something the user wanted to avoid. Why does this help or is needed at all?
    // Nobody knows, but this is Apples ridiculous toy OS, so why even ask such questions?
    if (PsychPrefStateGet_VisualDebugLevel() < 4)
        PsychYieldIntervalSeconds(0.5);

    // Level zero means: Place behind all other windows:
    if (windowLevel == 0) PsychCocoaSendBehind(cocoaWindow);

    // Levels 1 to 999 define window levels for the group of the window.
    // A level of -2 would leave this to the system:
    if (windowLevel > 0 && windowLevel < 1000) PsychCocoaSetWindowLevel(cocoaWindow, windowLevel);

    // Is the target display captured for a fullscreen window?
    if (PsychIsScreenCaptured(screenSettings->screenNumber)) {
        // Yes. Make sure our window is above the shielding window level:
        PsychCocoaSetWindowLevel(cocoaWindow, (int) CGShieldingWindowLevel());
    }

    // Store window handle in windowRecord:
    windowRecord->targetSpecific.windowHandle = cocoaWindow;

    // Store vblank startline aka true height of physical display screen in pixels:
    PsychGetScreenPixelSize(screenSettings->screenNumber, &scw, &sch);
    windowRecord->VBL_Startline = (int) sch;

    // Define pixelformat attributes for OpenGL contexts:

    // No pixelformat attribs to start with:
    attribcount = 0;

    attribs[attribcount++]=kCGLPFADisplayMask;
    attribs[attribcount++]=displayMask;

    // 10 bit per component integer framebuffer requested (10-10-10-2)?
    if (windowRecord->depth == 30) {
        // Request a 10 bit per color component framebuffer with 2 bit alpha channel:
        printf("PTB-INFO: Trying to enable 10 bpc, 30 bit integer framebuffer...\n");
        attribs[attribcount++]=kCGLPFANoRecovery;
        attribs[attribcount++]=kCGLPFAMinimumPolicy;
        attribs[attribcount++]=kCGLPFAColorSize;
        attribs[attribcount++]=10*3;
        attribs[attribcount++]=kCGLPFAAlphaSize;
        attribs[attribcount++]=2;
    }

    // 11 bit per component integer framebuffer requested (11-11-10-0)?
    if (windowRecord->depth == 33) {
        // Request a ~ 11 bit per color component framebuffer without alpha channel:
        printf("PTB-INFO: Trying to enable 11 bpc, 32 bit integer framebuffer...\n");
        attribs[attribcount++]=kCGLPFANoRecovery;
        attribs[attribcount++]=kCGLPFAMinimumPolicy;
        attribs[attribcount++]=kCGLPFAColorSize;
        attribs[attribcount++]=32;
        attribs[attribcount++]=kCGLPFAAlphaSize;
        attribs[attribcount++]=0;
    }

    // 16 bit per component integer framebuffer requested (16-16-16-16)?
    if (windowRecord->depth == 48) {
        // Request a 16 bit per color component framebuffer:
        printf("PTB-INFO: Trying to enable 16 bpc, 64 bit integer framebuffer...\n");
        attribs[attribcount++]=kCGLPFANoRecovery;
        attribs[attribcount++]=kCGLPFAMinimumPolicy;
        attribs[attribcount++]=kCGLPFAColorSize;
        attribs[attribcount++]=16*3;
        attribs[attribcount++]=kCGLPFAAlphaSize;
        attribs[attribcount++]=16;
    }

    // 16 bit per component, 64 bit framebuffer requested (16-16-16-16)?
    if (windowRecord->depth == 64) {
        // Request a floating point framebuffer in 16-bit half-float format, i.e., RGBA = 16 bits per component.
        printf("PTB-INFO: Trying to enable 16 bpc float framebuffer...\n");
        attribs[attribcount++]=kCGLPFAColorFloat;
        attribs[attribcount++]=kCGLPFAMinimumPolicy;
        attribs[attribcount++]=kCGLPFAColorSize;
        attribs[attribcount++]=16*3;
        attribs[attribcount++]=kCGLPFAAlphaSize;
        attribs[attribcount++]=16;
    }

    // 32 bit per component, 128 bit framebuffer requested (32-32-32-32)?
    if (windowRecord->depth == 128) {
        // Request a floating point framebuffer in 32-bit float format, i.e., RGBA = 32 bits per component.
        printf("PTB-INFO: Trying to enable 32 bpc float framebuffer...\n");
        attribs[attribcount++]=kCGLPFAColorFloat;
        attribs[attribcount++]=kCGLPFAMinimumPolicy;
        attribs[attribcount++]=kCGLPFAColorSize;
        attribs[attribcount++]=32*3;
        attribs[attribcount++]=kCGLPFAAlphaSize;
        attribs[attribcount++]=32;
    }

    // Possible to request use of the Apple floating point software renderer:
    if (conserveVRAM & kPsychUseSoftwareRenderer) {
        #ifndef kCGLRendererGenericFloatID
        #define kCGLRendererGenericFloatID    0x00020400
        #endif

        attribs[attribcount++]=AGL_RENDERER_ID;
        attribs[attribcount++]=kCGLRendererGenericFloatID;
    }

    // Support for 3D rendering requested?
    if (PsychPrefStateGet_3DGfx()) {
        // Yes. Allocate a 24-Bit depth and 8-Bit stencilbuffer for this purpose:
        attribs[attribcount++]=kCGLPFADepthSize;
        attribs[attribcount++]=24;
        attribs[attribcount++]=kCGLPFAStencilSize;
        attribs[attribcount++]=8;
        // Alloc an accumulation buffer as well?
        if (PsychPrefStateGet_3DGfx() & 2) {
            // Yes: Alloc accum buffer, request 64 bpp, aka 16 bits integer per color component if possible:
            attribs[attribcount++]=kCGLPFAAccumSize;
            attribs[attribcount++]=64;
        }
    }

    if(numBuffers>=2){
        // Enable double-buffering:
        attribs[attribcount++]=kCGLPFADoubleBuffer;
        if ((conserveVRAM & kPsychDisableAUXBuffers) == 0) {
            // Allocate one or two (for mono vs. stereo display) AUX buffers for "don't clear" mode of Screen('Flip'):
            // Not clearing the framebuffer after "Flip" is implemented by storing a backup-copy of
            // the backbuffer to AUXs before flip and restoring the content from AUXs after flip.
            // Unless the imaging pipeline is active, which doesn't need AUX buffers due to internal
            // storage of fb content in its drawbufferFBO's:
            attribs[attribcount++]=kCGLPFAAuxBuffers;
            attribs[attribcount++]=(stereomode==kPsychOpenGLStereo || stereomode==kPsychCompressedTLBRStereo || stereomode==kPsychCompressedTRBLStereo) ? 2 : 1;
        }
    }

    // If stereo display output is requested with OpenGL native stereo, request a stereo-enabled rendering context.
    // This is deprecated since 10.11 El Capitan, and in fact does no longer work - OpenGL quad buffered stereo is
    // dead on 10.11 on all tested GPU's from Intel, NVidia, AMD.
    if(stereomode==kPsychOpenGLStereo) {
        attribs[attribcount++] = kCGLPFAStereo;
    }

    // Multisampled Anti-Aliasing requested?
    if (windowRecord->multiSample > 0) {
        // Request a multisample buffer:
        attribs[attribcount++]= kCGLPFASampleBuffers;
        attribs[attribcount++]= 1;
        // Request at least multiSample samples per pixel:
        attribs[attribcount++]= kCGLPFASamples;
        attribs[attribcount++]= windowRecord->multiSample;
    }

    // Finalize attribute array with NULL.
    attribs[attribcount++]=(CGLPixelFormatAttribute)NULL;

    // Init to zero:
    windowRecord->targetSpecific.pixelFormatObject = NULL;
    windowRecord->targetSpecific.glusercontextObject = NULL;
    windowRecord->targetSpecific.glswapcontextObject = NULL;

    // Try to find matching pixelformat:
    error = CGLChoosePixelFormat(attribs, &(windowRecord->targetSpecific.pixelFormatObject), &numVirtualScreens);

    // No valid pixelformat found and stereo format requested?
    if ((error || (windowRecord->targetSpecific.pixelFormatObject == NULL)) && (stereomode == kPsychOpenGLStereo)) {
        // Yep: Stereo may be the culprit. Remove the stereo attribute by overwriting it with something
        // that is essentially a no-op, specifically kCGLPFAAccelerated which is supported by all real
        // renderers that might end up in this code-path:
        for (i = 0; i < attribcount && attribs[i] != kCGLPFAStereo; i++);
        attribs[i] = kCGLPFAAccelerated;
        
        // Retry query of pixelformat without request for native OpenGL quad-buffered stereo. If we succeed, we're
        // sort of ok, as the higher-level code will fallback to stereomode kPsychFrameSequentialStereo - our own
        // homegrown frame-sequential stereo support, which may be good enough.
        error = CGLChoosePixelFormat(attribs, &(windowRecord->targetSpecific.pixelFormatObject), &numVirtualScreens);
        if (error || (windowRecord->targetSpecific.pixelFormatObject == NULL)) {
            windowRecord->targetSpecific.pixelFormatObject = NULL;
            printf("\nPTB-ERROR[ChoosePixelFormat failed: %s]: Disabling OpenGL native quad-buffered stereo did not help. Moving on...\n\n", CGLErrorString(error));
        }
    }

    // Now try if choosing a matching format for a lower multisample mode helps to get unstuck:
    if (windowRecord->multiSample > 0) {
        if (windowRecord->targetSpecific.pixelFormatObject==NULL && windowRecord->multiSample > 0) {
            // Failed. Probably due to too demanding multisample requirements: Lets lower them...
            for (i = 0; i < attribcount && attribs[i] != kCGLPFASamples; i++);
            while (windowRecord->targetSpecific.pixelFormatObject == NULL && windowRecord->multiSample > 0) {
                attribs[i+1]--;
                windowRecord->multiSample--;
                error = CGLChoosePixelFormat(attribs, &(windowRecord->targetSpecific.pixelFormatObject), &numVirtualScreens);
            }

            if (windowRecord->multiSample == 0 && windowRecord->targetSpecific.pixelFormatObject == NULL) {
                // Ok, multisampling is now at zero and we still don't succeed. Disable multisampling completely:
                for (i=0; i<attribcount && attribs[i]!=kCGLPFASampleBuffers; i++);
                attribs[i+1] = 0;
                printf("\nPTB-ERROR[ChoosePixelFormat failed: %s]: Disabling multisample anti-aliasing did not help. Moving on...\n\n", CGLErrorString(error));
            }
        }
    }

    // Try choosing a matching display configuration again and create the window and rendering context:
    // If one of these two fails, then the installed gfx hardware is not good enough to satisfy our
    // requirements, or we have massive ressource shortage in the system. -> Screwed up anyway, so we abort.
    if (windowRecord->targetSpecific.pixelFormatObject == NULL) error = CGLChoosePixelFormat(attribs, &(windowRecord->targetSpecific.pixelFormatObject), &numVirtualScreens);
    if (error) {
        printf("\nPTB-ERROR[ChoosePixelFormat failed: %s]: Reason unknown. There could be insufficient video memory or a driver malfunction. Giving up.\n\n", CGLErrorString(error));
        return(FALSE);
    }

    // Create an OpenGL rendering context with the selected pixelformat: Share its ressources with 'slaveWindow's context, if slaveWindow is non-NULL.
    // If slaveWindow is non-NULL here, then slaveWindow is typically another onscreen window. Therefore this establishes OpenGL resource sharing across
    // different onscreen windows in a session, e.g., for multi-display operation:
    error=CGLCreateContext(windowRecord->targetSpecific.pixelFormatObject, ((windowRecord->slaveWindow) ? windowRecord->slaveWindow->targetSpecific.contextObject : NULL),
                           &(windowRecord->targetSpecific.contextObject));
    if (error) {
        printf("\nPTB-ERROR[ContextCreation failed: %s]: Could not create master OpenGL context for new onscreen window. Insufficient video memory?\n\n", CGLErrorString(error));
        return(FALSE);
    }

    // Enable the OpenGL rendering context associated with our window:
    error=CGLSetCurrentContext(windowRecord->targetSpecific.contextObject);
    if (error) {
        printf("\nPTB-ERROR[SetCurrentContext failed: %s]: Insufficient video memory\n\n", CGLErrorString(error));
        return(FALSE);
    }

    // NULL-out the AGL context field, just for safety...
    windowRecord->targetSpecific.deviceContext = NULL;

    // Ok, the master OpenGL rendering context for this new onscreen window is up and running.
    // Auto-detect and bind all available OpenGL extensions via GLEW:
    glerr = glewInit();
    if (GLEW_OK != glerr)
    {
        /* Problem: glewInit failed, something is seriously wrong. */
        printf("\nPTB-ERROR[GLEW init failed: %s]: Please report this to the forum. Will try to continue, but may crash soon!\n\n", glewGetErrorString(glerr));
        fflush(NULL);
    }
    else {
        if (PsychPrefStateGet_Verbosity()>3) printf("PTB-INFO: Using GLEW version %s for automatic detection of OpenGL extensions...\n", glewGetString(GLEW_VERSION));
    }

    // Enable multisampling if it was requested:
    if (windowRecord->multiSample > 0) glEnable(GL_MULTISAMPLE);

    // External 3D graphics support enabled?
    if (PsychPrefStateGet_3DGfx()) {
        // Yes. We need to create an extra OpenGL rendering context for the external
        // OpenGL code to provide optimal state-isolation. The context shares all
        // heavyweight ressources likes textures, FBOs, VBOs, PBOs, shader, display lists and
        // starts off as an identical copy of PTB's context as of here.
        error=CGLCreateContext(windowRecord->targetSpecific.pixelFormatObject, windowRecord->targetSpecific.contextObject, &(windowRecord->targetSpecific.glusercontextObject));
        if (error) {
            printf("\nPTB-ERROR[UserContextCreation failed: %s]: Creating a private OpenGL context for userspace OpenGL failed.\n\n", CGLErrorString(error));
            return(FALSE);
        }
    }

    // Create glswapcontextObject - An OpenGL context for exclusive use by parallel background threads,
    // e.g., our thread for async flip operations and self-made frame-sequential stereo:
    error=CGLCreateContext(windowRecord->targetSpecific.pixelFormatObject, windowRecord->targetSpecific.contextObject, &(windowRecord->targetSpecific.glswapcontextObject));
    if (error) {
        printf("\nPTB-ERROR[SwapContextCreation failed: %s]: Creating a private OpenGL context for async-bufferswaps failed.\n\n", CGLErrorString(error));
        CGLSetCurrentContext(NULL);
        return(FALSE);
    }

    // Store Cocoa onscreen window handle:
    windowRecord->targetSpecific.windowHandle = cocoaWindow;

    // Objective-C setup path, using Cocoa + NSOpenGLContext wrapped around already
    // existing and setup CGLContext:
    if (PsychCocoaSetupAndAssignOpenGLContextsFromCGLContexts(cocoaWindow, windowRecord)) {
        printf("\nPTB-ERROR[Cocoa OpenGL setup failed]: Setup failed for unknown reasons.\n\n");
        PsychCocoaDisposeWindow(windowRecord);
        return(FALSE);
    }

    // Check for output display rotation enabled. Will impair timing/timestamping because
    // it uses the desktop compositor for a rotated copy blit, instead of via rotated crtc
    // scanout, as most crtc's don't support this in hardware:
    if ((((int) CGDisplayRotation(cgDisplayID)) != 0) && (PsychPrefStateGet_Verbosity() > 1)) {
        printf("PTB-WARNING: Your onscreen windows output display has rotation enabled. It is not displaying in upright orientation.\n");
        printf("PTB-WARNING: On most graphics cards this will cause unreliable stimulus presentation timing and timestamping.\n");
        printf("PTB-WARNING: If you want non-upright stimulus presentation, look at 'help PsychImaging' on how to achieve this in\n");
        printf("PTB-WARNING: a way that doesn't impair timing. The subfunctions 'FlipHorizontal' and 'FlipVertical' are what you probably need.\n");
    }

    // First reference to this screen by a window?
    if (screenRefCount[screenSettings->screenNumber] == 0) {
        // High precision timestamping enabled? If so, we need to setup the fallback
        // timestamping methods in case beamposition timestamping doesn't work:
        if (PsychPrefStateGet_VBLTimestampingMode() > 0) {
            // Use of CoreVideo is needed on 10.7 and later due to brokeness of the old method (thanks Apple!):
            if (PsychPrefStateGet_Verbosity() > 2) {
                printf("PTB-INFO: Will use fragile CoreVideo timestamping as fallback if beamposition timestamping doesn't work.\n");
                // Recommend use of kernel driver if it isn't installed already for all but Intel GPU's:
                if (!PsychOSIsKernelDriverAvailable(screenSettings->screenNumber) && !strstr((char*) glGetString(GL_VENDOR), "Intel")) {
                    printf("PTB-INFO: Installation of the PsychtoolboxKernelDriver is strongly recommended if you care about precise visual\n");
                    printf("PTB-INFO: onset timestamping or timing. See 'help PsychtoolboxKernelDriver' for installation instructions.\n");
                }
            }

            if (NULL == cvDisplayLink[screenSettings->screenNumber]) {
                // CoreVideo timestamping:
                //
                // Create and start a CVDisplayLink for this screen.
                if (kCVReturnSuccess != CVDisplayLinkCreateWithCGDisplay(cgDisplayID, &cvDisplayLink[screenSettings->screenNumber])) {
                    if (PsychPrefStateGet_Verbosity()>1) printf("PTB-WARNING: Failed to create CVDisplayLink for screenId %i. This may impair VBL timestamping.\n", screenSettings->screenNumber);
                } else {
                    // Assign dummy output callback, as this is mandatory to get the link up and running:
                    CVDisplayLinkSetOutputCallback(cvDisplayLink[screenSettings->screenNumber], &PsychCVDisplayLinkOutputCallback, (void*) (long int) screenSettings->screenNumber);

                    // Setup shared data structure and mutex:
                    memset(&cvDisplayLinkData[screenSettings->screenNumber], 0, sizeof(cvDisplayLinkData[screenSettings->screenNumber]));
                    PsychInitMutex(&(cvDisplayLinkData[screenSettings->screenNumber].mutex));

                    // Start the link:
                    if (kCVReturnSuccess != CVDisplayLinkStart(cvDisplayLink[screenSettings->screenNumber])) {
                        // Failed to start: Release it again and report error:
                        CVDisplayLinkRelease(cvDisplayLink[screenSettings->screenNumber]);
                        cvDisplayLink[screenSettings->screenNumber] = NULL;

                        // Teardown shared data structure and mutex:
                        PsychDestroyMutex(&(cvDisplayLinkData[screenSettings->screenNumber].mutex));
                        if (PsychPrefStateGet_Verbosity()>1) printf("PTB-WARNING: Failed to start CVDisplayLink for screenId %i. This may impair VBL timestamping.\n", screenSettings->screenNumber);
                    }
                    else {
                        // Display link started: Report some stuff for the fun of it...
                        if (PsychPrefStateGet_Verbosity() > 3) {
                            // Wait for 50 msecs before query of video refresh from display link to give it a chance to start up:
                            PsychWaitIntervalSeconds(0.050);

                            printf("PTB-INFO: CVDisplayLink for screen %i created to work around the brokenness of Apple Mac OS/X 10.7 and later:\n", screenSettings->screenNumber);
                            printf("PTB-INFO: Video refresh interval as measured by CoreVideo display link: %f msecs.\n", (float) CVDisplayLinkGetActualOutputVideoRefreshPeriod(cvDisplayLink[screenSettings->screenNumber]) * 1000.0);
                            CVTime outLatency = CVDisplayLinkGetOutputVideoLatency(cvDisplayLink[screenSettings->screenNumber]);
                            printf("PTB-INFO: Video display output delay as reported by CoreVideo display link: %f msecs.\n", screenSettings->screenNumber, (float) (((double) outLatency.timeValue / (double) outLatency.timeScale) * 1000.0));
                        }
                    }
                }
            }
        }
        else {
            // VBLtimestampingmode 0 or -1 -- No CoreVideo fallback for timestamping if beamposition timestamping is unavailable:
            // This is the new default as of Psychtoolbox 3.0.12 to avoid the buggy, crashy, unreliably CoreVideo fallback.

            // Recommend use of kernel driver if it isn't installed already for all but Intel GPU's:
            if (!PsychOSIsKernelDriverAvailable(screenSettings->screenNumber) && !strstr((char*) glGetString(GL_VENDOR), "Intel")) {
                printf("PTB-INFO: Installation of the PsychtoolboxKernelDriver is strongly recommended if you care about precise visual\n");
                printf("PTB-INFO: onset timestamping or timing. See 'help PsychtoolboxKernelDriver' for installation instructions.\n");
            }
        }
    }

    // Retain reference of this window to its screen:
    screenRefCount[screenSettings->screenNumber]++;

    // Done.
    return(TRUE);
}