예제 #1
0
void StimulusDisplay::stateSystemCallback(const Datum &data, MWorksTime time) {
    unique_lock lock(display_lock);
    
    int newState = data.getInteger();
    
    if ((IDLE == newState) && displayLinksRunning) {
        
        // If another thread is waiting for a display refresh, allow it to complete before stopping
        // the display link
        while (waitingForRefresh) {
            refreshCond.wait(lock);
        }
        
        displayLinksRunning = false;
        currentOutputTimeUS = -1;
        
        // We need to release the lock before calling CVDisplayLinkStop, because
        // StimulusDisplay::displayLinkCallback could be blocked waiting for the lock, and
        // CVDisplayLinkStop won't return until displayLinkCallback exits, leading to deadlock.
        lock.unlock();
        
        // NOTE: As of OS X 10.11, stopping the display links from a non-main thread causes issues
        dispatch_sync(dispatch_get_main_queue(), ^{
            for (auto dl : displayLinks) {
                if (kCVReturnSuccess != CVDisplayLinkStop(dl)) {
                    merror(M_DISPLAY_MESSAGE_DOMAIN,
                           "Unable to stop updates on display %d",
                           CVDisplayLinkGetCurrentCGDisplay(dl));
                }
            }
        });
        
        mprintf(M_DISPLAY_MESSAGE_DOMAIN, "Display updates stopped");
        
    } else if ((RUNNING == newState) && !displayLinksRunning) {
예제 #2
0
DisplayRefreshMonitorMac::~DisplayRefreshMonitorMac()
{
    if (m_displayLink) {
        CVDisplayLinkStop(m_displayLink);
        CVDisplayLinkRelease(m_displayLink);
        m_displayLink = nullptr;
    }

    cancelCallOnMainThread(DisplayRefreshMonitor::handleDisplayRefreshedNotificationOnMainThread, this);
}
예제 #3
0
void StimulusDisplay::stateSystemCallback(const Datum &data, MWorksTime time) {
    unique_lock lock(display_lock);

    int newState = data.getInteger();

    if (IDLE == newState) {
        
        if (CVDisplayLinkIsRunning(displayLink)) {
            // If another thread is waiting for a display refresh, allow it to complete before stopping
            // the display link
            while (waitingForRefresh) {
                refreshCond.wait(lock);
            }

            // We need to release the lock before calling CVDisplayLinkStop, because
            // StimulusDisplay::displayLinkCallback could be blocked waiting for the lock, and
            // CVDisplayLinkStop won't return until displayLinkCallback exits, leading to deadlock.
            lock.unlock();
            
            if (kCVReturnSuccess != CVDisplayLinkStop(displayLink)) {
                merror(M_DISPLAY_MESSAGE_DOMAIN, "Unable to stop display updates");
            } else {
                currentOutputTimeUS = -1;
                mprintf(M_DISPLAY_MESSAGE_DOMAIN, "Display updates stopped");
            }
        }
        
    } else if (RUNNING == newState) {

        if (!CVDisplayLinkIsRunning(displayLink)) {

            lastFrameTime = 0;

            if (kCVReturnSuccess != CVDisplayLinkStart(displayLink)) {
                merror(M_DISPLAY_MESSAGE_DOMAIN, "Unable to start display updates");
            } else {
                // Wait for a refresh to complete, so we know that getCurrentOutputTimeUS() will return a valid time
                ensureRefresh(lock);
                
                mprintf(M_DISPLAY_MESSAGE_DOMAIN,
                        "Display updates started (main = %d, current = %d)",
                        CGMainDisplayID(),
                        CVDisplayLinkGetCurrentCGDisplay(displayLink));
            }

        }
        
    }
}
예제 #4
0
void PsychOSCloseWindow(PsychWindowRecordType *windowRecord)
{
    CGDirectDisplayID   cgDisplayID;

    // Disable rendering context:
    CGLSetCurrentContext(NULL);

    // Destroy pixelformat object:
    CGLDestroyPixelFormat(windowRecord->targetSpecific.pixelFormatObject);

    // Destroy rendering context:
    CGLReleaseContext(windowRecord->targetSpecific.contextObject);
    if (windowRecord->targetSpecific.glusercontextObject) CGLReleaseContext(windowRecord->targetSpecific.glusercontextObject);
    if (windowRecord->targetSpecific.glswapcontextObject) CGLReleaseContext(windowRecord->targetSpecific.glswapcontextObject);

    // Last reference to this screen? In that case we have to shutdown the fallback
    // vbl timestamping and vblank counting facilities for this screen:
    if (screenRefCount[windowRecord->screenNumber] == 1) {
        // Last one on this screen will be gone in a second.
        // Shutdown and release CVDisplayLink for this windows screen, if any:
        if (cvDisplayLink[windowRecord->screenNumber]) {
            if (PsychPrefStateGet_Verbosity() > 3) printf("PTB-INFO: Releasing CVDisplayLink for screen %i.\n", windowRecord->screenNumber);

            if (CVDisplayLinkIsRunning(cvDisplayLink[windowRecord->screenNumber])) CVDisplayLinkStop(cvDisplayLink[windowRecord->screenNumber]);
            PsychYieldIntervalSeconds(0.1);
            CVDisplayLinkRelease(cvDisplayLink[windowRecord->screenNumber]);
            cvDisplayLink[windowRecord->screenNumber] = NULL;
            PsychYieldIntervalSeconds(0.1);

            // Teardown shared data structure and mutex:
            PsychDestroyMutex(&(cvDisplayLinkData[windowRecord->screenNumber].mutex));
        }
    }

    // Release reference of this window to its screen:
    screenRefCount[windowRecord->screenNumber]--;

    // Destroy Cocoa onscreen window, if any:
    if (windowRecord->targetSpecific.windowHandle) PsychCocoaDisposeWindow(windowRecord);
    windowRecord->targetSpecific.windowHandle = NULL;

    return;
}
예제 #5
0
static CVReturn p1_display_video_clock_callback(
    CVDisplayLinkRef displayLink,
    const CVTimeStamp *inNow,
    const CVTimeStamp *inOutputTime,
    CVOptionFlags flagsIn,
    CVOptionFlags *flagsOut,
    void *displayLinkContext)
{
    P1DisplayVideoClock *dvclock = (P1DisplayVideoClock *) displayLinkContext;
    P1VideoClock *vclock = (P1VideoClock *) displayLinkContext;
    P1Object *obj = (P1Object *) displayLinkContext;
    CVReturn ret;

    p1_object_lock(obj);

    if (obj->state.current == P1_STATE_STOPPING) {
        ret = CVDisplayLinkStop(dvclock->display_link);
        if (ret != kCVReturnSuccess) {
            p1_log(obj, P1_LOG_ERROR, "Failed to stop display link: Core Video error %d", ret);
            obj->state.flags |= P1_FLAG_ERROR;
        }
        p1_display_video_clock_kill_session(dvclock);

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

        goto end;
    }

    if (obj->state.current == P1_STATE_STARTING) {
        // Get the display refresh period.
        double period = CVDisplayLinkGetActualOutputVideoRefreshPeriod(dvclock->display_link);
        if (period == 0.0)
            goto end;

        // Set the frame rate based on this and the divisor.
        vclock->fps_num = (uint32_t) round(1.0 / period);
        vclock->fps_den = dvclock->divisor;

        // Report running.
        obj->state.current = P1_STATE_RUNNING;
        p1_object_notify(obj);
    }

    if (obj->state.current == P1_STATE_RUNNING) {
        // Skip tick based on divisor.
        if (dvclock->skip_counter >= dvclock->divisor)
            dvclock->skip_counter = 0;
        if (dvclock->skip_counter++ != 0)
            goto end;

        p1_object_unlock(obj);
        p1_video_clock_tick(vclock, inNow->hostTime);
        return kCVReturnSuccess;
    }

end:
    p1_object_unlock(obj);

    return kCVReturnSuccess;
}