@@ -325,11 +325,19 @@ static inline MTLTextureUsage getMetalTextureUsage(TextureUsage usage) {
325325 if (frameCompleted.callback ) {
326326 scheduleFrameCompletedCallback ();
327327 }
328+ const auto timeNs = presentationTimeNs;
329+ presentationTimeNs = 0 ;
328330 if (drawable) {
329331 if (frameScheduled.callback ) {
330- scheduleFrameScheduledCallback ();
332+ scheduleFrameScheduledCallback (timeNs );
331333 } else {
332- [getPendingCommandBuffer (&context) presentDrawable: drawable];
334+ if (presentationTimeNs) {
335+ const CFTimeInterval timeSeconds =
336+ (CFTimeInterval) presentationTimeNs / 1000000000.0 ;
337+ [getPendingCommandBuffer (&context) presentDrawable: drawable atTime: timeSeconds];
338+ } else {
339+ [getPendingCommandBuffer (&context) presentDrawable: drawable];
340+ }
333341 }
334342 }
335343}
@@ -341,15 +349,22 @@ static inline MTLTextureUsage getMetalTextureUsage(TextureUsage usage) {
341349 PresentDrawableData& operator =(const PresentDrawableData&) = delete ;
342350
343351 static PresentDrawableData* create (id <CAMetalDrawable > drawable,
344- std::shared_ptr<std::mutex> drawableMutex, MetalDriver* driver, uint64_t flags) {
352+ std::shared_ptr<std::mutex> drawableMutex, MetalDriver* driver, uint64_t flags,
353+ int64_t presentationTimeNs) {
345354 assert_invariant (drawableMutex);
346355 assert_invariant (driver);
347- return new PresentDrawableData (drawable, drawableMutex, driver, flags);
356+ return new PresentDrawableData (drawable, drawableMutex, driver, flags, presentationTimeNs );
348357 }
349358
350359 static void maybePresentAndDestroyAsync (PresentDrawableData* that, bool shouldPresent) {
351360 if (shouldPresent) {
352- [that->mDrawable present ];
361+ if (that->mPresentationTimeNs ) {
362+ const CFTimeInterval timeSeconds =
363+ (CFTimeInterval) that->mPresentationTimeNs / 1000000000.0 ;
364+ [that->mDrawable presentAtTime: timeSeconds];
365+ } else {
366+ [that->mDrawable present ];
367+ }
353368 }
354369
355370 if (that->mFlags & SwapChain::CALLBACK_DEFAULT_USE_METAL_COMPLETION_HANDLER ) {
@@ -367,8 +382,12 @@ static void maybePresentAndDestroyAsync(PresentDrawableData* that, bool shouldPr
367382
368383private:
369384 PresentDrawableData (id <CAMetalDrawable > drawable, std::shared_ptr<std::mutex> drawableMutex,
370- MetalDriver* driver, uint64_t flags)
371- : mDrawable (drawable), mDrawableMutex (drawableMutex), mDriver (driver), mFlags (flags) {}
385+ MetalDriver* driver, uint64_t flags, int64_t presentationTimeNs)
386+ : mDrawable (drawable),
387+ mDrawableMutex (drawableMutex),
388+ mDriver(driver),
389+ mFlags(flags),
390+ mPresentationTimeNs(presentationTimeNs) {}
372391
373392 static void cleanupAndDestroy (PresentDrawableData *that) {
374393 if (that->mDrawable ) {
@@ -384,14 +403,15 @@ static void cleanupAndDestroy(PresentDrawableData *that) {
384403 std::shared_ptr<std::mutex> mDrawableMutex ;
385404 MetalDriver* mDriver = nullptr ;
386405 uint64_t mFlags = 0 ;
406+ int64_t mPresentationTimeNs = 0 ;
387407};
388408
389409void presentDrawable (bool presentFrame, void * user) {
390410 auto * presentDrawableData = static_cast <PresentDrawableData*>(user);
391411 PresentDrawableData::maybePresentAndDestroyAsync (presentDrawableData, presentFrame);
392412}
393413
394- void MetalSwapChain::scheduleFrameScheduledCallback () {
414+ void MetalSwapChain::scheduleFrameScheduledCallback (int64_t presentationTimeNs ) {
395415 if (!frameScheduled.callback ) {
396416 return ;
397417 }
@@ -400,8 +420,11 @@ void presentDrawable(bool presentFrame, void* user) {
400420
401421 struct Callback {
402422 Callback (std::shared_ptr<FrameScheduledCallback> callback, id <CAMetalDrawable > drawable,
403- std::shared_ptr<std::mutex> drawableMutex, MetalDriver* driver, uint64_t flags)
404- : f(callback), data(PresentDrawableData::create(drawable, drawableMutex, driver, flags)) {}
423+ std::shared_ptr<std::mutex> drawableMutex, MetalDriver* driver, uint64_t flags,
424+ int64_t presentationTimeNs)
425+ : f(callback),
426+ data (PresentDrawableData::create(drawable, drawableMutex, driver, flags,
427+ presentationTimeNs)) {}
405428 std::shared_ptr<FrameScheduledCallback> f;
406429 // PresentDrawableData* is destroyed by maybePresentAndDestroyAsync() later.
407430 std::unique_ptr<PresentDrawableData> data;
@@ -419,7 +442,7 @@ static void func(void* user) {
419442 uint64_t const flags = frameScheduled.flags;
420443 ReleasablePointer* callback = [[ReleasablePointer alloc ]
421444 initWithPointer: new Callback (frameScheduled.callback, drawable, layerDrawableMutex,
422- context.driver, flags)];
445+ context.driver, flags, presentationTimeNs )];
423446
424447 backend::CallbackHandler* handler = frameScheduled.handler;
425448 MetalDriver* driver = context.driver;
0 commit comments