Cocoa Port: Reduce threading overhead for framebuffer fetches and SPU_Emulate_user().
- Framebuffer fetches no longer run on a CocoaDSThread, but instead uses a pthread directly. This can be done since framebuffer fetching only serves one function and always receives the same execution message, making a full CocoaDSThread a waste. - SPU_Emulate_user() is no longer called on a separate thread, and instead is called in the emulation thread directly. For the typical SPU use case (SPU Sound Synchronization w/ Advanced SPU Logic), SPU_Emulator_user() becomes negligible, and so the threading overhead becomes unnecessary. In the use case where Dual SPU Synch/Asynch is used, Advanced SPU Logic is almost always disabled with it, and so the penalty of calling SPU_Emulator_user() on the emulation thread will be more than compensated by the performance increase of turning off Advanced SPU Logic. - Also do some code cleanup/refactoring here and there.
This commit is contained in:
parent
8f2c85fe86
commit
fda9fc2a89
|
@ -39,7 +39,7 @@ class GPUEventHandlerOSX;
|
|||
typedef std::map<CGDirectDisplayID, CVDisplayLinkRef> DisplayLinksActiveMap;
|
||||
typedef std::map<CGDirectDisplayID, int64_t> DisplayLinkFlushTimeLimitMap;
|
||||
|
||||
@interface MacClientSharedObject : CocoaDSThread
|
||||
@interface MacClientSharedObject : NSObject
|
||||
{
|
||||
GPUClientFetchObject *GPUFetchObject;
|
||||
pthread_rwlock_t *_rwlockFramebuffer[2];
|
||||
|
@ -50,6 +50,13 @@ typedef std::map<CGDirectDisplayID, int64_t> DisplayLinkFlushTimeLimitMap;
|
|||
|
||||
DisplayLinksActiveMap _displayLinksActiveList;
|
||||
DisplayLinkFlushTimeLimitMap _displayLinkFlushTimeList;
|
||||
|
||||
OSSpinLock spinlockFetchSignal;
|
||||
BOOL _isFetchSignalled;
|
||||
uint8_t _fetchIndex;
|
||||
pthread_t _threadFetch;
|
||||
pthread_cond_t _condSignalFetch;
|
||||
pthread_mutex_t _mutexFetchExecute;
|
||||
}
|
||||
|
||||
@property (assign, nonatomic) GPUClientFetchObject *GPUFetchObject;
|
||||
|
@ -69,6 +76,9 @@ typedef std::map<CGDirectDisplayID, int64_t> DisplayLinkFlushTimeLimitMap;
|
|||
- (void) displayLinkStartUsingID:(CGDirectDisplayID)displayID;
|
||||
- (void) displayLinkListUpdate;
|
||||
|
||||
- (void) signalFetchAtIndex:(uint8_t)index;
|
||||
- (void) runFetchLoop;
|
||||
|
||||
@end
|
||||
|
||||
@interface CocoaDSGPU : NSObject
|
||||
|
@ -131,6 +141,8 @@ extern "C"
|
|||
{
|
||||
#endif
|
||||
|
||||
static void* RunFetchThread(void *arg);
|
||||
|
||||
CVReturn MacDisplayLinkCallback(CVDisplayLinkRef displayLink,
|
||||
const CVTimeStamp *inNow,
|
||||
const CVTimeStamp *inOutputTime,
|
||||
|
|
|
@ -887,6 +887,13 @@ public:
|
|||
_displayLinkFlushTimeList.clear();
|
||||
[self displayLinkListUpdate];
|
||||
|
||||
spinlockFetchSignal = OS_SPINLOCK_INIT;
|
||||
_isFetchSignalled = NO;
|
||||
_fetchIndex = 0;
|
||||
pthread_cond_init(&_condSignalFetch, NULL);
|
||||
pthread_create(&_threadFetch, NULL, &RunFetchThread, self);
|
||||
pthread_mutex_init(&_mutexFetchExecute, NULL);
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(respondToScreenChange:)
|
||||
name:@"NSApplicationDidChangeScreenParametersNotification"
|
||||
|
@ -897,6 +904,13 @@ public:
|
|||
|
||||
- (void)dealloc
|
||||
{
|
||||
pthread_cancel(_threadFetch);
|
||||
pthread_join(_threadFetch, NULL);
|
||||
_threadFetch = NULL;
|
||||
|
||||
pthread_cond_destroy(&_condSignalFetch);
|
||||
pthread_mutex_destroy(&_mutexFetchExecute);
|
||||
|
||||
pthread_mutex_lock(&_mutexFlushVideo);
|
||||
|
||||
for (DisplayLinksActiveMap::iterator it = _displayLinksActiveList.begin(); it != _displayLinksActiveList.end(); ++it)
|
||||
|
@ -914,6 +928,7 @@ public:
|
|||
}
|
||||
|
||||
pthread_mutex_unlock(&_mutexFlushVideo);
|
||||
pthread_mutex_destroy(&_mutexFlushVideo);
|
||||
|
||||
pthread_mutex_t *currentMutex = _mutexOutputList;
|
||||
|
||||
|
@ -931,28 +946,10 @@ public:
|
|||
|
||||
pthread_rwlock_destroy(_rwlockFramebuffer[0]);
|
||||
pthread_rwlock_destroy(_rwlockFramebuffer[1]);
|
||||
pthread_mutex_destroy(&_mutexFlushVideo);
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void)handlePortMessage:(NSPortMessage *)portMessage
|
||||
{
|
||||
NSInteger message = (NSInteger)[portMessage msgid];
|
||||
NSArray *messageComponents = [portMessage components];
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case MESSAGE_FETCH_AND_PUSH_VIDEO:
|
||||
[self handleFetchFromBufferIndexAndPushVideo:[messageComponents objectAtIndex:0]];
|
||||
break;
|
||||
|
||||
default:
|
||||
[super handlePortMessage:portMessage];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void) handleFetchFromBufferIndexAndPushVideo:(NSData *)indexData
|
||||
{
|
||||
const NSInteger index = *(NSInteger *)[indexData bytes];
|
||||
|
@ -1013,7 +1010,7 @@ public:
|
|||
|
||||
for (CocoaDSOutput *cdsOutput in _cdsOutputList)
|
||||
{
|
||||
if ([cdsOutput isKindOfClass:[CocoaDSDisplay class]])
|
||||
if ([cdsOutput isKindOfClass:[CocoaDSDisplayVideo class]])
|
||||
{
|
||||
[CocoaDSUtil messageSendOneWay:[cdsOutput receivePort] msgID:MESSAGE_RECEIVE_GPU_FRAME];
|
||||
}
|
||||
|
@ -1036,9 +1033,9 @@ public:
|
|||
|
||||
for (CocoaDSOutput *cdsOutput in _cdsOutputList)
|
||||
{
|
||||
if ([cdsOutput isKindOfClass:[CocoaDSDisplay class]])
|
||||
if ([cdsOutput isKindOfClass:[CocoaDSDisplayVideo class]])
|
||||
{
|
||||
ClientDisplay3DView *cdv = [(CocoaDSDisplay *)cdsOutput clientDisplayView];
|
||||
ClientDisplay3DView *cdv = [(CocoaDSDisplayVideo *)cdsOutput clientDisplayView];
|
||||
cdv->FinishFrameAtIndex(bufferIndex);
|
||||
}
|
||||
}
|
||||
|
@ -1189,6 +1186,36 @@ public:
|
|||
pthread_mutex_unlock(&_mutexFlushVideo);
|
||||
}
|
||||
|
||||
- (void) signalFetchAtIndex:(uint8_t)index
|
||||
{
|
||||
pthread_mutex_lock(&_mutexFetchExecute);
|
||||
|
||||
_fetchIndex = index;
|
||||
_isFetchSignalled = YES;
|
||||
pthread_cond_signal(&_condSignalFetch);
|
||||
|
||||
pthread_mutex_unlock(&_mutexFetchExecute);
|
||||
}
|
||||
|
||||
- (void) runFetchLoop
|
||||
{
|
||||
do
|
||||
{
|
||||
pthread_mutex_lock(&_mutexFetchExecute);
|
||||
|
||||
while (!_isFetchSignalled)
|
||||
{
|
||||
pthread_cond_wait(&_condSignalFetch, &_mutexFetchExecute);
|
||||
}
|
||||
_isFetchSignalled = NO;
|
||||
|
||||
GPUFetchObject->FetchFromBufferIndex(_fetchIndex);
|
||||
[self pushVideoDataToAllDisplayViews];
|
||||
|
||||
pthread_mutex_unlock(&_mutexFetchExecute);
|
||||
} while(true);
|
||||
}
|
||||
|
||||
- (void) respondToScreenChange:(NSNotification *)aNotification
|
||||
{
|
||||
[self displayLinkListUpdate];
|
||||
|
@ -1256,7 +1283,7 @@ void GPUEventHandlerOSX::DidFrameEnd(bool isFrameSkipped, const NDSDisplayInfo &
|
|||
#if !defined(PORT_VERSION_OPENEMU)
|
||||
if (!isFrameSkipped)
|
||||
{
|
||||
[CocoaDSUtil messageSendOneWayWithInteger:[sharedViewObject receivePort] msgID:MESSAGE_FETCH_AND_PUSH_VIDEO integerValue:latestDisplayInfo.bufferIndex];
|
||||
[sharedViewObject signalFetchAtIndex:latestDisplayInfo.bufferIndex];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -1317,6 +1344,14 @@ CGLContextObj OSXOpenGLRendererContext = NULL;
|
|||
CGLPBufferObj OSXOpenGLRendererPBuffer = NULL;
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
static void* RunFetchThread(void *arg)
|
||||
{
|
||||
MacClientSharedObject *sharedData = (MacClientSharedObject *)arg;
|
||||
[sharedData runFetchLoop];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CVReturn MacDisplayLinkCallback(CVDisplayLinkRef displayLink,
|
||||
const CVTimeStamp *inNow,
|
||||
const CVTimeStamp *inOutputTime,
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "../../gdbstub.h"
|
||||
#include "../../slot1.h"
|
||||
#include "../../slot2.h"
|
||||
#include "../../SPU.h"
|
||||
#undef BOOL
|
||||
|
||||
// Need to include assert.h this way so that GDB stub will work
|
||||
|
@ -1031,6 +1032,7 @@ static void* RunCoreThread(void *arg)
|
|||
// Execute the frame and increment the frame counter.
|
||||
pthread_rwlock_wrlock(¶m->rwlockCoreExecute);
|
||||
NDS_exec<false>();
|
||||
SPU_Emulate_user();
|
||||
execControl->FetchOutputPostNDSExec();
|
||||
pthread_rwlock_unlock(¶m->rwlockCoreExecute);
|
||||
|
||||
|
@ -1069,7 +1071,7 @@ static void* RunCoreThread(void *arg)
|
|||
[(CocoaDSDisplay *)cdsOutput setNDSFrameInfo:ndsFrameInfo];
|
||||
}
|
||||
|
||||
if ( ![cdsOutput isKindOfClass:[CocoaDSDisplay class]] || (framesToSkip == 0) )
|
||||
if ( ![cdsOutput isKindOfClass:[CocoaDSSpeaker class]] && (![cdsOutput isKindOfClass:[CocoaDSDisplay class]] || (framesToSkip == 0)) )
|
||||
{
|
||||
[cdsOutput doCoreEmuFrame];
|
||||
}
|
||||
|
|
|
@ -96,10 +96,6 @@
|
|||
|
||||
@interface CocoaDSDisplay : CocoaDSOutput
|
||||
{
|
||||
ClientDisplay3DView *_cdv;
|
||||
ClientDisplayViewProperties _intermediateViewProps;
|
||||
NSSize displaySize;
|
||||
|
||||
uint32_t _receivedFrameIndex;
|
||||
uint32_t _currentReceivedFrameIndex;
|
||||
uint32_t _receivedFrameCount;
|
||||
|
@ -108,28 +104,21 @@
|
|||
|
||||
OSSpinLock spinlockReceivedFrameIndex;
|
||||
OSSpinLock spinlockNDSFrameInfo;
|
||||
OSSpinLock spinlockViewProperties;
|
||||
}
|
||||
|
||||
@property (assign, nonatomic) ClientDisplay3DView *clientDisplayView;
|
||||
@property (readonly) NSSize displaySize;
|
||||
|
||||
- (void) commitViewProperties:(const ClientDisplayViewProperties &)viewProps;
|
||||
|
||||
- (void) handleReceiveGPUFrame;
|
||||
- (void) handleChangeViewProperties;
|
||||
- (void) handleRequestScreenshot:(NSData *)fileURLStringData fileTypeData:(NSData *)fileTypeData;
|
||||
- (void) handleCopyToPasteboard;
|
||||
|
||||
- (void) takeFrameCount;
|
||||
- (void) setNDSFrameInfo:(const NDSFrameInfo &)ndsFrameInfo;
|
||||
- (NSImage *) image;
|
||||
- (NSBitmapImageRep *) bitmapImageRep;
|
||||
|
||||
@end
|
||||
|
||||
@interface CocoaDSDisplayVideo : CocoaDSDisplay
|
||||
{
|
||||
ClientDisplay3DView *_cdv;
|
||||
ClientDisplayViewProperties _intermediateViewProps;
|
||||
|
||||
OSSpinLock spinlockViewProperties;
|
||||
OSSpinLock spinlockIsHUDVisible;
|
||||
OSSpinLock spinlockUseVerticalSync;
|
||||
OSSpinLock spinlockVideoFiltersPreferGPU;
|
||||
|
@ -140,6 +129,7 @@
|
|||
OSSpinLock spinlockDisplayID;
|
||||
}
|
||||
|
||||
@property (assign, nonatomic) ClientDisplay3DView *clientDisplayView;
|
||||
@property (readonly, nonatomic) BOOL canFilterOnGPU;
|
||||
@property (readonly, nonatomic) BOOL willFilterOnGPU;
|
||||
@property (assign) BOOL isHUDVisible;
|
||||
|
@ -168,12 +158,19 @@
|
|||
@property (assign) NSInteger outputFilter;
|
||||
@property (assign) NSInteger pixelScaler;
|
||||
|
||||
- (void) commitViewProperties:(const ClientDisplayViewProperties &)viewProps;
|
||||
|
||||
- (void) handleChangeViewProperties;
|
||||
- (void) handleReceiveGPUFrame;
|
||||
- (void) handleReloadReprocessRedraw;
|
||||
- (void) handleReprocessRedraw;
|
||||
- (void) handleRedraw;
|
||||
- (void) handleCopyToPasteboard;
|
||||
- (void) handleRequestScreenshot:(NSData *)fileURLStringData fileTypeData:(NSData *)fileTypeData;
|
||||
|
||||
- (void) setScaleFactor:(float)theScaleFactor;
|
||||
- (void) hudUpdate;
|
||||
- (NSImage *) image;
|
||||
- (NSBitmapImageRep *) bitmapImageRep;
|
||||
|
||||
@end
|
||||
|
|
|
@ -501,9 +501,6 @@
|
|||
|
||||
@implementation CocoaDSDisplay
|
||||
|
||||
@dynamic clientDisplayView;
|
||||
@dynamic displaySize;
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
|
@ -514,9 +511,7 @@
|
|||
|
||||
spinlockReceivedFrameIndex = OS_SPINLOCK_INIT;
|
||||
spinlockNDSFrameInfo = OS_SPINLOCK_INIT;
|
||||
spinlockViewProperties = OS_SPINLOCK_INIT;
|
||||
|
||||
_cdv = NULL;
|
||||
_ndsFrameInfo.clear();
|
||||
|
||||
_receivedFrameIndex = 0;
|
||||
|
@ -531,38 +526,9 @@
|
|||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void) setClientDisplayView:(ClientDisplay3DView *)clientDisplayView
|
||||
{
|
||||
_cdv = clientDisplayView;
|
||||
}
|
||||
|
||||
- (ClientDisplay3DView *) clientDisplayView
|
||||
{
|
||||
return _cdv;
|
||||
}
|
||||
|
||||
- (void) commitViewProperties:(const ClientDisplayViewProperties &)viewProps
|
||||
{
|
||||
OSSpinLockLock(&spinlockViewProperties);
|
||||
_intermediateViewProps = viewProps;
|
||||
OSSpinLockUnlock(&spinlockViewProperties);
|
||||
|
||||
[self handleChangeViewProperties];
|
||||
}
|
||||
|
||||
- (NSSize) displaySize
|
||||
{
|
||||
pthread_rwlock_rdlock(self.rwlockProducer);
|
||||
NSSize size = NSMakeSize((CGFloat)GPU->GetCustomFramebufferWidth(), (_cdv->GetMode() == ClientDisplayMode_Dual) ? (CGFloat)(GPU->GetCustomFramebufferHeight() * 2): (CGFloat)GPU->GetCustomFramebufferHeight());
|
||||
pthread_rwlock_unlock(self.rwlockProducer);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
- (void)handlePortMessage:(NSPortMessage *)portMessage
|
||||
{
|
||||
NSInteger message = (NSInteger)[portMessage msgid];
|
||||
NSArray *messageComponents = [portMessage components];
|
||||
|
||||
switch (message)
|
||||
{
|
||||
|
@ -570,18 +536,6 @@
|
|||
[self handleReceiveGPUFrame];
|
||||
break;
|
||||
|
||||
case MESSAGE_CHANGE_VIEW_PROPERTIES:
|
||||
[self handleChangeViewProperties];
|
||||
break;
|
||||
|
||||
case MESSAGE_REQUEST_SCREENSHOT:
|
||||
[self handleRequestScreenshot:[messageComponents objectAtIndex:0] fileTypeData:[messageComponents objectAtIndex:1]];
|
||||
break;
|
||||
|
||||
case MESSAGE_COPY_TO_PASTEBOARD:
|
||||
[self handleCopyToPasteboard];
|
||||
break;
|
||||
|
||||
default:
|
||||
[super handlePortMessage:portMessage];
|
||||
break;
|
||||
|
@ -595,46 +549,6 @@
|
|||
OSSpinLockUnlock(&spinlockReceivedFrameIndex);
|
||||
}
|
||||
|
||||
- (void) handleChangeViewProperties
|
||||
{
|
||||
OSSpinLockLock(&spinlockViewProperties);
|
||||
_cdv->CommitViewProperties(_intermediateViewProps);
|
||||
OSSpinLockUnlock(&spinlockViewProperties);
|
||||
|
||||
_cdv->SetupViewProperties();
|
||||
}
|
||||
|
||||
- (void) handleRequestScreenshot:(NSData *)fileURLStringData fileTypeData:(NSData *)fileTypeData
|
||||
{
|
||||
NSString *fileURLString = [[NSString alloc] initWithData:fileURLStringData encoding:NSUTF8StringEncoding];
|
||||
NSURL *fileURL = [NSURL URLWithString:fileURLString];
|
||||
NSBitmapImageFileType fileType = *(NSBitmapImageFileType *)[fileTypeData bytes];
|
||||
|
||||
NSDictionary *userInfo = [[NSDictionary alloc] initWithObjectsAndKeys:
|
||||
fileURL, @"fileURL",
|
||||
[NSNumber numberWithInteger:(NSInteger)fileType], @"fileType",
|
||||
[self image], @"screenshotImage",
|
||||
nil];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:@"org.desmume.DeSmuME.requestScreenshotDidFinish" object:self userInfo:userInfo];
|
||||
[userInfo release];
|
||||
|
||||
[fileURLString release];
|
||||
}
|
||||
|
||||
- (void) handleCopyToPasteboard
|
||||
{
|
||||
NSImage *screenshot = [self image];
|
||||
if (screenshot == nil)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
NSPasteboard *pboard = [NSPasteboard generalPasteboard];
|
||||
[pboard declareTypes:[NSArray arrayWithObjects:NSTIFFPboardType, nil] owner:self];
|
||||
[pboard setData:[screenshot TIFFRepresentationUsingCompression:NSTIFFCompressionLZW factor:1.0f] forType:NSTIFFPboardType];
|
||||
}
|
||||
|
||||
- (void) takeFrameCount
|
||||
{
|
||||
OSSpinLockLock(&spinlockReceivedFrameIndex);
|
||||
|
@ -650,88 +564,11 @@
|
|||
OSSpinLockUnlock(&spinlockNDSFrameInfo);
|
||||
}
|
||||
|
||||
- (NSImage *) image
|
||||
{
|
||||
NSImage *newImage = [[NSImage alloc] initWithSize:[self displaySize]];
|
||||
if (newImage == nil)
|
||||
{
|
||||
return newImage;
|
||||
}
|
||||
|
||||
// Render the frame in an NSBitmapImageRep
|
||||
NSBitmapImageRep *newImageRep = [self bitmapImageRep];
|
||||
if (newImageRep == nil)
|
||||
{
|
||||
[newImage release];
|
||||
newImage = nil;
|
||||
return newImage;
|
||||
}
|
||||
|
||||
// Attach the rendered frame to the NSImageRep
|
||||
[newImage addRepresentation:newImageRep];
|
||||
|
||||
return [newImage autorelease];
|
||||
}
|
||||
|
||||
- (NSBitmapImageRep *) bitmapImageRep
|
||||
{
|
||||
GPUClientFetchObject &fetchObjMutable = (GPUClientFetchObject &)_cdv->GetFetchObject();
|
||||
NDSDisplayInfo &displayInfoMutable = (NDSDisplayInfo &)fetchObjMutable.GetFetchDisplayInfoForBufferIndex(fetchObjMutable.GetLastFetchIndex());
|
||||
|
||||
NSUInteger w = (NSUInteger)displayInfoMutable.customWidth;
|
||||
NSUInteger h = (_cdv->GetMode() == ClientDisplayMode_Dual) ? (NSUInteger)(displayInfoMutable.customHeight * 2) : (NSUInteger)displayInfoMutable.customHeight;
|
||||
|
||||
NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
|
||||
pixelsWide:w
|
||||
pixelsHigh:h
|
||||
bitsPerSample:8
|
||||
samplesPerPixel:4
|
||||
hasAlpha:YES
|
||||
isPlanar:NO
|
||||
colorSpaceName:NSCalibratedRGBColorSpace
|
||||
bytesPerRow:w * 4
|
||||
bitsPerPixel:32];
|
||||
|
||||
if(imageRep == nil)
|
||||
{
|
||||
return imageRep;
|
||||
}
|
||||
|
||||
void *displayBuffer = displayInfoMutable.masterCustomBuffer;
|
||||
uint32_t *bitmapData = (uint32_t *)[imageRep bitmapData];
|
||||
|
||||
pthread_rwlock_wrlock(self.rwlockProducer);
|
||||
|
||||
GPU->PostprocessDisplay(NDSDisplayID_Main, displayInfoMutable);
|
||||
GPU->PostprocessDisplay(NDSDisplayID_Touch, displayInfoMutable);
|
||||
GPU->ResolveDisplayToCustomFramebuffer(NDSDisplayID_Main, displayInfoMutable);
|
||||
GPU->ResolveDisplayToCustomFramebuffer(NDSDisplayID_Touch, displayInfoMutable);
|
||||
|
||||
if (displayInfoMutable.pixelBytes == 2)
|
||||
{
|
||||
ColorspaceConvertBuffer555To8888Opaque<false, true>((u16 *)displayBuffer, bitmapData, (w * h));
|
||||
}
|
||||
else if (displayInfoMutable.pixelBytes == 4)
|
||||
{
|
||||
memcpy(bitmapData, displayBuffer, w * h * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
pthread_rwlock_unlock(self.rwlockProducer);
|
||||
|
||||
#ifdef MSB_FIRST
|
||||
for (size_t i = 0; i < w * h; i++)
|
||||
{
|
||||
bitmapData[i] = LE_TO_LOCAL_32(bitmapData[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
return [imageRep autorelease];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CocoaDSDisplayVideo
|
||||
|
||||
@dynamic clientDisplayView;
|
||||
@dynamic canFilterOnGPU;
|
||||
@dynamic willFilterOnGPU;
|
||||
@dynamic isHUDVisible;
|
||||
|
@ -768,6 +605,9 @@
|
|||
return self;
|
||||
}
|
||||
|
||||
_cdv = NULL;
|
||||
|
||||
spinlockViewProperties = OS_SPINLOCK_INIT;
|
||||
spinlockIsHUDVisible = OS_SPINLOCK_INIT;
|
||||
spinlockUseVerticalSync = OS_SPINLOCK_INIT;
|
||||
spinlockVideoFiltersPreferGPU = OS_SPINLOCK_INIT;
|
||||
|
@ -785,6 +625,25 @@
|
|||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void) setClientDisplayView:(ClientDisplay3DView *)clientDisplayView
|
||||
{
|
||||
_cdv = clientDisplayView;
|
||||
}
|
||||
|
||||
- (ClientDisplay3DView *) clientDisplayView
|
||||
{
|
||||
return _cdv;
|
||||
}
|
||||
|
||||
- (void) commitViewProperties:(const ClientDisplayViewProperties &)viewProps
|
||||
{
|
||||
OSSpinLockLock(&spinlockViewProperties);
|
||||
_intermediateViewProps = viewProps;
|
||||
OSSpinLockUnlock(&spinlockViewProperties);
|
||||
|
||||
[self handleChangeViewProperties];
|
||||
}
|
||||
|
||||
- (BOOL) canFilterOnGPU
|
||||
{
|
||||
return (_cdv->CanFilterOnGPU()) ? YES : NO;
|
||||
|
@ -1198,9 +1057,14 @@
|
|||
- (void)handlePortMessage:(NSPortMessage *)portMessage
|
||||
{
|
||||
NSInteger message = (NSInteger)[portMessage msgid];
|
||||
NSArray *messageComponents = [portMessage components];
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case MESSAGE_CHANGE_VIEW_PROPERTIES:
|
||||
[self handleChangeViewProperties];
|
||||
break;
|
||||
|
||||
case MESSAGE_RELOAD_REPROCESS_REDRAW:
|
||||
[self handleReloadReprocessRedraw];
|
||||
break;
|
||||
|
@ -1213,6 +1077,14 @@
|
|||
[self handleRedraw];
|
||||
break;
|
||||
|
||||
case MESSAGE_COPY_TO_PASTEBOARD:
|
||||
[self handleCopyToPasteboard];
|
||||
break;
|
||||
|
||||
case MESSAGE_REQUEST_SCREENSHOT:
|
||||
[self handleRequestScreenshot:[messageComponents objectAtIndex:0] fileTypeData:[messageComponents objectAtIndex:1]];
|
||||
break;
|
||||
|
||||
default:
|
||||
[super handlePortMessage:portMessage];
|
||||
break;
|
||||
|
@ -1226,6 +1098,15 @@
|
|||
_cdv->HandleEmulatorFrameEndEvent();
|
||||
}
|
||||
|
||||
- (void) handleChangeViewProperties
|
||||
{
|
||||
OSSpinLockLock(&spinlockViewProperties);
|
||||
_cdv->CommitViewProperties(_intermediateViewProps);
|
||||
OSSpinLockUnlock(&spinlockViewProperties);
|
||||
|
||||
_cdv->SetupViewProperties();
|
||||
}
|
||||
|
||||
- (void) handleReceiveGPUFrame
|
||||
{
|
||||
[super handleReceiveGPUFrame];
|
||||
|
@ -1257,6 +1138,37 @@
|
|||
_cdv->UpdateView();
|
||||
}
|
||||
|
||||
- (void) handleCopyToPasteboard
|
||||
{
|
||||
NSImage *screenshot = [self image];
|
||||
if (screenshot == nil)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
NSPasteboard *pboard = [NSPasteboard generalPasteboard];
|
||||
[pboard declareTypes:[NSArray arrayWithObjects:NSTIFFPboardType, nil] owner:self];
|
||||
[pboard setData:[screenshot TIFFRepresentationUsingCompression:NSTIFFCompressionLZW factor:1.0f] forType:NSTIFFPboardType];
|
||||
}
|
||||
|
||||
- (void) handleRequestScreenshot:(NSData *)fileURLStringData fileTypeData:(NSData *)fileTypeData
|
||||
{
|
||||
NSString *fileURLString = [[NSString alloc] initWithData:fileURLStringData encoding:NSUTF8StringEncoding];
|
||||
NSURL *fileURL = [NSURL URLWithString:fileURLString];
|
||||
NSBitmapImageFileType fileType = *(NSBitmapImageFileType *)[fileTypeData bytes];
|
||||
|
||||
NSDictionary *userInfo = [[NSDictionary alloc] initWithObjectsAndKeys:
|
||||
fileURL, @"fileURL",
|
||||
[NSNumber numberWithInteger:(NSInteger)fileType], @"fileType",
|
||||
[self image], @"screenshotImage",
|
||||
nil];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:@"org.desmume.DeSmuME.requestScreenshotDidFinish" object:self userInfo:userInfo];
|
||||
[userInfo release];
|
||||
|
||||
[fileURLString release];
|
||||
}
|
||||
|
||||
- (void) setScaleFactor:(float)theScaleFactor
|
||||
{
|
||||
OSSpinLockLock(&spinlockIsHUDVisible);
|
||||
|
@ -1276,4 +1188,86 @@
|
|||
OSSpinLockUnlock(&spinlockNDSFrameInfo);
|
||||
}
|
||||
|
||||
- (NSImage *) image
|
||||
{
|
||||
pthread_rwlock_rdlock(self.rwlockProducer);
|
||||
NSSize displaySize = NSMakeSize((CGFloat)GPU->GetCustomFramebufferWidth(), (_cdv->GetMode() == ClientDisplayMode_Dual) ? (CGFloat)(GPU->GetCustomFramebufferHeight() * 2): (CGFloat)GPU->GetCustomFramebufferHeight());
|
||||
pthread_rwlock_unlock(self.rwlockProducer);
|
||||
|
||||
NSImage *newImage = [[NSImage alloc] initWithSize:displaySize];
|
||||
if (newImage == nil)
|
||||
{
|
||||
return newImage;
|
||||
}
|
||||
|
||||
// Render the frame in an NSBitmapImageRep
|
||||
NSBitmapImageRep *newImageRep = [self bitmapImageRep];
|
||||
if (newImageRep == nil)
|
||||
{
|
||||
[newImage release];
|
||||
newImage = nil;
|
||||
return newImage;
|
||||
}
|
||||
|
||||
// Attach the rendered frame to the NSImageRep
|
||||
[newImage addRepresentation:newImageRep];
|
||||
|
||||
return [newImage autorelease];
|
||||
}
|
||||
|
||||
- (NSBitmapImageRep *) bitmapImageRep
|
||||
{
|
||||
GPUClientFetchObject &fetchObjMutable = (GPUClientFetchObject &)_cdv->GetFetchObject();
|
||||
NDSDisplayInfo &displayInfoMutable = (NDSDisplayInfo &)fetchObjMutable.GetFetchDisplayInfoForBufferIndex(fetchObjMutable.GetLastFetchIndex());
|
||||
|
||||
NSUInteger w = (NSUInteger)displayInfoMutable.customWidth;
|
||||
NSUInteger h = (_cdv->GetMode() == ClientDisplayMode_Dual) ? (NSUInteger)(displayInfoMutable.customHeight * 2) : (NSUInteger)displayInfoMutable.customHeight;
|
||||
|
||||
NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
|
||||
pixelsWide:w
|
||||
pixelsHigh:h
|
||||
bitsPerSample:8
|
||||
samplesPerPixel:4
|
||||
hasAlpha:YES
|
||||
isPlanar:NO
|
||||
colorSpaceName:NSCalibratedRGBColorSpace
|
||||
bytesPerRow:w * 4
|
||||
bitsPerPixel:32];
|
||||
|
||||
if (imageRep == nil)
|
||||
{
|
||||
return imageRep;
|
||||
}
|
||||
|
||||
void *displayBuffer = displayInfoMutable.masterCustomBuffer;
|
||||
uint32_t *bitmapData = (uint32_t *)[imageRep bitmapData];
|
||||
|
||||
pthread_rwlock_wrlock(self.rwlockProducer);
|
||||
|
||||
GPU->PostprocessDisplay(NDSDisplayID_Main, displayInfoMutable);
|
||||
GPU->PostprocessDisplay(NDSDisplayID_Touch, displayInfoMutable);
|
||||
GPU->ResolveDisplayToCustomFramebuffer(NDSDisplayID_Main, displayInfoMutable);
|
||||
GPU->ResolveDisplayToCustomFramebuffer(NDSDisplayID_Touch, displayInfoMutable);
|
||||
|
||||
if (displayInfoMutable.pixelBytes == 2)
|
||||
{
|
||||
ColorspaceConvertBuffer555To8888Opaque<false, true>((u16 *)displayBuffer, bitmapData, (w * h));
|
||||
}
|
||||
else if (displayInfoMutable.pixelBytes == 4)
|
||||
{
|
||||
memcpy(bitmapData, displayBuffer, w * h * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
pthread_rwlock_unlock(self.rwlockProducer);
|
||||
|
||||
#ifdef MSB_FIRST
|
||||
for (size_t i = 0; i < w * h; i++)
|
||||
{
|
||||
bitmapData[i] = LE_TO_LOCAL_32(bitmapData[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
return [imageRep autorelease];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -1323,7 +1323,7 @@ static std::unordered_map<NSScreen *, DisplayWindowController *> _screenMap; //
|
|||
|
||||
// Set up the video output thread.
|
||||
CocoaDSDisplayVideo *newDisplayOutput = [[[CocoaDSDisplayVideo alloc] init] autorelease];
|
||||
[newDisplayOutput setClientDisplayView:[view clientDisplay3DView]];
|
||||
[newDisplayOutput setClientDisplayView:[newView clientDisplay3DView]];
|
||||
|
||||
ClientDisplayView *cdv = [newDisplayOutput clientDisplayView];
|
||||
NSString *fontPath = [[NSBundle mainBundle] pathForResource:@"SourceSansPro-Bold" ofType:@"otf"];
|
||||
|
|
|
@ -810,32 +810,32 @@
|
|||
{
|
||||
const float vol = [self currentVolumeValue];
|
||||
[self setCurrentVolumeValue:vol];
|
||||
[CocoaDSUtil messageSendOneWayWithFloat:[cdsSpeaker receivePort] msgID:MESSAGE_SET_VOLUME floatValue:vol];
|
||||
[[self cdsSpeaker] setVolume:vol];
|
||||
}
|
||||
|
||||
- (IBAction) changeAudioEngine:(id)sender
|
||||
{
|
||||
[CocoaDSUtil messageSendOneWayWithInteger:[cdsSpeaker receivePort] msgID:MESSAGE_SET_AUDIO_PROCESS_METHOD integerValue:[CocoaDSUtil getIBActionSenderTag:sender]];
|
||||
[[self cdsSpeaker] setAudioOutputEngine:[CocoaDSUtil getIBActionSenderTag:sender]];
|
||||
}
|
||||
|
||||
- (IBAction) changeSpuAdvancedLogic:(id)sender
|
||||
{
|
||||
[CocoaDSUtil messageSendOneWayWithBool:[cdsSpeaker receivePort] msgID:MESSAGE_SET_SPU_ADVANCED_LOGIC boolValue:[CocoaDSUtil getIBActionSenderButtonStateBool:sender]];
|
||||
[[self cdsSpeaker] setSpuAdvancedLogic:[CocoaDSUtil getIBActionSenderButtonStateBool:sender]];
|
||||
}
|
||||
|
||||
- (IBAction) changeSpuInterpolationMode:(id)sender
|
||||
{
|
||||
[CocoaDSUtil messageSendOneWayWithInteger:[cdsSpeaker receivePort] msgID:MESSAGE_SET_SPU_INTERPOLATION_MODE integerValue:[CocoaDSUtil getIBActionSenderTag:sender]];
|
||||
[[self cdsSpeaker] setSpuInterpolationMode:[CocoaDSUtil getIBActionSenderTag:sender]];
|
||||
}
|
||||
|
||||
- (IBAction) changeSpuSyncMode:(id)sender
|
||||
{
|
||||
[CocoaDSUtil messageSendOneWayWithInteger:[cdsSpeaker receivePort] msgID:MESSAGE_SET_SPU_SYNC_MODE integerValue:[CocoaDSUtil getIBActionSenderTag:sender]];
|
||||
[[self cdsSpeaker] setSpuSyncMode:[CocoaDSUtil getIBActionSenderTag:sender]];
|
||||
}
|
||||
|
||||
- (IBAction) changeSpuSyncMethod:(id)sender
|
||||
{
|
||||
[CocoaDSUtil messageSendOneWayWithInteger:[cdsSpeaker receivePort] msgID:MESSAGE_SET_SPU_SYNC_METHOD integerValue:[CocoaDSUtil getIBActionSenderTag:sender]];
|
||||
[[self cdsSpeaker] setSpuSyncMethod:[CocoaDSUtil getIBActionSenderTag:sender]];
|
||||
}
|
||||
|
||||
- (IBAction) toggleAllDisplays:(id)sender
|
||||
|
@ -1533,7 +1533,7 @@
|
|||
}
|
||||
|
||||
[self setCurrentVolumeValue:vol];
|
||||
[CocoaDSUtil messageSendOneWayWithFloat:[cdsSpeaker receivePort] msgID:MESSAGE_SET_VOLUME floatValue:vol];
|
||||
[[self cdsSpeaker] setVolume:vol];
|
||||
}
|
||||
|
||||
- (void) cmdToggleGPUState:(NSValue *)cmdAttrValue
|
||||
|
|
|
@ -1127,7 +1127,7 @@
|
|||
{
|
||||
const VideoFilterAttributes vfAttr = VideoFilter::GetAttributesByID(filterID);
|
||||
|
||||
id<MTLCommandBuffer> cb = [[sharedData commandQueue] commandBufferWithUnretainedReferences];
|
||||
id<MTLCommandBuffer> cb = [self newCommandBuffer];
|
||||
id<MTLBlitCommandEncoder> dummyEncoder = [cb blitCommandEncoder];
|
||||
[dummyEncoder endEncoding];
|
||||
[cb commit];
|
||||
|
@ -1145,7 +1145,7 @@
|
|||
options:MTLResourceStorageModeManaged
|
||||
deallocator:nil]];
|
||||
|
||||
cb = [[sharedData commandQueue] commandBufferWithUnretainedReferences];
|
||||
cb = [self newCommandBuffer];
|
||||
dummyEncoder = [cb blitCommandEncoder];
|
||||
[dummyEncoder endEncoding];
|
||||
[cb commit];
|
||||
|
@ -1285,7 +1285,7 @@
|
|||
VideoFilter *vfMain = _cdv->GetPixelScalerObject(NDSDisplayID_Main);
|
||||
VideoFilter *vfTouch = _cdv->GetPixelScalerObject(NDSDisplayID_Touch);
|
||||
|
||||
id<MTLCommandBuffer> cb = [[sharedData commandQueue] commandBufferWithUnretainedReferences];
|
||||
id<MTLCommandBuffer> cb = [self newCommandBuffer];
|
||||
id<MTLComputeCommandEncoder> cce = [cb computeCommandEncoder];
|
||||
|
||||
// Run the video source filters and the pixel scalers
|
||||
|
@ -1591,7 +1591,7 @@
|
|||
// Now that everything is set up, go ahead and draw everything.
|
||||
id<CAMetalDrawable> layerDrawable = [self nextDrawable];
|
||||
[colorAttachment0Desc setTexture:[layerDrawable texture]];
|
||||
id<MTLCommandBuffer> cb = [[sharedData commandQueue] commandBufferWithUnretainedReferences];
|
||||
id<MTLCommandBuffer> cb = [self newCommandBuffer];
|
||||
id<MTLRenderCommandEncoder> ce = [cb renderCommandEncoderWithDescriptor:_outputRenderPassDesc];
|
||||
|
||||
if (_needEncodeViewport)
|
||||
|
@ -1804,8 +1804,11 @@ void MacMetalFetchObject::FetchFromBufferIndex(const u8 index)
|
|||
MacClientSharedObject *sharedViewObject = (MacClientSharedObject *)this->_clientData;
|
||||
this->_useDirectToCPUFilterPipeline = ([sharedViewObject numberViewsUsingDirectToCPUFiltering] > 0);
|
||||
|
||||
@autoreleasepool
|
||||
{
|
||||
[(MetalDisplayViewSharedData *)this->_clientData fetchFromBufferIndex:index];
|
||||
}
|
||||
}
|
||||
|
||||
void MacMetalFetchObject::_FetchNativeDisplayByID(const NDSDisplayID displayID, const u8 bufferIndex)
|
||||
{
|
||||
|
|
|
@ -183,13 +183,6 @@
|
|||
|
||||
// Init the DS emulation core.
|
||||
CocoaDSCore *newCore = [[[CocoaDSCore alloc] init] autorelease];
|
||||
MacClientSharedObject *sharedViewObject = [[newCore cdsGPU] sharedData];
|
||||
|
||||
[NSThread detachNewThreadSelector:@selector(runThread:) toTarget:sharedViewObject withObject:nil];
|
||||
while ([sharedViewObject thread] == nil)
|
||||
{
|
||||
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01]];
|
||||
}
|
||||
|
||||
// Init the DS controller.
|
||||
[[newCore cdsController] setDelegate:emuControl];
|
||||
|
@ -205,13 +198,6 @@
|
|||
[slot2WindowDelegate setHidManager:[inputManager hidManager]];
|
||||
[slot2WindowDelegate setAutoSelectedDeviceText:[[slot2WindowDelegate deviceManager] autoSelectedDeviceName]];
|
||||
|
||||
// Start up the threads for our outputs.
|
||||
[NSThread detachNewThreadSelector:@selector(runThread:) toTarget:newSpeaker withObject:nil];
|
||||
while ([newSpeaker thread] == nil)
|
||||
{
|
||||
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01]];
|
||||
}
|
||||
|
||||
// Set up all the object controllers.
|
||||
[cdsCoreController setContent:newCore];
|
||||
[romInfoPanelController setContent:[CocoaDSRom romNotLoadedBindings]];
|
||||
|
|
Loading…
Reference in New Issue