Cocoa Port:

- Fix bug where video filters weren't preferring to use the GPU by default.
- Display threads now each pull a copy of the video frame from the emulation thread, rather than the emulation thread pushing copies of the video frame to each display thread. (Slight performance improvement when many display threads are used.)
This commit is contained in:
rogerman 2014-04-13 00:23:52 +00:00
parent 608b9b3986
commit f02a1e83ee
6 changed files with 128 additions and 46 deletions

View File

@ -14,6 +14,8 @@
<real>1</real> <real>1</real>
<key>DisplayView_Deposterize</key> <key>DisplayView_Deposterize</key>
<false/> <false/>
<key>DisplayView_FiltersPreferGPU</key>
<true/>
<key>DisplayView_Mode</key> <key>DisplayView_Mode</key>
<integer>2</integer> <integer>2</integer>
<key>DisplayView_OutputFilter</key> <key>DisplayView_OutputFilter</key>

View File

@ -43,6 +43,7 @@ typedef struct
pthread_mutex_t mutexOutputList; pthread_mutex_t mutexOutputList;
pthread_mutex_t mutexThreadExecute; pthread_mutex_t mutexThreadExecute;
pthread_cond_t condThreadExecute; pthread_cond_t condThreadExecute;
pthread_rwlock_t rwCoreExecute;
} CoreThreadParam; } CoreThreadParam;
@interface CocoaDSCore : NSObject @interface CocoaDSCore : NSObject
@ -122,6 +123,7 @@ typedef struct
@property (retain) NSURL *slot1R4URL; @property (retain) NSURL *slot1R4URL;
@property (readonly) pthread_mutex_t *mutexCoreExecute; @property (readonly) pthread_mutex_t *mutexCoreExecute;
@property (readonly) pthread_rwlock_t *rwCoreExecute;
- (BOOL) ejectCardFlag; - (BOOL) ejectCardFlag;
- (void) setEjectCardFlag; - (void) setEjectCardFlag;

View File

