From ff2e6cb2201388c2bf3faabdd969149a2af06dc1 Mon Sep 17 00:00:00 2001 From: rogerman Date: Fri, 10 Feb 2017 11:28:35 -0800 Subject: [PATCH] Cocoa Port: Increment/decrement the number of display views in need of CPU filtering, instead of looping through all outputs to determine it. Prevents a possible deadlock when changing CPU-based pixel scalers. - Also do some additional code cleanup. --- .../src/frontend/cocoa/ClientDisplayView.cpp | 7 ++- desmume/src/frontend/cocoa/cocoa_GPU.h | 5 +- desmume/src/frontend/cocoa/cocoa_GPU.mm | 48 +++++++------------ desmume/src/frontend/cocoa/cocoa_output.h | 3 +- desmume/src/frontend/cocoa/cocoa_output.mm | 6 +++ .../userinterface/DisplayWindowController.mm | 38 +++++++++++++++ .../cocoa/userinterface/MacOGLDisplayView.mm | 2 +- 7 files changed, 74 insertions(+), 35 deletions(-) diff --git a/desmume/src/frontend/cocoa/ClientDisplayView.cpp b/desmume/src/frontend/cocoa/ClientDisplayView.cpp index 9ae8f53f8..ccb23a593 100644 --- a/desmume/src/frontend/cocoa/ClientDisplayView.cpp +++ b/desmume/src/frontend/cocoa/ClientDisplayView.cpp @@ -354,17 +354,20 @@ void ClientDisplayView::SetPixelScaler(const VideoFilterTypeID filterID) const size_t newDstBufferWidth = (this->_vf[NDSDisplayID_Main]->GetSrcWidth() + this->_vf[NDSDisplayID_Touch]->GetSrcWidth()) * newFilterAttr.scaleMultiply / newFilterAttr.scaleDivide; const size_t newDstBufferHeight = (this->_vf[NDSDisplayID_Main]->GetSrcHeight() + this->_vf[NDSDisplayID_Touch]->GetSrcHeight()) * newFilterAttr.scaleMultiply / newFilterAttr.scaleDivide; + uint32_t *oldMasterBuffer = NULL; + if ( (oldDstBufferWidth != newDstBufferWidth) || (oldDstBufferHeight != newDstBufferHeight) ) { - uint32_t *oldMasterBuffer = this->_vfMasterDstBuffer; + oldMasterBuffer = this->_vfMasterDstBuffer; this->_ResizeCPUPixelScaler(newFilterID); - free_aligned(oldMasterBuffer); } this->_vf[NDSDisplayID_Main]->ChangeFilterByID(newFilterID); this->_vf[NDSDisplayID_Touch]->ChangeFilterByID(newFilterID); this->_pixelScaler = newFilterID; + + free_aligned(oldMasterBuffer); } VideoFilter* ClientDisplayView::GetPixelScalerObject(const NDSDisplayID displayID) diff --git a/desmume/src/frontend/cocoa/cocoa_GPU.h b/desmume/src/frontend/cocoa/cocoa_GPU.h index 32d111207..b4b9cadb2 100644 --- a/desmume/src/frontend/cocoa/cocoa_GPU.h +++ b/desmume/src/frontend/cocoa/cocoa_GPU.h @@ -38,14 +38,17 @@ class GPUEventHandlerOSX; pthread_rwlock_t *_rwlockFramebuffer[2]; pthread_mutex_t *_mutexOutputList; NSMutableArray *_cdsOutputList; + volatile int32_t numberViewsUsingCPUFiltering; } @property (assign, nonatomic) GPUClientFetchObject *GPUFetchObject; +@property (readonly, nonatomic) int32_t numberViewsUsingCPUFiltering; - (const NDSDisplayInfo &) fetchDisplayInfoForIndex:(const u8)bufferIndex; - (pthread_rwlock_t *) rwlockFramebufferAtIndex:(const u8)bufferIndex; - (void) setOutputList:(NSMutableArray *)theOutputList mutex:(pthread_mutex_t *)theMutex; -- (BOOL) isCPUFilteringNeeded; +- (void) incrementViewsUsingCPUFiltering; +- (void) decrementViewsUsingCPUFiltering; - (void) handleFetchFromBufferIndexAndPushVideo:(NSData *)indexData; - (void) pushVideoDataToAllDisplayViews; - (void) finishAllDisplayViewsAtIndex:(const u8)bufferIndex; diff --git a/desmume/src/frontend/cocoa/cocoa_GPU.mm b/desmume/src/frontend/cocoa/cocoa_GPU.mm index 1ec8c99b8..a1f8b4a5e 100644 --- a/desmume/src/frontend/cocoa/cocoa_GPU.mm +++ b/desmume/src/frontend/cocoa/cocoa_GPU.mm @@ -153,13 +153,21 @@ public: GPU->SetEventHandler(gpuEvent); GPU->SetWillAutoResolveToCustomBuffer(false); + fetchObject = NULL; + #ifdef ENABLE_APPLE_METAL if (IsOSXVersionSupported(10, 11, 0)) { fetchObject = new MacMetalFetchObject; + if (fetchObject->GetClientData() == nil) + { + delete fetchObject; + fetchObject = NULL; + } } - else #endif + + if (fetchObject == NULL) { fetchObject = new MacOGLClientFetchObject; } @@ -852,6 +860,7 @@ public: @implementation MacClientSharedObject @synthesize GPUFetchObject; +@synthesize numberViewsUsingCPUFiltering; - (id)init { @@ -870,6 +879,7 @@ public: GPUFetchObject = nil; _mutexOutputList = NULL; _cdsOutputList = nil; + numberViewsUsingCPUFiltering = 0; return self; } @@ -952,36 +962,14 @@ public: _mutexOutputList = theMutex; } -- (BOOL) isCPUFilteringNeeded +- (void) incrementViewsUsingCPUFiltering { - bool useCPUFilterPipeline = NO; - pthread_mutex_t *currentMutex = _mutexOutputList; - - if (currentMutex != NULL) - { - pthread_mutex_lock(currentMutex); - } - - for (CocoaDSOutput *cdsOutput in _cdsOutputList) - { - if ([cdsOutput isKindOfClass:[CocoaDSDisplay class]]) - { - ClientDisplay3DView *cdv = [(CocoaDSDisplay *)cdsOutput clientDisplayView]; - - if (!cdv->WillFilterOnGPU() && (cdv->GetPixelScaler() != VideoFilterTypeID_None)) - { - useCPUFilterPipeline = YES; - break; - } - } - } - - if (currentMutex != NULL) - { - pthread_mutex_unlock(currentMutex); - } - - return useCPUFilterPipeline; + OSAtomicIncrement32(&numberViewsUsingCPUFiltering); +} + +- (void) decrementViewsUsingCPUFiltering +{ + OSAtomicDecrement32(&numberViewsUsingCPUFiltering); } - (void) pushVideoDataToAllDisplayViews diff --git a/desmume/src/frontend/cocoa/cocoa_output.h b/desmume/src/frontend/cocoa/cocoa_output.h index 36f13ca98..db7f25327 100644 --- a/desmume/src/frontend/cocoa/cocoa_output.h +++ b/desmume/src/frontend/cocoa/cocoa_output.h @@ -140,7 +140,8 @@ struct NDSFrameInfo; OSSpinLock spinlockPixelScaler; } -@property (readonly) BOOL canFilterOnGPU; +@property (readonly, nonatomic) BOOL canFilterOnGPU; +@property (readonly, nonatomic) BOOL willFilterOnGPU; @property (assign) BOOL isHUDVisible; @property (assign) BOOL isHUDVideoFPSVisible; @property (assign) BOOL isHUDRender3DFPSVisible; diff --git a/desmume/src/frontend/cocoa/cocoa_output.mm b/desmume/src/frontend/cocoa/cocoa_output.mm index 08d55401c..4470e3e19 100644 --- a/desmume/src/frontend/cocoa/cocoa_output.mm +++ b/desmume/src/frontend/cocoa/cocoa_output.mm @@ -733,6 +733,7 @@ @implementation CocoaDSDisplayVideo @dynamic canFilterOnGPU; +@dynamic willFilterOnGPU; @dynamic isHUDVisible; @dynamic isHUDVideoFPSVisible; @dynamic isHUDRender3DFPSVisible; @@ -774,6 +775,11 @@ return (_cdv->CanFilterOnGPU()) ? YES : NO; } +- (BOOL) willFilterOnGPU +{ + return (_cdv->WillFilterOnGPU()) ? YES : NO; +} + - (void) setIsHUDVisible:(BOOL)theState { OSSpinLockLock(&spinlockIsHUDVisible); diff --git a/desmume/src/frontend/cocoa/userinterface/DisplayWindowController.mm b/desmume/src/frontend/cocoa/userinterface/DisplayWindowController.mm index 99f4c88cc..a6e74a834 100644 --- a/desmume/src/frontend/cocoa/userinterface/DisplayWindowController.mm +++ b/desmume/src/frontend/cocoa/userinterface/DisplayWindowController.mm @@ -1751,7 +1751,26 @@ static std::unordered_map _screenMap; // - (void) setVideoFiltersPreferGPU:(BOOL)theState { + const BOOL oldState = (![[self cdsVideoOutput] willFilterOnGPU] && ([[self cdsVideoOutput] pixelScaler] != VideoFilterTypeID_None)); [[self cdsVideoOutput] setVideoFiltersPreferGPU:theState]; + const BOOL newState = (![[self cdsVideoOutput] willFilterOnGPU] && ([[self cdsVideoOutput] pixelScaler] != VideoFilterTypeID_None)); + + if (oldState != newState) + { + DisplayWindowController *windowController = (DisplayWindowController *)[[self window] delegate]; + CocoaDSCore *cdsCore = (CocoaDSCore *)[[[windowController emuControl] cdsCoreController] content]; + CocoaDSGPU *cdsGPU = [cdsCore cdsGPU]; + MacClientSharedObject *macSharedData = [cdsGPU sharedData]; + + if (newState) + { + [macSharedData incrementViewsUsingCPUFiltering]; + } + else + { + [macSharedData decrementViewsUsingCPUFiltering]; + } + } } - (BOOL) videoFiltersPreferGPU @@ -1781,7 +1800,26 @@ static std::unordered_map _screenMap; // - (void) setPixelScaler:(NSInteger)filterID { + const BOOL oldState = (![[self cdsVideoOutput] willFilterOnGPU] && ([[self cdsVideoOutput] pixelScaler] != VideoFilterTypeID_None)); [[self cdsVideoOutput] setPixelScaler:filterID]; + const BOOL newState = (![[self cdsVideoOutput] willFilterOnGPU] && ([[self cdsVideoOutput] pixelScaler] != VideoFilterTypeID_None)); + + if (oldState != newState) + { + DisplayWindowController *windowController = (DisplayWindowController *)[[self window] delegate]; + CocoaDSCore *cdsCore = (CocoaDSCore *)[[[windowController emuControl] cdsCoreController] content]; + CocoaDSGPU *cdsGPU = [cdsCore cdsGPU]; + MacClientSharedObject *macSharedData = [cdsGPU sharedData]; + + if (newState) + { + [macSharedData incrementViewsUsingCPUFiltering]; + } + else + { + [macSharedData decrementViewsUsingCPUFiltering]; + } + } } - (NSInteger) pixelScaler diff --git a/desmume/src/frontend/cocoa/userinterface/MacOGLDisplayView.mm b/desmume/src/frontend/cocoa/userinterface/MacOGLDisplayView.mm index 8db823f2b..046f59e31 100644 --- a/desmume/src/frontend/cocoa/userinterface/MacOGLDisplayView.mm +++ b/desmume/src/frontend/cocoa/userinterface/MacOGLDisplayView.mm @@ -199,7 +199,7 @@ void MacOGLClientFetchObject::SetFetchBuffers(const NDSDisplayInfo ¤tDispl void MacOGLClientFetchObject::FetchFromBufferIndex(const u8 index) { MacClientSharedObject *sharedViewObject = (MacClientSharedObject *)this->_clientData; - this->_useCPUFilterPipeline = ([sharedViewObject isCPUFilteringNeeded]) ? true : false; + this->_useCPUFilterPipeline = ([sharedViewObject numberViewsUsingCPUFiltering] > 0); pthread_rwlock_rdlock([sharedViewObject rwlockFramebufferAtIndex:index]);