mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-30 00:32:57 -04:00
cocoa: use CVDisplayLink on macOS to sync video to display(s)
Closes #487 Fixes #486
This commit is contained in:
parent
8a38337e6b
commit
0fa0ad673f
@ -20,6 +20,7 @@
|
||||
|
||||
#import <AppKit/NSOpenGL.h>
|
||||
#import <OpenGL/OpenGL.h>
|
||||
#import <CoreVideo/CoreVideo.h>
|
||||
|
||||
/**
|
||||
* A tiny specialization on GLGraphicsStateGuardian to add some Cocoa-specific
|
||||
@ -38,14 +39,21 @@ public:
|
||||
CocoaGraphicsStateGuardian *share_with);
|
||||
|
||||
virtual ~CocoaGraphicsStateGuardian();
|
||||
bool setup_vsync();
|
||||
|
||||
INLINE void lock_context();
|
||||
INLINE void unlock_context();
|
||||
|
||||
NSOpenGLContext *_share_context;
|
||||
NSOpenGLContext *_context;
|
||||
NSOpenGLPixelFormat *_format = nullptr;
|
||||
FrameBufferProperties _fbprops;
|
||||
|
||||
CVDisplayLinkRef _display_link = nullptr;
|
||||
Mutex _swap_lock;
|
||||
ConditionVar _swap_condition;
|
||||
AtomicAdjust::Integer _last_wait_frame = 0;
|
||||
|
||||
protected:
|
||||
virtual void query_gl_version();
|
||||
virtual void *do_get_extension_func(const char *name);
|
||||
|
@ -28,6 +28,20 @@
|
||||
#define NSAppKitVersionNumber10_7 1138
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Called whenever a display wants a frame. The context argument contains the
|
||||
* applicable CocoaGraphicsStateGuardian.
|
||||
*/
|
||||
static CVReturn
|
||||
display_link_cb(CVDisplayLinkRef link, const CVTimeStamp *now,
|
||||
const CVTimeStamp* output_time, CVOptionFlags flags_in,
|
||||
CVOptionFlags *flags_out, void *context) {
|
||||
CocoaGraphicsStateGuardian *gsg = (CocoaGraphicsStateGuardian *)context;
|
||||
MutexHolder swap_holder(gsg->_swap_lock);
|
||||
gsg->_swap_condition.notify();
|
||||
return kCVReturnSuccess;
|
||||
}
|
||||
|
||||
TypeHandle CocoaGraphicsStateGuardian::_type_handle;
|
||||
|
||||
/**
|
||||
@ -36,7 +50,8 @@ TypeHandle CocoaGraphicsStateGuardian::_type_handle;
|
||||
CocoaGraphicsStateGuardian::
|
||||
CocoaGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe,
|
||||
CocoaGraphicsStateGuardian *share_with) :
|
||||
GLGraphicsStateGuardian(engine, pipe)
|
||||
GLGraphicsStateGuardian(engine, pipe),
|
||||
_swap_condition(_swap_lock)
|
||||
{
|
||||
_share_context = nil;
|
||||
_context = nil;
|
||||
@ -52,12 +67,59 @@ CocoaGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe,
|
||||
*/
|
||||
CocoaGraphicsStateGuardian::
|
||||
~CocoaGraphicsStateGuardian() {
|
||||
if (_format != nil) {
|
||||
[_format release];
|
||||
}
|
||||
if (_display_link != nil) {
|
||||
CVDisplayLinkRelease(_display_link);
|
||||
_display_link = nil;
|
||||
MutexHolder swap_holder(_swap_lock);
|
||||
_swap_condition.notify();
|
||||
}
|
||||
if (_context != nil) {
|
||||
[_context clearDrawable];
|
||||
[_context release];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a CVDisplayLink, which tells us when the display the window is on
|
||||
* will want a frame.
|
||||
*/
|
||||
bool CocoaGraphicsStateGuardian::
|
||||
setup_vsync() {
|
||||
if (_display_link != nil) {
|
||||
// Already set up.
|
||||
return true;
|
||||
}
|
||||
|
||||
CVReturn result = CVDisplayLinkCreateWithActiveCGDisplays(&_display_link);
|
||||
if (result != kCVReturnSuccess) {
|
||||
cocoadisplay_cat.error() << "Failed to create CVDisplayLink.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
result = CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(_display_link, (CGLContextObj)[_context CGLContextObj], (CGLPixelFormatObj)[_format CGLPixelFormatObj]);
|
||||
if (result != kCVReturnSuccess) {
|
||||
cocoadisplay_cat.error() << "Failed to set CVDisplayLink's current display.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
result = CVDisplayLinkSetOutputCallback(_display_link, &display_link_cb, this);
|
||||
if (result != kCVReturnSuccess) {
|
||||
cocoadisplay_cat.error() << "Failed to set CVDisplayLink output callback.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
result = CVDisplayLinkStart(_display_link);
|
||||
if (result != kCVReturnSuccess) {
|
||||
cocoadisplay_cat.error() << "Failed to start the CVDisplayLink.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the FrameBufferProperties to match the indicated config.
|
||||
*/
|
||||
@ -262,15 +324,15 @@ choose_pixel_format(const FrameBufferProperties &properties,
|
||||
// TODO: print out renderer
|
||||
|
||||
_context = [[NSOpenGLContext alloc] initWithFormat:format shareContext:_share_context];
|
||||
[format release];
|
||||
_format = format;
|
||||
if (_context == nil) {
|
||||
cocoadisplay_cat.error() <<
|
||||
"Failed to create OpenGL context!\n";
|
||||
return;
|
||||
}
|
||||
|
||||
// Set vsync setting on the context
|
||||
GLint swap = sync_video ? 1 : 0;
|
||||
// Disable vsync via the built-in mechanism, which doesn't work on Mojave
|
||||
GLint swap = 0;
|
||||
[_context setValues:&swap forParameter:NSOpenGLCPSwapInterval];
|
||||
|
||||
cocoadisplay_cat.debug()
|
||||
|
@ -23,6 +23,8 @@
|
||||
#import <AppKit/NSView.h>
|
||||
#import <AppKit/NSWindow.h>
|
||||
|
||||
#import <CoreVideo/CoreVideo.h>
|
||||
|
||||
/**
|
||||
* An interface to the Cocoa system for managing OpenGL windows under Mac OS
|
||||
* X.
|
||||
@ -92,6 +94,7 @@ private:
|
||||
PT(GraphicsWindowInputDevice) _input;
|
||||
bool _mouse_hidden;
|
||||
bool _context_needs_update;
|
||||
bool _vsync_enabled = false;
|
||||
|
||||
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
|
||||
CGDisplayModeRef _fullscreen_mode;
|
||||
|
@ -274,6 +274,14 @@ end_flip() {
|
||||
CocoaGraphicsStateGuardian *cocoagsg;
|
||||
DCAST_INTO_V(cocoagsg, _gsg);
|
||||
|
||||
if (_vsync_enabled) {
|
||||
AtomicAdjust::Integer cur_frame = ClockObject::get_global_clock()->get_frame_count();
|
||||
if (AtomicAdjust::set(cocoagsg->_last_wait_frame, cur_frame) != cur_frame) {
|
||||
MutexHolder swap_holder(cocoagsg->_swap_lock);
|
||||
cocoagsg->_swap_condition.wait();
|
||||
}
|
||||
}
|
||||
|
||||
cocoagsg->lock_context();
|
||||
|
||||
// Swap the front and back buffer.
|
||||
@ -669,6 +677,8 @@ open_window() {
|
||||
mouse_mode_relative();
|
||||
}
|
||||
|
||||
_vsync_enabled = sync_video && cocoagsg->setup_vsync();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -710,6 +720,8 @@ close_window() {
|
||||
_view = nil;
|
||||
}
|
||||
|
||||
_vsync_enabled = false;
|
||||
|
||||
GraphicsWindow::close_window();
|
||||
}
|
||||
|
||||
@ -1491,6 +1503,7 @@ handle_close_event() {
|
||||
cocoagsg->unlock_context();
|
||||
}
|
||||
_gsg.clear();
|
||||
_vsync_enabled = false;
|
||||
}
|
||||
|
||||
// Dump the view, too
|
||||
|
Loading…
x
Reference in New Issue
Block a user