diff --git a/desmume/src/cocoa/DefaultUserPrefs.plist b/desmume/src/cocoa/DefaultUserPrefs.plist
index 072fcb44e..2fae988a2 100644
--- a/desmume/src/cocoa/DefaultUserPrefs.plist
+++ b/desmume/src/cocoa/DefaultUserPrefs.plist
@@ -14,6 +14,8 @@
1
DisplayView_Deposterize
+ DisplayView_FiltersPreferGPU
+
DisplayView_Mode
2
DisplayView_OutputFilter
diff --git a/desmume/src/cocoa/cocoa_core.h b/desmume/src/cocoa/cocoa_core.h
index dc6b0e8ef..ef1fc1803 100644
--- a/desmume/src/cocoa/cocoa_core.h
+++ b/desmume/src/cocoa/cocoa_core.h
@@ -43,6 +43,7 @@ typedef struct
pthread_mutex_t mutexOutputList;
pthread_mutex_t mutexThreadExecute;
pthread_cond_t condThreadExecute;
+ pthread_rwlock_t rwCoreExecute;
} CoreThreadParam;
@interface CocoaDSCore : NSObject
@@ -122,6 +123,7 @@ typedef struct
@property (retain) NSURL *slot1R4URL;
@property (readonly) pthread_mutex_t *mutexCoreExecute;
+@property (readonly) pthread_rwlock_t *rwCoreExecute;
- (BOOL) ejectCardFlag;
- (void) setEjectCardFlag;
diff --git a/desmume/src/cocoa/cocoa_core.mm b/desmume/src/cocoa/cocoa_core.mm
index d12ef0404..b5e17ac84 100644
--- a/desmume/src/cocoa/cocoa_core.mm
+++ b/desmume/src/cocoa/cocoa_core.mm
@@ -76,6 +76,7 @@ volatile bool execute = true;
@synthesize slot1R4URL;
@dynamic mutexCoreExecute;
+@dynamic rwCoreExecute;
- (id)init
{
@@ -143,6 +144,7 @@ volatile bool execute = true;
pthread_mutex_init(&threadParam.mutexOutputList, NULL);
pthread_mutex_init(&threadParam.mutexThreadExecute, NULL);
pthread_cond_init(&threadParam.condThreadExecute, NULL);
+ pthread_rwlock_init(&threadParam.rwCoreExecute, NULL);
pthread_create(&coreThread, NULL, &RunCoreThread, &threadParam);
[cdsGPU setMutexProducer:self.mutexCoreExecute];
@@ -176,6 +178,7 @@ volatile bool execute = true;
pthread_cond_destroy(&threadParam.condThreadExecute);
pthread_mutex_destroy(&threadParam.mutexOutputList);
pthread_mutex_destroy(&threadParam.mutexCoreExecute);
+ pthread_rwlock_destroy(&threadParam.rwCoreExecute);
NDS_DeInit();
@@ -596,6 +599,11 @@ volatile bool execute = true;
return &threadParam.mutexCoreExecute;
}
+- (pthread_rwlock_t *) rwCoreExecute
+{
+ return &threadParam.rwCoreExecute;
+}
+
- (void) setEjectCardFlag
{
if (nds.cardEjected)
@@ -778,22 +786,23 @@ volatile bool execute = true;
- (void) addOutput:(CocoaDSOutput *)theOutput
{
pthread_mutex_lock(&threadParam.mutexOutputList);
- theOutput.mutexProducer = self.mutexCoreExecute;
- [self.cdsOutputList addObject:theOutput];
+ [theOutput setMutexProducer:[self mutexCoreExecute]];
+ [theOutput setRwProducer:[self rwCoreExecute]];
+ [[self cdsOutputList] addObject:theOutput];
pthread_mutex_unlock(&threadParam.mutexOutputList);
}
- (void) removeOutput:(CocoaDSOutput *)theOutput
{
pthread_mutex_lock(&threadParam.mutexOutputList);
- [self.cdsOutputList removeObject:theOutput];
+ [[self cdsOutputList] removeObject:theOutput];
pthread_mutex_unlock(&threadParam.mutexOutputList);
}
- (void) removeAllOutputs
{
pthread_mutex_lock(&threadParam.mutexOutputList);
- [self.cdsOutputList removeAllObjects];
+ [[self cdsOutputList] removeAllObjects];
pthread_mutex_unlock(&threadParam.mutexOutputList);
}
@@ -947,7 +956,11 @@ static void* RunCoreThread(void *arg)
// Execute the frame and increment the frame counter.
pthread_mutex_lock(¶m->mutexCoreExecute);
+
+ pthread_rwlock_wrlock(¶m->rwCoreExecute);
NDS_exec();
+ pthread_rwlock_unlock(¶m->rwCoreExecute);
+
frameNum = currFrameCounter;
pthread_mutex_unlock(¶m->mutexCoreExecute);
@@ -984,11 +997,13 @@ static void* RunCoreThread(void *arg)
}
case CORESTATE_FRAMEADVANCE:
+ {
for(CocoaDSOutput *cdsOutput in cdsOutputList)
{
[cdsOutput doCoreEmuFrame];
}
break;
+ }
case CORESTATE_FRAMEJUMP:
{
diff --git a/desmume/src/cocoa/cocoa_globals.h b/desmume/src/cocoa/cocoa_globals.h
index b1c608425..0f303ee40 100644
--- a/desmume/src/cocoa/cocoa_globals.h
+++ b/desmume/src/cocoa/cocoa_globals.h
@@ -462,6 +462,12 @@ enum
DS_DISPLAY_TYPE_DUAL
};
+enum
+{
+ VIDEO_SOURCE_INTERNAL = 0,
+ VIDEO_SOURCE_EMULATOR = 1
+};
+
enum
{
DS_DISPLAY_ORIENTATION_VERTICAL = 0,
diff --git a/desmume/src/cocoa/cocoa_output.h b/desmume/src/cocoa/cocoa_output.h
index b47c27814..5e793d009 100644
--- a/desmume/src/cocoa/cocoa_output.h
+++ b/desmume/src/cocoa/cocoa_output.h
@@ -36,9 +36,10 @@ typedef struct
typedef struct
{
- NSInteger displayModeID;
- size_t width; // Measured in pixels
- size_t height; // Measured in pixels
+ int32_t videoSourceID;
+ int32_t displayModeID;
+ uint16_t width; // Measured in pixels
+ uint16_t height; // Measured in pixels
} DisplaySrcPixelAttributes;
@interface CocoaDSOutput : CocoaDSThread
@@ -51,6 +52,7 @@ typedef struct
pthread_mutex_t *mutexProducer;
pthread_mutex_t *mutexConsume;
+ pthread_rwlock_t *rwProducer;
}
@property (assign) BOOL isStateChanged;
@@ -59,6 +61,7 @@ typedef struct
@property (retain) NSData *frameAttributesData;
@property (readonly) NSMutableDictionary *property;
@property (assign) pthread_mutex_t *mutexProducer;
+@property (assign) pthread_rwlock_t *rwProducer;
@property (readonly) pthread_mutex_t *mutexConsume;
- (void) doCoreEmuFrame;
@@ -158,7 +161,8 @@ typedef struct
- (void) handleRequestScreenshot:(NSData *)fileURLStringData fileTypeData:(NSData *)fileTypeData;
- (void) handleCopyToPasteboard;
-- (void) fillVideoFrameWithColor:(UInt16)colorValue;
+- (NSData *) videoFrameUsingRGBA5551:(uint16_t)colorValue pixelCount:(size_t)pixCount;
+- (void) sendVideoFrameOfRGBA5551:(uint16_t)colorValue;
- (NSImage *) image;
- (NSBitmapImageRep *) bitmapImageRep;
diff --git a/desmume/src/cocoa/cocoa_output.mm b/desmume/src/cocoa/cocoa_output.mm
index 60c1f83cb..9dfed76ff 100644
--- a/desmume/src/cocoa/cocoa_output.mm
+++ b/desmume/src/cocoa/cocoa_output.mm
@@ -40,6 +40,7 @@
@synthesize property;
@synthesize mutexProducer;
@synthesize mutexConsume;
+@synthesize rwProducer;
- (id)init
{
@@ -598,34 +599,24 @@
- (void) doCoreEmuFrame
{
- NSData *gpuData = nil;
NSInteger displayModeID = [self displayMode];
NSSize displayFrameSize = [self frameSize];
- // Here, we copy the raw GPU data from the emulation core.
- //
- // The core data contains the GPU pixels from both the main and touch screens. So
- // depending on the display type, we copy only the pixels from the respective screen.
- if (displayModeID == DS_DISPLAY_TYPE_MAIN)
- {
- gpuData = [[NSData alloc] initWithBytes:GPU_screen length:GPU_SCREEN_SIZE_BYTES];
- }
- else if(displayModeID == DS_DISPLAY_TYPE_TOUCH)
- {
- gpuData = [[NSData alloc] initWithBytes:(GPU_screen + GPU_SCREEN_SIZE_BYTES) length:GPU_SCREEN_SIZE_BYTES];
- }
- else if(displayModeID == DS_DISPLAY_TYPE_DUAL)
- {
- gpuData = [[NSData alloc] initWithBytes:GPU_screen length:GPU_SCREEN_SIZE_BYTES * 2];
- }
+ // We will be ignoring the actual video data here since we will be pulling the video data
+ // from the consumer thread instead.
+ NSData *gpuData = [[NSData alloc] init];
+
+ DisplaySrcPixelAttributes attr;
+ attr.videoSourceID = VIDEO_SOURCE_EMULATOR;
+ attr.displayModeID = (int32_t)displayModeID;
+ attr.width = (uint16_t)displayFrameSize.width;
+ attr.height = (uint16_t)displayFrameSize.height;
- DisplaySrcPixelAttributes attr = {displayModeID, (size_t)displayFrameSize.width, (size_t)displayFrameSize.height};
NSData *attributesData = [[NSData alloc] initWithBytes:&attr length:sizeof(DisplaySrcPixelAttributes)];
NSArray *messageComponents = [[NSArray alloc] initWithObjects:gpuData, attributesData, nil];
[CocoaDSUtil messageSendOneWayWithMessageComponents:self.receivePort msgID:MESSAGE_EMU_FRAME_PROCESSED array:messageComponents];
- // Now that we've finished sending the GPU data, release the local copy.
[gpuData release];
[attributesData release];
[messageComponents release];
@@ -687,12 +678,12 @@
- (void) handleSetViewToBlack
{
- [self fillVideoFrameWithColor:0x8000];
+ [self sendVideoFrameOfRGBA5551:0x8000];
}
- (void) handleSetViewToWhite
{
- [self fillVideoFrameWithColor:0xFFFF];
+ [self sendVideoFrameOfRGBA5551:0xFFFF];
}
- (void) handleRequestScreenshot:(NSData *)fileURLStringData fileTypeData:(NSData *)fileTypeData
@@ -726,30 +717,52 @@
[pboard setData:[screenshot TIFFRepresentationUsingCompression:NSTIFFCompressionLZW factor:1.0f] forType:NSTIFFPboardType];
}
-- (void) fillVideoFrameWithColor:(UInt16)colorValue
+- (NSData *) videoFrameUsingRGBA5551:(uint16_t)colorValue pixelCount:(size_t)pixCount
{
- const NSInteger displayModeID = [self displayMode];
- const NSSize displayFrameSize = [self frameSize];
- const size_t numberBytes = (displayModeID == DS_DISPLAY_TYPE_DUAL) ? GPU_SCREEN_SIZE_BYTES * 2 : GPU_SCREEN_SIZE_BYTES;
-
- UInt16 *gpuBytes = (UInt16 *)malloc(numberBytes);
+ NSData *gpuData = nil;
+ const size_t bufSize = pixCount * sizeof(uint16_t);
+ uint16_t *gpuBytes = (uint16_t *)malloc(bufSize);
if (gpuBytes == NULL)
{
- return;
+ return gpuData;
}
- const UInt16 colorValuePattern[] = {colorValue, colorValue, colorValue, colorValue, colorValue, colorValue, colorValue, colorValue};
- memset_pattern16(gpuBytes, colorValuePattern, numberBytes);
- NSData *gpuData = [[NSData alloc] initWithBytes:gpuBytes length:numberBytes];
+ if (pixCount % 16 == 0)
+ {
+ const uint16_t colorValuePattern[] = {colorValue, colorValue, colorValue, colorValue, colorValue, colorValue, colorValue, colorValue};
+ memset_pattern16(gpuBytes, colorValuePattern, bufSize);
+ }
+ else
+ {
+ memset(gpuBytes, colorValue, bufSize);
+ }
+
+
+ gpuData = [NSData dataWithBytes:gpuBytes length:bufSize];
free(gpuBytes);
gpuBytes = nil;
- DisplaySrcPixelAttributes attr = {displayModeID, (size_t)displayFrameSize.width, (size_t)displayFrameSize.height};
- NSData *attributesData = [[[NSData alloc] initWithBytes:&attr length:sizeof(DisplaySrcPixelAttributes)] autorelease];
+ return gpuData;
+}
+
+- (void) sendVideoFrameOfRGBA5551:(uint16_t)colorValue
+{
+ const NSInteger displayModeID = [self displayMode];
+ const NSSize displayFrameSize = [self frameSize];
+ const size_t pixCount = (displayModeID == DS_DISPLAY_TYPE_DUAL) ? GPU_DISPLAY_WIDTH * GPU_DISPLAY_HEIGHT * 2 : GPU_DISPLAY_WIDTH * GPU_DISPLAY_HEIGHT;
- [self handleEmuFrameProcessed:gpuData attributes:attributesData];
- [gpuData release];
+ NSData *videoData = [self videoFrameUsingRGBA5551:colorValue pixelCount:pixCount];
+
+ DisplaySrcPixelAttributes attr;
+ attr.videoSourceID = VIDEO_SOURCE_INTERNAL;
+ attr.displayModeID = (int32_t)displayModeID;
+ attr.width = (uint16_t)displayFrameSize.width;
+ attr.height = (uint16_t)displayFrameSize.height;
+
+ NSData *attributesData = [NSData dataWithBytes:&attr length:sizeof(DisplaySrcPixelAttributes)];
+
+ [self handleEmuFrameProcessed:videoData attributes:attributesData];
}
- (NSImage *) image
@@ -899,13 +912,53 @@
return;
}
- const DisplaySrcPixelAttributes attr = *(DisplaySrcPixelAttributes *)[attributesData bytes];
+ NSData *newVideoFrame = mainData;
+ DisplaySrcPixelAttributes attr = *(DisplaySrcPixelAttributes *)[attributesData bytes];
const NSInteger frameDisplayMode = attr.displayModeID;
+ const NSInteger frameSource = attr.videoSourceID;
const NSInteger frameWidth = attr.width;
const NSInteger frameHeight = attr.height;
- [(id)delegate doProcessVideoFrame:[mainData bytes] displayMode:frameDisplayMode width:frameWidth height:frameHeight];
- [super handleEmuFrameProcessed:mainData attributes:attributesData];
+ if (frameSource == VIDEO_SOURCE_EMULATOR)
+ {
+ // Note that we simply received the attributes of the video data, not the actual
+ // video data itself. So from here, we need to pull the video data from the
+ // emulator and copy it to this thread.
+ //
+ // The video data contains the pixels from both the main and touch screens. So
+ // depending on the display mode, we copy only the pixels from the respective
+ // screen.
+
+ pthread_rwlock_rdlock([self rwProducer]);
+
+ switch (frameDisplayMode)
+ {
+ case DS_DISPLAY_TYPE_MAIN:
+ newVideoFrame = [NSData dataWithBytes:GPU_screen length:GPU_SCREEN_SIZE_BYTES];
+ break;
+
+ case DS_DISPLAY_TYPE_TOUCH:
+ newVideoFrame = [NSData dataWithBytes:(GPU_screen + GPU_SCREEN_SIZE_BYTES) length:GPU_SCREEN_SIZE_BYTES];
+ break;
+
+ case DS_DISPLAY_TYPE_DUAL:
+ newVideoFrame = [NSData dataWithBytes:GPU_screen length:GPU_SCREEN_SIZE_BYTES*2];
+ break;
+
+ default:
+ break;
+ }
+
+ pthread_rwlock_unlock([self rwProducer]);
+ }
+
+ [(id)delegate doProcessVideoFrame:[newVideoFrame bytes] displayMode:frameDisplayMode width:frameWidth height:frameHeight];
+
+ // If we need to use our saved frame data, make sure that we don't pull from the
+ // emulation thread again.
+ attr.videoSourceID = VIDEO_SOURCE_INTERNAL;
+ NSData *savedAttributesData = [NSData dataWithBytes:&attr length:sizeof(DisplaySrcPixelAttributes)];
+ [super handleEmuFrameProcessed:newVideoFrame attributes:savedAttributesData];
}
- (void) handleResizeView:(NSData *)rectData