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 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 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; this->_allowViewFlushes = allowFlushes;
} }
void ClientDisplayViewInterface::FlushView() void ClientDisplayViewInterface::FlushView(void *userData)
{ {
// Do nothing. This is implementation dependent. // Do nothing. This is implementation dependent.
this->_viewNeedsFlush = false; 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 // Touch screen input handling
void ClientDisplayViewInterface::GetNDSPoint(const ClientDisplayPresenterProperties &props, void ClientDisplayViewInterface::GetNDSPoint(const ClientDisplayPresenterProperties &props,
const double logicalClientWidth, const double logicalClientHeight, 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 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 it under the terms of the GNU General Public License as published by
@ -355,7 +355,9 @@ public:
bool GetAllowViewFlushes() const; bool GetAllowViewFlushes() const;
virtual void SetAllowViewFlushes(bool allowFlushes); 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 // Touch screen input handling
void GetNDSPoint(const ClientDisplayPresenterProperties &props, void GetNDSPoint(const ClientDisplayPresenterProperties &props,

View File

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

View File

@ -24,16 +24,16 @@
#include "../../rasterize.h" #include "../../rasterize.h"
#ifdef MAC_OS_X_VERSION_10_7 #ifdef MAC_OS_X_VERSION_10_7
#include "../../OGLRender_3_2.h" #include "../../OGLRender_3_2.h"
#else #else
#include "../../OGLRender.h" #include "../../OGLRender.h"
#endif #endif
#include <OpenGL/OpenGL.h> #include <OpenGL/OpenGL.h>
#import "userinterface/MacOGLDisplayView.h" #import "userinterface/MacOGLDisplayView.h"
#ifdef ENABLE_APPLE_METAL #ifdef ENABLE_APPLE_METAL
#import "userinterface/MacMetalDisplayView.h" #import "userinterface/MacMetalDisplayView.h"
#endif #endif
#ifdef BOOL #ifdef BOOL
@ -1219,6 +1219,8 @@ public:
CGDirectDisplayID displayID = CVDisplayLinkGetCurrentCGDisplay(displayLink); CGDirectDisplayID displayID = CVDisplayLinkGetCurrentCGDisplay(displayLink);
bool didFlushOccur = false; bool didFlushOccur = false;
std::vector<ClientDisplay3DView *> cdvFlushList;
if (currentRWLock != NULL) if (currentRWLock != NULL)
{ {
pthread_rwlock_rdlock(currentRWLock); pthread_rwlock_rdlock(currentRWLock);
@ -1234,13 +1236,21 @@ public:
if (cdv->GetViewNeedsFlush()) if (cdv->GetViewNeedsFlush())
{ {
cdv->FlushView(); cdvFlushList.push_back(cdv);
didFlushOccur = true;
} }
} }
} }
} }
const size_t listSize = cdvFlushList.size();
if (listSize > 0)
{
[self flushMultipleViews:cdvFlushList];
[self finalizeFlushMultipleViews:cdvFlushList];
didFlushOccur = true;
}
if (currentRWLock != NULL) if (currentRWLock != NULL)
{ {
pthread_rwlock_unlock(currentRWLock); 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 - (void) displayLinkStartUsingID:(CGDirectDisplayID)displayID
{ {
CVDisplayLinkRef displayLink = NULL; 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 // 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 // directly to the view, since the OpenGL context will already be what
// is assigned. // is assigned.
cdv->FlushView(); cdv->FlushAndFinalizeImmediate();
return; return;
} }
@ -2144,7 +2144,7 @@ static std::unordered_map<NSScreen *, DisplayWindowController *> _screenMap; //
if (isMetalLayer) if (isMetalLayer)
{ {
cdv->FlushView(); cdv->FlushAndFinalizeImmediate();
} }
else else
{ {
@ -2226,12 +2226,12 @@ static std::unordered_map<NSScreen *, DisplayWindowController *> _screenMap; //
- (void)updateLayer - (void)updateLayer
{ {
[self clientDisplayView]->FlushView(); [self clientDisplayView]->FlushAndFinalizeImmediate();
} }
- (void)drawRect:(NSRect)dirtyRect - (void)drawRect:(NSRect)dirtyRect
{ {
[self clientDisplayView]->FlushView(); [self clientDisplayView]->FlushAndFinalizeImmediate();
} }
- (void)setFrame:(NSRect)rect - (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) 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) 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 @end
@interface MacMetalDisplayPresenterObject : NSObject @interface MacMetalDisplayPresenterObject : NSObject
@ -261,13 +264,17 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties;
MacDisplayLayeredView *_cdv; MacDisplayLayeredView *_cdv;
MacMetalDisplayPresenterObject *presenterObject; MacMetalDisplayPresenterObject *presenterObject;
dispatch_semaphore_t _semDrawable; dispatch_semaphore_t _semDrawable;
id<CAMetalDrawable> layerDrawable;
} }
@property (readonly, nonatomic) MacMetalDisplayPresenterObject *presenterObject; @property (readonly, nonatomic) MacMetalDisplayPresenterObject *presenterObject;
@property (retain) id<CAMetalDrawable> layerDrawable;
- (id) initWithDisplayPresenterObject:(MacMetalDisplayPresenterObject *)thePresenterObject; - (id) initWithDisplayPresenterObject:(MacMetalDisplayPresenterObject *)thePresenterObject;
- (void) setupLayer; - (void) setupLayer;
- (void) renderToDrawable; - (void) renderToDrawableUsingCommandBuffer:(id<MTLCommandBuffer>)cb;
- (void) presentDrawableWithCommandBuffer:(id<MTLCommandBuffer>)cb;
- (void) renderAndPresentDrawableImmediate;
@end @end
@ -360,7 +367,9 @@ public:
virtual void SetAllowViewFlushes(bool allowFlushes); virtual void SetAllowViewFlushes(bool allowFlushes);
// Client view interface // Client view interface
virtual void FlushView(); virtual void FlushView(void *userData);
virtual void FinalizeFlush(void *userData);
virtual void FlushAndFinalizeImmediate();
}; };
#pragma mark - #pragma mark -

View File

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

View File

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

View File

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