Cocoa Port: For Metal display views, replace all locks with semaphores, which are the correct synchronization primitive to use here.

- Also change the CocoaDSOutput list lock from a mutex to a rwlock, since testing has shown that there is more thread contention here than I previously thought.
This commit is contained in:
rogerman 2017-12-05 13:43:30 -08:00
parent f9109568b8
commit 26ac91edd0
9 changed files with 308 additions and 337 deletions

View File

@ -19,6 +19,7 @@
#import <CoreVideo/CoreVideo.h> #import <CoreVideo/CoreVideo.h>
#include <pthread.h> #include <pthread.h>
#include <libkern/OSAtomic.h> #include <libkern/OSAtomic.h>
#include <semaphore.h>
#include <map> #include <map>
#import "cocoa_util.h" #import "cocoa_util.h"
@ -48,8 +49,8 @@ typedef std::map<CGDirectDisplayID, int64_t> DisplayLinkFlushTimeLimitMap;
@interface MacClientSharedObject : NSObject @interface MacClientSharedObject : NSObject
{ {
GPUClientFetchObject *GPUFetchObject; GPUClientFetchObject *GPUFetchObject;
pthread_rwlock_t *_rwlockFramebuffer[2]; sem_t *_semFramebuffer[2];
pthread_mutex_t *_mutexOutputList; pthread_rwlock_t *_rwlockOutputList;
pthread_mutex_t _mutexDisplayLinkLists; pthread_mutex_t _mutexDisplayLinkLists;
NSMutableArray *_cdsOutputList; NSMutableArray *_cdsOutputList;
volatile int32_t numberViewsUsingDirectToCPUFiltering; volatile int32_t numberViewsUsingDirectToCPUFiltering;
@ -58,7 +59,7 @@ typedef std::map<CGDirectDisplayID, int64_t> DisplayLinkFlushTimeLimitMap;
DisplayLinkFlushTimeLimitMap _displayLinkFlushTimeList; DisplayLinkFlushTimeLimitMap _displayLinkFlushTimeList;
OSSpinLock spinlockFetchSignal; OSSpinLock spinlockFetchSignal;
BOOL _isFetchSignalled; uint32_t _threadMessageID;
uint8_t _fetchIndex; uint8_t _fetchIndex;
pthread_t _threadFetch; pthread_t _threadFetch;
pthread_cond_t _condSignalFetch; pthread_cond_t _condSignalFetch;
@ -68,8 +69,8 @@ typedef std::map<CGDirectDisplayID, int64_t> DisplayLinkFlushTimeLimitMap;
@property (assign, nonatomic) GPUClientFetchObject *GPUFetchObject; @property (assign, nonatomic) GPUClientFetchObject *GPUFetchObject;
@property (readonly, nonatomic) volatile int32_t numberViewsUsingDirectToCPUFiltering; @property (readonly, nonatomic) volatile int32_t numberViewsUsingDirectToCPUFiltering;
- (pthread_rwlock_t *) rwlockFramebufferAtIndex:(const u8)bufferIndex; - (sem_t *) semaphoreFramebufferAtIndex:(const u8)bufferIndex;
- (void) setOutputList:(NSMutableArray *)theOutputList mutex:(pthread_mutex_t *)theMutex; - (void) setOutputList:(NSMutableArray *)theOutputList rwlock:(pthread_rwlock_t *)theRWLock;
- (void) incrementViewsUsingDirectToCPUFiltering; - (void) incrementViewsUsingDirectToCPUFiltering;
- (void) decrementViewsUsingDirectToCPUFiltering; - (void) decrementViewsUsingDirectToCPUFiltering;
- (void) pushVideoDataToAllDisplayViews; - (void) pushVideoDataToAllDisplayViews;
@ -79,7 +80,7 @@ typedef std::map<CGDirectDisplayID, int64_t> DisplayLinkFlushTimeLimitMap;
- (void) displayLinkListUpdate; - (void) displayLinkListUpdate;
- (void) fetchSynchronousAtIndex:(uint8_t)index; - (void) fetchSynchronousAtIndex:(uint8_t)index;
- (void) signalFetchAtIndex:(uint8_t)index; - (void) signalFetchAtIndex:(uint8_t)index message:(int32_t)messageID;
- (void) runFetchLoop; - (void) runFetchLoop;
@end @end
@ -135,7 +136,7 @@ typedef std::map<CGDirectDisplayID, int64_t> DisplayLinkFlushTimeLimitMap;
@property (readonly, nonatomic) GPUClientFetchObject *fetchObject; @property (readonly, nonatomic) GPUClientFetchObject *fetchObject;
@property (readonly, nonatomic) MacClientSharedObject *sharedData; @property (readonly, nonatomic) MacClientSharedObject *sharedData;
- (void) setOutputList:(NSMutableArray *)theOutputList mutexPtr:(pthread_mutex_t *)theMutex; - (void) setOutputList:(NSMutableArray *)theOutputList rwlock:(pthread_rwlock_t *)theRWLock;
#endif #endif
- (BOOL) gpuStateByBit:(const UInt32)stateBit; - (BOOL) gpuStateByBit:(const UInt32)stateBit;

View File

@ -253,16 +253,16 @@ public:
gpuEvent->FramebufferLock(); gpuEvent->FramebufferLock();
#ifdef ENABLE_SHARED_FETCH_OBJECT #ifdef ENABLE_SHARED_FETCH_OBJECT
pthread_rwlock_wrlock([[self sharedData] rwlockFramebufferAtIndex:0]); sem_wait([[self sharedData] semaphoreFramebufferAtIndex:0]);
pthread_rwlock_wrlock([[self sharedData] rwlockFramebufferAtIndex:1]); sem_wait([[self sharedData] semaphoreFramebufferAtIndex:1]);
#endif #endif
GPU->SetCustomFramebufferSize(w, h); GPU->SetCustomFramebufferSize(w, h);
#ifdef ENABLE_SHARED_FETCH_OBJECT #ifdef ENABLE_SHARED_FETCH_OBJECT
fetchObject->SetFetchBuffers(GPU->GetDisplayInfo()); fetchObject->SetFetchBuffers(GPU->GetDisplayInfo());
pthread_rwlock_unlock([[self sharedData] rwlockFramebufferAtIndex:1]); sem_post([[self sharedData] semaphoreFramebufferAtIndex:1]);
pthread_rwlock_unlock([[self sharedData] rwlockFramebufferAtIndex:0]); sem_post([[self sharedData] semaphoreFramebufferAtIndex:0]);
#endif #endif
gpuEvent->FramebufferUnlock(); gpuEvent->FramebufferUnlock();
@ -314,16 +314,16 @@ public:
if (colorFormat != dispInfo.colorFormat) if (colorFormat != dispInfo.colorFormat)
{ {
#ifdef ENABLE_SHARED_FETCH_OBJECT #ifdef ENABLE_SHARED_FETCH_OBJECT
pthread_rwlock_wrlock([[self sharedData] rwlockFramebufferAtIndex:0]); sem_wait([[self sharedData] semaphoreFramebufferAtIndex:0]);
pthread_rwlock_wrlock([[self sharedData] rwlockFramebufferAtIndex:1]); sem_wait([[self sharedData] semaphoreFramebufferAtIndex:1]);
#endif #endif
GPU->SetColorFormat((NDSColorFormat)colorFormat); GPU->SetColorFormat((NDSColorFormat)colorFormat);
#ifdef ENABLE_SHARED_FETCH_OBJECT #ifdef ENABLE_SHARED_FETCH_OBJECT
fetchObject->SetFetchBuffers(GPU->GetDisplayInfo()); fetchObject->SetFetchBuffers(GPU->GetDisplayInfo());
pthread_rwlock_unlock([[self sharedData] rwlockFramebufferAtIndex:1]); sem_post([[self sharedData] semaphoreFramebufferAtIndex:1]);
pthread_rwlock_unlock([[self sharedData] rwlockFramebufferAtIndex:0]); sem_post([[self sharedData] semaphoreFramebufferAtIndex:0]);
#endif #endif
} }
@ -343,9 +343,9 @@ public:
} }
#ifdef ENABLE_SHARED_FETCH_OBJECT #ifdef ENABLE_SHARED_FETCH_OBJECT
- (void) setOutputList:(NSMutableArray *)theOutputList mutexPtr:(pthread_mutex_t *)theMutex - (void) setOutputList:(NSMutableArray *)theOutputList rwlock:(pthread_rwlock_t *)theRWLock
{ {
[(MacClientSharedObject *)fetchObject->GetClientData() setOutputList:theOutputList mutex:theMutex]; [(MacClientSharedObject *)fetchObject->GetClientData() setOutputList:theOutputList rwlock:theRWLock];
} }
#endif #endif
@ -866,18 +866,18 @@ public:
#ifdef ENABLE_SHARED_FETCH_OBJECT #ifdef ENABLE_SHARED_FETCH_OBJECT
const u8 bufferIndex = GPU->GetDisplayInfo().bufferIndex; const u8 bufferIndex = GPU->GetDisplayInfo().bufferIndex;
pthread_rwlock_wrlock([[self sharedData] rwlockFramebufferAtIndex:bufferIndex]); sem_wait([[self sharedData] semaphoreFramebufferAtIndex:bufferIndex]);
#endif #endif
GPU->ClearWithColor(colorBGRA5551); GPU->ClearWithColor(colorBGRA5551);
#ifdef ENABLE_SHARED_FETCH_OBJECT #ifdef ENABLE_SHARED_FETCH_OBJECT
pthread_rwlock_unlock([[self sharedData] rwlockFramebufferAtIndex:bufferIndex]); sem_post([[self sharedData] semaphoreFramebufferAtIndex:bufferIndex]);
#endif #endif
gpuEvent->FramebufferUnlock(); gpuEvent->FramebufferUnlock();
#ifdef ENABLE_SHARED_FETCH_OBJECT #ifdef ENABLE_SHARED_FETCH_OBJECT
[[self sharedData] signalFetchAtIndex:bufferIndex]; [[self sharedData] signalFetchAtIndex:bufferIndex message:MESSAGE_FETCH_AND_PUSH_VIDEO];
#endif #endif
} }
@ -918,15 +918,32 @@ public:
return self; return self;
} }
_rwlockFramebuffer[0] = (pthread_rwlock_t *)malloc(sizeof(pthread_rwlock_t)); _semFramebuffer[0] = sem_open("desmume_semFramebuffer0", O_CREAT | O_EXCL, 0777, 1);
_rwlockFramebuffer[1] = (pthread_rwlock_t *)malloc(sizeof(pthread_rwlock_t)); if (_semFramebuffer[0] == SEM_FAILED)
{
sem_unlink("desmume_semFramebuffer0");
_semFramebuffer[0] = sem_open("desmume_semFramebuffer0", O_CREAT | O_EXCL, 0777, 1);
if (_semFramebuffer[0] == SEM_FAILED)
{
puts("desmume_semFramebuffer0 failed!");
}
}
_semFramebuffer[1] = sem_open("desmume_semFramebuffer1", O_CREAT | O_EXCL, 0777, 1);
if (_semFramebuffer[1] == SEM_FAILED)
{
sem_unlink("desmume_semFramebuffer1");
_semFramebuffer[1] = sem_open("desmume_semFramebuffer1", O_CREAT | O_EXCL, 0777, 1);
if (_semFramebuffer[1] == SEM_FAILED)
{
puts("desmume_semFramebuffer1 failed!");
}
}
pthread_rwlock_init(_rwlockFramebuffer[0], NULL);
pthread_rwlock_init(_rwlockFramebuffer[1], NULL);
pthread_mutex_init(&_mutexDisplayLinkLists, NULL); pthread_mutex_init(&_mutexDisplayLinkLists, NULL);
GPUFetchObject = nil; GPUFetchObject = nil;
_mutexOutputList = NULL; _rwlockOutputList = NULL;
_cdsOutputList = nil; _cdsOutputList = nil;
numberViewsUsingDirectToCPUFiltering = 0; numberViewsUsingDirectToCPUFiltering = 0;
@ -935,7 +952,7 @@ public:
[self displayLinkListUpdate]; [self displayLinkListUpdate];
spinlockFetchSignal = OS_SPINLOCK_INIT; spinlockFetchSignal = OS_SPINLOCK_INIT;
_isFetchSignalled = NO; _threadMessageID = MESSAGE_NONE;
_fetchIndex = 0; _fetchIndex = 0;
pthread_cond_init(&_condSignalFetch, NULL); pthread_cond_init(&_condSignalFetch, NULL);
pthread_create(&_threadFetch, NULL, &RunFetchThread, self); pthread_create(&_threadFetch, NULL, &RunFetchThread, self);
@ -980,50 +997,52 @@ public:
pthread_mutex_unlock(&_mutexDisplayLinkLists); pthread_mutex_unlock(&_mutexDisplayLinkLists);
pthread_mutex_destroy(&_mutexDisplayLinkLists); pthread_mutex_destroy(&_mutexDisplayLinkLists);
pthread_mutex_t *currentMutex = _mutexOutputList; pthread_rwlock_t *currentRWLock = _rwlockOutputList;
if (currentMutex != NULL) if (currentRWLock != NULL)
{ {
pthread_mutex_lock(currentMutex); pthread_rwlock_wrlock(currentRWLock);
} }
[_cdsOutputList release]; [_cdsOutputList release];
if (currentMutex != NULL) if (currentRWLock != NULL)
{ {
pthread_mutex_unlock(currentMutex); pthread_rwlock_unlock(currentRWLock);
} }
pthread_rwlock_destroy(_rwlockFramebuffer[0]); sem_close(_semFramebuffer[0]);
pthread_rwlock_destroy(_rwlockFramebuffer[1]); sem_close(_semFramebuffer[1]);
sem_unlink("desmume_semFramebuffer0");
sem_unlink("desmume_semFramebuffer1");
[super dealloc]; [super dealloc];
} }
- (pthread_rwlock_t *) rwlockFramebufferAtIndex:(const u8)bufferIndex - (sem_t *) semaphoreFramebufferAtIndex:(const u8)bufferIndex
{ {
return _rwlockFramebuffer[bufferIndex]; return _semFramebuffer[bufferIndex];
} }
- (void) setOutputList:(NSMutableArray *)theOutputList mutex:(pthread_mutex_t *)theMutex - (void) setOutputList:(NSMutableArray *)theOutputList rwlock:(pthread_rwlock_t *)theRWLock
{ {
pthread_mutex_t *currentMutex = _mutexOutputList; pthread_rwlock_t *currentRWLock = _rwlockOutputList;
if (currentMutex != NULL) if (currentRWLock != NULL)
{ {
pthread_mutex_lock(currentMutex); pthread_rwlock_wrlock(currentRWLock);
} }
[_cdsOutputList release]; [_cdsOutputList release];
_cdsOutputList = theOutputList; _cdsOutputList = theOutputList;
[_cdsOutputList retain]; [_cdsOutputList retain];
if (currentMutex != NULL) if (currentRWLock != NULL)
{ {
pthread_mutex_unlock(currentMutex); pthread_rwlock_unlock(currentRWLock);
} }
_mutexOutputList = theMutex; _rwlockOutputList = theRWLock;
} }
- (void) incrementViewsUsingDirectToCPUFiltering - (void) incrementViewsUsingDirectToCPUFiltering
@ -1038,11 +1057,11 @@ public:
- (void) pushVideoDataToAllDisplayViews - (void) pushVideoDataToAllDisplayViews
{ {
pthread_mutex_t *currentMutex = _mutexOutputList; pthread_rwlock_t *currentRWLock = _rwlockOutputList;
if (currentMutex != NULL) if (currentRWLock != NULL)
{ {
pthread_mutex_lock(currentMutex); pthread_rwlock_rdlock(currentRWLock);
} }
for (CocoaDSOutput *cdsOutput in _cdsOutputList) for (CocoaDSOutput *cdsOutput in _cdsOutputList)
@ -1053,21 +1072,21 @@ public:
} }
} }
if (currentMutex != NULL) if (currentRWLock != NULL)
{ {
pthread_mutex_unlock(currentMutex); pthread_rwlock_unlock(currentRWLock);
} }
} }
- (void) flushAllDisplaysOnDisplayLink:(CVDisplayLinkRef)displayLink timeStamp:(const CVTimeStamp *)timeStamp - (void) flushAllDisplaysOnDisplayLink:(CVDisplayLinkRef)displayLink timeStamp:(const CVTimeStamp *)timeStamp
{ {
pthread_mutex_t *currentMutex = _mutexOutputList; pthread_rwlock_t *currentRWLock = _rwlockOutputList;
CGDirectDisplayID displayID = CVDisplayLinkGetCurrentCGDisplay(displayLink); CGDirectDisplayID displayID = CVDisplayLinkGetCurrentCGDisplay(displayLink);
bool didFlushOccur = false; bool didFlushOccur = false;
if (currentMutex != NULL) if (currentRWLock != NULL)
{ {
pthread_mutex_lock(currentMutex); pthread_rwlock_rdlock(currentRWLock);
} }
for (CocoaDSOutput *cdsOutput in _cdsOutputList) for (CocoaDSOutput *cdsOutput in _cdsOutputList)
@ -1087,9 +1106,9 @@ public:
} }
} }
if (currentMutex != NULL) if (currentRWLock != NULL)
{ {
pthread_mutex_unlock(currentMutex); pthread_rwlock_unlock(currentRWLock);
} }
if (didFlushOccur) if (didFlushOccur)
@ -1195,12 +1214,12 @@ public:
GPUFetchObject->FetchFromBufferIndex(index); GPUFetchObject->FetchFromBufferIndex(index);
} }
- (void) signalFetchAtIndex:(uint8_t)index - (void) signalFetchAtIndex:(uint8_t)index message:(int32_t)messageID
{ {
pthread_mutex_lock(&_mutexFetchExecute); pthread_mutex_lock(&_mutexFetchExecute);
_fetchIndex = index; _fetchIndex = index;
_isFetchSignalled = YES; _threadMessageID = messageID;
pthread_cond_signal(&_condSignalFetch); pthread_cond_signal(&_condSignalFetch);
pthread_mutex_unlock(&_mutexFetchExecute); pthread_mutex_unlock(&_mutexFetchExecute);
@ -1212,14 +1231,15 @@ public:
do do
{ {
while (!_isFetchSignalled) while (_threadMessageID == MESSAGE_NONE)
{ {
pthread_cond_wait(&_condSignalFetch, &_mutexFetchExecute); pthread_cond_wait(&_condSignalFetch, &_mutexFetchExecute);
} }
_isFetchSignalled = NO;
GPUFetchObject->FetchFromBufferIndex(_fetchIndex); GPUFetchObject->FetchFromBufferIndex(_fetchIndex);
[self pushVideoDataToAllDisplayViews]; [self pushVideoDataToAllDisplayViews];
_threadMessageID = MESSAGE_NONE;
} while(true); } while(true);
} }
@ -1275,7 +1295,7 @@ void GPUEventHandlerOSX::DidFrameBegin(bool isFrameSkipRequested, const u8 targe
if (!isFrameSkipRequested) if (!isFrameSkipRequested)
{ {
MacClientSharedObject *sharedViewObject = (MacClientSharedObject *)this->_fetchObject->GetClientData(); MacClientSharedObject *sharedViewObject = (MacClientSharedObject *)this->_fetchObject->GetClientData();
pthread_rwlock_wrlock([sharedViewObject rwlockFramebufferAtIndex:targetBufferIndex]); sem_wait([sharedViewObject semaphoreFramebufferAtIndex:targetBufferIndex]);
} }
#endif #endif
} }
@ -1287,7 +1307,7 @@ void GPUEventHandlerOSX::DidFrameEnd(bool isFrameSkipped, const NDSDisplayInfo &
if (!isFrameSkipped) if (!isFrameSkipped)
{ {
this->_fetchObject->SetFetchDisplayInfo(latestDisplayInfo); this->_fetchObject->SetFetchDisplayInfo(latestDisplayInfo);
pthread_rwlock_unlock([sharedViewObject rwlockFramebufferAtIndex:latestDisplayInfo.bufferIndex]); sem_post([sharedViewObject semaphoreFramebufferAtIndex:latestDisplayInfo.bufferIndex]);
} }
#endif #endif
@ -1296,7 +1316,7 @@ void GPUEventHandlerOSX::DidFrameEnd(bool isFrameSkipped, const NDSDisplayInfo &
#ifdef ENABLE_SHARED_FETCH_OBJECT #ifdef ENABLE_SHARED_FETCH_OBJECT
if (!isFrameSkipped) if (!isFrameSkipped)
{ {
[sharedViewObject signalFetchAtIndex:latestDisplayInfo.bufferIndex]; [sharedViewObject signalFetchAtIndex:latestDisplayInfo.bufferIndex message:MESSAGE_FETCH_AND_PUSH_VIDEO];
} }
#endif #endif
} }

