From 7ae952f3664d15688603171c17d5a9e652367085 Mon Sep 17 00:00:00 2001 From: rogerman Date: Sat, 10 Mar 2012 20:42:49 +0000 Subject: [PATCH] Cocoa Port: - Reverse locking mechanics for the core emulation loop's producer/consumer threads. (Instead of the producer telling consumers to lock, now consumers check if the producer is locked.) - Add additional error check for the execution state within the core emulation loop. - Reduce spin lock time when setting the GPU state flags. - Improve thread safety when changing the execution state. --- desmume/src/cocoa/cocoa_core.mm | 20 +++++---- desmume/src/cocoa/cocoa_output.h | 6 ++- desmume/src/cocoa/cocoa_output.mm | 75 ++++++++++++++++--------------- 3 files changed, 55 insertions(+), 46 deletions(-) diff --git a/desmume/src/cocoa/cocoa_core.mm b/desmume/src/cocoa/cocoa_core.mm index 70a6d3c44..e8b95808f 100644 --- a/desmume/src/cocoa/cocoa_core.mm +++ b/desmume/src/cocoa/cocoa_core.mm @@ -465,6 +465,8 @@ static BOOL isCoreStarted = NO; - (void) setCoreState:(NSInteger)coreState { + pthread_mutex_lock(&threadParam.mutexThreadExecute); + if (threadParam.state == CORESTATE_PAUSE) { prevCoreState = CORESTATE_PAUSE; @@ -474,7 +476,6 @@ static BOOL isCoreStarted = NO; prevCoreState = CORESTATE_EXECUTE; } - pthread_mutex_lock(&threadParam.mutexThreadExecute); threadParam.state = coreState; pthread_cond_signal(&threadParam.condThreadExecute); pthread_mutex_unlock(&threadParam.mutexThreadExecute); @@ -618,6 +619,7 @@ static BOOL isCoreStarted = NO; - (void) addOutput:(CocoaDSOutput *)theOutput { + theOutput.mutexProducer = self.mutexCoreExecute; [self.cdsOutputList addObject:theOutput]; } @@ -673,16 +675,20 @@ void* RunCoreThread(void *arg) // We'll just jump directly to ending the input processing. NDS_endProcessingInput(); - for(CocoaDSOutput *cdsOutput in cdsOutputList) - { - pthread_mutex_lock(cdsOutput.mutexOutputFrame); - } - // Execute the frame and increment the frame counter. pthread_mutex_lock(param->mutexCoreExecute); NDS_exec(); pthread_mutex_unlock(param->mutexCoreExecute); + // Check if an internal execution error occurred that halted the emulation. + if (!execute) + { + pthread_mutex_unlock(¶m->mutexThreadExecute); + // TODO: Message the core that emulation halted. + NSLog(@"The emulator halted during execution. Was it an internal error that caused this?"); + continue; + } + if (param->framesToSkip == 0) { param->frameCount++; @@ -692,12 +698,10 @@ void* RunCoreThread(void *arg) { if (param->framesToSkip > 0 && [cdsOutput isMemberOfClass:[CocoaDSDisplay class]]) { - pthread_mutex_unlock(cdsOutput.mutexOutputFrame); continue; } [cdsOutput doCoreEmuFrame]; - pthread_mutex_unlock(cdsOutput.mutexOutputFrame); } // Determine the number of frames to skip based on how much time "debt" diff --git a/desmume/src/cocoa/cocoa_output.h b/desmume/src/cocoa/cocoa_output.h index bd73d8eae..cd0237d93 100644 --- a/desmume/src/cocoa/cocoa_output.h +++ b/desmume/src/cocoa/cocoa_output.h @@ -30,14 +30,16 @@ NSData *frameData; NSMutableDictionary *property; - pthread_mutex_t *mutexOutputFrame; + pthread_mutex_t *mutexProducer; + pthread_mutex_t *mutexConsume; } @property (assign) BOOL isStateChanged; @property (assign) NSUInteger frameCount; @property (retain) NSData *frameData; @property (readonly) NSMutableDictionary *property; -@property (readonly) pthread_mutex_t *mutexOutputFrame; +@property (assign) pthread_mutex_t *mutexProducer; +@property (readonly) pthread_mutex_t *mutexConsume; - (void) doCoreEmuFrame; - (void) handleEmuFrameProcessed:(NSData *)theData; diff --git a/desmume/src/cocoa/cocoa_output.mm b/desmume/src/cocoa/cocoa_output.mm index 06398e691..275764cc8 100644 --- a/desmume/src/cocoa/cocoa_output.mm +++ b/desmume/src/cocoa/cocoa_output.mm @@ -45,7 +45,8 @@ GPU3DInterface *core3DList[] = { @synthesize frameCount; @synthesize frameData; @synthesize property; -@synthesize mutexOutputFrame; +@synthesize mutexProducer; +@synthesize mutexConsume; - (id)init { @@ -62,8 +63,8 @@ GPU3DInterface *core3DList[] = { property = [[NSMutableDictionary alloc] init]; [property setValue:[NSDate date] forKey:@"outputTime"]; - mutexOutputFrame = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t)); - pthread_mutex_init(mutexOutputFrame, NULL); + mutexConsume = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t)); + pthread_mutex_init(mutexConsume, NULL); return self; } @@ -85,9 +86,9 @@ GPU3DInterface *core3DList[] = { self.frameData = nil; [property release]; - pthread_mutex_destroy(mutexOutputFrame); - free(mutexOutputFrame); - mutexOutputFrame = nil; + pthread_mutex_destroy(mutexConsume); + free(mutexConsume); + mutexConsume = NULL; [super dealloc]; } @@ -199,7 +200,7 @@ GPU3DInterface *core3DList[] = { [property setValue:[NSNumber numberWithInteger:methodID] forKey:@"audioOutputEngine"]; OSSpinLockUnlock(&spinlockAudioOutputEngine); - pthread_mutex_lock(self.mutexOutputFrame); + pthread_mutex_lock(self.mutexProducer); NSInteger result = -1; @@ -213,7 +214,7 @@ GPU3DInterface *core3DList[] = { SPU_ChangeSoundCore(SNDCORE_DUMMY, 0); } - pthread_mutex_unlock(self.mutexOutputFrame); + pthread_mutex_unlock(self.mutexProducer); // Force the volume back to it's original setting. [self setVolume:[self volume]]; @@ -234,9 +235,9 @@ GPU3DInterface *core3DList[] = { [property setValue:[NSNumber numberWithBool:state] forKey:@"spuAdvancedLogic"]; OSSpinLockUnlock(&spinlockSpuAdvancedLogic); - pthread_mutex_lock(self.mutexOutputFrame); + pthread_mutex_lock(self.mutexProducer); CommonSettings.spu_advanced = state; - pthread_mutex_unlock(self.mutexOutputFrame); + pthread_mutex_unlock(self.mutexProducer); } - (BOOL) spuAdvancedLogic @@ -254,9 +255,9 @@ GPU3DInterface *core3DList[] = { [property setValue:[NSNumber numberWithInteger:modeID] forKey:@"spuInterpolationMode"]; OSSpinLockUnlock(&spinlockSpuInterpolationMode); - pthread_mutex_lock(self.mutexOutputFrame); + pthread_mutex_lock(self.mutexProducer); CommonSettings.spuInterpolationMode = (SPUInterpolationMode)modeID; - pthread_mutex_unlock(self.mutexOutputFrame); + pthread_mutex_unlock(self.mutexProducer); } - (NSInteger) spuInterpolationMode @@ -276,9 +277,9 @@ GPU3DInterface *core3DList[] = { NSInteger methodID = [self spuSyncMethod]; - pthread_mutex_lock(self.mutexOutputFrame); + pthread_mutex_lock(self.mutexProducer); SPU_SetSynchMode(modeID, methodID); - pthread_mutex_unlock(self.mutexOutputFrame); + pthread_mutex_unlock(self.mutexProducer); } - (NSInteger) spuSyncMode @@ -298,9 +299,9 @@ GPU3DInterface *core3DList[] = { NSInteger modeID = [self spuSyncMode]; - pthread_mutex_lock(self.mutexOutputFrame); + pthread_mutex_lock(self.mutexProducer); SPU_SetSynchMode(modeID, methodID); - pthread_mutex_unlock(self.mutexOutputFrame); + pthread_mutex_unlock(self.mutexProducer); } - (NSInteger) spuSyncMethod @@ -554,8 +555,10 @@ GPU3DInterface *core3DList[] = { - (void) setGpuStateFlags:(UInt32)flags { OSSpinLockLock(&spinlockGpuState); - gpuStateFlags = flags; + OSSpinLockUnlock(&spinlockGpuState); + + pthread_mutex_lock(self.mutexProducer); if (flags & GPUSTATE_MAIN_GPU_MASK) { @@ -689,7 +692,7 @@ GPU3DInterface *core3DList[] = { [property setValue:[NSNumber numberWithBool:NO] forKey:@"gpuStateSubOBJ"]; } - OSSpinLockUnlock(&spinlockGpuState); + pthread_mutex_unlock(self.mutexProducer); } - (UInt32) gpuStateFlags @@ -771,9 +774,9 @@ GPU3DInterface *core3DList[] = { [property setValue:[NSNumber numberWithInteger:methodID] forKey:@"render3DRenderingEngine"]; OSSpinLockUnlock(&spinlockRender3DRenderingEngine); - pthread_mutex_lock(self.mutexOutputFrame); + pthread_mutex_lock(self.mutexProducer); NDS_3D_ChangeCore(methodID); - pthread_mutex_unlock(self.mutexOutputFrame); + pthread_mutex_unlock(self.mutexProducer); } - (NSInteger) render3DRenderingEngine @@ -797,9 +800,9 @@ GPU3DInterface *core3DList[] = { cState = true; } - pthread_mutex_lock(self.mutexOutputFrame); + pthread_mutex_lock(self.mutexProducer); CommonSettings.GFX3D_HighResolutionInterpolateColor = cState; - pthread_mutex_unlock(self.mutexOutputFrame); + pthread_mutex_unlock(self.mutexProducer); } - (BOOL) render3DHighPrecisionColorInterpolation @@ -823,9 +826,9 @@ GPU3DInterface *core3DList[] = { cState = true; } - pthread_mutex_lock(self.mutexOutputFrame); + pthread_mutex_lock(self.mutexProducer); CommonSettings.GFX3D_EdgeMark = cState; - pthread_mutex_unlock(self.mutexOutputFrame); + pthread_mutex_unlock(self.mutexProducer); } - (BOOL) render3DEdgeMarking @@ -849,9 +852,9 @@ GPU3DInterface *core3DList[] = { cState = true; } - pthread_mutex_lock(self.mutexOutputFrame); + pthread_mutex_lock(self.mutexProducer); CommonSettings.GFX3D_Fog = cState; - pthread_mutex_unlock(self.mutexOutputFrame); + pthread_mutex_unlock(self.mutexProducer); } - (BOOL) render3DFog @@ -875,9 +878,9 @@ GPU3DInterface *core3DList[] = { cState = true; } - pthread_mutex_lock(self.mutexOutputFrame); + pthread_mutex_lock(self.mutexProducer); CommonSettings.GFX3D_Texture = cState; - pthread_mutex_unlock(self.mutexOutputFrame); + pthread_mutex_unlock(self.mutexProducer); } - (BOOL) render3DTextures @@ -895,9 +898,9 @@ GPU3DInterface *core3DList[] = { [property setValue:[NSNumber numberWithInteger:threshold] forKey:@"render3DDepthComparisonThreshold"]; OSSpinLockUnlock(&spinlockRender3DDepthComparisonThreshold); - pthread_mutex_lock(self.mutexOutputFrame); + pthread_mutex_lock(self.mutexProducer); CommonSettings.GFX3D_Zelda_Shadow_Depth_Hack = threshold; - pthread_mutex_unlock(self.mutexOutputFrame); + pthread_mutex_unlock(self.mutexProducer); } - (NSUInteger) render3DDepthComparisonThreshold @@ -936,15 +939,15 @@ GPU3DInterface *core3DList[] = { numberCores = numberThreads; } - pthread_mutex_lock(self.mutexOutputFrame); + pthread_mutex_lock(self.mutexProducer); CommonSettings.num_cores = numberCores; - pthread_mutex_unlock(self.mutexOutputFrame); + pthread_mutex_unlock(self.mutexProducer); if ([self render3DRenderingEngine] == CORE3DLIST_SWRASTERIZE) { - pthread_mutex_lock(self.mutexOutputFrame); + pthread_mutex_lock(self.mutexProducer); NDS_3D_ChangeCore(CORE3DLIST_SWRASTERIZE); - pthread_mutex_unlock(self.mutexOutputFrame); + pthread_mutex_unlock(self.mutexProducer); } } @@ -969,9 +972,9 @@ GPU3DInterface *core3DList[] = { cState = true; } - pthread_mutex_lock(self.mutexOutputFrame); + pthread_mutex_lock(self.mutexProducer); CommonSettings.GFX3D_LineHack = cState; - pthread_mutex_unlock(self.mutexOutputFrame); + pthread_mutex_unlock(self.mutexProducer); } - (BOOL) render3DLineHack