@ -76,6 +76,7 @@ volatile bool execute = true;
@synthesize slot1R4URL; @synthesize slot1R4URL;
@dynamic mutexCoreExecute; @dynamic mutexCoreExecute;
@dynamic rwCoreExecute;
- (id)init - (id)init
{ {
@ -143,6 +144,7 @@ volatile bool execute = true;
pthread_mutex_init(&threadParam.mutexOutputList, NULL); pthread_mutex_init(&threadParam.mutexOutputList, 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.rwCoreExecute, NULL);
pthread_create(&coreThread, NULL, &RunCoreThread, &threadParam); pthread_create(&coreThread, NULL, &RunCoreThread, &threadParam);
[cdsGPU setMutexProducer:self.mutexCoreExecute]; [cdsGPU setMutexProducer:self.mutexCoreExecute];
@ -176,6 +178,7 @@ volatile bool execute = true;
pthread_cond_destroy(&threadParam.condThreadExecute); pthread_cond_destroy(&threadParam.condThreadExecute);
pthread_mutex_destroy(&threadParam.mutexOutputList); pthread_mutex_destroy(&threadParam.mutexOutputList);
pthread_mutex_destroy(&threadParam.mutexCoreExecute); pthread_mutex_destroy(&threadParam.mutexCoreExecute);
pthread_rwlock_destroy(&threadParam.rwCoreExecute);
NDS_DeInit(); NDS_DeInit();
@ -596,6 +599,11 @@ volatile bool execute = true;
return &threadParam.mutexCoreExecute; return &threadParam.mutexCoreExecute;
} }
- (pthread_rwlock_t *) rwCoreExecute
{
return &threadParam.rwCoreExecute;
}
- (void) setEjectCardFlag - (void) setEjectCardFlag
{ {
if (nds.cardEjected) if (nds.cardEjected)
@ -778,22 +786,23 @@ volatile bool execute = true;
- (void) addOutput:(CocoaDSOutput *)theOutput - (void) addOutput:(CocoaDSOutput *)theOutput
{ {
pthread_mutex_lock(&threadParam.mutexOutputList); pthread_mutex_lock(&threadParam.mutexOutputList);
theOutput.mutexProducer = self.mutexCoreExecute; [theOutput setMutexProducer:[self mutexCoreExecute]];
[self.cdsOutputList addObject:theOutput]; [theOutput setRwProducer:[self rwCoreExecute]];
[[self cdsOutputList] addObject:theOutput];
pthread_mutex_unlock(&threadParam.mutexOutputList); pthread_mutex_unlock(&threadParam.mutexOutputList);
} }
- (void) removeOutput:(CocoaDSOutput *)theOutput - (void) removeOutput:(CocoaDSOutput *)theOutput
{ {
pthread_mutex_lock(&threadParam.mutexOutputList); pthread_mutex_lock(&threadParam.mutexOutputList);
[self.cdsOutputList removeObject:theOutput]; [[self cdsOutputList] removeObject:theOutput];
pthread_mutex_unlock(&threadParam.mutexOutputList); pthread_mutex_unlock(&threadParam.mutexOutputList);
} }
- (void) removeAllOutputs - (void) removeAllOutputs
{ {
pthread_mutex_lock(&threadParam.mutexOutputList); pthread_mutex_lock(&threadParam.mutexOutputList);
[self.cdsOutputList removeAllObjects]; [[self cdsOutputList] removeAllObjects];
pthread_mutex_unlock(&threadParam.mutexOutputList); pthread_mutex_unlock(&threadParam.mutexOutputList);
} }
@ -947,7 +956,11 @@ static void* RunCoreThread(void *arg)
// Execute the frame and increment the frame counter. // Execute the frame and increment the frame counter.
pthread_mutex_lock(&param->mutexCoreExecute); pthread_mutex_lock(&param->mutexCoreExecute);
pthread_rwlock_wrlock(&param->rwCoreExecute);
NDS_exec<false>(); NDS_exec<false>();
pthread_rwlock_unlock(&param->rwCoreExecute);
frameNum = currFrameCounter; frameNum = currFrameCounter;
pthread_mutex_unlock(&param->mutexCoreExecute); pthread_mutex_unlock(&param->mutexCoreExecute);
@ -984,11 +997,13 @@ static void* RunCoreThread(void *arg)
} }
case CORESTATE_FRAMEADVANCE: case CORESTATE_FRAMEADVANCE:
{
for(CocoaDSOutput *cdsOutput in cdsOutputList) for(CocoaDSOutput *cdsOutput in cdsOutputList)
{ {
[cdsOutput doCoreEmuFrame]; [cdsOutput doCoreEmuFrame];
} }
break; break;
}
case CORESTATE_FRAMEJUMP: case CORESTATE_FRAMEJUMP:
{ {

View File

@ -462,6 +462,12 @@ enum
DS_DISPLAY_TYPE_DUAL DS_DISPLAY_TYPE_DUAL
}; };
enum
{
VIDEO_SOURCE_INTERNAL = 0,
VIDEO_SOURCE_EMULATOR = 1
};
enum enum
{ {
DS_DISPLAY_ORIENTATION_VERTICAL = 0, DS_DISPLAY_ORIENTATION_VERTICAL = 0,

View File

@ -36,9 +36,10 @@ typedef struct
typedef struct typedef struct
{ {
NSInteger displayModeID; int32_t videoSourceID;
size_t width; // Measured in pixels int32_t displayModeID;
size_t height; // Measured in pixels uint16_t width; // Measured in pixels
uint16_t height; // Measured in pixels
} DisplaySrcPixelAttributes; } DisplaySrcPixelAttributes;
@interface CocoaDSOutput : CocoaDSThread @interface CocoaDSOutput : CocoaDSThread
@ -51,6 +52,7 @@ typedef struct
pthread_mutex_t *mutexProducer; pthread_mutex_t *mutexProducer;
pthread_mutex_t *mutexConsume; pthread_mutex_t *mutexConsume;
pthread_rwlock_t *rwProducer;
} }
@property (assign) BOOL isStateChanged; @property (assign) BOOL isStateChanged;
@ -59,6 +61,7 @@ typedef struct
@property (retain) NSData *frameAttributesData; @property (retain) NSData *frameAttributesData;
@property (readonly) NSMutableDictionary *property; @property (readonly) NSMutableDictionary *property;
@property (assign) pthread_mutex_t *mutexProducer; @property (assign) pthread_mutex_t *mutexProducer;
@property (assign) pthread_rwlock_t *rwProducer;
@property (readonly) pthread_mutex_t *mutexConsume; @property (readonly) pthread_mutex_t *mutexConsume;
- (void) doCoreEmuFrame; - (void) doCoreEmuFrame;
@ -158,7 +161,8 @@ typedef struct
- (void) handleRequestScreenshot:(NSData *)fileURLStringData fileTypeData:(NSData *)fileTypeData; - (void) handleRequestScreenshot:(NSData *)fileURLStringData fileTypeData:(NSData *)fileTypeData;
- (void) handleCopyToPasteboard; - (void) handleCopyToPasteboard;
- (void) fillVideoFrameWithColor:(UInt16)colorValue; - (NSData *) videoFrameUsingRGBA5551:(uint16_t)colorValue pixelCount:(size_t)pixCount;
- (void) sendVideoFrameOfRGBA5551:(uint16_t)colorValue;
- (NSImage *) image; - (NSImage *) image;
- (NSBitmapImageRep *) bitmapImageRep; - (NSBitmapImageRep *) bitmapImageRep;

