Skip to content

Commit

Permalink
macOS display link improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisd1100 committed Dec 26, 2023
1 parent 4658aca commit 09ccf9d
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 3 deletions.
52 changes: 52 additions & 0 deletions src/unix/apple/macosx/gfx/display-link.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT License was not distributed with this file,
// You can obtain one at https://spdx.org/licenses/MIT.html.

struct display_link {
CVDisplayLinkRef link;
dispatch_semaphore_t semaphore;
MTY_Atomic64 counter;
};

static CVReturn display_link_output(CVDisplayLinkRef displayLink, const CVTimeStamp *inNow,
const CVTimeStamp *inOutputTime, CVOptionFlags flagsIn, CVOptionFlags *flagsOut,
void *displayLinkContext)
{
struct display_link *ctx = displayLinkContext;

dispatch_semaphore_signal(ctx->semaphore);

MTY_Atomic64Add(&ctx->counter, 1);

return 0;
}

static void display_link_destroy(struct display_link *ctx)
{
if (ctx->link) {
CVDisplayLinkStop(ctx->link);
CVDisplayLinkRelease(ctx->link);
ctx->link = NULL;
}

ctx->semaphore = nil;
}

static int64_t display_link_get_counter(struct display_link *ctx)
{
return MTY_Atomic64Get(&ctx->counter);
}

static void display_link_delay(struct display_link *ctx, uint32_t interval)
{
for (uint32_t x = 0; x < interval; x++) {
if (!ctx->link) {
ctx->semaphore = dispatch_semaphore_create(0);
CVDisplayLinkCreateWithCGDisplay(CGMainDisplayID(), &ctx->link);
CVDisplayLinkSetOutputCallback(ctx->link, display_link_output, ctx);
CVDisplayLinkStart(ctx->link);
}

dispatch_semaphore_wait(ctx->semaphore, DISPATCH_TIME_FOREVER);
}
}
28 changes: 27 additions & 1 deletion src/unix/apple/macosx/gfx/metal-ctx.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#include <AppKit/AppKit.h>
#include <QuartzCore/CAMetalLayer.h>

#include "gfx/sync.h"
#include "display-link.h"
#include "scale.h"

struct metal_ctx {
Expand All @@ -17,6 +19,9 @@
id<CAMetalDrawable> back_buffer;
id<MTLCommandQueue> cq;
CGSize size;

struct sync sync;
struct display_link dlink;
};

static void metal_ctx_mt_block(void (^block)(void))
Expand All @@ -43,7 +48,14 @@ static void metal_ctx_mt_block(void (^block)(void))
ctx->layer = [CAMetalLayer layer];
ctx->layer.device = device;
ctx->layer.pixelFormat = MTLPixelFormatBGRA8Unorm;
ctx->layer.displaySyncEnabled = vsync ? YES : NO;

if (vsync) {
sync_set_interval(&ctx->sync, 100);
ctx->layer.displaySyncEnabled = YES;

} else {
ctx->layer.displaySyncEnabled = NO;
}

ctx->cq = [ctx->layer.device newCommandQueue];

Expand All @@ -61,6 +73,8 @@ void mty_metal_ctx_destroy(struct gfx_ctx **gfx_ctx)

struct metal_ctx *ctx = (struct metal_ctx *) *gfx_ctx;

display_link_destroy(&ctx->dlink);

ctx->window = nil;
ctx->layer = nil;
ctx->cq = nil;
Expand Down Expand Up @@ -122,18 +136,30 @@ static void metal_ctx_refresh(struct metal_ctx *ctx)

void mty_metal_ctx_set_sync_interval(struct gfx_ctx *gfx_ctx, uint32_t interval)
{
struct metal_ctx *ctx = (struct metal_ctx *) gfx_ctx;

sync_set_interval(&ctx->sync, interval);
}

void mty_metal_ctx_present(struct gfx_ctx *gfx_ctx)
{
struct metal_ctx *ctx = (struct metal_ctx *) gfx_ctx;

if (ctx->back_buffer) {
int64_t ctr = display_link_get_counter(&ctx->dlink);

id<MTLCommandBuffer> cb = [ctx->cq commandBuffer];
[cb presentDrawable:ctx->back_buffer];
[cb commit];
[cb waitUntilCompleted];

ctr = display_link_get_counter(&ctx->dlink) - ctr;

int64_t interval = sync_next_interval(&ctx->sync);

if (interval - ctr > 0)
display_link_delay(&ctx->dlink, interval - ctr);

ctx->back_buffer = nil;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/windows/gfx/d3d11-ctx.c
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ struct gfx_ctx *mty_d3d11_ctx_create(void *native_window, bool vsync)
ctx->hwnd = (HWND) native_window;

if (vsync)
sync_set_interval(&ctx->sync, 1);
sync_set_interval(&ctx->sync, 100);

d3d11_ctx_get_size(ctx, &ctx->width, &ctx->height);

Expand Down
2 changes: 1 addition & 1 deletion src/windows/gfx/d3d12-ctx.c
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ struct gfx_ctx *mty_d3d12_ctx_create(void *native_window, bool vsync)
ctx->hwnd = (HWND) native_window;

if (vsync)
sync_set_interval(&ctx->sync, 1);
sync_set_interval(&ctx->sync, 100);

d3d12_ctx_get_size(ctx, &ctx->width, &ctx->height);

Expand Down

0 comments on commit 09ccf9d

Please sign in to comment.