osx vsync notification

This commit is contained in:
Reuben Dunnington 2023-08-27 20:47:32 -07:00
parent aa1c5ef915
commit d9703519b9
Signed by: rdunnington
GPG Key ID: 4EC5290E704FD482
1 changed files with 102 additions and 0 deletions

View File

@ -304,7 +304,10 @@ oc_key_code oc_label_to_key(oc_str8 label)
@interface OCWindow : NSWindow
{
oc_window_data* mpWindow;
@public
CVDisplayLinkRef displayLink;
}
- (id)initWithWindowData:(oc_window_data*)window contentRect:(NSRect)rect styleMask:(uint32)style;
@end
@ -703,6 +706,9 @@ void oc_install_keyboard_layout_listener()
- (BOOL)windowShouldClose:(id)sender
{
OCWindow* ocWindow = (OCWindow*)mpWindow->osx.nsWindow;
CVDisplayLinkStop(ocWindow->displayLink);
mpWindow->shouldClose = true;
oc_event event = {};
@ -1126,6 +1132,8 @@ void oc_init()
[NSApp run];
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
[NSApp activateIgnoringOtherApps:YES];
oc_vsync_init();
}
}
}
@ -2336,3 +2344,97 @@ int oc_directory_create(oc_str8 path)
}
}
}
static CVReturn oc_display_link_callback(
CVDisplayLinkRef displayLink,
const CVTimeStamp* inNow,
const CVTimeStamp* inOutputTime,
CVOptionFlags flagsIn,
CVOptionFlags* flagsOut,
void* displayLinkContext)
{
oc_event event = { 0 };
event.type = OC_EVENT_FRAME;
oc_queue_event(&event);
OCWindow* ocWindow = (OCWindow*)displayLinkContext;
CGDirectDisplayID displays[4];
uint32_t matchingDisplayCount;
CGError err = CGGetDisplaysWithRect(ocWindow.frame, 4, displays, &matchingDisplayCount);
if(err == kCGErrorSuccess)
{
// determine which display has the greatest intersecting area
if(matchingDisplayCount > 0)
{
CGDirectDisplayID* selectedDisplay = NULL;
CGFloat selectedIntersectArea = 0.0f;
for(uint32_t i = 0; i < matchingDisplayCount; ++i)
{
CGRect displayBounds = CGDisplayBounds(displays[i]);
CGRect intersection = CGRectIntersection(ocWindow.frame, displayBounds);
CGFloat intersectArea = intersection.size.width * intersection.size.width;
if(selectedDisplay == NULL || intersectArea < selectedIntersectArea)
{
selectedDisplay = displays + i;
selectedIntersectArea = intersectArea;
}
}
if(selectedDisplay)
{
CGDirectDisplayID currentDisplay = CVDisplayLinkGetCurrentCGDisplay(ocWindow->displayLink);
if(currentDisplay != *selectedDisplay)
{
CVDisplayLinkSetCurrentCGDisplay(ocWindow->displayLink, *selectedDisplay);
}
}
}
}
else
{
oc_log_error("CGGetDisplaysWithRect failed with error: %d\n", err);
}
return kCVReturnSuccess;
}
void oc_vsync_init(void)
{
}
void oc_vsync_window(oc_window window)
{
oc_window_data* windowData = oc_window_ptr_from_handle(window);
if(!windowData)
{
return;
}
OCWindow* ocWindow = (OCWindow*)windowData->osx.nsWindow;
CVReturn ret;
if((ret = CVDisplayLinkCreateWithActiveCGDisplays(&ocWindow->displayLink)) != kCVReturnSuccess)
{
oc_log_error("CVDisplayLinkCreateWithActiveCGDisplays error: %d\n", ret);
}
CGDirectDisplayID mainDisplay = CGMainDisplayID();
if((ret = CVDisplayLinkSetCurrentCGDisplay(ocWindow->displayLink, mainDisplay)) != kCVReturnSuccess)
{
oc_log_error("CVDisplayLinkSetCurrentCGDisplay ret: %d\n", ret);
}
if((ret = CVDisplayLinkSetOutputCallback(ocWindow->displayLink, oc_display_link_callback, ocWindow)) != kCVReturnSuccess)
{
oc_log_error("CVDisplayLinkSetOutputCallback ret: %d\n", ret);
}
if((ret = CVDisplayLinkStart(ocWindow->displayLink)) != kCVReturnSuccess)
{
oc_log_error("CVDisplayLinkStart ret: %d\n", ret);
}
}