Cocoa Port: Fix a bug in Metal display views where the internal V-sync would cause the total frame rate to be divided amongst multiple visible display views.

This commit is contained in:
rogerman 2018-08-23 09:56:23 -07:00
parent 5c85bcd732
commit 5d384f9eae
9 changed files with 174 additions and 41 deletions

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2017 DeSmuME team
Copyright (C) 2017-2018 DeSmuME team
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -1290,12 +1290,23 @@ void ClientDisplayViewInterface::SetAllowViewFlushes(bool allowFlushes)
this->_allowViewFlushes = allowFlushes;
}
void ClientDisplayViewInterface::FlushView()
void ClientDisplayViewInterface::FlushView(void *userData)
{
// Do nothing. This is implementation dependent.
this->_viewNeedsFlush = false;
}
void ClientDisplayViewInterface::FinalizeFlush(void *userData)
{
// Do nothing. This is implementation dependent.
}
void ClientDisplayViewInterface::FlushAndFinalizeImmediate()
{
this->FlushView(NULL);
this->FinalizeFlush(NULL);
}
// Touch screen input handling
void ClientDisplayViewInterface::GetNDSPoint(const ClientDisplayPresenterProperties &props,
const double logicalClientWidth, const double logicalClientHeight,

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2017 DeSmuME team
Copyright (C) 2017-2018 DeSmuME team
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -355,7 +355,9 @@ public:
bool GetAllowViewFlushes() const;
virtual void SetAllowViewFlushes(bool allowFlushes);
virtual void FlushView();
virtual void FlushView(void *userData);
virtual void FinalizeFlush(void *userData);
virtual void FlushAndFinalizeImmediate();
// Touch screen input handling
void GetNDSPoint(const ClientDisplayPresenterProperties &props,

View File

@ -23,6 +23,7 @@
#include <mach/semaphore.h>
#include <mach/sync_policy.h>
#include <map>
#include <vector>
#import "cocoa_util.h"
#include "../../GPU.h"
@ -57,6 +58,7 @@ enum ClientDisplayBufferState
};
class GPUEventHandlerOSX;
class ClientDisplay3DView;
#ifdef ENABLE_SHARED_FETCH_OBJECT
@ -102,7 +104,10 @@ typedef std::map<CGDirectDisplayID, int64_t> DisplayLinkFlushTimeLimitMap;
- (void) incrementViewsUsingDirectToCPUFiltering;
- (void) decrementViewsUsingDirectToCPUFiltering;
- (void) pushVideoDataToAllDisplayViews;
- (void) flushAllDisplaysOnDisplayLink:(CVDisplayLinkRef)displayLink timeStamp:(const CVTimeStamp *)timeStamp;
- (void) flushMultipleViews:(const std::vector<ClientDisplay3DView *> &)cdvFlushList;
- (void) finalizeFlushMultipleViews:(const std::vector<ClientDisplay3DView *> &)cdvFlushList;
- (void) displayLinkStartUsingID:(CGDirectDisplayID)displayID;
- (void) displayLinkListUpdate;

View File

@ -24,16 +24,16 @@
#include "../../rasterize.h"
#ifdef MAC_OS_X_VERSION_10_7
#include "../../OGLRender_3_2.h"
#include "../../OGLRender_3_2.h"
#else
#include "../../OGLRender.h"
#include "../../OGLRender.h"
#endif
#include <OpenGL/OpenGL.h>
#import "userinterface/MacOGLDisplayView.h"
#ifdef ENABLE_APPLE_METAL
#import "userinterface/MacMetalDisplayView.h"
#import "userinterface/MacMetalDisplayView.h"
#endif
#ifdef BOOL
@ -1219,6 +1219,8 @@ public:
CGDirectDisplayID displayID = CVDisplayLinkGetCurrentCGDisplay(displayLink);
bool didFlushOccur = false;
std::vector<ClientDisplay3DView *> cdvFlushList;
if (currentRWLock != NULL)
{
pthread_rwlock_rdlock(currentRWLock);
@ -1234,13 +1236,21 @@ public:
if (cdv->GetViewNeedsFlush())
{
cdv->FlushView();
didFlushOccur = true;
cdvFlushList.push_back(cdv);
}
}
}
}
const size_t listSize = cdvFlushList.size();
if (listSize > 0)
{
[self flushMultipleViews:cdvFlushList];
[self finalizeFlushMultipleViews:cdvFlushList];
didFlushOccur = true;
}
if (currentRWLock != NULL)
{
pthread_rwlock_unlock(currentRWLock);
@ -1257,6 +1267,28 @@ public:
}
}
- (void) flushMultipleViews:(const std::vector<ClientDisplay3DView *> &)cdvFlushList
{
const size_t listSize = cdvFlushList.size();
for (size_t i = 0; i < listSize; i++)
{
ClientDisplay3DView *cdv = (ClientDisplay3DView *)cdvFlushList[i];
cdv->FlushView(NULL);
}
}
- (void) finalizeFlushMultipleViews:(const std::vector<ClientDisplay3DView *> &)cdvFlushList
{
const size_t listSize = cdvFlushList.size();
for (size_t i = 0; i < listSize; i++)
{
ClientDisplay3DView *cdv = (ClientDisplay3DView *)cdvFlushList[i];
cdv->FinalizeFlush(NULL);
}
}
- (void) displayLinkStartUsingID:(CGDirectDisplayID)displayID
{
CVDisplayLinkRef displayLink = NULL;

View File

@ -2128,7 +2128,7 @@ static std::unordered_map<NSScreen *, DisplayWindowController *> _screenMap; //
// If localOGLContext isn't nil, then we will not assign the local layer
// directly to the view, since the OpenGL context will already be what
// is assigned.
cdv->FlushView();
cdv->FlushAndFinalizeImmediate();
return;
}
@ -2144,7 +2144,7 @@ static std::unordered_map<NSScreen *, DisplayWindowController *> _screenMap; //
if (isMetalLayer)
{
cdv->FlushView();
cdv->FlushAndFinalizeImmediate();
}
else
{
@ -2226,12 +2226,12 @@ static std::unordered_map<NSScreen *, DisplayWindowController *> _screenMap; //
- (void)updateLayer
{
[self clientDisplayView]->FlushView();
[self clientDisplayView]->FlushAndFinalizeImmediate();
}
- (void)drawRect:(NSRect)dirtyRect
{
[self clientDisplayView]->FlushView();
[self clientDisplayView]->FlushAndFinalizeImmediate();
}
- (void)setFrame:(NSRect)rect

View File

@ -168,6 +168,9 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties;
- (void) fetchNativeDisplayByID:(const NDSDisplayID)displayID bufferIndex:(const u8)bufferIndex blitCommandEncoder:(id<MTLBlitCommandEncoder>)bce;
- (void) fetchCustomDisplayByID:(const NDSDisplayID)displayID bufferIndex:(const u8)bufferIndex blitCommandEncoder:(id<MTLBlitCommandEncoder>)bce;
- (void) flushMultipleViews:(const std::vector<ClientDisplay3DView *> &)cdvFlushList;;
- (void) finalizeFlushMultipleViews:(const std::vector<ClientDisplay3DView *> &)cdvFlushList;
@end
@interface MacMetalDisplayPresenterObject : NSObject
@ -261,13 +264,17 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties;
MacDisplayLayeredView *_cdv;
MacMetalDisplayPresenterObject *presenterObject;
dispatch_semaphore_t _semDrawable;
id<CAMetalDrawable> layerDrawable;
}
@property (readonly, nonatomic) MacMetalDisplayPresenterObject *presenterObject;
@property (retain) id<CAMetalDrawable> layerDrawable;
- (id) initWithDisplayPresenterObject:(MacMetalDisplayPresenterObject *)thePresenterObject;
- (void) setupLayer;
- (void) renderToDrawable;
- (void) renderToDrawableUsingCommandBuffer:(id<MTLCommandBuffer>)cb;
- (void) presentDrawableWithCommandBuffer:(id<MTLCommandBuffer>)cb;
- (void) renderAndPresentDrawableImmediate;
@end
@ -360,7 +367,9 @@ public:
virtual void SetAllowViewFlushes(bool allowFlushes);
// Client view interface
virtual void FlushView();
virtual void FlushView(void *userData);
virtual void FinalizeFlush(void *userData);
virtual void FlushAndFinalizeImmediate();
};
#pragma mark -

