mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-30 16:58:40 -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 <AppKit/NSOpenGL.h>
|
||||||
#import <OpenGL/OpenGL.h>
|
#import <OpenGL/OpenGL.h>
|
||||||
|
#import <CoreVideo/CoreVideo.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A tiny specialization on GLGraphicsStateGuardian to add some Cocoa-specific
|
* A tiny specialization on GLGraphicsStateGuardian to add some Cocoa-specific
|
||||||
@ -38,14 +39,21 @@ public:
|
|||||||
CocoaGraphicsStateGuardian *share_with);
|
CocoaGraphicsStateGuardian *share_with);
|
||||||
|
|
||||||
virtual ~CocoaGraphicsStateGuardian();
|
virtual ~CocoaGraphicsStateGuardian();
|
||||||
|
bool setup_vsync();
|
||||||
|
|
||||||
INLINE void lock_context();
|
INLINE void lock_context();
|
||||||
INLINE void unlock_context();
|
INLINE void unlock_context();
|
||||||
|
|
||||||
NSOpenGLContext *_share_context;
|
NSOpenGLContext *_share_context;
|
||||||
NSOpenGLContext *_context;
|
NSOpenGLContext *_context;
|
||||||
|
NSOpenGLPixelFormat *_format = nullptr;
|
||||||
FrameBufferProperties _fbprops;
|
FrameBufferProperties _fbprops;
|
||||||
|
|
||||||
|
CVDisplayLinkRef _display_link = nullptr;
|
||||||
|
Mutex _swap_lock;
|
||||||
|
ConditionVar _swap_condition;
|
||||||
|
AtomicAdjust::Integer _last_wait_frame = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void query_gl_version();
|
virtual void query_gl_version();
|
||||||
virtual void *do_get_extension_func(const char *name);
|
virtual void *do_get_extension_func(const char *name);
|
||||||
|
@ -28,6 +28,20 @@
|
|||||||
#define NSAppKitVersionNumber10_7 1138
|
#define NSAppKitVersionNumber10_7 1138
|
||||||
#endif
|
#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;
|
TypeHandle CocoaGraphicsStateGuardian::_type_handle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -36,7 +50,8 @@ TypeHandle CocoaGraphicsStateGuardian::_type_handle;
|
|||||||
CocoaGraphicsStateGuardian::
|
CocoaGraphicsStateGuardian::
|
||||||
CocoaGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe,
|
CocoaGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe,
|
||||||
CocoaGraphicsStateGuardian *share_with) :
|
CocoaGraphicsStateGuardian *share_with) :
|
||||||
GLGraphicsStateGuardian(engine, pipe)
|
GLGraphicsStateGuardian(engine, pipe),
|
||||||
|
_swap_condition(_swap_lock)
|
||||||
{
|
{
|
||||||
_share_context = nil;
|
_share_context = nil;
|
||||||
_context = nil;
|
_context = nil;
|
||||||
@ -52,12 +67,59 @@ CocoaGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe,
|
|||||||
*/
|
*/
|
||||||
CocoaGraphicsStateGuardian::
|
CocoaGraphicsStateGuardian::
|
||||||
~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) {
|
if (_context != nil) {
|
||||||
[_context clearDrawable];
|
[_context clearDrawable];
|
||||||
[_context release];
|
[_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.
|
* Gets the FrameBufferProperties to match the indicated config.
|
||||||
*/
|
*/
|
||||||
@ -262,15 +324,15 @@ choose_pixel_format(const FrameBufferProperties &properties,
|
|||||||
// TODO: print out renderer
|
// TODO: print out renderer
|
||||||
|
|
||||||
_context = [[NSOpenGLContext alloc] initWithFormat:format shareContext:_share_context];
|
_context = [[NSOpenGLContext alloc] initWithFormat:format shareContext:_share_context];
|
||||||
[format release];
|
_format = format;
|
||||||
if (_context == nil) {
|
if (_context == nil) {
|
||||||
cocoadisplay_cat.error() <<
|
cocoadisplay_cat.error() <<
|
||||||
"Failed to create OpenGL context!\n";
|
"Failed to create OpenGL context!\n";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set vsync setting on the context
|
// Disable vsync via the built-in mechanism, which doesn't work on Mojave
|
||||||
GLint swap = sync_video ? 1 : 0;
|
GLint swap = 0;
|
||||||
[_context setValues:&swap forParameter:NSOpenGLCPSwapInterval];
|
[_context setValues:&swap forParameter:NSOpenGLCPSwapInterval];
|
||||||
|
|
||||||
cocoadisplay_cat.debug()
|
cocoadisplay_cat.debug()
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
#import <AppKit/NSView.h>
|
#import <AppKit/NSView.h>
|
||||||
#import <AppKit/NSWindow.h>
|
#import <AppKit/NSWindow.h>
|
||||||
|
|
||||||
|
#import <CoreVideo/CoreVideo.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface to the Cocoa system for managing OpenGL windows under Mac OS
|
* An interface to the Cocoa system for managing OpenGL windows under Mac OS
|
||||||
* X.
|
* X.
|
||||||
@ -92,6 +94,7 @@ private:
|
|||||||
PT(GraphicsWindowInputDevice) _input;
|
PT(GraphicsWindowInputDevice) _input;
|
||||||
bool _mouse_hidden;
|
bool _mouse_hidden;
|
||||||
bool _context_needs_update;
|
bool _context_needs_update;
|
||||||
|
bool _vsync_enabled = false;
|
||||||
|
|
||||||
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
|
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
|
||||||
CGDisplayModeRef _fullscreen_mode;
|
CGDisplayModeRef _fullscreen_mode;
|
||||||
|
@ -274,6 +274,14 @@ end_flip() {
|
|||||||
CocoaGraphicsStateGuardian *cocoagsg;
|
CocoaGraphicsStateGuardian *cocoagsg;
|
||||||
DCAST_INTO_V(cocoagsg, _gsg);
|
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();
|
cocoagsg->lock_context();
|
||||||
|
|
||||||
// Swap the front and back buffer.
|
// Swap the front and back buffer.
|
||||||
@ -669,6 +677,8 @@ open_window() {
|
|||||||
mouse_mode_relative();
|
mouse_mode_relative();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_vsync_enabled = sync_video && cocoagsg->setup_vsync();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -710,6 +720,8 @@ close_window() {
|
|||||||
_view = nil;
|
_view = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_vsync_enabled = false;
|
||||||
|
|
||||||
GraphicsWindow::close_window();
|
GraphicsWindow::close_window();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1491,6 +1503,7 @@ handle_close_event() {
|
|||||||
cocoagsg->unlock_context();
|
cocoagsg->unlock_context();
|
||||||
}
|
}
|
||||||
_gsg.clear();
|
_gsg.clear();
|
||||||
|
_vsync_enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dump the view, too
|
// Dump the view, too
|
||||||
|
Loading…
x
Reference in New Issue
Block a user