View File

@ -40,6 +40,7 @@
@synthesize property; @synthesize property;
@synthesize mutexProducer; @synthesize mutexProducer;
@synthesize mutexConsume; @synthesize mutexConsume;
@synthesize rwProducer;
- (id)init - (id)init
{ {
@ -598,34 +599,24 @@
- (void) doCoreEmuFrame - (void) doCoreEmuFrame
{ {
NSData *gpuData = nil;
NSInteger displayModeID = [self displayMode]; NSInteger displayModeID = [self displayMode];
NSSize displayFrameSize = [self frameSize]; NSSize displayFrameSize = [self frameSize];
// Here, we copy the raw GPU data from the emulation core. // We will be ignoring the actual video data here since we will be pulling the video data
// // from the consumer thread instead.
// The core data contains the GPU pixels from both the main and touch screens. So NSData *gpuData = [[NSData alloc] init];
// depending on the display type, we copy only the pixels from the respective screen.
if (displayModeID == DS_DISPLAY_TYPE_MAIN) DisplaySrcPixelAttributes attr;
{ attr.videoSourceID = VIDEO_SOURCE_EMULATOR;
gpuData = [[NSData alloc] initWithBytes:GPU_screen length:GPU_SCREEN_SIZE_BYTES]; attr.displayModeID = (int32_t)displayModeID;
} attr.width = (uint16_t)displayFrameSize.width;
else if(displayModeID == DS_DISPLAY_TYPE_TOUCH) attr.height = (uint16_t)displayFrameSize.height;
{
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];
}
DisplaySrcPixelAttributes attr = {displayModeID, (size_t)displayFrameSize.width, (size_t)displayFrameSize.height};
NSData *attributesData = [[NSData alloc] initWithBytes:&attr length:sizeof(DisplaySrcPixelAttributes)]; NSData *attributesData = [[NSData alloc] initWithBytes:&attr length:sizeof(DisplaySrcPixelAttributes)];
NSArray *messageComponents = [[NSArray alloc] initWithObjects:gpuData, attributesData, nil]; NSArray *messageComponents = [[NSArray alloc] initWithObjects:gpuData, attributesData, nil];
[CocoaDSUtil messageSendOneWayWithMessageComponents:self.receivePort msgID:MESSAGE_EMU_FRAME_PROCESSED array:messageComponents]; [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]; [gpuData release];
[attributesData release]; [attributesData release];
[messageComponents release]; [messageComponents release];
@ -687,12 +678,12 @@
- (void) handleSetViewToBlack - (void) handleSetViewToBlack
{ {
[self fillVideoFrameWithColor:0x8000]; [self sendVideoFrameOfRGBA5551:0x8000];
} }
- (void) handleSetViewToWhite - (void) handleSetViewToWhite
{ {
[self fillVideoFrameWithColor:0xFFFF]; [self sendVideoFrameOfRGBA5551:0xFFFF];
} }
- (void) handleRequestScreenshot:(NSData *)fileURLStringData fileTypeData:(NSData *)fileTypeData - (void) handleRequestScreenshot:(NSData *)fileURLStringData fileTypeData:(NSData *)fileTypeData
@ -726,30 +717,52 @@
[pboard setData:[screenshot TIFFRepresentationUsingCompression:NSTIFFCompressionLZW factor:1.0f] forType:NSTIFFPboardType]; [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]; NSData *gpuData = nil;
const NSSize displayFrameSize = [self frameSize]; const size_t bufSize = pixCount * sizeof(uint16_t);
const size_t numberBytes = (displayModeID == DS_DISPLAY_TYPE_DUAL) ? GPU_SCREEN_SIZE_BYTES * 2 : GPU_SCREEN_SIZE_BYTES; uint16_t *gpuBytes = (uint16_t *)malloc(bufSize);
UInt16 *gpuBytes = (UInt16 *)malloc(numberBytes);
if (gpuBytes == NULL) if (gpuBytes == NULL)
{ {
return; return gpuData;
} }
const UInt16 colorValuePattern[] = {colorValue, colorValue, colorValue, colorValue, colorValue, colorValue, colorValue, colorValue}; if (pixCount % 16 == 0)
memset_pattern16(gpuBytes, colorValuePattern, numberBytes); {
NSData *gpuData = [[NSData alloc] initWithBytes:gpuBytes length:numberBytes]; 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); free(gpuBytes);
gpuBytes = nil; gpuBytes = nil;
DisplaySrcPixelAttributes attr = {displayModeID, (size_t)displayFrameSize.width, (size_t)displayFrameSize.height}; return gpuData;
NSData *attributesData = [[[NSData alloc] initWithBytes:&attr length:sizeof(DisplaySrcPixelAttributes)] autorelease]; }
[self handleEmuFrameProcessed:gpuData attributes:attributesData]; - (void) sendVideoFrameOfRGBA5551:(uint16_t)colorValue
[gpuData release]; {
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;
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 - (NSImage *) image
@ -899,13 +912,53 @@
return; return;
} }
const DisplaySrcPixelAttributes attr = *(DisplaySrcPixelAttributes *)[attributesData bytes]; NSData *newVideoFrame = mainData;
DisplaySrcPixelAttributes attr = *(DisplaySrcPixelAttributes *)[attributesData bytes];
const NSInteger frameDisplayMode = attr.displayModeID; const NSInteger frameDisplayMode = attr.displayModeID;
const NSInteger frameSource = attr.videoSourceID;
const NSInteger frameWidth = attr.width; const NSInteger frameWidth = attr.width;
const NSInteger frameHeight = attr.height; const NSInteger frameHeight = attr.height;
[(id<CocoaDSDisplayVideoDelegate>)delegate doProcessVideoFrame:[mainData bytes] displayMode:frameDisplayMode width:frameWidth height:frameHeight]; if (frameSource == VIDEO_SOURCE_EMULATOR)
[super handleEmuFrameProcessed:mainData attributes:attributesData]; {
// 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<CocoaDSDisplayVideoDelegate>)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 - (void) handleResizeView:(NSData *)rectData