View File

@ -38,7 +38,7 @@ typedef void *gdbstub_handle_t;
typedef struct typedef struct
{ {
CocoaDSCore *cdsCore; CocoaDSCore *cdsCore;
pthread_mutex_t mutexOutputList; pthread_rwlock_t rwlockOutputList;
pthread_mutex_t mutexThreadExecute; pthread_mutex_t mutexThreadExecute;
pthread_cond_t condThreadExecute; pthread_cond_t condThreadExecute;
pthread_rwlock_t rwlockCoreExecute; pthread_rwlock_t rwlockCoreExecute;

View File

@ -173,7 +173,7 @@ volatile bool execute = true;
threadParam.cdsCore = self; threadParam.cdsCore = self;
pthread_mutex_init(&threadParam.mutexOutputList, NULL); pthread_rwlock_init(&threadParam.rwlockOutputList, NULL);
pthread_mutex_init(&threadParam.mutexThreadExecute, NULL); pthread_mutex_init(&threadParam.mutexThreadExecute, NULL);
pthread_cond_init(&threadParam.condThreadExecute, NULL); pthread_cond_init(&threadParam.condThreadExecute, NULL);
pthread_rwlock_init(&threadParam.rwlockCoreExecute, NULL); pthread_rwlock_init(&threadParam.rwlockCoreExecute, NULL);
@ -198,7 +198,7 @@ volatile bool execute = true;
sp.sched_priority = sched_get_priority_max(thePolicy); sp.sched_priority = sched_get_priority_max(thePolicy);
pthread_setschedparam(coreThread, thePolicy, &sp); pthread_setschedparam(coreThread, thePolicy, &sp);
[cdsGPU setOutputList:cdsOutputList mutexPtr:&threadParam.mutexOutputList]; [cdsGPU setOutputList:cdsOutputList rwlock:&threadParam.rwlockOutputList];
OSXDriver *newDriver = new OSXDriver; OSXDriver *newDriver = new OSXDriver;
newDriver->SetCoreThreadMutexLock(&threadParam.mutexThreadExecute); newDriver->SetCoreThreadMutexLock(&threadParam.mutexThreadExecute);
@ -231,7 +231,7 @@ volatile bool execute = true;
pthread_mutex_destroy(&threadParam.mutexThreadExecute); pthread_mutex_destroy(&threadParam.mutexThreadExecute);
pthread_cond_destroy(&threadParam.condThreadExecute); pthread_cond_destroy(&threadParam.condThreadExecute);
pthread_mutex_destroy(&threadParam.mutexOutputList); pthread_rwlock_destroy(&threadParam.rwlockOutputList);
pthread_rwlock_destroy(&threadParam.rwlockCoreExecute); pthread_rwlock_destroy(&threadParam.rwlockCoreExecute);
[self setIsGdbStubStarted:NO]; [self setIsGdbStubStarted:NO];
@ -644,7 +644,7 @@ volatile bool execute = true;
execControl->SetExecutionBehavior((ExecutionBehavior)coreState); execControl->SetExecutionBehavior((ExecutionBehavior)coreState);
pthread_mutex_lock(&threadParam.mutexOutputList); pthread_rwlock_rdlock(&threadParam.rwlockOutputList);
switch ((ExecutionBehavior)coreState) switch ((ExecutionBehavior)coreState)
{ {
@ -718,7 +718,7 @@ volatile bool execute = true;
break; break;
} }
pthread_mutex_unlock(&threadParam.mutexOutputList); pthread_rwlock_unlock(&threadParam.rwlockOutputList);
pthread_cond_signal(&threadParam.condThreadExecute); pthread_cond_signal(&threadParam.condThreadExecute);
pthread_mutex_unlock(&threadParam.mutexThreadExecute); pthread_mutex_unlock(&threadParam.mutexThreadExecute);
@ -878,6 +878,8 @@ volatile bool execute = true;
// count every other instance the timer fires. // count every other instance the timer fires.
_isTimerAtSecond = !_isTimerAtSecond; _isTimerAtSecond = !_isTimerAtSecond;
pthread_rwlock_rdlock(&threadParam.rwlockOutputList);
for (CocoaDSOutput *cdsOutput in cdsOutputList) for (CocoaDSOutput *cdsOutput in cdsOutputList)
{ {
if ([cdsOutput isKindOfClass:[CocoaDSDisplay class]]) if ([cdsOutput isKindOfClass:[CocoaDSDisplay class]])
@ -888,6 +890,8 @@ volatile bool execute = true;
} }
} }
} }
pthread_rwlock_unlock(&threadParam.rwlockOutputList);
} }
- (NSUInteger) frameNumber - (NSUInteger) frameNumber
@ -897,7 +901,7 @@ volatile bool execute = true;
- (void) addOutput:(CocoaDSOutput *)theOutput - (void) addOutput:(CocoaDSOutput *)theOutput
{ {
pthread_mutex_lock(&threadParam.mutexOutputList); pthread_rwlock_wrlock(&threadParam.rwlockOutputList);
if ([theOutput isKindOfClass:[CocoaDSDisplay class]]) if ([theOutput isKindOfClass:[CocoaDSDisplay class]])
{ {
@ -909,21 +913,21 @@ volatile bool execute = true;
} }
[[self cdsOutputList] addObject:theOutput]; [[self cdsOutputList] addObject:theOutput];
pthread_mutex_unlock(&threadParam.mutexOutputList); pthread_rwlock_unlock(&threadParam.rwlockOutputList);
} }
- (void) removeOutput:(CocoaDSOutput *)theOutput - (void) removeOutput:(CocoaDSOutput *)theOutput
{ {
pthread_mutex_lock(&threadParam.mutexOutputList); pthread_rwlock_wrlock(&threadParam.rwlockOutputList);
[[self cdsOutputList] removeObject:theOutput]; [[self cdsOutputList] removeObject:theOutput];
pthread_mutex_unlock(&threadParam.mutexOutputList); pthread_rwlock_unlock(&threadParam.rwlockOutputList);
} }
- (void) removeAllOutputs - (void) removeAllOutputs
{ {
pthread_mutex_lock(&threadParam.mutexOutputList); pthread_rwlock_wrlock(&threadParam.rwlockOutputList);
[[self cdsOutputList] removeAllObjects]; [[self cdsOutputList] removeAllObjects];
pthread_mutex_unlock(&threadParam.mutexOutputList); pthread_rwlock_unlock(&threadParam.rwlockOutputList);
} }
- (NSString *) cpuEmulationEngineString - (NSString *) cpuEmulationEngineString
@ -1200,7 +1204,7 @@ static void* RunCoreThread(void *arg)
executionSpeedAverageFramesCollected = 0.0; executionSpeedAverageFramesCollected = 0.0;
} }
pthread_mutex_lock(&param->mutexOutputList); pthread_rwlock_rdlock(&param->rwlockOutputList);
switch (behavior) switch (behavior)
{ {
@ -1227,7 +1231,7 @@ static void* RunCoreThread(void *arg)
break; break;
} }
pthread_mutex_unlock(&param->mutexOutputList); pthread_rwlock_unlock(&param->rwlockOutputList);
switch (behavior) switch (behavior)
{ {

View File

@ -334,6 +334,8 @@ enum
*/ */
enum enum
{ {
MESSAGE_NONE = 0,
MESSAGE_CHECK_FOR_RESPONSE = 100, // Message to check if a port is responding. Usually sent to make sure that a thread is alive. MESSAGE_CHECK_FOR_RESPONSE = 100, // Message to check if a port is responding. Usually sent to make sure that a thread is alive.
MESSAGE_CHECK_RESPONSE_ECHO, // Response message when another port sends MESSAGE_CHECK_FOR_RESPONSE. Sent to confirm that a thread is indeed alive. MESSAGE_CHECK_RESPONSE_ECHO, // Response message when another port sends MESSAGE_CHECK_FOR_RESPONSE. Sent to confirm that a thread is indeed alive.
MESSAGE_EXIT_THREAD, // Sent whenever there is a need to stop a thread. MESSAGE_EXIT_THREAD, // Sent whenever there is a need to stop a thread.

View File

@ -21,6 +21,7 @@
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
#import <Metal/Metal.h> #import <Metal/Metal.h>
#include <libkern/OSAtomic.h> #include <libkern/OSAtomic.h>
#include <semaphore.h>
#import "DisplayViewCALayer.h" #import "DisplayViewCALayer.h"
#import "../cocoa_GPU.h" #import "../cocoa_GPU.h"
@ -39,8 +40,6 @@ struct MetalProcessedFrameInfo
{ {
uint8_t bufferIndex; uint8_t bufferIndex;
id<MTLTexture> tex[2]; id<MTLTexture> tex[2];
bool isMainDisplayProcessed;
bool isTouchDisplayProcessed;
}; };
typedef struct MetalProcessedFrameInfo MetalProcessedFrameInfo; typedef struct MetalProcessedFrameInfo MetalProcessedFrameInfo;
@ -65,6 +64,7 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties;
id<MTLComputePipelineState> _fetch888Pipeline; id<MTLComputePipelineState> _fetch888Pipeline;
id<MTLComputePipelineState> _fetch555ConvertOnlyPipeline; id<MTLComputePipelineState> _fetch555ConvertOnlyPipeline;
id<MTLComputePipelineState> _fetch666ConvertOnlyPipeline; id<MTLComputePipelineState> _fetch666ConvertOnlyPipeline;
id<MTLComputePipelineState> _fetch888PassthroughOnlyPipeline;
id<MTLComputePipelineState> deposterizePipeline; id<MTLComputePipelineState> deposterizePipeline;
id<MTLRenderPipelineState> hudPipeline; id<MTLRenderPipelineState> hudPipeline;
id<MTLRenderPipelineState> hudRGBAPipeline; id<MTLRenderPipelineState> hudRGBAPipeline;
@ -185,8 +185,7 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties;
BOOL needsScreenVerticesUpdate; BOOL needsScreenVerticesUpdate;
BOOL needsHUDVerticesUpdate; BOOL needsHUDVerticesUpdate;
pthread_mutex_t _mutexTexProcessUpdate; sem_t *_semTexProcessUpdate;
pthread_mutex_t _mutexBufferUpdate;
bool _needEncodeViewport; bool _needEncodeViewport;
MTLViewport _newViewport; MTLViewport _newViewport;
bool _willDrawHUD; bool _willDrawHUD;
@ -200,8 +199,7 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties;
@property (readonly, nonatomic) ClientDisplay3DPresenter *cdp; @property (readonly, nonatomic) ClientDisplay3DPresenter *cdp;
@property (assign, nonatomic) MetalDisplayViewSharedData *sharedData; @property (assign, nonatomic) MetalDisplayViewSharedData *sharedData;
@property (readonly, nonatomic) MTLRenderPassColorAttachmentDescriptor *colorAttachment0Desc; @property (readonly, nonatomic) MTLRenderPassColorAttachmentDescriptor *colorAttachment0Desc;
@property (readonly, nonatomic) pthread_mutex_t *mutexTexProcessUpdate; @property (readonly, nonatomic) sem_t *semTexProcessUpdate;
@property (readonly, nonatomic) pthread_mutex_t *mutexBufferUpdate;
@property (retain) id<MTLComputePipelineState> pixelScalePipeline; @property (retain) id<MTLComputePipelineState> pixelScalePipeline;
@property (retain) id<MTLRenderPipelineState> outputRGBAPipeline; @property (retain) id<MTLRenderPipelineState> outputRGBAPipeline;
@property (retain) id<MTLRenderPipelineState> outputDrawablePipeline; @property (retain) id<MTLRenderPipelineState> outputDrawablePipeline;
@ -225,6 +223,7 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties;
- (void) resizeCPUPixelScalerUsingFilterID:(const VideoFilterTypeID)filterID; - (void) resizeCPUPixelScalerUsingFilterID:(const VideoFilterTypeID)filterID;
- (void) copyHUDFontUsingFace:(const FT_Face &)fontFace size:(const size_t)glyphSize tileSize:(const size_t)glyphTileSize info:(GlyphInfo *)glyphInfo; - (void) copyHUDFontUsingFace:(const FT_Face &)fontFace size:(const size_t)glyphSize tileSize:(const size_t)glyphTileSize info:(GlyphInfo *)glyphInfo;
- (void) processDisplays; - (void) processDisplays;
- (void) updateTexCoordBuffer;
- (void) updateRenderBuffers; - (void) updateRenderBuffers;
- (void) renderForCommandBuffer:(id<MTLCommandBuffer>)cb - (void) renderForCommandBuffer:(id<MTLCommandBuffer>)cb
outputPipelineState:(id<MTLRenderPipelineState>)outputPipelineState outputPipelineState:(id<MTLRenderPipelineState>)outputPipelineState
@ -282,7 +281,7 @@ private:
protected: protected:
MacMetalDisplayPresenterObject *_presenterObject; MacMetalDisplayPresenterObject *_presenterObject;
pthread_mutex_t _mutexProcessPtr; pthread_mutex_t _mutexProcessPtr;
pthread_rwlock_t _cpuFilterRWLock[2][2]; sem_t *_semCPUFilter[2][2];
virtual void _UpdateNormalSize(); virtual void _UpdateNormalSize();
virtual void _UpdateOrder(); virtual void _UpdateOrder();
@ -299,7 +298,7 @@ public:
MacMetalDisplayPresenterObject* GetPresenterObject() const; MacMetalDisplayPresenterObject* GetPresenterObject() const;
pthread_mutex_t* GetMutexProcessPtr(); pthread_mutex_t* GetMutexProcessPtr();
pthread_rwlock_t* GetCPUFilterRWLock(const NDSDisplayID displayID, const uint8_t bufferIndex); sem_t* GetCPUFilterSemaphore(const NDSDisplayID displayID, const uint8_t bufferIndex);
virtual void Init(); virtual void Init();
virtual void SetSharedData(MacClientSharedObject *sharedObject); virtual void SetSharedData(MacClientSharedObject *sharedObject);
@ -312,7 +311,6 @@ public:
// Client view interface // Client view interface
virtual void ProcessDisplays(); virtual void ProcessDisplays();
virtual void UpdateLayout();
virtual void CopyFrameToBuffer(uint32_t *dstBuffer); virtual void CopyFrameToBuffer(uint32_t *dstBuffer);
}; };

View File

@ -17,6 +17,13 @@
#include "MacMetalDisplayView.h" #include "MacMetalDisplayView.h"
#include <stdio.h>
#include <semaphore.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
#include "../cocoa_globals.h"
#include "../../../common.h" #include "../../../common.h"
@implementation MetalDisplayViewSharedData @implementation MetalDisplayViewSharedData
@ -71,6 +78,7 @@
_fetch888Pipeline = [[device newComputePipelineStateWithFunction:[defaultLibrary newFunctionWithName:@"nds_fetch888"] error:nil] retain]; _fetch888Pipeline = [[device newComputePipelineStateWithFunction:[defaultLibrary newFunctionWithName:@"nds_fetch888"] error:nil] retain];
_fetch555ConvertOnlyPipeline = [[device newComputePipelineStateWithFunction:[defaultLibrary newFunctionWithName:@"nds_fetch555ConvertOnly"] error:nil] retain]; _fetch555ConvertOnlyPipeline = [[device newComputePipelineStateWithFunction:[defaultLibrary newFunctionWithName:@"nds_fetch555ConvertOnly"] error:nil] retain];
_fetch666ConvertOnlyPipeline = [[device newComputePipelineStateWithFunction:[defaultLibrary newFunctionWithName:@"nds_fetch666ConvertOnly"] error:nil] retain]; _fetch666ConvertOnlyPipeline = [[device newComputePipelineStateWithFunction:[defaultLibrary newFunctionWithName:@"nds_fetch666ConvertOnly"] error:nil] retain];
_fetch888PassthroughOnlyPipeline = [[device newComputePipelineStateWithFunction:[defaultLibrary newFunctionWithName:@"nds_fetch888PassthroughOnly"] error:nil] retain];
deposterizePipeline = [[device newComputePipelineStateWithFunction:[defaultLibrary newFunctionWithName:@"src_filter_deposterize"] error:nil] retain]; deposterizePipeline = [[device newComputePipelineStateWithFunction:[defaultLibrary newFunctionWithName:@"src_filter_deposterize"] error:nil] retain];
if ( IsOSXVersion(10, 13, 0) || IsOSXVersion(10, 13, 1) || IsOSXVersion(10, 13, 2) || IsOSXVersion(10, 13, 3) || IsOSXVersion(10, 13, 4) ) if ( IsOSXVersion(10, 13, 0) || IsOSXVersion(10, 13, 1) || IsOSXVersion(10, 13, 2) || IsOSXVersion(10, 13, 3) || IsOSXVersion(10, 13, 4) )
@ -249,6 +257,7 @@
[_fetch888Pipeline release]; [_fetch888Pipeline release];
[_fetch555ConvertOnlyPipeline release]; [_fetch555ConvertOnlyPipeline release];
[_fetch666ConvertOnlyPipeline release]; [_fetch666ConvertOnlyPipeline release];
[_fetch888PassthroughOnlyPipeline release];
[deposterizePipeline release]; [deposterizePipeline release];
[hudPipeline release]; [hudPipeline release];
[hudRGBAPipeline release]; [hudRGBAPipeline release];
@ -585,72 +594,69 @@
isUsingFramebufferDirectlyTouch = false; isUsingFramebufferDirectlyTouch = false;
} }
} }
else if (currentDisplayInfo.colorFormat != NDSColorFormat_BGR888_Rev) else
{ {
bool isPipelineStateSet = false;
if (currentDisplayInfo.colorFormat == NDSColorFormat_BGR555_Rev) if (currentDisplayInfo.colorFormat == NDSColorFormat_BGR555_Rev)
{ {
// 16-bit textures aren't handled natively in Metal for macOS, so we need to explicitly convert to 32-bit here. // 16-bit textures aren't handled natively in Metal for macOS, so we need to explicitly convert to 32-bit here.
[cce setComputePipelineState:_fetch555ConvertOnlyPipeline]; [cce setComputePipelineState:_fetch555ConvertOnlyPipeline];
isPipelineStateSet = true;
} }
else if ( (currentDisplayInfo.colorFormat == NDSColorFormat_BGR666_Rev) && else if ( (currentDisplayInfo.colorFormat == NDSColorFormat_BGR666_Rev) &&
(currentDisplayInfo.needConvertColorFormat[NDSDisplayID_Main] || currentDisplayInfo.needConvertColorFormat[NDSDisplayID_Touch]) ) (currentDisplayInfo.needConvertColorFormat[NDSDisplayID_Main] || currentDisplayInfo.needConvertColorFormat[NDSDisplayID_Touch]) )
{ {
[cce setComputePipelineState:_fetch666ConvertOnlyPipeline]; [cce setComputePipelineState:_fetch666ConvertOnlyPipeline];
isPipelineStateSet = true; }
else
{
[cce setComputePipelineState:_fetch888PassthroughOnlyPipeline];
} }
if (isPipelineStateSet) if (isMainEnabled)
{ {
if (isMainEnabled) if (!currentDisplayInfo.didPerformCustomRender[NDSDisplayID_Main])
{ {
if (!currentDisplayInfo.didPerformCustomRender[NDSDisplayID_Main]) [cce setTexture:_texDisplayFetchNative[NDSDisplayID_Main][index] atIndex:0];
{ [cce setTexture:_texDisplayPostprocessNative[NDSDisplayID_Main][index] atIndex:1];
[cce setTexture:_texDisplayFetchNative[NDSDisplayID_Main][index] atIndex:0]; [cce dispatchThreadgroups:_fetchThreadGroupsPerGridNative
[cce setTexture:_texDisplayPostprocessNative[NDSDisplayID_Main][index] atIndex:1]; threadsPerThreadgroup:_fetchThreadsPerGroup];
[cce dispatchThreadgroups:_fetchThreadGroupsPerGridNative
threadsPerThreadgroup:_fetchThreadsPerGroup];
texFetchTargetMain = _texDisplayPostprocessNative[NDSDisplayID_Main][index];
}
else
{
[cce setTexture:_texDisplayFetchCustom[NDSDisplayID_Main][index] atIndex:0];
[cce setTexture:_texDisplayPostprocessCustom[NDSDisplayID_Main][index] atIndex:1];
[cce dispatchThreadgroups:_fetchThreadGroupsPerGridCustom
threadsPerThreadgroup:_fetchThreadsPerGroup];
texFetchTargetMain = _texDisplayPostprocessCustom[NDSDisplayID_Main][index];
}
isUsingFramebufferDirectlyMain = false; texFetchTargetMain = _texDisplayPostprocessNative[NDSDisplayID_Main][index];
}
else
{
[cce setTexture:_texDisplayFetchCustom[NDSDisplayID_Main][index] atIndex:0];
[cce setTexture:_texDisplayPostprocessCustom[NDSDisplayID_Main][index] atIndex:1];
[cce dispatchThreadgroups:_fetchThreadGroupsPerGridCustom
threadsPerThreadgroup:_fetchThreadsPerGroup];
texFetchTargetMain = _texDisplayPostprocessCustom[NDSDisplayID_Main][index];
} }
if (isTouchEnabled) isUsingFramebufferDirectlyMain = false;
}
if (isTouchEnabled)
{
if (!currentDisplayInfo.didPerformCustomRender[NDSDisplayID_Touch])
{ {
if (!currentDisplayInfo.didPerformCustomRender[NDSDisplayID_Touch]) [cce setTexture:_texDisplayFetchNative[NDSDisplayID_Touch][index] atIndex:0];
{ [cce setTexture:_texDisplayPostprocessNative[NDSDisplayID_Touch][index] atIndex:1];
[cce setTexture:_texDisplayFetchNative[NDSDisplayID_Touch][index] atIndex:0]; [cce dispatchThreadgroups:_fetchThreadGroupsPerGridNative
[cce setTexture:_texDisplayPostprocessNative[NDSDisplayID_Touch][index] atIndex:1]; threadsPerThreadgroup:_fetchThreadsPerGroup];
[cce dispatchThreadgroups:_fetchThreadGroupsPerGridNative
threadsPerThreadgroup:_fetchThreadsPerGroup];
texFetchTargetTouch = _texDisplayPostprocessNative[NDSDisplayID_Touch][index];
}
else
{
[cce setTexture:_texDisplayFetchCustom[NDSDisplayID_Touch][index] atIndex:0];
[cce setTexture:_texDisplayPostprocessCustom[NDSDisplayID_Touch][index] atIndex:1];
[cce dispatchThreadgroups:_fetchThreadGroupsPerGridCustom
threadsPerThreadgroup:_fetchThreadsPerGroup];
texFetchTargetTouch = _texDisplayPostprocessCustom[NDSDisplayID_Touch][index];
}
isUsingFramebufferDirectlyTouch = false; texFetchTargetTouch = _texDisplayPostprocessNative[NDSDisplayID_Touch][index];
} }
else
{
[cce setTexture:_texDisplayFetchCustom[NDSDisplayID_Touch][index] atIndex:0];
[cce setTexture:_texDisplayPostprocessCustom[NDSDisplayID_Touch][index] atIndex:1];
[cce dispatchThreadgroups:_fetchThreadGroupsPerGridCustom
threadsPerThreadgroup:_fetchThreadsPerGroup];
texFetchTargetTouch = _texDisplayPostprocessCustom[NDSDisplayID_Touch][index];
}
isUsingFramebufferDirectlyTouch = false;
} }
} }
@ -666,7 +672,7 @@
- (void) fetchFromBufferIndex:(const u8)index - (void) fetchFromBufferIndex:(const u8)index
{ {
pthread_rwlock_rdlock([self rwlockFramebufferAtIndex:index]); sem_wait([self semaphoreFramebufferAtIndex:index]);
id<MTLCommandBuffer> cb = [commandQueue commandBufferWithUnretainedReferences]; id<MTLCommandBuffer> cb = [commandQueue commandBufferWithUnretainedReferences];
_fetchEncoder = [cb blitCommandEncoder]; _fetchEncoder = [cb blitCommandEncoder];
@ -680,18 +686,17 @@
if (index == 0) if (index == 0)
{ {
[cb addCompletedHandler:^(id<MTLCommandBuffer> block) { [cb addCompletedHandler:^(id<MTLCommandBuffer> block) {
pthread_rwlock_unlock([self rwlockFramebufferAtIndex:0]); sem_post([self semaphoreFramebufferAtIndex:0]);
}]; }];
} }
else else
{ {
[cb addCompletedHandler:^(id<MTLCommandBuffer> block) { [cb addCompletedHandler:^(id<MTLCommandBuffer> block) {
pthread_rwlock_unlock([self rwlockFramebufferAtIndex:1]); sem_post([self semaphoreFramebufferAtIndex:1]);
}]; }];
} }
[cb commit]; [cb commit];
[cb waitUntilScheduled];
} }
- (void) fetchNativeDisplayByID:(const NDSDisplayID)displayID bufferIndex:(const u8)bufferIndex - (void) fetchNativeDisplayByID:(const NDSDisplayID)displayID bufferIndex:(const u8)bufferIndex
@ -745,8 +750,7 @@
@synthesize cdp; @synthesize cdp;
@synthesize sharedData; @synthesize sharedData;
@synthesize colorAttachment0Desc; @synthesize colorAttachment0Desc;
@dynamic mutexTexProcessUpdate; @dynamic semTexProcessUpdate;
@dynamic mutexBufferUpdate;
@synthesize pixelScalePipeline; @synthesize pixelScalePipeline;
@synthesize outputRGBAPipeline; @synthesize outputRGBAPipeline;
@synthesize outputDrawablePipeline; @synthesize outputDrawablePipeline;
@ -825,11 +829,17 @@
_processedFrameInfo.bufferIndex = 0; _processedFrameInfo.bufferIndex = 0;
_processedFrameInfo.tex[NDSDisplayID_Main] = nil; _processedFrameInfo.tex[NDSDisplayID_Main] = nil;
_processedFrameInfo.tex[NDSDisplayID_Touch] = nil; _processedFrameInfo.tex[NDSDisplayID_Touch] = nil;
_processedFrameInfo.isMainDisplayProcessed = false;
_processedFrameInfo.isTouchDisplayProcessed = false;
pthread_mutex_init(&_mutexTexProcessUpdate, NULL); _semTexProcessUpdate = sem_open("desmume_semTexProcessUpdate", O_CREAT | O_EXCL, 0777, 1);
pthread_mutex_init(&_mutexBufferUpdate, NULL); if (_semTexProcessUpdate == SEM_FAILED)
{
sem_unlink("desmume_semTexProcessUpdate");
_semTexProcessUpdate = sem_open("desmume_semTexProcessUpdate", O_CREAT | O_EXCL, 0777, 1);
if (_semTexProcessUpdate == SEM_FAILED)
{
puts("desmume_semTexProcessUpdate failed!");
}
}
return self; return self;
} }
@ -868,20 +878,15 @@
[self setSharedData:nil]; [self setSharedData:nil];
pthread_mutex_destroy(&_mutexTexProcessUpdate); sem_close(_semTexProcessUpdate);
pthread_mutex_destroy(&_mutexBufferUpdate); sem_unlink("desmume_semTexProcessUpdate");
[super dealloc]; [super dealloc];
} }
- (pthread_mutex_t *) mutexTexProcessUpdate - (sem_t *) semTexProcessUpdate
{ {
return &_mutexTexProcessUpdate; return _semTexProcessUpdate;
}
- (pthread_mutex_t *) mutexBufferUpdate
{
return &_mutexBufferUpdate;
} }
- (VideoFilterTypeID) pixelScaler - (VideoFilterTypeID) pixelScaler
@ -1314,27 +1319,15 @@
id<MTLTexture> texMain = (selectedDisplaySource[NDSDisplayID_Main] == NDSDisplayID_Main) ? [sharedData texFetchMain] : [sharedData texFetchTouch]; id<MTLTexture> texMain = (selectedDisplaySource[NDSDisplayID_Main] == NDSDisplayID_Main) ? [sharedData texFetchMain] : [sharedData texFetchTouch];
id<MTLTexture> texTouch = (selectedDisplaySource[NDSDisplayID_Touch] == NDSDisplayID_Touch) ? [sharedData texFetchTouch] : [sharedData texFetchMain]; id<MTLTexture> texTouch = (selectedDisplaySource[NDSDisplayID_Touch] == NDSDisplayID_Touch) ? [sharedData texFetchTouch] : [sharedData texFetchMain];
bool isDisplayProcessedMain = ![sharedData isUsingFramebufferDirectlyAtIndex:bufferIndex displayID:selectedDisplaySource[NDSDisplayID_Main]];
bool isDisplayProcessedTouch = ![sharedData isUsingFramebufferDirectlyAtIndex:bufferIndex displayID:selectedDisplaySource[NDSDisplayID_Touch]];
if ( (fetchDisplayInfo.pixelBytes != 0) && (useDeposterize || (cdp->GetPixelScaler() != VideoFilterTypeID_None)) ) if ( (fetchDisplayInfo.pixelBytes != 0) && (useDeposterize || (cdp->GetPixelScaler() != VideoFilterTypeID_None)) )
{ {
const bool willFilterOnGPU = cdp->WillFilterOnGPU(); const bool willFilterOnGPU = cdp->WillFilterOnGPU();
const bool shouldProcessDisplay[2] = { (!fetchDisplayInfo.didPerformCustomRender[selectedDisplaySource[NDSDisplayID_Main]] || !fetchDisplayInfo.isCustomSizeRequested) && cdp->IsSelectedDisplayEnabled(NDSDisplayID_Main) && (mode == ClientDisplayMode_Main || mode == ClientDisplayMode_Dual), const bool shouldProcessDisplay[2] = { (!fetchDisplayInfo.didPerformCustomRender[selectedDisplaySource[NDSDisplayID_Main]] || !fetchDisplayInfo.isCustomSizeRequested) && cdp->IsSelectedDisplayEnabled(NDSDisplayID_Main) && (mode == ClientDisplayMode_Main || mode == ClientDisplayMode_Dual),
(!fetchDisplayInfo.didPerformCustomRender[selectedDisplaySource[NDSDisplayID_Touch]] || !fetchDisplayInfo.isCustomSizeRequested) && cdp->IsSelectedDisplayEnabled(NDSDisplayID_Touch) && (mode == ClientDisplayMode_Touch || mode == ClientDisplayMode_Dual) && (selectedDisplaySource[NDSDisplayID_Main] != selectedDisplaySource[NDSDisplayID_Touch]) }; (!fetchDisplayInfo.didPerformCustomRender[selectedDisplaySource[NDSDisplayID_Touch]] || !fetchDisplayInfo.isCustomSizeRequested) && cdp->IsSelectedDisplayEnabled(NDSDisplayID_Touch) && (mode == ClientDisplayMode_Touch || mode == ClientDisplayMode_Dual) && (selectedDisplaySource[NDSDisplayID_Main] != selectedDisplaySource[NDSDisplayID_Touch]) };
bool texFetchMainNeedsLock = (useDeposterize || ((cdp->GetPixelScaler() != VideoFilterTypeID_None) && willFilterOnGPU)) && shouldProcessDisplay[NDSDisplayID_Main];
bool texFetchTouchNeedsLock = (useDeposterize || ((cdp->GetPixelScaler() != VideoFilterTypeID_None) && willFilterOnGPU)) && shouldProcessDisplay[NDSDisplayID_Touch];
bool needsFetchBuffersLock = texFetchMainNeedsLock || texFetchTouchNeedsLock;
id<MTLCommandBuffer> cb = [self newCommandBuffer]; id<MTLCommandBuffer> cb = [self newCommandBuffer];
id<MTLComputeCommandEncoder> cce = [cb computeCommandEncoder]; id<MTLComputeCommandEncoder> cce = [cb computeCommandEncoder];
if (needsFetchBuffersLock)
{
pthread_rwlock_rdlock([sharedData rwlockFramebufferAtIndex:bufferIndex]);
}
// Run the video source filters and the pixel scalers // Run the video source filters and the pixel scalers
if (useDeposterize) if (useDeposterize)
{ {
@ -1353,12 +1346,10 @@
threadsPerThreadgroup:[sharedData deposterizeThreadsPerGroup]]; threadsPerThreadgroup:[sharedData deposterizeThreadsPerGroup]];
texMain = _texDisplaySrcDeposterize[NDSDisplayID_Main][1]; texMain = _texDisplaySrcDeposterize[NDSDisplayID_Main][1];
isDisplayProcessedMain = true;
if (selectedDisplaySource[NDSDisplayID_Main] == selectedDisplaySource[NDSDisplayID_Touch]) if (selectedDisplaySource[NDSDisplayID_Main] == selectedDisplaySource[NDSDisplayID_Touch])
{ {
texTouch = texMain; texTouch = texMain;
isDisplayProcessedTouch = true;
} }
} }
@ -1375,35 +1366,6 @@
threadsPerThreadgroup:[sharedData deposterizeThreadsPerGroup]]; threadsPerThreadgroup:[sharedData deposterizeThreadsPerGroup]];
texTouch = _texDisplaySrcDeposterize[NDSDisplayID_Touch][1]; texTouch = _texDisplaySrcDeposterize[NDSDisplayID_Touch][1];
isDisplayProcessedTouch = true;
}
if (needsFetchBuffersLock)
{
needsFetchBuffersLock = !isDisplayProcessedMain || !isDisplayProcessedTouch;
[cce endEncoding];
if (!needsFetchBuffersLock)
{
if (bufferIndex == 0)
{
[cb addCompletedHandler:^(id<MTLCommandBuffer> block) {
pthread_rwlock_unlock([sharedData rwlockFramebufferAtIndex:0]);
}];
}
else
{
[cb addCompletedHandler:^(id<MTLCommandBuffer> block) {
pthread_rwlock_unlock([sharedData rwlockFramebufferAtIndex:1]);
}];
}
}
[cb commit];
cb = [self newCommandBuffer];
cce = [cb computeCommandEncoder];
} }
} }
@ -1424,14 +1386,12 @@
texMain = [self texDisplayPixelScaleMain]; texMain = [self texDisplayPixelScaleMain];
width[NDSDisplayID_Main] = [[self texDisplayPixelScaleMain] width]; width[NDSDisplayID_Main] = [[self texDisplayPixelScaleMain] width];
height[NDSDisplayID_Main] = [[self texDisplayPixelScaleMain] height]; height[NDSDisplayID_Main] = [[self texDisplayPixelScaleMain] height];
isDisplayProcessedMain = true;
if (selectedDisplaySource[NDSDisplayID_Main] == selectedDisplaySource[NDSDisplayID_Touch]) if (selectedDisplaySource[NDSDisplayID_Main] == selectedDisplaySource[NDSDisplayID_Touch])
{ {
texTouch = texMain; texTouch = texMain;
width[NDSDisplayID_Touch] = width[NDSDisplayID_Main]; width[NDSDisplayID_Touch] = width[NDSDisplayID_Main];
height[NDSDisplayID_Touch] = height[NDSDisplayID_Main]; height[NDSDisplayID_Touch] = height[NDSDisplayID_Main];
isDisplayProcessedTouch = true;
} }
} }
@ -1445,32 +1405,6 @@
texTouch = [self texDisplayPixelScaleTouch]; texTouch = [self texDisplayPixelScaleTouch];
width[NDSDisplayID_Touch] = [[self texDisplayPixelScaleTouch] width]; width[NDSDisplayID_Touch] = [[self texDisplayPixelScaleTouch] width];
height[NDSDisplayID_Touch] = [[self texDisplayPixelScaleTouch] height]; height[NDSDisplayID_Touch] = [[self texDisplayPixelScaleTouch] height];
isDisplayProcessedTouch = true;
}
if (needsFetchBuffersLock)
{
needsFetchBuffersLock = false;
[cce endEncoding];
if (bufferIndex == 0)
{
[cb addCompletedHandler:^(id<MTLCommandBuffer> block) {
pthread_rwlock_unlock([sharedData rwlockFramebufferAtIndex:0]);
}];
}
else
{
[cb addCompletedHandler:^(id<MTLCommandBuffer> block) {
pthread_rwlock_unlock([sharedData rwlockFramebufferAtIndex:1]);
}];
}
[cb commit];
cb = [self newCommandBuffer];
cce = [cb computeCommandEncoder];
} }
} }
@ -1529,7 +1463,7 @@
if (shouldProcessDisplay[NDSDisplayID_Main] && ([self texDisplayPixelScaleMain] != nil)) if (shouldProcessDisplay[NDSDisplayID_Main] && ([self texDisplayPixelScaleMain] != nil))
{ {
pthread_rwlock_rdlock(((MacMetalDisplayPresenter *)cdp)->GetCPUFilterRWLock(NDSDisplayID_Main, bufferIndex)); sem_wait(((MacMetalDisplayPresenter *)cdp)->GetCPUFilterSemaphore(NDSDisplayID_Main, bufferIndex));
needsCPUFilterUnlockMain = true; needsCPUFilterUnlockMain = true;
vfMain->RunFilter(); vfMain->RunFilter();
@ -1537,7 +1471,7 @@
{ {
[[self bufCPUFilterDstMain] didModifyRange:NSMakeRange(0, vfMain->GetDstWidth() * vfMain->GetDstHeight() * sizeof(uint32_t))]; [[self bufCPUFilterDstMain] didModifyRange:NSMakeRange(0, vfMain->GetDstWidth() * vfMain->GetDstHeight() * sizeof(uint32_t))];
needsCPUFilterUnlockMain = false; needsCPUFilterUnlockMain = false;
pthread_rwlock_unlock(((MacMetalDisplayPresenter *)cdp)->GetCPUFilterRWLock(NDSDisplayID_Main, bufferIndex)); sem_post(((MacMetalDisplayPresenter *)cdp)->GetCPUFilterSemaphore(NDSDisplayID_Main, bufferIndex));
} }
[bce copyFromBuffer:[self bufCPUFilterDstMain] [bce copyFromBuffer:[self bufCPUFilterDstMain]
@ -1553,20 +1487,18 @@
texMain = [self texDisplayPixelScaleMain]; texMain = [self texDisplayPixelScaleMain];
width[NDSDisplayID_Main] = [[self texDisplayPixelScaleMain] width]; width[NDSDisplayID_Main] = [[self texDisplayPixelScaleMain] width];
height[NDSDisplayID_Main] = [[self texDisplayPixelScaleMain] height]; height[NDSDisplayID_Main] = [[self texDisplayPixelScaleMain] height];
isDisplayProcessedMain = true;
if (selectedDisplaySource[NDSDisplayID_Main] == selectedDisplaySource[NDSDisplayID_Touch]) if (selectedDisplaySource[NDSDisplayID_Main] == selectedDisplaySource[NDSDisplayID_Touch])
{ {
texTouch = texMain; texTouch = texMain;
width[NDSDisplayID_Touch] = width[NDSDisplayID_Main]; width[NDSDisplayID_Touch] = width[NDSDisplayID_Main];
height[NDSDisplayID_Touch] = height[NDSDisplayID_Main]; height[NDSDisplayID_Touch] = height[NDSDisplayID_Main];
isDisplayProcessedTouch = true;
} }
} }
if (shouldProcessDisplay[NDSDisplayID_Touch] && ([self texDisplayPixelScaleTouch] != nil)) if (shouldProcessDisplay[NDSDisplayID_Touch] && ([self texDisplayPixelScaleTouch] != nil))
{ {
pthread_rwlock_rdlock(((MacMetalDisplayPresenter *)cdp)->GetCPUFilterRWLock(NDSDisplayID_Touch, bufferIndex)); sem_wait(((MacMetalDisplayPresenter *)cdp)->GetCPUFilterSemaphore(NDSDisplayID_Touch, bufferIndex));
needsCPUFilterUnlockTouch = true; needsCPUFilterUnlockTouch = true;
vfTouch->RunFilter(); vfTouch->RunFilter();
@ -1574,7 +1506,7 @@
{ {
[[self bufCPUFilterDstTouch] didModifyRange:NSMakeRange(0, vfTouch->GetDstWidth() * vfTouch->GetDstHeight() * sizeof(uint32_t))]; [[self bufCPUFilterDstTouch] didModifyRange:NSMakeRange(0, vfTouch->GetDstWidth() * vfTouch->GetDstHeight() * sizeof(uint32_t))];
needsCPUFilterUnlockTouch = false; needsCPUFilterUnlockTouch = false;
pthread_rwlock_unlock(((MacMetalDisplayPresenter *)cdp)->GetCPUFilterRWLock(NDSDisplayID_Touch, bufferIndex)); sem_post(((MacMetalDisplayPresenter *)cdp)->GetCPUFilterSemaphore(NDSDisplayID_Touch, bufferIndex));
} }
[bce copyFromBuffer:[self bufCPUFilterDstTouch] [bce copyFromBuffer:[self bufCPUFilterDstTouch]
@ -1590,7 +1522,6 @@
texTouch = [self texDisplayPixelScaleTouch]; texTouch = [self texDisplayPixelScaleTouch];
width[NDSDisplayID_Touch] = [[self texDisplayPixelScaleTouch] width]; width[NDSDisplayID_Touch] = [[self texDisplayPixelScaleTouch] width];
height[NDSDisplayID_Touch] = [[self texDisplayPixelScaleTouch] height]; height[NDSDisplayID_Touch] = [[self texDisplayPixelScaleTouch] height];
isDisplayProcessedTouch = true;
} }
[bce endEncoding]; [bce endEncoding];
@ -1605,15 +1536,15 @@
if (bufferIndex == 0) if (bufferIndex == 0)
{ {
[cb addCompletedHandler:^(id<MTLCommandBuffer> block) { [cb addCompletedHandler:^(id<MTLCommandBuffer> block) {
pthread_rwlock_unlock(((MacMetalDisplayPresenter *)cdp)->GetCPUFilterRWLock(NDSDisplayID_Main, 0)); sem_post(((MacMetalDisplayPresenter *)cdp)->GetCPUFilterSemaphore(NDSDisplayID_Main, 0));
pthread_rwlock_unlock(((MacMetalDisplayPresenter *)cdp)->GetCPUFilterRWLock(NDSDisplayID_Touch, 0)); sem_post(((MacMetalDisplayPresenter *)cdp)->GetCPUFilterSemaphore(NDSDisplayID_Touch, 0));
}]; }];
} }
else else
{ {
[cb addCompletedHandler:^(id<MTLCommandBuffer> block) { [cb addCompletedHandler:^(id<MTLCommandBuffer> block) {
pthread_rwlock_unlock(((MacMetalDisplayPresenter *)cdp)->GetCPUFilterRWLock(NDSDisplayID_Main, 1)); sem_post(((MacMetalDisplayPresenter *)cdp)->GetCPUFilterSemaphore(NDSDisplayID_Main, 1));
pthread_rwlock_unlock(((MacMetalDisplayPresenter *)cdp)->GetCPUFilterRWLock(NDSDisplayID_Touch, 1)); sem_post(((MacMetalDisplayPresenter *)cdp)->GetCPUFilterSemaphore(NDSDisplayID_Touch, 1));
}]; }];
} }
} }
@ -1622,13 +1553,13 @@
if (bufferIndex == 0) if (bufferIndex == 0)
{ {
[cb addCompletedHandler:^(id<MTLCommandBuffer> block) { [cb addCompletedHandler:^(id<MTLCommandBuffer> block) {
pthread_rwlock_unlock(((MacMetalDisplayPresenter *)cdp)->GetCPUFilterRWLock(NDSDisplayID_Main, 0)); sem_post(((MacMetalDisplayPresenter *)cdp)->GetCPUFilterSemaphore(NDSDisplayID_Main, 0));
}]; }];
} }
else else
{ {
[cb addCompletedHandler:^(id<MTLCommandBuffer> block) { [cb addCompletedHandler:^(id<MTLCommandBuffer> block) {
pthread_rwlock_unlock(((MacMetalDisplayPresenter *)cdp)->GetCPUFilterRWLock(NDSDisplayID_Main, 1)); sem_post(((MacMetalDisplayPresenter *)cdp)->GetCPUFilterSemaphore(NDSDisplayID_Main, 1));
}]; }];
} }
} }
@ -1638,13 +1569,13 @@
if (bufferIndex == 0) if (bufferIndex == 0)
{ {
[cb addCompletedHandler:^(id<MTLCommandBuffer> block) { [cb addCompletedHandler:^(id<MTLCommandBuffer> block) {
pthread_rwlock_unlock(((MacMetalDisplayPresenter *)cdp)->GetCPUFilterRWLock(NDSDisplayID_Touch, 0)); sem_post(((MacMetalDisplayPresenter *)cdp)->GetCPUFilterSemaphore(NDSDisplayID_Touch, 0));
}]; }];
} }
else else
{ {
[cb addCompletedHandler:^(id<MTLCommandBuffer> block) { [cb addCompletedHandler:^(id<MTLCommandBuffer> block) {
pthread_rwlock_unlock(((MacMetalDisplayPresenter *)cdp)->GetCPUFilterRWLock(NDSDisplayID_Touch, 1)); sem_post(((MacMetalDisplayPresenter *)cdp)->GetCPUFilterSemaphore(NDSDisplayID_Touch, 1));
}]; }];
} }
} }
@ -1653,27 +1584,30 @@
} }
// Update the texture coordinates // Update the texture coordinates
pthread_mutex_lock(&_mutexTexProcessUpdate); sem_wait(_semTexProcessUpdate);
cdp->SetScreenTextureCoordinates((float)width[NDSDisplayID_Main], (float)height[NDSDisplayID_Main],
(float)width[NDSDisplayID_Touch], (float)height[NDSDisplayID_Touch],
(float *)[_displayTexCoordBuffer contents]);
[_displayTexCoordBuffer didModifyRange:NSMakeRange(0, sizeof(float) * (4 * 8))];
// Update the frame info // Update the frame info
id<MTLTexture> oldDisplayProcessedMain = _processedFrameInfo.tex[NDSDisplayID_Main]; id<MTLTexture> oldDisplayProcessedMain = _processedFrameInfo.tex[NDSDisplayID_Main];
id<MTLTexture> oldDisplayProcessedTouch = _processedFrameInfo.tex[NDSDisplayID_Touch]; id<MTLTexture> oldDisplayProcessedTouch = _processedFrameInfo.tex[NDSDisplayID_Touch];
_processedFrameInfo.bufferIndex = bufferIndex; _processedFrameInfo.bufferIndex = bufferIndex;
_processedFrameInfo.isMainDisplayProcessed = isDisplayProcessedMain;
_processedFrameInfo.isTouchDisplayProcessed = isDisplayProcessedTouch;
_processedFrameInfo.tex[NDSDisplayID_Main] = [texMain retain]; _processedFrameInfo.tex[NDSDisplayID_Main] = [texMain retain];
_processedFrameInfo.tex[NDSDisplayID_Touch] = [texTouch retain]; _processedFrameInfo.tex[NDSDisplayID_Touch] = [texTouch retain];
[self updateTexCoordBuffer];
[oldDisplayProcessedMain release]; [oldDisplayProcessedMain release];
[oldDisplayProcessedTouch release]; [oldDisplayProcessedTouch release];
pthread_mutex_unlock(&_mutexTexProcessUpdate); sem_post(_semTexProcessUpdate);
}
- (void) updateTexCoordBuffer
{
cdp->SetScreenTextureCoordinates((float)[_processedFrameInfo.tex[NDSDisplayID_Main] width], (float)[_processedFrameInfo.tex[NDSDisplayID_Main] height],
(float)[_processedFrameInfo.tex[NDSDisplayID_Touch] width], (float)[_processedFrameInfo.tex[NDSDisplayID_Touch] height],
(float *)[_displayTexCoordBuffer contents]);
[_displayTexCoordBuffer didModifyRange:NSMakeRange(0, sizeof(float) * (4 * 8))];
} }
- (void) updateRenderBuffers - (void) updateRenderBuffers
@ -1690,8 +1624,6 @@
newViewport.znear = 0.0; newViewport.znear = 0.0;
newViewport.zfar = 1.0; newViewport.zfar = 1.0;
pthread_mutex_lock(&_mutexBufferUpdate);
if ([self needsViewportUpdate]) if ([self needsViewportUpdate])
{ {
needEncodeViewport = true; needEncodeViewport = true;
@ -1790,8 +1722,6 @@
_willDrawHUDInput = cdp->GetHUDShowInput(); _willDrawHUDInput = cdp->GetHUDShowInput();
_hudStringLength = cdp->GetHUDString().length(); _hudStringLength = cdp->GetHUDString().length();
_hudTouchLineLength = hudTouchLineLength; _hudTouchLineLength = hudTouchLineLength;
pthread_mutex_unlock(&_mutexBufferUpdate);
} }
- (void) renderForCommandBuffer:(id<MTLCommandBuffer>)cb - (void) renderForCommandBuffer:(id<MTLCommandBuffer>)cb
@ -1943,6 +1873,17 @@
const size_t clientWidth = cdp->GetPresenterProperties().clientWidth; const size_t clientWidth = cdp->GetPresenterProperties().clientWidth;
const size_t clientHeight = cdp->GetPresenterProperties().clientHeight; const size_t clientHeight = cdp->GetPresenterProperties().clientHeight;
// Create a unique semaphore name based on mach_absolute_time().
char semaphoreName[64];
memset(semaphoreName, '\0', sizeof(semaphoreName));
snprintf(semaphoreName, sizeof(semaphoreName), "desmume_semRenderToBuffer_0x%016llX", (unsigned long long)mach_absolute_time());
sem_t *semRenderToBuffer = sem_open(semaphoreName, O_CREAT, 0777, 1);
if (semRenderToBuffer == SEM_FAILED)
{
puts("desmume_semRenderToBuffer failed!");
}
@autoreleasepool @autoreleasepool
{ {
MTLTextureDescriptor *texRenderDesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm MTLTextureDescriptor *texRenderDesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm
@ -1956,19 +1897,13 @@
id<MTLTexture> texRender = [[sharedData device] newTextureWithDescriptor:texRenderDesc]; id<MTLTexture> texRender = [[sharedData device] newTextureWithDescriptor:texRenderDesc];
id<MTLBuffer> dstMTLBuffer = [[sharedData device] newBufferWithLength:clientWidth * clientHeight * sizeof(uint32_t) options:MTLResourceStorageModeManaged]; id<MTLBuffer> dstMTLBuffer = [[sharedData device] newBufferWithLength:clientWidth * clientHeight * sizeof(uint32_t) options:MTLResourceStorageModeManaged];
pthread_mutex_lock(&_mutexTexProcessUpdate); sem_wait(_semTexProcessUpdate);
const bool needsFetchBuffersLock = !_processedFrameInfo.isMainDisplayProcessed || !_processedFrameInfo.isTouchDisplayProcessed;
if (needsFetchBuffersLock)
{
pthread_rwlock_rdlock([sharedData rwlockFramebufferAtIndex:_processedFrameInfo.bufferIndex]);
}
// Now that everything is set up, go ahead and draw everything. // Now that everything is set up, go ahead and draw everything.
[colorAttachment0Desc setTexture:texRender]; [colorAttachment0Desc setTexture:texRender];
id<MTLCommandBuffer> cb = [self newCommandBuffer]; id<MTLCommandBuffer> cb = [self newCommandBuffer];
pthread_mutex_lock(&_mutexBufferUpdate); [self updateRenderBuffers];
[self renderForCommandBuffer:cb [self renderForCommandBuffer:cb
outputPipelineState:[self outputRGBAPipeline] outputPipelineState:[self outputRGBAPipeline]
@ -1976,35 +1911,13 @@
texDisplayMain:_processedFrameInfo.tex[NDSDisplayID_Main] texDisplayMain:_processedFrameInfo.tex[NDSDisplayID_Main]
texDisplayTouch:_processedFrameInfo.tex[NDSDisplayID_Touch]]; texDisplayTouch:_processedFrameInfo.tex[NDSDisplayID_Touch]];
if (needsFetchBuffersLock) [cb addCompletedHandler:^(id<MTLCommandBuffer> block) {
{ sem_post(_semTexProcessUpdate);
if (_processedFrameInfo.bufferIndex == 0) }];
{
[cb addCompletedHandler:^(id<MTLCommandBuffer> block) {
pthread_mutex_unlock(&_mutexBufferUpdate);
pthread_rwlock_unlock([sharedData rwlockFramebufferAtIndex:0]);
pthread_mutex_unlock(&_mutexTexProcessUpdate);
}];
}
else
{
[cb addCompletedHandler:^(id<MTLCommandBuffer> block) {
pthread_mutex_unlock(&_mutexBufferUpdate);
pthread_rwlock_unlock([sharedData rwlockFramebufferAtIndex:1]);
pthread_mutex_unlock(&_mutexTexProcessUpdate);
}];
}
}
else
{
[cb addCompletedHandler:^(id<MTLCommandBuffer> block) {
pthread_mutex_unlock(&_mutexBufferUpdate);
pthread_mutex_unlock(&_mutexTexProcessUpdate);
}];
}
[cb commit]; [cb commit];
sem_wait(semRenderToBuffer);
cb = [self newCommandBuffer]; cb = [self newCommandBuffer];
id<MTLBlitCommandEncoder> bce = [cb blitCommandEncoder]; id<MTLBlitCommandEncoder> bce = [cb blitCommandEncoder];
@ -2021,14 +1934,23 @@
[bce synchronizeResource:dstMTLBuffer]; [bce synchronizeResource:dstMTLBuffer];
[bce endEncoding]; [bce endEncoding];
[cb addCompletedHandler:^(id<MTLCommandBuffer> block) {
sem_post(semRenderToBuffer);
}];
[cb commit]; [cb commit];
[cb waitUntilCompleted];
// Wait on this thread until the GPU completes its task, then continue execution on this thread.
sem_wait(semRenderToBuffer);
sem_post(semRenderToBuffer);
memcpy(dstBuffer, [dstMTLBuffer contents], clientWidth * clientHeight * sizeof(uint32_t)); memcpy(dstBuffer, [dstMTLBuffer contents], clientWidth * clientHeight * sizeof(uint32_t));
[texRender release]; [texRender release];
[dstMTLBuffer release]; [dstMTLBuffer release];
} }
sem_close(semRenderToBuffer);
sem_unlink(semaphoreName);
} }
@end @end
@ -2073,20 +1995,16 @@
{ {
@autoreleasepool @autoreleasepool
{ {
pthread_mutex_lock([presenterObject mutexTexProcessUpdate]); sem_wait([presenterObject semTexProcessUpdate]);
const MetalProcessedFrameInfo &processedInfo = [presenterObject processedFrameInfo]; const MetalProcessedFrameInfo &processedInfo = [presenterObject processedFrameInfo];
const bool needsFetchBuffersLock = !processedInfo.isMainDisplayProcessed || !processedInfo.isTouchDisplayProcessed;
if (needsFetchBuffersLock)
{
pthread_rwlock_rdlock([[presenterObject sharedData] rwlockFramebufferAtIndex:processedInfo.bufferIndex]);
}
// Now that everything is set up, go ahead and draw everything. // Now that everything is set up, go ahead and draw everything.
id<CAMetalDrawable> layerDrawable = [self nextDrawable]; id<CAMetalDrawable> layerDrawable = [self nextDrawable];
[[presenterObject colorAttachment0Desc] setTexture:[layerDrawable texture]]; [[presenterObject colorAttachment0Desc] setTexture:[layerDrawable texture]];
id<MTLCommandBuffer> cb = [presenterObject newCommandBuffer]; id<MTLCommandBuffer> cb = [presenterObject newCommandBuffer];
pthread_mutex_lock([presenterObject mutexBufferUpdate]);
[presenterObject updateRenderBuffers];
[presenterObject renderForCommandBuffer:cb [presenterObject renderForCommandBuffer:cb
outputPipelineState:[presenterObject outputDrawablePipeline] outputPipelineState:[presenterObject outputDrawablePipeline]
@ -2096,32 +2014,9 @@
[cb presentDrawable:layerDrawable]; [cb presentDrawable:layerDrawable];
if (needsFetchBuffersLock) [cb addCompletedHandler:^(id<MTLCommandBuffer> block) {
{ sem_post([presenterObject semTexProcessUpdate]);
if (processedInfo.bufferIndex == 0) }];
{
[cb addCompletedHandler:^(id<MTLCommandBuffer> block) {
pthread_mutex_unlock([presenterObject mutexBufferUpdate]);
pthread_rwlock_unlock([[presenterObject sharedData] rwlockFramebufferAtIndex:0]);
pthread_mutex_unlock([presenterObject mutexTexProcessUpdate]);
}];
}
else
{
[cb addCompletedHandler:^(id<MTLCommandBuffer> block) {
pthread_mutex_unlock([presenterObject mutexBufferUpdate]);
pthread_rwlock_unlock([[presenterObject sharedData] rwlockFramebufferAtIndex:1]);
pthread_mutex_unlock([presenterObject mutexTexProcessUpdate]);
}];
}
}
else
{
[cb addCompletedHandler:^(id<MTLCommandBuffer> block) {
pthread_mutex_unlock([presenterObject mutexBufferUpdate]);
pthread_mutex_unlock([presenterObject mutexTexProcessUpdate]);
}];
}
[cb commit]; [cb commit];
} }
@ -2265,10 +2160,14 @@ MacMetalDisplayPresenter::~MacMetalDisplayPresenter()
pthread_mutex_destroy(&this->_mutexProcessPtr); pthread_mutex_destroy(&this->_mutexProcessPtr);
pthread_rwlock_destroy(&this->_cpuFilterRWLock[NDSDisplayID_Main][0]); sem_close(this->_semCPUFilter[NDSDisplayID_Main][0]);
pthread_rwlock_destroy(&this->_cpuFilterRWLock[NDSDisplayID_Touch][0]); sem_close(this->_semCPUFilter[NDSDisplayID_Main][1]);
pthread_rwlock_destroy(&this->_cpuFilterRWLock[NDSDisplayID_Main][1]); sem_close(this->_semCPUFilter[NDSDisplayID_Touch][0]);
pthread_rwlock_destroy(&this->_cpuFilterRWLock[NDSDisplayID_Touch][1]); sem_close(this->_semCPUFilter[NDSDisplayID_Touch][1]);
sem_unlink("desmume_semCPUFilterMain0");
sem_unlink("desmume_semCPUFilterMain1");
sem_unlink("desmume_semCPUFilterTouch0");
sem_unlink("desmume_semCPUFilterTouch1");
} }
void MacMetalDisplayPresenter::__InstanceInit(MacClientSharedObject *sharedObject) void MacMetalDisplayPresenter::__InstanceInit(MacClientSharedObject *sharedObject)
@ -2286,10 +2185,49 @@ void MacMetalDisplayPresenter::__InstanceInit(MacClientSharedObject *sharedObjec
pthread_mutex_init(&_mutexProcessPtr, NULL); pthread_mutex_init(&_mutexProcessPtr, NULL);
pthread_rwlock_init(&_cpuFilterRWLock[NDSDisplayID_Main][0], NULL); _semCPUFilter[NDSDisplayID_Main][0] = sem_open("desmume_semCPUFilterMain0", O_CREAT | O_EXCL, 0777, 1);
pthread_rwlock_init(&_cpuFilterRWLock[NDSDisplayID_Touch][0], NULL); if (_semCPUFilter[NDSDisplayID_Main][0] == SEM_FAILED)
pthread_rwlock_init(&_cpuFilterRWLock[NDSDisplayID_Main][1], NULL); {
pthread_rwlock_init(&_cpuFilterRWLock[NDSDisplayID_Touch][1], NULL); sem_unlink("desmume_semCPUFilterMain0");
_semCPUFilter[NDSDisplayID_Main][0] = sem_open("desmume_semCPUFilterMain0", O_CREAT | O_EXCL, 0777, 1);
if (_semCPUFilter[NDSDisplayID_Main][0] == SEM_FAILED)
{
puts("desmume_semCPUFilterMain0 failed!");
}
}
_semCPUFilter[NDSDisplayID_Main][1] = sem_open("desmume_semCPUFilterMain1", O_CREAT | O_EXCL, 0777, 1);
if (_semCPUFilter[NDSDisplayID_Main][1] == SEM_FAILED)
{
sem_unlink("desmume_semCPUFilterMain1");
_semCPUFilter[NDSDisplayID_Main][1] = sem_open("desmume_semCPUFilterMain1", O_CREAT | O_EXCL, 0777, 1);
if (_semCPUFilter[NDSDisplayID_Main][1] == SEM_FAILED)
{
puts("desmume_semCPUFilterMain1 failed!");
}
}
_semCPUFilter[NDSDisplayID_Touch][0] = sem_open("desmume_semCPUFilterTouch0", O_CREAT | O_EXCL, 0777, 1);
if (_semCPUFilter[NDSDisplayID_Touch][0] == SEM_FAILED)
{
sem_unlink("desmume_semCPUFilterTouch0");
_semCPUFilter[NDSDisplayID_Touch][0] = sem_open("desmume_semCPUFilterTouch0", O_CREAT | O_EXCL, 0777, 1);
if (_semCPUFilter[NDSDisplayID_Touch][0] == SEM_FAILED)
{
puts("desmume_semCPUFilterTouch0 failed!");
}
}
_semCPUFilter[NDSDisplayID_Touch][1] = sem_open("desmume_semCPUFilterTouch1", O_CREAT | O_EXCL, 0777, 1);
if (_semCPUFilter[NDSDisplayID_Touch][1] == SEM_FAILED)
{
sem_unlink("desmume_semCPUFilterTouch1");
_semCPUFilter[NDSDisplayID_Touch][1] = sem_open("desmume_semCPUFilterTouch1", O_CREAT | O_EXCL, 0777, 1);
if (_semCPUFilter[NDSDisplayID_Touch][1] == SEM_FAILED)
{
puts("desmume_semCPUFilterTouch1 failed!");
}
}
} }
void MacMetalDisplayPresenter::_UpdateNormalSize() void MacMetalDisplayPresenter::_UpdateNormalSize()
@ -2329,9 +2267,9 @@ void MacMetalDisplayPresenter::_LoadNativeDisplayByID(const NDSDisplayID display
const uint8_t bufferIndex = fetchObjMutable.GetLastFetchIndex(); const uint8_t bufferIndex = fetchObjMutable.GetLastFetchIndex();
pthread_rwlock_wrlock(&this->_cpuFilterRWLock[displayID][bufferIndex]); sem_wait(this->_semCPUFilter[displayID][bufferIndex]);
fetchObjMutable.CopyFromSrcClone(vf->GetSrcBufferPtr(), displayID, bufferIndex); fetchObjMutable.CopyFromSrcClone(vf->GetSrcBufferPtr(), displayID, bufferIndex);
pthread_rwlock_unlock(&this->_cpuFilterRWLock[displayID][bufferIndex]); sem_post(this->_semCPUFilter[displayID][bufferIndex]);
} }
} }
@ -2351,9 +2289,9 @@ pthread_mutex_t* MacMetalDisplayPresenter::GetMutexProcessPtr()
return &this->_mutexProcessPtr; return &this->_mutexProcessPtr;
} }
pthread_rwlock_t* MacMetalDisplayPresenter::GetCPUFilterRWLock(const NDSDisplayID displayID, const uint8_t bufferIndex) sem_t* MacMetalDisplayPresenter::GetCPUFilterSemaphore(const NDSDisplayID displayID, const uint8_t bufferIndex)
{ {
return &this->_cpuFilterRWLock[displayID][bufferIndex]; return this->_semCPUFilter[displayID][bufferIndex];
} }
void MacMetalDisplayPresenter::Init() void MacMetalDisplayPresenter::Init()
@ -2406,11 +2344,6 @@ void MacMetalDisplayPresenter::ProcessDisplays()
[this->_presenterObject processDisplays]; [this->_presenterObject processDisplays];
} }
void MacMetalDisplayPresenter::UpdateLayout()
{
[this->_presenterObject updateRenderBuffers];
}
void MacMetalDisplayPresenter::CopyFrameToBuffer(uint32_t *dstBuffer) void MacMetalDisplayPresenter::CopyFrameToBuffer(uint32_t *dstBuffer)
{ {
[this->_presenterObject renderToBuffer:dstBuffer]; [this->_presenterObject renderToBuffer:dstBuffer];

View File

@ -513,6 +513,19 @@ kernel void nds_fetch666ConvertOnly(const uint2 position [[thread_position_in_gr
outTexture.write(float4(outColor, 1.0f), position); outTexture.write(float4(outColor, 1.0f), position);
} }
kernel void nds_fetch888PassthroughOnly(const uint2 position [[thread_position_in_grid]],
const texture2d<float, access::read> inTexture [[texture(0)]],
texture2d<float, access::write> outTexture [[texture(1)]])
{
if ( (position.x > inTexture.get_width() - 1) || (position.y > inTexture.get_height() - 1) )
{
return;
}
const float3 outColor = inTexture.read(position).rgb;
outTexture.write(float4(outColor, 1.0f), position);
}
float3 nds_apply_master_brightness(const float3 inColor, const uchar mode, const float intensity) float3 nds_apply_master_brightness(const float3 inColor, const uchar mode, const float intensity)
{ {
switch (mode) switch (mode)

View File

@ -194,14 +194,14 @@ void MacOGLClientFetchObject::FetchFromBufferIndex(const u8 index)
MacClientSharedObject *sharedViewObject = (MacClientSharedObject *)this->_clientData; MacClientSharedObject *sharedViewObject = (MacClientSharedObject *)this->_clientData;
this->_useDirectToCPUFilterPipeline = ([sharedViewObject numberViewsUsingDirectToCPUFiltering] > 0); this->_useDirectToCPUFilterPipeline = ([sharedViewObject numberViewsUsingDirectToCPUFiltering] > 0);
pthread_rwlock_rdlock([sharedViewObject rwlockFramebufferAtIndex:index]); sem_wait([sharedViewObject semaphoreFramebufferAtIndex:index]);
CGLLockContext(this->_context); CGLLockContext(this->_context);
CGLSetCurrentContext(this->_context); CGLSetCurrentContext(this->_context);
this->OGLClientFetchObject::FetchFromBufferIndex(index); this->OGLClientFetchObject::FetchFromBufferIndex(index);
CGLUnlockContext(this->_context); CGLUnlockContext(this->_context);
pthread_rwlock_unlock([sharedViewObject rwlockFramebufferAtIndex:index]); sem_post([sharedViewObject semaphoreFramebufferAtIndex:index]);
} }
GLuint MacOGLClientFetchObject::GetFetchTexture(const NDSDisplayID displayID) GLuint MacOGLClientFetchObject::GetFetchTexture(const NDSDisplayID displayID)
@ -435,7 +435,7 @@ void MacOGLDisplayPresenter::WriteLockEmuFramebuffer(const uint8_t bufferIndex)
const GPUClientFetchObject &fetchObj = this->GetFetchObject(); const GPUClientFetchObject &fetchObj = this->GetFetchObject();
MacClientSharedObject *sharedViewObject = (MacClientSharedObject *)fetchObj.GetClientData(); MacClientSharedObject *sharedViewObject = (MacClientSharedObject *)fetchObj.GetClientData();
pthread_rwlock_wrlock([sharedViewObject rwlockFramebufferAtIndex:bufferIndex]); sem_wait([sharedViewObject semaphoreFramebufferAtIndex:bufferIndex]);
} }
void MacOGLDisplayPresenter::ReadLockEmuFramebuffer(const uint8_t bufferIndex) void MacOGLDisplayPresenter::ReadLockEmuFramebuffer(const uint8_t bufferIndex)
@ -443,7 +443,7 @@ void MacOGLDisplayPresenter::ReadLockEmuFramebuffer(const uint8_t bufferIndex)
const GPUClientFetchObject &fetchObj = this->GetFetchObject(); const GPUClientFetchObject &fetchObj = this->GetFetchObject();
MacClientSharedObject *sharedViewObject = (MacClientSharedObject *)fetchObj.GetClientData(); MacClientSharedObject *sharedViewObject = (MacClientSharedObject *)fetchObj.GetClientData();
pthread_rwlock_rdlock([sharedViewObject rwlockFramebufferAtIndex:bufferIndex]); sem_wait([sharedViewObject semaphoreFramebufferAtIndex:bufferIndex]);
} }
void MacOGLDisplayPresenter::UnlockEmuFramebuffer(const uint8_t bufferIndex) void MacOGLDisplayPresenter::UnlockEmuFramebuffer(const uint8_t bufferIndex)
@ -451,7 +451,7 @@ void MacOGLDisplayPresenter::UnlockEmuFramebuffer(const uint8_t bufferIndex)
const GPUClientFetchObject &fetchObj = this->GetFetchObject(); const GPUClientFetchObject &fetchObj = this->GetFetchObject();
MacClientSharedObject *sharedViewObject = (MacClientSharedObject *)fetchObj.GetClientData(); MacClientSharedObject *sharedViewObject = (MacClientSharedObject *)fetchObj.GetClientData();
pthread_rwlock_unlock([sharedViewObject rwlockFramebufferAtIndex:bufferIndex]); sem_post([sharedViewObject semaphoreFramebufferAtIndex:bufferIndex]);
} }
#pragma mark - #pragma mark -