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:
parent
608b9b3986
commit
f02a1e83ee
|
@ -14,6 +14,8 @@
|
|||
<real>1</real>
|
||||
<key>DisplayView_Deposterize</key>
|
||||
<false/>
|
||||
<key>DisplayView_FiltersPreferGPU</key>
|
||||
<true/>
|
||||
<key>DisplayView_Mode</key>
|
||||
<integer>2</integer>
|
||||
<key>DisplayView_OutputFilter</key>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<false>();
|
||||
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:
|
||||
{
|
||||
|
|
|
@ -462,6 +462,12 @@ enum
|
|||
DS_DISPLAY_TYPE_DUAL
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
VIDEO_SOURCE_INTERNAL = 0,
|
||||
VIDEO_SOURCE_EMULATOR = 1
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
DS_DISPLAY_ORIENTATION_VERTICAL = 0,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<CocoaDSDisplayVideoDelegate>)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<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
|
||||
|
|
Loading…
Reference in New Issue