View File

@ -150,7 +150,7 @@
idxBufferPtr[j+5] = k+0;
}
id<MTLCommandBuffer> cb = [_fetchCommandQueue commandBufferWithUnretainedReferences];;
id<MTLCommandBuffer> cb = [_fetchCommandQueue commandBufferWithUnretainedReferences];
id<MTLBlitCommandEncoder> bce = [cb blitCommandEncoder];
[bce copyFromBuffer:tempHUDIndexBuffer
@ -383,8 +383,11 @@
#ifdef MAC_OS_X_VERSION_10_13
if (_isSharedBufferTextureSupported)
{
_texDisplayFetchNative[NDSDisplayID_Main][i] = [_bufDisplayFetchNative[NDSDisplayID_Main][i] newTextureWithDescriptor:newTexDisplayNativeDesc offset:0 bytesPerRow:_nativeLineSize];
_texDisplayFetchNative[NDSDisplayID_Touch][i] = [_bufDisplayFetchNative[NDSDisplayID_Touch][i] newTextureWithDescriptor:newTexDisplayNativeDesc offset:0 bytesPerRow:_nativeLineSize];
if (@available(macOS 10_13, *))
{
_texDisplayFetchNative[NDSDisplayID_Main][i] = [_bufDisplayFetchNative[NDSDisplayID_Main][i] newTextureWithDescriptor:newTexDisplayNativeDesc offset:0 bytesPerRow:_nativeLineSize];
_texDisplayFetchNative[NDSDisplayID_Touch][i] = [_bufDisplayFetchNative[NDSDisplayID_Touch][i] newTextureWithDescriptor:newTexDisplayNativeDesc offset:0 bytesPerRow:_nativeLineSize];
}
}
else
#endif
@ -409,8 +412,11 @@
#ifdef MAC_OS_X_VERSION_10_13
if (_isSharedBufferTextureSupported)
{
_texDisplayFetchCustom[NDSDisplayID_Main][i] = [_bufDisplayFetchCustom[NDSDisplayID_Main][i] newTextureWithDescriptor:newTexDisplayCustomDesc offset:0 bytesPerRow:_customLineSize];
_texDisplayFetchCustom[NDSDisplayID_Touch][i] = [_bufDisplayFetchCustom[NDSDisplayID_Touch][i] newTextureWithDescriptor:newTexDisplayCustomDesc offset:0 bytesPerRow:_customLineSize];
if (@available(macOS 10_13, *))
{
_texDisplayFetchCustom[NDSDisplayID_Main][i] = [_bufDisplayFetchCustom[NDSDisplayID_Main][i] newTextureWithDescriptor:newTexDisplayCustomDesc offset:0 bytesPerRow:_customLineSize];
_texDisplayFetchCustom[NDSDisplayID_Touch][i] = [_bufDisplayFetchCustom[NDSDisplayID_Touch][i] newTextureWithDescriptor:newTexDisplayCustomDesc offset:0 bytesPerRow:_customLineSize];
}
}
else
#endif
@ -731,6 +737,34 @@
}
}
- (void) flushMultipleViews:(const std::vector<ClientDisplay3DView *> &)cdvFlushList
{
const size_t listSize = cdvFlushList.size();
id<MTLCommandBuffer> cb = [commandQueue commandBufferWithUnretainedReferences];
for (size_t i = 0; i < listSize; i++)
{
ClientDisplay3DView *cdv = (ClientDisplay3DView *)cdvFlushList[i];
cdv->FlushView(cb);
}
[cb commit];
}
- (void) finalizeFlushMultipleViews:(const std::vector<ClientDisplay3DView *> &)cdvFlushList
{
const size_t listSize = cdvFlushList.size();
id<MTLCommandBuffer> cb = [commandQueue commandBufferWithUnretainedReferences];
for (size_t i = 0; i < listSize; i++)
{
ClientDisplay3DView *cdv = (ClientDisplay3DView *)cdvFlushList[i];
cdv->FinalizeFlush(cb);
}
[cb commit];
}
@end
@implementation MacMetalDisplayPresenterObject
@ -2142,6 +2176,7 @@
@synthesize _cdv;
@synthesize presenterObject;
@synthesize layerDrawable;
- (id) initWithDisplayPresenterObject:(MacMetalDisplayPresenterObject *)thePresenterObject
{
@ -2153,6 +2188,7 @@
_cdv = NULL;
_semDrawable = dispatch_semaphore_create(3);
layerDrawable = nil;
presenterObject = thePresenterObject;
if (thePresenterObject != nil)
@ -2168,6 +2204,7 @@
- (void)dealloc
{
[self setLayerDrawable:nil];
dispatch_release(_semDrawable);
[super dealloc];
@ -2182,46 +2219,37 @@
}
}
- (void) renderToDrawable
- (void) renderToDrawableUsingCommandBuffer:(id<MTLCommandBuffer>)cb
{
@autoreleasepool
{
// Now that everything is set up, go ahead and draw everything.
dispatch_semaphore_wait(_semDrawable, DISPATCH_TIME_FOREVER);
id<CAMetalDrawable> layerDrawable = [[self nextDrawable] retain];
id<CAMetalDrawable> drawable = [self nextDrawable];
if (layerDrawable != nil)
if (drawable != nil)
{
[[presenterObject colorAttachment0Desc] setTexture:[layerDrawable texture]];
id<MTLCommandBuffer> cbRender = [presenterObject newCommandBuffer];
id<MTLCommandBuffer> cbPresent = [presenterObject newCommandBuffer];
[[presenterObject colorAttachment0Desc] setTexture:[drawable texture]];
const MetalTexturePair texProcess = [presenterObject texPairProcess];
const MetalRenderFrameInfo mrfi = [presenterObject renderFrameInfo];
[presenterObject renderForCommandBuffer:cbRender
[presenterObject renderForCommandBuffer:cb
outputPipelineState:[presenterObject outputDrawablePipeline]
hudPipelineState:[[presenterObject sharedData] hudPipeline]
texDisplays:texProcess
mrfi:mrfi
doYFlip:NO];
[cbRender addScheduledHandler:^(id<MTLCommandBuffer> block) {
[cb addScheduledHandler:^(id<MTLCommandBuffer> block) {
[presenterObject setRenderBufferState:ClientDisplayBufferState_Reading index:mrfi.renderIndex];
}];
[cbRender addCompletedHandler:^(id<MTLCommandBuffer> block) {
[cb addCompletedHandler:^(id<MTLCommandBuffer> block) {
[presenterObject renderFinishAtIndex:mrfi.renderIndex];
}];
[cbPresent presentDrawable:layerDrawable];
[cbPresent addCompletedHandler:^(id<MTLCommandBuffer> block) {
[layerDrawable release];
dispatch_semaphore_signal(_semDrawable);
}];
[cbRender commit];
[cbPresent commit];
[self setLayerDrawable:drawable];
}
else
{
@ -2230,6 +2258,32 @@
}
}
- (void) presentDrawableWithCommandBuffer:(id<MTLCommandBuffer>)cb
{
id<CAMetalDrawable> drawable = [self layerDrawable];
if (drawable == nil)
{
return;
}
[cb presentDrawable:drawable];
[cb addCompletedHandler:^(id<MTLCommandBuffer> block) {
[self setLayerDrawable:nil];
dispatch_semaphore_signal(_semDrawable);
}];
}
- (void) renderAndPresentDrawableImmediate
{
id<MTLCommandBuffer> cb = [presenterObject newCommandBuffer];
_cdv->FlushView(cb);
[cb commit];
cb = [presenterObject newCommandBuffer];
_cdv->FinalizeFlush(cb);
[cb commit];
}
@end
#pragma mark -
@ -2575,13 +2629,23 @@ void MacMetalDisplayView::SetAllowViewFlushes(bool allowFlushes)
[sharedData displayLinkStartUsingID:displayID];
}
void MacMetalDisplayView::FlushView()
void MacMetalDisplayView::FlushView(void *userData)
{
OSSpinLockLock(&this->_spinlockViewNeedsFlush);
this->_viewNeedsFlush = false;
OSSpinLockUnlock(&this->_spinlockViewNeedsFlush);
[(DisplayViewMetalLayer *)this->_caLayer renderToDrawable];
[(DisplayViewMetalLayer *)this->_caLayer renderToDrawableUsingCommandBuffer:(id<MTLCommandBuffer>)userData];
}
void MacMetalDisplayView::FinalizeFlush(void *userData)
{
[(DisplayViewMetalLayer *)this->_caLayer presentDrawableWithCommandBuffer:(id<MTLCommandBuffer>)userData];
}
void MacMetalDisplayView::FlushAndFinalizeImmediate()
{
[(DisplayViewMetalLayer *)this->_caLayer renderAndPresentDrawableImmediate];
}
#pragma mark -

View File

@ -133,7 +133,8 @@ public:
virtual void SetUseVerticalSync(const bool useVerticalSync);
// Client view interface
virtual void FlushView();
virtual void FlushView(void *userData);
virtual void FinalizeFlush(void *userData);
};
#endif // _MAC_OGLDISPLAYOUTPUT_H_

View File

@ -538,7 +538,7 @@ void MacOGLDisplayView::SetUseVerticalSync(const bool useVerticalSync)
CGLUnlockContext(context);
}
void MacOGLDisplayView::FlushView()
void MacOGLDisplayView::FlushView(void *userData)
{
OSSpinLockLock(&this->_spinlockViewNeedsFlush);
this->_viewNeedsFlush = false;
@ -549,6 +549,15 @@ void MacOGLDisplayView::FlushView()
CGLLockContext(context);
CGLSetCurrentContext(context);
((MacOGLDisplayPresenter *)this->_presenter)->RenderFrameOGL(false);
CGLUnlockContext(context);
}
void MacOGLDisplayView::FinalizeFlush(void *userData)
{
CGLContextObj context = ((MacOGLDisplayPresenter *)this->_presenter)->GetContext();
CGLLockContext(context);
CGLSetCurrentContext(context);
CGLFlushDrawable(context);
CGLUnlockContext(context);
}