Cocoa Port: Rework how Metal display views flush to screen, improving their overall performance.
- Fix a bug where Metal display views can block emulation execution if the user very quickly spams inputs while the input HUD is shown. - Metal display views are no longer frame capped -- they can now run to their fullest performance potential, as fast as the host hardware will allow. This behavior is now consistent with OpenGL display views. - As a side-effect, non-layer backed OpenGL display views also have a performance improvement.
This commit is contained in:
parent
759a039e25
commit
4957d7be5b
|
@ -81,6 +81,7 @@ void ClientDisplayView::__InstanceInit(const ClientDisplayViewProperties &props)
|
|||
_selectedSourceForDisplay[NDSDisplayID_Main] = NDSDisplayID_Main;
|
||||
_selectedSourceForDisplay[NDSDisplayID_Touch] = NDSDisplayID_Touch;
|
||||
|
||||
_displayViewID = 0;
|
||||
_useVerticalSync = false;
|
||||
_scaleFactor = 1.0;
|
||||
|
||||
|
@ -112,7 +113,9 @@ void ClientDisplayView::__InstanceInit(const ClientDisplayViewProperties &props)
|
|||
_outHudString = _hudString;
|
||||
_hudInputString = "<^>vABXYLRSsgf x:000 y:000";
|
||||
_hudNeedsUpdate = true;
|
||||
_viewNeedsFlush = false;
|
||||
_allowViewUpdates = true;
|
||||
_allowViewFlushes = true;
|
||||
|
||||
FT_Error error = FT_Init_FreeType(&_ftLibrary);
|
||||
if (error)
|
||||
|
@ -225,6 +228,22 @@ void ClientDisplayView::Init()
|
|||
// Do nothing. This is implementation dependent.
|
||||
}
|
||||
|
||||
int64_t ClientDisplayView::GetDisplayViewID()
|
||||
{
|
||||
return this->_displayViewID;
|
||||
}
|
||||
|
||||
void ClientDisplayView::SetDisplayViewID(int64_t displayViewID)
|
||||
{
|
||||
// This implementation-dependent value will never be used internally.
|
||||
this->_displayViewID = displayViewID;
|
||||
}
|
||||
|
||||
bool ClientDisplayView::GetViewNeedsFlush()
|
||||
{
|
||||
return this->_viewNeedsFlush;
|
||||
}
|
||||
|
||||
bool ClientDisplayView::GetUseVerticalSync() const
|
||||
{
|
||||
return this->_useVerticalSync;
|
||||
|
@ -809,11 +828,21 @@ bool ClientDisplayView::GetAllowViewUpdates() const
|
|||
return this->_allowViewUpdates;
|
||||
}
|
||||
|
||||
void ClientDisplayView::SetAllowViewUpdates(const bool allowUpdates)
|
||||
void ClientDisplayView::SetAllowViewUpdates(bool allowUpdates)
|
||||
{
|
||||
this->_allowViewUpdates = allowUpdates;
|
||||
}
|
||||
|
||||
bool ClientDisplayView::GetAllowViewFlushes() const
|
||||
{
|
||||
return this->_allowViewFlushes;
|
||||
}
|
||||
|
||||
void ClientDisplayView::SetAllowViewFlushes(bool allowFlushes)
|
||||
{
|
||||
this->_allowViewFlushes = allowFlushes;
|
||||
}
|
||||
|
||||
void ClientDisplayView::_LoadNativeDisplayByID(const NDSDisplayID displayID)
|
||||
{
|
||||
// Do nothing. This is implementation dependent.
|
||||
|
@ -979,6 +1008,13 @@ void ClientDisplayView::ProcessDisplays()
|
|||
void ClientDisplayView::UpdateView()
|
||||
{
|
||||
// Do nothing. This is implementation dependent.
|
||||
this->_viewNeedsFlush = true;
|
||||
}
|
||||
|
||||
void ClientDisplayView::FlushView()
|
||||
{
|
||||
// Do nothing. This is implementation dependent.
|
||||
this->_viewNeedsFlush = false;
|
||||
}
|
||||
|
||||
void ClientDisplayView::FinishFrameAtIndex(const u8 bufferIndex)
|
||||
|
|
|
@ -152,6 +152,7 @@ protected:
|
|||
bool _isSelectedDisplayEnabled[2];
|
||||
NDSDisplayID _selectedSourceForDisplay[2];
|
||||
|
||||
int64_t _displayViewID;
|
||||
bool _useVerticalSync;
|
||||
double _scaleFactor;
|
||||
|
||||
|
@ -183,7 +184,9 @@ protected:
|
|||
std::string _hudInputString;
|
||||
std::string _outHudString;
|
||||
bool _hudNeedsUpdate;
|
||||
bool _viewNeedsFlush;
|
||||
bool _allowViewUpdates;
|
||||
bool _allowViewFlushes;
|
||||
|
||||
FT_Library _ftLibrary;
|
||||
const char *_lastFontFilePath;
|
||||
|
@ -218,6 +221,11 @@ public:
|
|||
|
||||
virtual void Init();
|
||||
|
||||
int64_t GetDisplayViewID();
|
||||
virtual void SetDisplayViewID(int64_t displayViewID);
|
||||
|
||||
virtual bool GetViewNeedsFlush();
|
||||
|
||||
bool GetUseVerticalSync() const;
|
||||
virtual void SetUseVerticalSync(const bool useVerticalSync);
|
||||
double GetScaleFactor() const;
|
||||
|
@ -304,11 +312,14 @@ public:
|
|||
void SetFetchObject(GPUClientFetchObject *fetchObject);
|
||||
|
||||
bool GetAllowViewUpdates() const;
|
||||
void SetAllowViewUpdates(const bool allowUpdates);
|
||||
virtual void SetAllowViewUpdates(bool allowUpdates);
|
||||
bool GetAllowViewFlushes() const;
|
||||
virtual void SetAllowViewFlushes(bool allowFlushes);
|
||||
|
||||
virtual void LoadDisplays();
|
||||
virtual void ProcessDisplays();
|
||||
virtual void UpdateView();
|
||||
virtual void FlushView();
|
||||
virtual void FinishFrameAtIndex(const u8 bufferIndex);
|
||||
|
||||
// Emulator interface
|
||||
|
|
|
@ -877,6 +877,9 @@
|
|||
ABADF11F1DEA4D0000A142B1 /* Database.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABADF1171DEA4C1200A142B1 /* Database.cpp */; };
|
||||
ABADF1201DEA4D0000A142B1 /* Database.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABADF1171DEA4C1200A142B1 /* Database.cpp */; };
|
||||
ABADF1211DEA4D0000A142B1 /* Database.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABADF1171DEA4C1200A142B1 /* Database.cpp */; };
|
||||
ABAE1F6F1F6873E70080EFE3 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ABAE1F6E1F6873E70080EFE3 /* CoreVideo.framework */; };
|
||||
ABAE1F701F6874090080EFE3 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ABAE1F6E1F6873E70080EFE3 /* CoreVideo.framework */; };
|
||||
ABAE1F711F6874090080EFE3 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ABAE1F6E1F6873E70080EFE3 /* CoreVideo.framework */; };
|
||||
ABAF0A411A96E67200B95B75 /* RomInfoPanel.mm in Sources */ = {isa = PBXBuildFile; fileRef = ABAF0A401A96E67200B95B75 /* RomInfoPanel.mm */; };
|
||||
ABAF0A421A96E67200B95B75 /* RomInfoPanel.mm in Sources */ = {isa = PBXBuildFile; fileRef = ABAF0A401A96E67200B95B75 /* RomInfoPanel.mm */; };
|
||||
ABAF0A431A96E67200B95B75 /* RomInfoPanel.mm in Sources */ = {isa = PBXBuildFile; fileRef = ABAF0A401A96E67200B95B75 /* RomInfoPanel.mm */; };
|
||||
|
@ -1566,6 +1569,7 @@
|
|||
ABADF1161DEA4C1200A142B1 /* Database.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Database.h; sourceTree = "<group>"; };
|
||||
ABADF1171DEA4C1200A142B1 /* Database.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Database.cpp; sourceTree = "<group>"; };
|
||||
ABADF11A1DEA4CF700A142B1 /* features_cpu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = features_cpu.c; sourceTree = "<group>"; };
|
||||
ABAE1F6E1F6873E70080EFE3 /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = System/Library/Frameworks/CoreVideo.framework; sourceTree = SDKROOT; };
|
||||
ABAF0A3F1A96E67200B95B75 /* RomInfoPanel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RomInfoPanel.h; sourceTree = "<group>"; };
|
||||
ABAF0A401A96E67200B95B75 /* RomInfoPanel.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RomInfoPanel.mm; sourceTree = "<group>"; };
|
||||
ABB0FBC41A9E5CEA0060C55A /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = System/Library/Frameworks/CoreAudio.framework; sourceTree = SDKROOT; };
|
||||
|
@ -1932,6 +1936,7 @@
|
|||
ABC570D5134431DA00E7B0B1 /* OpenGL.framework in Frameworks */,
|
||||
AB3BF4341E256309003E2B24 /* QuartzCore.framework in Frameworks */,
|
||||
AB4676F314AB12D60002FF94 /* libz.dylib in Frameworks */,
|
||||
ABAE1F711F6874090080EFE3 /* CoreVideo.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -1946,6 +1951,7 @@
|
|||
AB74EC8A1738499C0026C41E /* Carbon.framework in Frameworks */,
|
||||
AB796D6815CDCBA200C59155 /* Cocoa.framework in Frameworks */,
|
||||
ABB0FBC71A9E5D080060C55A /* CoreAudio.framework in Frameworks */,
|
||||
ABAE1F6F1F6873E70080EFE3 /* CoreVideo.framework in Frameworks */,
|
||||
AB564907186E6F0C002740F4 /* ForceFeedback.framework in Frameworks */,
|
||||
AB796D6915CDCBA200C59155 /* Foundation.framework in Frameworks */,
|
||||
AB796D6A15CDCBA200C59155 /* IOKit.framework in Frameworks */,
|
||||
|
@ -1974,6 +1980,7 @@
|
|||
AB8F3D281A53AC2600A80BF6 /* OpenGL.framework in Frameworks */,
|
||||
AB3BF4351E256309003E2B24 /* QuartzCore.framework in Frameworks */,
|
||||
AB8F3D291A53AC2600A80BF6 /* libz.dylib in Frameworks */,
|
||||
ABAE1F701F6874090080EFE3 /* CoreVideo.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -2062,6 +2069,7 @@
|
|||
AB74EC891738499C0026C41E /* Carbon.framework */,
|
||||
1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */,
|
||||
ABB0FBC41A9E5CEA0060C55A /* CoreAudio.framework */,
|
||||
ABAE1F6E1F6873E70080EFE3 /* CoreVideo.framework */,
|
||||
AB564906186E6F0C002740F4 /* ForceFeedback.framework */,
|
||||
29B97325FDCFA39411CA2CEA /* Foundation.framework */,
|
||||
AB350BA41478AC96007165AC /* IOKit.framework */,
|
||||
|
|
|
@ -782,6 +782,11 @@
|
|||
AB43528917D5BA95007417C8 /* fsnitro.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB43528617D5BA95007417C8 /* fsnitro.cpp */; };
|
||||
AB43528A17D5BA95007417C8 /* fsnitro.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB43528617D5BA95007417C8 /* fsnitro.cpp */; };
|
||||
AB43528B17D5BA95007417C8 /* fsnitro.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB43528617D5BA95007417C8 /* fsnitro.cpp */; };
|
||||
AB446DA11F69DB56002F32B6 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB446DA01F69DB56002F32B6 /* CoreVideo.framework */; };
|
||||
AB446DB31F69DB68002F32B6 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB446DA01F69DB56002F32B6 /* CoreVideo.framework */; };
|
||||
AB446DB41F69DB68002F32B6 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB446DA01F69DB56002F32B6 /* CoreVideo.framework */; };
|
||||
AB446DB51F69DB69002F32B6 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB446DA01F69DB56002F32B6 /* CoreVideo.framework */; };
|
||||
AB446DB61F69DB69002F32B6 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB446DA01F69DB56002F32B6 /* CoreVideo.framework */; };
|
||||
AB4C4C3F16F55C64002E07CD /* AAFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB4C4C2A16F55C64002E07CD /* AAFilter.cpp */; };
|
||||
AB4C4C4016F55C64002E07CD /* cpu_detect_x86_gcc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB4C4C2B16F55C64002E07CD /* cpu_detect_x86_gcc.cpp */; };
|
||||
AB4C4C4116F55C64002E07CD /* FIFOSampleBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB4C4C2C16F55C64002E07CD /* FIFOSampleBuffer.cpp */; };
|
||||
|
@ -1912,6 +1917,7 @@
|
|||
AB43527117D5BA5E007417C8 /* slot1_retail_mcrom_debug.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = slot1_retail_mcrom_debug.cpp; sourceTree = "<group>"; };
|
||||
AB43528517D5BA95007417C8 /* fsnitro.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fsnitro.h; sourceTree = "<group>"; };
|
||||
AB43528617D5BA95007417C8 /* fsnitro.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = fsnitro.cpp; sourceTree = "<group>"; };
|
||||
AB446DA01F69DB56002F32B6 /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = System/Library/Frameworks/CoreVideo.framework; sourceTree = SDKROOT; };
|
||||
AB4C4C2A16F55C64002E07CD /* AAFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AAFilter.cpp; sourceTree = "<group>"; };
|
||||
AB4C4C2B16F55C64002E07CD /* cpu_detect_x86_gcc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cpu_detect_x86_gcc.cpp; sourceTree = "<group>"; };
|
||||
AB4C4C2C16F55C64002E07CD /* FIFOSampleBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FIFOSampleBuffer.cpp; sourceTree = "<group>"; };
|
||||
|
@ -2305,6 +2311,7 @@
|
|||
AB2A9A731725F00F0062C1A1 /* OpenGL.framework in Frameworks */,
|
||||
AB1CC8001AA509C2008B0A16 /* CoreAudio.framework in Frameworks */,
|
||||
AB3E69801E25FB9800D4CC75 /* QuartzCore.framework in Frameworks */,
|
||||
AB446DB61F69DB69002F32B6 /* CoreVideo.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -2325,6 +2332,7 @@
|
|||
AB2F3C4015CF9C6000858373 /* OpenGL.framework in Frameworks */,
|
||||
AB1CC80A1AA509DF008B0A16 /* CoreAudio.framework in Frameworks */,
|
||||
AB3E697F1E25FB9700D4CC75 /* QuartzCore.framework in Frameworks */,
|
||||
AB446DB51F69DB69002F32B6 /* CoreVideo.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -2345,6 +2353,7 @@
|
|||
AB711F761481C35F009011C8 /* OpenGL.framework in Frameworks */,
|
||||
AB1CC80D1AA509E1008B0A16 /* CoreAudio.framework in Frameworks */,
|
||||
AB3E69451E25FB8400D4CC75 /* QuartzCore.framework in Frameworks */,
|
||||
AB446DA11F69DB56002F32B6 /* CoreVideo.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -2365,6 +2374,7 @@
|
|||
AB73AA2E1507C9F500A310C8 /* OpenGL.framework in Frameworks */,
|
||||
AB1CC80C1AA509E0008B0A16 /* CoreAudio.framework in Frameworks */,
|
||||
AB3E697D1E25FB9600D4CC75 /* QuartzCore.framework in Frameworks */,
|
||||
AB446DB31F69DB68002F32B6 /* CoreVideo.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -2385,6 +2395,7 @@
|
|||
ABAD104415ACE7A00000EC47 /* OpenGL.framework in Frameworks */,
|
||||
AB1CC80B1AA509E0008B0A16 /* CoreAudio.framework in Frameworks */,
|
||||
AB3E697E1E25FB9700D4CC75 /* QuartzCore.framework in Frameworks */,
|
||||
AB446DB41F69DB68002F32B6 /* CoreVideo.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -2453,6 +2464,7 @@
|
|||
ABB6AD5C173A3F2B00EC2E8D /* Carbon.framework */,
|
||||
1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */,
|
||||
AB1CC7FF1AA509C2008B0A16 /* CoreAudio.framework */,
|
||||
AB446DA01F69DB56002F32B6 /* CoreVideo.framework */,
|
||||
AB8C6E56186CD07E00E3EC64 /* ForceFeedback.framework */,
|
||||
29B97325FDCFA39411CA2CEA /* Foundation.framework */,
|
||||
AB350BA41478AC96007165AC /* IOKit.framework */,
|
||||
|
|
|
@ -16,8 +16,10 @@
|
|||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <CoreVideo/CoreVideo.h>
|
||||
#include <pthread.h>
|
||||
#include <libkern/OSAtomic.h>
|
||||
#include <map>
|
||||
|
||||
#import "cocoa_util.h"
|
||||
#include "../../GPU.h"
|
||||
|
@ -30,15 +32,24 @@
|
|||
#define ENABLE_APPLE_METAL
|
||||
#endif
|
||||
|
||||
#define VIDEO_FLUSH_TIME_LIMIT_OFFSET 8 // The amount of time, in seconds, to wait for a flush to occur on a given CVDisplayLink before stopping it.
|
||||
|
||||
class GPUEventHandlerOSX;
|
||||
|
||||
typedef std::map<CGDirectDisplayID, CVDisplayLinkRef> DisplayLinksActiveMap;
|
||||
typedef std::map<CGDirectDisplayID, int64_t> DisplayLinkFlushTimeLimitMap;
|
||||
|
||||
@interface MacClientSharedObject : CocoaDSThread
|
||||
{
|
||||
GPUClientFetchObject *GPUFetchObject;
|
||||
pthread_rwlock_t *_rwlockFramebuffer[2];
|
||||
pthread_mutex_t *_mutexOutputList;
|
||||
pthread_mutex_t _mutexFlushVideo;
|
||||
NSMutableArray *_cdsOutputList;
|
||||
volatile int32_t numberViewsUsingDirectToCPUFiltering;
|
||||
|
||||
DisplayLinksActiveMap _displayLinksActiveList;
|
||||
DisplayLinkFlushTimeLimitMap _displayLinkFlushTimeList;
|
||||
}
|
||||
|
||||
@property (assign, nonatomic) GPUClientFetchObject *GPUFetchObject;
|
||||
|
@ -52,6 +63,11 @@ class GPUEventHandlerOSX;
|
|||
- (void) handleFetchFromBufferIndexAndPushVideo:(NSData *)indexData;
|
||||
- (void) pushVideoDataToAllDisplayViews;
|
||||
- (void) finishAllDisplayViewsAtIndex:(const u8)bufferIndex;
|
||||
- (void) flushAllDisplaysOnDisplayLink:(CVDisplayLinkRef)displayLink timeStamp:(const CVTimeStamp *)timeStamp;
|
||||
|
||||
- (BOOL) isDisplayLinkRunningUsingID:(CGDirectDisplayID)displayID;
|
||||
- (void) displayLinkStartUsingID:(CGDirectDisplayID)displayID;
|
||||
- (void) displayLinkListUpdate;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -115,6 +131,13 @@ extern "C"
|
|||
{
|
||||
#endif
|
||||
|
||||
CVReturn MacDisplayLinkCallback(CVDisplayLinkRef displayLink,
|
||||
const CVTimeStamp *inNow,
|
||||
const CVTimeStamp *inOutputTime,
|
||||
CVOptionFlags flagsIn,
|
||||
CVOptionFlags *flagsOut,
|
||||
void *displayLinkContext);
|
||||
|
||||
bool OSXOpenGLRendererInit();
|
||||
bool OSXOpenGLRendererBegin();
|
||||
void OSXOpenGLRendererEnd();
|
||||
|
|
|
@ -876,17 +876,45 @@ public:
|
|||
|
||||
pthread_rwlock_init(_rwlockFramebuffer[0], NULL);
|
||||
pthread_rwlock_init(_rwlockFramebuffer[1], NULL);
|
||||
pthread_mutex_init(&_mutexFlushVideo, NULL);
|
||||
|
||||
GPUFetchObject = nil;
|
||||
_mutexOutputList = NULL;
|
||||
_cdsOutputList = nil;
|
||||
numberViewsUsingDirectToCPUFiltering = 0;
|
||||
|
||||
_displayLinksActiveList.clear();
|
||||
_displayLinkFlushTimeList.clear();
|
||||
[self displayLinkListUpdate];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(respondToScreenChange:)
|
||||
name:@"NSApplicationDidChangeScreenParametersNotification"
|
||||
object:NSApp];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
pthread_mutex_lock(&_mutexFlushVideo);
|
||||
|
||||
for (DisplayLinksActiveMap::iterator it = _displayLinksActiveList.begin(); it != _displayLinksActiveList.end(); ++it)
|
||||
{
|
||||
CGDirectDisplayID displayID = it->first;
|
||||
CVDisplayLinkRef displayLinkRef = it->second;
|
||||
if (CVDisplayLinkIsRunning(displayLinkRef))
|
||||
{
|
||||
CVDisplayLinkStop(displayLinkRef);
|
||||
CVDisplayLinkRelease(displayLinkRef);
|
||||
}
|
||||
|
||||
_displayLinksActiveList.erase(displayID);
|
||||
_displayLinkFlushTimeList.erase(displayID);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&_mutexFlushVideo);
|
||||
|
||||
pthread_mutex_t *currentMutex = _mutexOutputList;
|
||||
|
||||
if (currentMutex != NULL)
|
||||
|
@ -903,6 +931,7 @@ public:
|
|||
|
||||
pthread_rwlock_destroy(_rwlockFramebuffer[0]);
|
||||
pthread_rwlock_destroy(_rwlockFramebuffer[1]);
|
||||
pthread_mutex_destroy(&_mutexFlushVideo);
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
@ -1020,6 +1049,151 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
- (void) flushAllDisplaysOnDisplayLink:(CVDisplayLinkRef)displayLink timeStamp:(const CVTimeStamp *)timeStamp
|
||||
{
|
||||
pthread_mutex_t *currentMutex = _mutexOutputList;
|
||||
CGDirectDisplayID displayID = CVDisplayLinkGetCurrentCGDisplay(displayLink);
|
||||
bool didFlushOccur = false;
|
||||
|
||||
if (currentMutex != NULL)
|
||||
{
|
||||
pthread_mutex_lock(currentMutex);
|
||||
}
|
||||
|
||||
for (CocoaDSOutput *cdsOutput in _cdsOutputList)
|
||||
{
|
||||
if ([cdsOutput isKindOfClass:[CocoaDSDisplayVideo class]])
|
||||
{
|
||||
if ([(CocoaDSDisplayVideo *)cdsOutput currentDisplayID] == displayID)
|
||||
{
|
||||
ClientDisplay3DView *cdv = [(CocoaDSDisplayVideo *)cdsOutput clientDisplayView];
|
||||
|
||||
if (cdv->GetViewNeedsFlush())
|
||||
{
|
||||
cdv->FlushView();
|
||||
didFlushOccur = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentMutex != NULL)
|
||||
{
|
||||
pthread_mutex_unlock(currentMutex);
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&_mutexFlushVideo);
|
||||
|
||||
if (didFlushOccur)
|
||||
{
|
||||
// Set the new time limit to 8 seconds after the current time.
|
||||
_displayLinkFlushTimeList[displayID] = timeStamp->videoTime + (timeStamp->videoTimeScale * VIDEO_FLUSH_TIME_LIMIT_OFFSET);
|
||||
}
|
||||
else if (timeStamp->videoTime > _displayLinkFlushTimeList[displayID])
|
||||
{
|
||||
CVDisplayLinkStop(displayLink);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&_mutexFlushVideo);
|
||||
}
|
||||
|
||||
- (BOOL) isDisplayLinkRunningUsingID:(CGDirectDisplayID)displayID
|
||||
{
|
||||
CVDisplayLinkRef displayLink = NULL;
|
||||
|
||||
pthread_mutex_lock(&_mutexFlushVideo);
|
||||
|
||||
if (_displayLinksActiveList.find(displayID) != _displayLinksActiveList.end())
|
||||
{
|
||||
displayLink = _displayLinksActiveList[displayID];
|
||||
}
|
||||
|
||||
const BOOL isRunning = ( (displayLink != NULL) && CVDisplayLinkIsRunning(displayLink) ) ? YES : NO;
|
||||
|
||||
pthread_mutex_unlock(&_mutexFlushVideo);
|
||||
|
||||
return isRunning;
|
||||
}
|
||||
|
||||
- (void) displayLinkStartUsingID:(CGDirectDisplayID)displayID
|
||||
{
|
||||
CVDisplayLinkRef displayLink = NULL;
|
||||
|
||||
pthread_mutex_lock(&_mutexFlushVideo);
|
||||
|
||||
if (_displayLinksActiveList.find(displayID) != _displayLinksActiveList.end())
|
||||
{
|
||||
displayLink = _displayLinksActiveList[displayID];
|
||||
}
|
||||
|
||||
if (displayLink != NULL)
|
||||
{
|
||||
CVDisplayLinkStart(displayLink);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&_mutexFlushVideo);
|
||||
}
|
||||
|
||||
- (void) displayLinkListUpdate
|
||||
{
|
||||
// Set up the display links
|
||||
NSArray *screenList = [NSScreen screens];
|
||||
std::set<CGDirectDisplayID> screenActiveDisplayIDsList;
|
||||
|
||||
pthread_mutex_lock(&_mutexFlushVideo);
|
||||
|
||||
// Add new CGDirectDisplayIDs for new screens
|
||||
for (size_t i = 0; i < [screenList count]; i++)
|
||||
{
|
||||
NSScreen *screen = [screenList objectAtIndex:i];
|
||||
NSDictionary<NSString *, id> *deviceDescription = [screen deviceDescription];
|
||||
NSNumber *idNumber = (NSNumber *)[deviceDescription valueForKey:@"NSScreenNumber"];
|
||||
|
||||
CGDirectDisplayID displayID = [idNumber unsignedIntValue];
|
||||
bool isDisplayLinkStillActive = (_displayLinksActiveList.find(displayID) != _displayLinksActiveList.end());
|
||||
|
||||
if (!isDisplayLinkStillActive)
|
||||
{
|
||||
CVDisplayLinkRef newDisplayLink;
|
||||
CVDisplayLinkCreateWithActiveCGDisplays(&newDisplayLink);
|
||||
CVDisplayLinkSetCurrentCGDisplay(newDisplayLink, displayID);
|
||||
CVDisplayLinkSetOutputCallback(newDisplayLink, &MacDisplayLinkCallback, self);
|
||||
|
||||
_displayLinksActiveList[displayID] = newDisplayLink;
|
||||
_displayLinkFlushTimeList[displayID] = 0;
|
||||
}
|
||||
|
||||
// While we're iterating through NSScreens, save the CGDirectDisplayID to a temporary list for later use.
|
||||
screenActiveDisplayIDsList.insert(displayID);
|
||||
}
|
||||
|
||||
// Remove old CGDirectDisplayIDs for screens that no longer exist
|
||||
for (DisplayLinksActiveMap::iterator it = _displayLinksActiveList.begin(); it != _displayLinksActiveList.end(); ++it)
|
||||
{
|
||||
CGDirectDisplayID displayID = it->first;
|
||||
CVDisplayLinkRef displayLinkRef = it->second;
|
||||
|
||||
if (screenActiveDisplayIDsList.find(displayID) == screenActiveDisplayIDsList.end())
|
||||
{
|
||||
if (CVDisplayLinkIsRunning(displayLinkRef))
|
||||
{
|
||||
CVDisplayLinkStop(displayLinkRef);
|
||||
CVDisplayLinkRelease(displayLinkRef);
|
||||
}
|
||||
|
||||
_displayLinksActiveList.erase(displayID);
|
||||
_displayLinkFlushTimeList.erase(displayID);
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&_mutexFlushVideo);
|
||||
}
|
||||
|
||||
- (void) respondToScreenChange:(NSNotification *)aNotification
|
||||
{
|
||||
[self displayLinkListUpdate];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
@ -1143,6 +1317,19 @@ CGLContextObj OSXOpenGLRendererContext = NULL;
|
|||
CGLPBufferObj OSXOpenGLRendererPBuffer = NULL;
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
CVReturn MacDisplayLinkCallback(CVDisplayLinkRef displayLink,
|
||||
const CVTimeStamp *inNow,
|
||||
const CVTimeStamp *inOutputTime,
|
||||
CVOptionFlags flagsIn,
|
||||
CVOptionFlags *flagsOut,
|
||||
void *displayLinkContext)
|
||||
{
|
||||
MacClientSharedObject *sharedData = (MacClientSharedObject *)displayLinkContext;
|
||||
[sharedData flushAllDisplaysOnDisplayLink:displayLink timeStamp:inNow];
|
||||
|
||||
return kCVReturnSuccess;
|
||||
}
|
||||
|
||||
bool OSXOpenGLRendererInit()
|
||||
{
|
||||
static bool isContextAlreadyCreated = false;
|
||||
|
|
|
@ -137,6 +137,7 @@
|
|||
OSSpinLock spinlockSourceDeposterize;
|
||||
OSSpinLock spinlockPixelScaler;
|
||||
OSSpinLock spinlockDisplayVideoSource;
|
||||
OSSpinLock spinlockDisplayID;
|
||||
}
|
||||
|
||||
@property (readonly, nonatomic) BOOL canFilterOnGPU;
|
||||
|
@ -160,6 +161,7 @@
|
|||
@property (assign) uint32_t hudColorInputPendingOnly;
|
||||
@property (assign) NSInteger displayMainVideoSource;
|
||||
@property (assign) NSInteger displayTouchVideoSource;
|
||||
@property (assign) uint32_t currentDisplayID;
|
||||
@property (assign) BOOL useVerticalSync;
|
||||
@property (assign) BOOL videoFiltersPreferGPU;
|
||||
@property (assign) BOOL sourceDeposterize;
|
||||
|
|
|
@ -751,6 +751,7 @@
|
|||
@dynamic hudColorInputPendingAndApplied;
|
||||
@dynamic hudColorInputAppliedOnly;
|
||||
@dynamic hudColorInputPendingOnly;
|
||||
@dynamic currentDisplayID;
|
||||
@dynamic useVerticalSync;
|
||||
@dynamic videoFiltersPreferGPU;
|
||||
@dynamic sourceDeposterize;
|
||||
|
@ -774,6 +775,7 @@
|
|||
spinlockSourceDeposterize = OS_SPINLOCK_INIT;
|
||||
spinlockPixelScaler = OS_SPINLOCK_INIT;
|
||||
spinlockDisplayVideoSource = OS_SPINLOCK_INIT;
|
||||
spinlockDisplayID = OS_SPINLOCK_INIT;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
@ -1097,6 +1099,22 @@
|
|||
return displayVideoSource;
|
||||
}
|
||||
|
||||
- (void) setCurrentDisplayID:(uint32_t)theDisplayID
|
||||
{
|
||||
OSSpinLockLock(&spinlockDisplayID);
|
||||
_cdv->SetDisplayViewID((int64_t)theDisplayID);
|
||||
OSSpinLockUnlock(&spinlockDisplayID);
|
||||
}
|
||||
|
||||
- (uint32_t) currentDisplayID
|
||||
{
|
||||
OSSpinLockLock(&spinlockDisplayID);
|
||||
const uint32_t displayID = (uint32_t)_cdv->GetDisplayViewID();
|
||||
OSSpinLockUnlock(&spinlockDisplayID);
|
||||
|
||||
return displayID;
|
||||
}
|
||||
|
||||
- (void) setUseVerticalSync:(BOOL)theState
|
||||
{
|
||||
OSSpinLockLock(&spinlockUseVerticalSync);
|
||||
|
|
|
@ -21,6 +21,10 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
||||
#import "InputManager.h"
|
||||
|
||||
@class CocoaDSDisplayVideo;
|
||||
@class MacClientSharedObject;
|
||||
class ClientDisplay3DView;
|
||||
|
||||
@protocol DisplayViewCALayer <NSObject>
|
||||
|
@ -30,17 +34,68 @@ class ClientDisplay3DView;
|
|||
|
||||
@end
|
||||
|
||||
@protocol CocoaDisplayViewProtocol <InputHIDManagerTarget, NSObject>
|
||||
|
||||
@required
|
||||
@property (retain) InputManager *inputManager;
|
||||
@property (retain) CocoaDSDisplayVideo *cdsVideoOutput;
|
||||
@property (readonly, nonatomic) ClientDisplay3DView *clientDisplay3DView;
|
||||
@property (readonly) BOOL canUseShaderBasedFilters;
|
||||
@property (assign, nonatomic) BOOL allowViewUpdates;
|
||||
@property (assign) BOOL isHUDVisible;
|
||||
@property (assign) BOOL isHUDVideoFPSVisible;
|
||||
@property (assign) BOOL isHUDRender3DFPSVisible;
|
||||
@property (assign) BOOL isHUDFrameIndexVisible;
|
||||
@property (assign) BOOL isHUDLagFrameCountVisible;
|
||||
@property (assign) BOOL isHUDCPULoadAverageVisible;
|
||||
@property (assign) BOOL isHUDRealTimeClockVisible;
|
||||
@property (assign) BOOL isHUDInputVisible;
|
||||
@property (assign) NSColor *hudColorVideoFPS;
|
||||
@property (assign) NSColor *hudColorRender3DFPS;
|
||||
@property (assign) NSColor *hudColorFrameIndex;
|
||||
@property (assign) NSColor *hudColorLagFrameCount;
|
||||
@property (assign) NSColor *hudColorCPULoadAverage;
|
||||
@property (assign) NSColor *hudColorRTC;
|
||||
@property (assign) NSColor *hudColorInputPendingAndApplied;
|
||||
@property (assign) NSColor *hudColorInputAppliedOnly;
|
||||
@property (assign) NSColor *hudColorInputPendingOnly;
|
||||
@property (assign) NSInteger displayMainVideoSource;
|
||||
@property (assign) NSInteger displayTouchVideoSource;
|
||||
@property (assign) BOOL useVerticalSync;
|
||||
@property (assign) BOOL videoFiltersPreferGPU;
|
||||
@property (assign) BOOL sourceDeposterize;
|
||||
@property (assign) NSInteger outputFilter;
|
||||
@property (assign) NSInteger pixelScaler;
|
||||
|
||||
- (void) setupLayer;
|
||||
- (void) requestScreenshot:(NSURL *)fileURL fileType:(NSBitmapImageFileType)fileType;
|
||||
|
||||
@end
|
||||
|
||||
class DisplayViewCALayerInterface
|
||||
{
|
||||
private:
|
||||
NSView *_nsView;
|
||||
CALayer<DisplayViewCALayer> *_frontendLayer;
|
||||
bool _willRenderToCALayer;
|
||||
|
||||
MacClientSharedObject *_sharedData;
|
||||
|
||||
public:
|
||||
DisplayViewCALayerInterface();
|
||||
|
||||
NSView* GetNSView() const;
|
||||
void SetNSView(NSView *theView);
|
||||
|
||||
CALayer<DisplayViewCALayer>* GetFrontendLayer() const;
|
||||
void SetFrontendLayer(CALayer<DisplayViewCALayer> *layer);
|
||||
void CALayerDisplay();
|
||||
|
||||
bool GetRenderToCALayer() const;
|
||||
void SetRenderToCALayer(const bool renderToLayer);
|
||||
|
||||
MacClientSharedObject* GetSharedData();
|
||||
void SetSharedData(MacClientSharedObject *sharedObject);
|
||||
};
|
||||
|
||||
#endif // _DISPLAYVIEWCALAYER_H
|
||||
|
|
|
@ -16,10 +16,24 @@
|
|||
*/
|
||||
|
||||
#import "DisplayViewCALayer.h"
|
||||
#import "../cocoa_GPU.h"
|
||||
|
||||
DisplayViewCALayerInterface::DisplayViewCALayerInterface()
|
||||
{
|
||||
_nsView = nil;
|
||||
_frontendLayer = nil;
|
||||
_sharedData = nil;
|
||||
_willRenderToCALayer = false;
|
||||
}
|
||||
|
||||
NSView* DisplayViewCALayerInterface::GetNSView() const
|
||||
{
|
||||
return this->_nsView;
|
||||
}
|
||||
|
||||
void DisplayViewCALayerInterface::SetNSView(NSView *theView)
|
||||
{
|
||||
this->_nsView = theView;
|
||||
}
|
||||
|
||||
CALayer<DisplayViewCALayer>* DisplayViewCALayerInterface::GetFrontendLayer() const
|
||||
|
@ -36,3 +50,23 @@ void DisplayViewCALayerInterface::CALayerDisplay()
|
|||
{
|
||||
[this->_frontendLayer setNeedsDisplay];
|
||||
}
|
||||
|
||||
bool DisplayViewCALayerInterface::GetRenderToCALayer() const
|
||||
{
|
||||
return this->_willRenderToCALayer;
|
||||
}
|
||||
|
||||
void DisplayViewCALayerInterface::SetRenderToCALayer(const bool renderToLayer)
|
||||
{
|
||||
this->_willRenderToCALayer = renderToLayer;
|
||||
}
|
||||
|
||||
MacClientSharedObject* DisplayViewCALayerInterface::GetSharedData()
|
||||
{
|
||||
return this->_sharedData;
|
||||
}
|
||||
|
||||
void DisplayViewCALayerInterface::SetSharedData(MacClientSharedObject *sharedObject)
|
||||
{
|
||||
this->_sharedData = sharedObject;
|
||||
}
|
||||
|
|
|
@ -17,11 +17,9 @@
|
|||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <OpenGL/OpenGL.h>
|
||||
#include <libkern/OSAtomic.h>
|
||||
#include <map>
|
||||
|
||||
#import "InputManager.h"
|
||||
#import "cocoa_output.h"
|
||||
#import "DisplayViewCALayer.h"
|
||||
|
||||
#include "../ClientDisplayView.h"
|
||||
#undef BOOL
|
||||
|
@ -30,7 +28,9 @@
|
|||
#define DISPLAY_VIDEO_SOURCE_TOUCH_TAG_BASE 2000
|
||||
|
||||
@class CocoaDSController;
|
||||
@class CocoaDSDisplayVideo;
|
||||
@class EmuControllerDelegate;
|
||||
@class InputManager;
|
||||
class OGLVideoOutput;
|
||||
|
||||
// Subclass NSWindow for full screen windows so that we can override some methods.
|
||||
|
@ -38,7 +38,7 @@ class OGLVideoOutput;
|
|||
{ }
|
||||
@end
|
||||
|
||||
@interface DisplayView : NSView <InputHIDManagerTarget>
|
||||
@interface DisplayView : NSView<CocoaDisplayViewProtocol>
|
||||
{
|
||||
InputManager *inputManager;
|
||||
CocoaDSDisplayVideo *cdsVideoOutput;
|
||||
|
@ -46,41 +46,8 @@ class OGLVideoOutput;
|
|||
NSOpenGLContext *localOGLContext;
|
||||
}
|
||||
|
||||
@property (retain) InputManager *inputManager;
|
||||
@property (retain) CocoaDSDisplayVideo *cdsVideoOutput;
|
||||
@property (readonly, nonatomic) ClientDisplay3DView *clientDisplay3DView;
|
||||
@property (readonly) BOOL canUseShaderBasedFilters;
|
||||
@property (assign, nonatomic) BOOL allowViewUpdates;
|
||||
@property (assign) BOOL isHUDVisible;
|
||||
@property (assign) BOOL isHUDVideoFPSVisible;
|
||||
@property (assign) BOOL isHUDRender3DFPSVisible;
|
||||
@property (assign) BOOL isHUDFrameIndexVisible;
|
||||
@property (assign) BOOL isHUDLagFrameCountVisible;
|
||||
@property (assign) BOOL isHUDCPULoadAverageVisible;
|
||||
@property (assign) BOOL isHUDRealTimeClockVisible;
|
||||
@property (assign) BOOL isHUDInputVisible;
|
||||
@property (assign) NSColor *hudColorVideoFPS;
|
||||
@property (assign) NSColor *hudColorRender3DFPS;
|
||||
@property (assign) NSColor *hudColorFrameIndex;
|
||||
@property (assign) NSColor *hudColorLagFrameCount;
|
||||
@property (assign) NSColor *hudColorCPULoadAverage;
|
||||
@property (assign) NSColor *hudColorRTC;
|
||||
@property (assign) NSColor *hudColorInputPendingAndApplied;
|
||||
@property (assign) NSColor *hudColorInputAppliedOnly;
|
||||
@property (assign) NSColor *hudColorInputPendingOnly;
|
||||
@property (assign) NSInteger displayMainVideoSource;
|
||||
@property (assign) NSInteger displayTouchVideoSource;
|
||||
@property (assign) BOOL useVerticalSync;
|
||||
@property (assign) BOOL videoFiltersPreferGPU;
|
||||
@property (assign) BOOL sourceDeposterize;
|
||||
@property (assign) NSInteger outputFilter;
|
||||
@property (assign) NSInteger pixelScaler;
|
||||
|
||||
- (void) setupLayer;
|
||||
|
||||
- (BOOL) handleKeyPress:(NSEvent *)theEvent keyPressed:(BOOL)keyPressed;
|
||||
- (BOOL) handleMouseButton:(NSEvent *)theEvent buttonPressed:(BOOL)buttonPressed;
|
||||
- (void) requestScreenshot:(NSURL *)fileURL fileType:(NSBitmapImageFileType)fileType;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -101,7 +68,7 @@ class OGLVideoOutput;
|
|||
NSSlider *microphoneGainSlider;
|
||||
NSButton *microphoneMuteButton;
|
||||
|
||||
DisplayView *view;
|
||||
NSView<CocoaDisplayViewProtocol> *view;
|
||||
EmuControllerDelegate *emuControl;
|
||||
CocoaDSDisplayVideo *cdsVideoOutput;
|
||||
NSScreen *assignedScreen;
|
||||
|
@ -131,7 +98,7 @@ class OGLVideoOutput;
|
|||
@property (readonly) IBOutlet NSSlider *microphoneGainSlider;
|
||||
@property (readonly) IBOutlet NSButton *microphoneMuteButton;
|
||||
|
||||
@property (retain) DisplayView *view;
|
||||
@property (retain) NSView<CocoaDisplayViewProtocol> *view;
|
||||
@property (retain) EmuControllerDelegate *emuControl;
|
||||
@property (retain) CocoaDSDisplayVideo *cdsVideoOutput;
|
||||
@property (assign) NSScreen *assignedScreen;
|
||||
|
@ -179,6 +146,7 @@ class OGLVideoOutput;
|
|||
- (double) maxViewScaleInHostScreen:(double)contentBoundsWidth height:(double)contentBoundsHeight;
|
||||
- (void) enterFullScreen;
|
||||
- (void) exitFullScreen;
|
||||
- (void) updateDisplayID;
|
||||
|
||||
- (IBAction) copy:(id)sender;
|
||||
- (IBAction) changeHardwareMicGain:(id)sender;
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#import "cocoa_GPU.h"
|
||||
#import "cocoa_file.h"
|
||||
#import "cocoa_input.h"
|
||||
#import "cocoa_output.h"
|
||||
#import "cocoa_globals.h"
|
||||
#import "cocoa_videofilter.h"
|
||||
#import "cocoa_util.h"
|
||||
|
@ -747,6 +748,16 @@ static std::unordered_map<NSScreen *, DisplayWindowController *> _screenMap; //
|
|||
[masterWindow display];
|
||||
}
|
||||
|
||||
- (void) updateDisplayID
|
||||
{
|
||||
NSScreen *screen = [[self window] screen];
|
||||
NSDictionary<NSString *, id> *deviceDescription = [screen deviceDescription];
|
||||
NSNumber *idNumber = (NSNumber *)[deviceDescription valueForKey:@"NSScreenNumber"];
|
||||
CGDirectDisplayID displayID = [idNumber unsignedIntValue];
|
||||
|
||||
[[[self view] cdsVideoOutput] setCurrentDisplayID:displayID];
|
||||
}
|
||||
|
||||
- (void) respondToScreenChange:(NSNotification *)aNotification
|
||||
{
|
||||
if (_canUseMavericksFullScreen)
|
||||
|
@ -1353,19 +1364,19 @@ static std::unordered_map<NSScreen *, DisplayWindowController *> _screenMap; //
|
|||
- (void)windowDidLoad
|
||||
{
|
||||
NSRect newViewFrameRect = NSMakeRect(0.0f, (CGFloat)_statusBarHeight, (CGFloat)_localViewProps.clientWidth, (CGFloat)_localViewProps.clientHeight);
|
||||
DisplayView *newView = [[[DisplayView alloc] initWithFrame:newViewFrameRect] autorelease];
|
||||
NSView<CocoaDisplayViewProtocol> *newView = (NSView<CocoaDisplayViewProtocol> *)[[[DisplayView alloc] initWithFrame:newViewFrameRect] autorelease];
|
||||
[self setView:newView];
|
||||
|
||||
// Set up the master window that is associated with this window controller.
|
||||
[self setMasterWindow:[self window]];
|
||||
[masterWindow setTitle:(NSString *)[[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"]];
|
||||
[[masterWindow contentView] addSubview:view];
|
||||
[masterWindow setInitialFirstResponder:view];
|
||||
[[masterWindow contentView] addSubview:newView];
|
||||
[masterWindow setInitialFirstResponder:newView];
|
||||
[[emuControl windowList] addObject:self];
|
||||
[emuControl updateAllWindowTitles];
|
||||
|
||||
[view setupLayer];
|
||||
[view setInputManager:[emuControl inputManager]];
|
||||
[newView setupLayer];
|
||||
[newView setInputManager:[emuControl inputManager]];
|
||||
|
||||
// Set up the scaling factor if this is a Retina window
|
||||
float scaleFactor = 1.0f;
|
||||
|
@ -1403,7 +1414,7 @@ static std::unordered_map<NSScreen *, DisplayWindowController *> _screenMap; //
|
|||
}
|
||||
|
||||
[self setCdsVideoOutput:newDisplayOutput];
|
||||
[view setCdsVideoOutput:newDisplayOutput];
|
||||
[newView setCdsVideoOutput:newDisplayOutput];
|
||||
|
||||
// Add the video thread to the output list.
|
||||
[emuControl addOutputToCore:newDisplayOutput];
|
||||
|
@ -1554,6 +1565,12 @@ static std::unordered_map<NSScreen *, DisplayWindowController *> _screenMap; //
|
|||
[emuControl updateDisplayPanelTitles];
|
||||
}
|
||||
|
||||
- (void)windowDidChangeScreen:(NSNotification *)notification
|
||||
{
|
||||
[self updateDisplayID];
|
||||
[[view cdsVideoOutput] clientDisplayView]->UpdateView();
|
||||
}
|
||||
|
||||
#if defined(MAC_OS_X_VERSION_10_7) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7)
|
||||
|
||||
- (NSSize)window:(NSWindow *)window willUseFullScreenContentSize:(NSSize)proposedSize
|
||||
|
@ -1749,7 +1766,63 @@ static std::unordered_map<NSScreen *, DisplayWindowController *> _screenMap; //
|
|||
[super dealloc];
|
||||
}
|
||||
|
||||
#pragma mark Dynamic Property Methods
|
||||
#pragma mark Class Methods
|
||||
|
||||
- (BOOL) handleKeyPress:(NSEvent *)theEvent keyPressed:(BOOL)keyPressed
|
||||
{
|
||||
BOOL isHandled = NO;
|
||||
DisplayWindowController *windowController = (DisplayWindowController *)[[self window] delegate];
|
||||
|
||||
MacInputDevicePropertiesEncoder *inputEncoder = [inputManager inputEncoder];
|
||||
const ClientInputDeviceProperties inputProperty = inputEncoder->EncodeKeyboardInput((int32_t)[theEvent keyCode], (keyPressed) ? true : false);
|
||||
|
||||
if (keyPressed && [theEvent window] != nil)
|
||||
{
|
||||
NSString *newStatusText = [NSString stringWithFormat:@"%s:%s", inputProperty.deviceName, inputProperty.elementName];
|
||||
[[windowController emuControl] setStatusText:newStatusText];
|
||||
}
|
||||
|
||||
isHandled = [inputManager dispatchCommandUsingInputProperties:&inputProperty];
|
||||
return isHandled;
|
||||
}
|
||||
|
||||
- (BOOL) handleMouseButton:(NSEvent *)theEvent buttonPressed:(BOOL)buttonPressed
|
||||
{
|
||||
BOOL isHandled = NO;
|
||||
DisplayWindowController *windowController = (DisplayWindowController *)[[self window] delegate];
|
||||
ClientDisplayView *cdv = [(id<DisplayViewCALayer>)localLayer clientDisplay3DView];
|
||||
const ClientDisplayMode displayMode = cdv->GetMode();
|
||||
|
||||
// Convert the clicked location from window coordinates, to view coordinates,
|
||||
// and finally to DS touchscreen coordinates.
|
||||
const int32_t buttonNumber = (int32_t)[theEvent buttonNumber];
|
||||
uint8_t x = 0;
|
||||
uint8_t y = 0;
|
||||
|
||||
if (displayMode != ClientDisplayMode_Main)
|
||||
{
|
||||
const NSEventType eventType = [theEvent type];
|
||||
const bool isInitialMouseDown = (eventType == NSLeftMouseDown) || (eventType == NSRightMouseDown) || (eventType == NSOtherMouseDown);
|
||||
|
||||
// Convert the clicked location from window coordinates, to view coordinates, and finally to NDS touchscreen coordinates.
|
||||
const NSPoint clientLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil];
|
||||
cdv->GetNDSPoint((int)buttonNumber, isInitialMouseDown, clientLoc.x, clientLoc.y, x, y);
|
||||
}
|
||||
|
||||
MacInputDevicePropertiesEncoder *inputEncoder = [inputManager inputEncoder];
|
||||
const ClientInputDeviceProperties inputProperty = inputEncoder->EncodeMouseInput(buttonNumber, (float)x, (float)y, (buttonPressed) ? true : false);
|
||||
|
||||
if (buttonPressed && [theEvent window] != nil)
|
||||
{
|
||||
NSString *newStatusText = (displayMode == ClientDisplayMode_Main) ? [NSString stringWithFormat:@"%s:%s", inputProperty.deviceName, inputProperty.elementName] : [NSString stringWithFormat:@"%s:%s X:%i Y:%i", inputProperty.deviceName, inputProperty.elementName, (int)inputProperty.intCoordX, (int)inputProperty.intCoordY];
|
||||
[[windowController emuControl] setStatusText:newStatusText];
|
||||
}
|
||||
|
||||
isHandled = [inputManager dispatchCommandUsingInputProperties:&inputProperty];
|
||||
return isHandled;
|
||||
}
|
||||
|
||||
#pragma mark CocoaDisplayView Protocol
|
||||
|
||||
- (ClientDisplay3DView *) clientDisplay3DView
|
||||
{
|
||||
|
@ -2068,12 +2141,12 @@ static std::unordered_map<NSScreen *, DisplayWindowController *> _screenMap; //
|
|||
return [[self cdsVideoOutput] pixelScaler];
|
||||
}
|
||||
|
||||
#pragma mark Class Methods
|
||||
- (void) setupLayer
|
||||
{
|
||||
DisplayWindowController *windowController = (DisplayWindowController *)[[self window] delegate];
|
||||
CocoaDSCore *cdsCore = (CocoaDSCore *)[[[windowController emuControl] cdsCoreController] content];
|
||||
CocoaDSGPU *cdsGPU = [cdsCore cdsGPU];
|
||||
BOOL isMetalLayer = NO;
|
||||
|
||||
#ifdef ENABLE_APPLE_METAL
|
||||
MacClientSharedObject *macSharedData = [cdsGPU sharedData];
|
||||
|
@ -2082,15 +2155,19 @@ static std::unordered_map<NSScreen *, DisplayWindowController *> _screenMap; //
|
|||
localLayer = [[DisplayViewMetalLayer alloc] init];
|
||||
[(DisplayViewMetalLayer *)localLayer setSharedData:(MetalDisplayViewSharedData *)macSharedData];
|
||||
|
||||
MacMetalDisplayView *cdv = (MacMetalDisplayView *)[(id<DisplayViewCALayer>)localLayer clientDisplay3DView];
|
||||
cdv->SetFetchObject([cdsGPU fetchObject]);
|
||||
cdv->Init();
|
||||
MacMetalDisplayView *macMTLCDV = (MacMetalDisplayView *)[(id<DisplayViewCALayer>)localLayer clientDisplay3DView];
|
||||
macMTLCDV->SetFetchObject([cdsGPU fetchObject]);
|
||||
macMTLCDV->Init();
|
||||
macMTLCDV->SetNSView(self);
|
||||
macMTLCDV->SetSharedData([cdsGPU sharedData]);
|
||||
|
||||
if ([(DisplayViewMetalLayer *)localLayer device] == nil)
|
||||
{
|
||||
[localLayer release];
|
||||
localLayer = nil;
|
||||
}
|
||||
|
||||
isMetalLayer = YES;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -2100,6 +2177,8 @@ static std::unordered_map<NSScreen *, DisplayWindowController *> _screenMap; //
|
|||
MacOGLDisplayView *macOGLCDV = (MacOGLDisplayView *)[(id<DisplayViewCALayer>)localLayer clientDisplay3DView];
|
||||
macOGLCDV->SetFetchObject([cdsGPU fetchObject]);
|
||||
macOGLCDV->Init();
|
||||
macOGLCDV->SetNSView(self);
|
||||
macOGLCDV->SetSharedData([cdsGPU sharedData]);
|
||||
|
||||
// For macOS 10.8 Mountain Lion and later, we can use the CAOpenGLLayer directly. But for
|
||||
// earlier versions of macOS, using the CALayer directly will cause too many strange issues,
|
||||
|
@ -2118,28 +2197,52 @@ static std::unordered_map<NSScreen *, DisplayWindowController *> _screenMap; //
|
|||
#endif
|
||||
localOGLContext = macOGLCDV->GetNSContext();
|
||||
[localOGLContext retain];
|
||||
macOGLCDV->SetRenderToCALayer(false);
|
||||
}
|
||||
}
|
||||
|
||||
ClientDisplay3DView *cdv = [(id<DisplayViewCALayer>)localLayer clientDisplay3DView];
|
||||
cdv->UpdateView();
|
||||
|
||||
if (localOGLContext != nil)
|
||||
{
|
||||
// If localOGLContext isn't nil, then we will not assign the local layer
|
||||
// directly to the view, since the OpenGL context will already be what
|
||||
// is assigned.
|
||||
cdv->FlushView();
|
||||
return;
|
||||
}
|
||||
|
||||
[localLayer setNeedsDisplay];
|
||||
[self setLayer:localLayer];
|
||||
[self setWantsLayer:YES];
|
||||
|
||||
#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6)
|
||||
if ([self respondsToSelector:@selector(setLayerContentsRedrawPolicy:)])
|
||||
{
|
||||
[self setLayerContentsRedrawPolicy:NSViewLayerContentsRedrawNever];
|
||||
}
|
||||
if ([self respondsToSelector:@selector(setLayerContentsRedrawPolicy:)])
|
||||
{
|
||||
[self setLayerContentsRedrawPolicy:NSViewLayerContentsRedrawNever];
|
||||
}
|
||||
#endif
|
||||
|
||||
[self setLayer:localLayer];
|
||||
[self setWantsLayer:YES];
|
||||
|
||||
if (isMetalLayer)
|
||||
{
|
||||
cdv->FlushView();
|
||||
}
|
||||
else
|
||||
{
|
||||
[localLayer setNeedsDisplay];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) requestScreenshot:(NSURL *)fileURL fileType:(NSBitmapImageFileType)fileType
|
||||
{
|
||||
NSString *fileURLString = [fileURL absoluteString];
|
||||
NSData *fileURLStringData = [fileURLString dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSData *bitmapImageFileTypeData = [[NSData alloc] initWithBytes:&fileType length:sizeof(NSBitmapImageFileType)];
|
||||
NSArray *messageComponents = [[NSArray alloc] initWithObjects:fileURLStringData, bitmapImageFileTypeData, nil];
|
||||
|
||||
[CocoaDSUtil messageSendOneWayWithMessageComponents:[[self cdsVideoOutput] receivePort] msgID:MESSAGE_REQUEST_SCREENSHOT array:messageComponents];
|
||||
|
||||
[bitmapImageFileTypeData release];
|
||||
[messageComponents release];
|
||||
}
|
||||
|
||||
#pragma mark InputHIDManagerTarget Protocol
|
||||
|
@ -2187,73 +2290,6 @@ static std::unordered_map<NSScreen *, DisplayWindowController *> _screenMap; //
|
|||
return isHandled;
|
||||
}
|
||||
|
||||
- (BOOL) handleKeyPress:(NSEvent *)theEvent keyPressed:(BOOL)keyPressed
|
||||
{
|
||||
BOOL isHandled = NO;
|
||||
DisplayWindowController *windowController = (DisplayWindowController *)[[self window] delegate];
|
||||
|
||||
MacInputDevicePropertiesEncoder *inputEncoder = [inputManager inputEncoder];
|
||||
const ClientInputDeviceProperties inputProperty = inputEncoder->EncodeKeyboardInput((int32_t)[theEvent keyCode], (keyPressed) ? true : false);
|
||||
|
||||
if (keyPressed && [theEvent window] != nil)
|
||||
{
|
||||
NSString *newStatusText = [NSString stringWithFormat:@"%s:%s", inputProperty.deviceName, inputProperty.elementName];
|
||||
[[windowController emuControl] setStatusText:newStatusText];
|
||||
}
|
||||
|
||||
isHandled = [inputManager dispatchCommandUsingInputProperties:&inputProperty];
|
||||
return isHandled;
|
||||
}
|
||||
|
||||
- (BOOL) handleMouseButton:(NSEvent *)theEvent buttonPressed:(BOOL)buttonPressed
|
||||
{
|
||||
BOOL isHandled = NO;
|
||||
DisplayWindowController *windowController = (DisplayWindowController *)[[self window] delegate];
|
||||
ClientDisplayView *cdv = [(id<DisplayViewCALayer>)localLayer clientDisplay3DView];
|
||||
const ClientDisplayMode displayMode = cdv->GetMode();
|
||||
|
||||
// Convert the clicked location from window coordinates, to view coordinates,
|
||||
// and finally to DS touchscreen coordinates.
|
||||
const int32_t buttonNumber = (int32_t)[theEvent buttonNumber];
|
||||
uint8_t x = 0;
|
||||
uint8_t y = 0;
|
||||
|
||||
if (displayMode != ClientDisplayMode_Main)
|
||||
{
|
||||
const NSEventType eventType = [theEvent type];
|
||||
const bool isInitialMouseDown = (eventType == NSLeftMouseDown) || (eventType == NSRightMouseDown) || (eventType == NSOtherMouseDown);
|
||||
|
||||
// Convert the clicked location from window coordinates, to view coordinates, and finally to NDS touchscreen coordinates.
|
||||
const NSPoint clientLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil];
|
||||
cdv->GetNDSPoint((int)buttonNumber, isInitialMouseDown, clientLoc.x, clientLoc.y, x, y);
|
||||
}
|
||||
|
||||
MacInputDevicePropertiesEncoder *inputEncoder = [inputManager inputEncoder];
|
||||
const ClientInputDeviceProperties inputProperty = inputEncoder->EncodeMouseInput(buttonNumber, (float)x, (float)y, (buttonPressed) ? true : false);
|
||||
|
||||
if (buttonPressed && [theEvent window] != nil)
|
||||
{
|
||||
NSString *newStatusText = (displayMode == ClientDisplayMode_Main) ? [NSString stringWithFormat:@"%s:%s", inputProperty.deviceName, inputProperty.elementName] : [NSString stringWithFormat:@"%s:%s X:%i Y:%i", inputProperty.deviceName, inputProperty.elementName, (int)inputProperty.intCoordX, (int)inputProperty.intCoordY];
|
||||
[[windowController emuControl] setStatusText:newStatusText];
|
||||
}
|
||||
|
||||
isHandled = [inputManager dispatchCommandUsingInputProperties:&inputProperty];
|
||||
return isHandled;
|
||||
}
|
||||
|
||||
- (void) requestScreenshot:(NSURL *)fileURL fileType:(NSBitmapImageFileType)fileType
|
||||
{
|
||||
NSString *fileURLString = [fileURL absoluteString];
|
||||
NSData *fileURLStringData = [fileURLString dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSData *bitmapImageFileTypeData = [[NSData alloc] initWithBytes:&fileType length:sizeof(NSBitmapImageFileType)];
|
||||
NSArray *messageComponents = [[NSArray alloc] initWithObjects:fileURLStringData, bitmapImageFileTypeData, nil];
|
||||
|
||||
[CocoaDSUtil messageSendOneWayWithMessageComponents:[[self cdsVideoOutput] receivePort] msgID:MESSAGE_REQUEST_SCREENSHOT array:messageComponents];
|
||||
|
||||
[bitmapImageFileTypeData release];
|
||||
[messageComponents release];
|
||||
}
|
||||
|
||||
#pragma mark NSView Methods
|
||||
|
||||
- (void)lockFocus
|
||||
|
@ -2283,12 +2319,12 @@ static std::unordered_map<NSScreen *, DisplayWindowController *> _screenMap; //
|
|||
|
||||
- (void)updateLayer
|
||||
{
|
||||
[self clientDisplay3DView]->UpdateView();
|
||||
[self clientDisplay3DView]->FlushView();
|
||||
}
|
||||
|
||||
- (void)drawRect:(NSRect)dirtyRect
|
||||
{
|
||||
[self clientDisplay3DView]->UpdateView();
|
||||
[self clientDisplay3DView]->FlushView();
|
||||
}
|
||||
|
||||
- (void)setFrame:(NSRect)rect
|
||||
|
@ -2327,7 +2363,7 @@ static std::unordered_map<NSScreen *, DisplayWindowController *> _screenMap; //
|
|||
[localLayer setBounds:CGRectMake(0.0f, 0.0f, props.clientWidth, props.clientHeight)];
|
||||
}
|
||||
#ifdef ENABLE_APPLE_METAL
|
||||
else if ([[self layer] isKindOfClass:[CAMetalLayer class]])
|
||||
else if ([localLayer isKindOfClass:[CAMetalLayer class]])
|
||||
{
|
||||
[(CAMetalLayer *)localLayer setDrawableSize:CGSizeMake(props.clientWidth, props.clientHeight)];
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <Metal/Metal.h>
|
||||
#include <libkern/OSAtomic.h>
|
||||
|
||||
#import "DisplayViewCALayer.h"
|
||||
#import "../cocoa_GPU.h"
|
||||
|
@ -187,7 +188,15 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties;
|
|||
BOOL needsScreenVerticesUpdate;
|
||||
BOOL needsHUDVerticesUpdate;
|
||||
|
||||
dispatch_semaphore_t availableResources;
|
||||
pthread_mutex_t _mutexDisplayTextureUpdate;
|
||||
pthread_mutex_t _mutexBufferUpdate;
|
||||
bool _needEncodeViewport;
|
||||
MTLViewport _newViewport;
|
||||
bool _willDrawDisplays;
|
||||
bool _willDrawHUD;
|
||||
bool _willDrawHUDInput;
|
||||
size_t _hudStringLength;
|
||||
size_t _hudTouchLineLength;
|
||||
}
|
||||
|
||||
@property (assign, nonatomic) MetalDisplayViewSharedData *sharedData;
|
||||
|
@ -213,7 +222,8 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties;
|
|||
- (void) resizeCPUPixelScalerUsingFilterID:(const VideoFilterTypeID)filterID;
|
||||
- (void) copyHUDFontUsingFace:(const FT_Face &)fontFace size:(const size_t)glyphSize tileSize:(const size_t)glyphTileSize info:(GlyphInfo *)glyphInfo;
|
||||
- (void) processDisplays;
|
||||
- (void) renderToDrawable;
|
||||
- (void) updateRenderBuffers;
|
||||
- (void) renderAndFlushDrawable;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -246,6 +256,7 @@ class MacMetalDisplayView : public ClientDisplay3DView, public DisplayViewCALaye
|
|||
{
|
||||
protected:
|
||||
pthread_mutex_t *_mutexProcessPtr;
|
||||
OSSpinLock _spinlockViewNeedsFlush;
|
||||
|
||||
virtual void _UpdateNormalSize();
|
||||
virtual void _UpdateOrder();
|
||||
|
@ -262,6 +273,8 @@ public:
|
|||
pthread_mutex_t* GetMutexProcessPtr() const;
|
||||
|
||||
virtual void Init();
|
||||
virtual bool GetViewNeedsFlush();
|
||||
virtual void SetAllowViewFlushes(bool allowFlushes);
|
||||
|
||||
virtual void CopyHUDFont(const FT_Face &fontFace, const size_t glyphSize, const size_t glyphTileSize, GlyphInfo *glyphInfo);
|
||||
|
||||
|
@ -273,6 +286,7 @@ public:
|
|||
// Client view interface
|
||||
virtual void ProcessDisplays();
|
||||
virtual void UpdateView();
|
||||
virtual void FlushView();
|
||||
};
|
||||
|
||||
#pragma mark -
|
||||
|
|
|
@ -199,13 +199,14 @@
|
|||
[texDisplayLoad32Desc setResourceOptions:MTLResourceStorageModeManaged];
|
||||
[texDisplayLoad32Desc setStorageMode:MTLStorageModeManaged];
|
||||
[texDisplayLoad32Desc setCpuCacheMode:MTLCPUCacheModeWriteCombined];
|
||||
[texDisplayLoad32Desc setUsage:MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite];
|
||||
|
||||
[texDisplayLoad32Desc setUsage:MTLTextureUsageShaderRead];
|
||||
texDisplayFetch32NativeMain = [[device newTextureWithDescriptor:texDisplayLoad32Desc] retain];
|
||||
texDisplayFetch32NativeTouch = [[device newTextureWithDescriptor:texDisplayLoad32Desc] retain];
|
||||
texDisplayFetch32CustomMain = [[device newTextureWithDescriptor:texDisplayLoad32Desc] retain];
|
||||
texDisplayFetch32CustomTouch = [[device newTextureWithDescriptor:texDisplayLoad32Desc] retain];
|
||||
|
||||
[texDisplayLoad32Desc setUsage:MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite];
|
||||
texDisplayPostprocessNativeMain = [[device newTextureWithDescriptor:texDisplayLoad32Desc] retain];
|
||||
texDisplayPostprocessCustomMain = [[device newTextureWithDescriptor:texDisplayLoad32Desc] retain];
|
||||
texDisplayPostprocessNativeTouch = [[device newTextureWithDescriptor:texDisplayLoad32Desc] retain];
|
||||
|
@ -750,7 +751,6 @@
|
|||
}
|
||||
|
||||
sharedData = nil;
|
||||
availableResources = dispatch_semaphore_create(3);
|
||||
|
||||
_cdv = new MacMetalDisplayView();
|
||||
_cdv->SetFrontendLayer(self);
|
||||
|
@ -760,6 +760,7 @@
|
|||
[colorAttachment0Desc setLoadAction:MTLLoadActionClear];
|
||||
[colorAttachment0Desc setStoreAction:MTLStoreActionStore];
|
||||
[colorAttachment0Desc setClearColor:MTLClearColorMake(0.0, 0.0, 0.0, 1.0)];
|
||||
[colorAttachment0Desc setTexture:nil];
|
||||
|
||||
pixelScalePipeline = nil;
|
||||
displayOutputPipeline = nil;
|
||||
|
@ -795,6 +796,9 @@
|
|||
needsScreenVerticesUpdate = YES;
|
||||
needsHUDVerticesUpdate = YES;
|
||||
|
||||
pthread_mutex_init(&_mutexDisplayTextureUpdate, NULL);
|
||||
pthread_mutex_init(&_mutexBufferUpdate, NULL);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
@ -821,6 +825,7 @@
|
|||
[self setTexDisplayPixelScaleMain:nil];
|
||||
[self setTexDisplayPixelScaleTouch:nil];
|
||||
|
||||
[[self colorAttachment0Desc] setTexture:nil];
|
||||
[self setPixelScalePipeline:nil];
|
||||
[self setDisplayOutputPipeline:nil];
|
||||
[self setTexHUDCharMap:nil];
|
||||
|
@ -828,7 +833,8 @@
|
|||
[self setSharedData:nil];
|
||||
delete _cdv;
|
||||
|
||||
dispatch_release(availableResources);
|
||||
pthread_mutex_destroy(&_mutexDisplayTextureUpdate);
|
||||
pthread_mutex_destroy(&_mutexBufferUpdate);
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
@ -1250,6 +1256,8 @@
|
|||
const bool useDeposterize = _cdv->GetSourceDeposterize();
|
||||
const NDSDisplayID selectedDisplaySource[2] = { _cdv->GetSelectedDisplaySourceForDisplay(NDSDisplayID_Main), _cdv->GetSelectedDisplaySourceForDisplay(NDSDisplayID_Touch) };
|
||||
|
||||
pthread_mutex_lock(&_mutexDisplayTextureUpdate);
|
||||
|
||||
if (selectedDisplaySource[NDSDisplayID_Main] == NDSDisplayID_Main)
|
||||
{
|
||||
_texDisplayOutput[NDSDisplayID_Main] = [sharedData texDisplaySrcTargetMain];
|
||||
|
@ -1447,15 +1455,17 @@
|
|||
(float)[_texDisplayOutput[NDSDisplayID_Touch] width], (float)[_texDisplayOutput[NDSDisplayID_Touch] height],
|
||||
(float *)[_displayTexCoordBuffer contents]);
|
||||
[_displayTexCoordBuffer didModifyRange:NSMakeRange(0, sizeof(float) * (4 * 8))];
|
||||
|
||||
pthread_mutex_unlock(&_mutexDisplayTextureUpdate);
|
||||
}
|
||||
|
||||
- (void) renderToDrawable
|
||||
- (void) updateRenderBuffers
|
||||
{
|
||||
const NDSDisplayInfo &displayInfo = _cdv->GetEmuDisplayInfo();
|
||||
|
||||
// Set up the view properties.
|
||||
BOOL didChangeViewProperties = NO;
|
||||
BOOL needEncodeViewport = NO;
|
||||
bool didChangeViewProperties = false;
|
||||
bool needEncodeViewport = false;
|
||||
|
||||
MTLViewport newViewport;
|
||||
newViewport.originX = 0.0;
|
||||
|
@ -1465,14 +1475,16 @@
|
|||
newViewport.znear = 0.0;
|
||||
newViewport.zfar = 1.0;
|
||||
|
||||
pthread_mutex_lock(&_mutexBufferUpdate);
|
||||
|
||||
if ([self needsViewportUpdate])
|
||||
{
|
||||
needEncodeViewport = YES;
|
||||
needEncodeViewport = true;
|
||||
|
||||
DisplayViewShaderProperties *viewProps = (DisplayViewShaderProperties *)[_cdvPropertiesBuffer contents];
|
||||
viewProps->width = _cdv->GetViewProperties().clientWidth;
|
||||
viewProps->height = _cdv->GetViewProperties().clientHeight;
|
||||
didChangeViewProperties = YES;
|
||||
didChangeViewProperties = true;
|
||||
|
||||
[self setNeedsViewportUpdate:NO];
|
||||
}
|
||||
|
@ -1483,7 +1495,7 @@
|
|||
viewProps->rotation = _cdv->GetViewProperties().rotation;
|
||||
viewProps->viewScale = _cdv->GetViewProperties().viewScale;
|
||||
viewProps->lowerHUDMipMapLevel = ( ((float)HUD_TEXTBOX_BASE_SCALE * _cdv->GetHUDObjectScale() / _cdv->GetScaleFactor()) >= (2.0/3.0) ) ? 0 : 1;
|
||||
didChangeViewProperties = YES;
|
||||
didChangeViewProperties = true;
|
||||
|
||||
[self setNeedsRotationScaleUpdate:NO];
|
||||
}
|
||||
|
@ -1494,7 +1506,7 @@
|
|||
}
|
||||
|
||||
// Set up the display properties.
|
||||
BOOL willDrawDisplays = (displayInfo.pixelBytes != 0);
|
||||
bool willDrawDisplays = (displayInfo.pixelBytes != 0);
|
||||
if (willDrawDisplays && [self needsScreenVerticesUpdate])
|
||||
{
|
||||
_cdv->SetScreenVertices((float *)[_displayVtxPositionBuffer contents]);
|
||||
|
@ -1506,7 +1518,7 @@
|
|||
// Set up the HUD properties.
|
||||
size_t hudLength = _cdv->GetHUDString().length();
|
||||
size_t hudTouchLineLength = 0;
|
||||
BOOL willDrawHUD = _cdv->GetHUDVisibility() && ([self texHUDCharMap] != nil);
|
||||
bool willDrawHUD = _cdv->GetHUDVisibility() && ([self texHUDCharMap] != nil);
|
||||
|
||||
if (_cdv->GetHUDShowInput())
|
||||
{
|
||||
|
@ -1558,165 +1570,168 @@
|
|||
_cdv->ClearHUDNeedsUpdate();
|
||||
}
|
||||
|
||||
// Now that everything is set up, request a layer drawable and draw everything.
|
||||
dispatch_semaphore_wait(availableResources, DISPATCH_TIME_FOREVER);
|
||||
_needEncodeViewport = needEncodeViewport;
|
||||
_newViewport = newViewport;
|
||||
_willDrawDisplays = willDrawDisplays;
|
||||
_willDrawHUD = willDrawHUD;
|
||||
_willDrawHUDInput = _cdv->GetHUDShowInput();
|
||||
_hudStringLength = _cdv->GetHUDString().length();
|
||||
_hudTouchLineLength = hudTouchLineLength;
|
||||
|
||||
id<CAMetalDrawable> drawable = [self nextDrawable];
|
||||
if (drawable == nil)
|
||||
pthread_mutex_unlock(&_mutexBufferUpdate);
|
||||
}
|
||||
|
||||
- (void) renderAndFlushDrawable
|
||||
{
|
||||
@autoreleasepool
|
||||
{
|
||||
puts("MacMetalDisplayView: No drawable object was available!\n");
|
||||
dispatch_semaphore_signal(availableResources);
|
||||
return;
|
||||
}
|
||||
|
||||
id<MTLTexture> texture = [drawable texture];
|
||||
if (texture == nil)
|
||||
{
|
||||
dispatch_semaphore_signal(availableResources);
|
||||
return;
|
||||
}
|
||||
|
||||
[[self colorAttachment0Desc] setTexture:texture];
|
||||
|
||||
id<MTLCommandBuffer> cb = [[sharedData commandQueue] commandBufferWithUnretainedReferences];
|
||||
id<MTLRenderCommandEncoder> ce = [cb renderCommandEncoderWithDescriptor:_outputRenderPassDesc];
|
||||
|
||||
if (needEncodeViewport)
|
||||
{
|
||||
[ce setViewport:newViewport];
|
||||
}
|
||||
|
||||
// Draw the NDS displays.
|
||||
if (willDrawDisplays)
|
||||
{
|
||||
[ce setRenderPipelineState:[self displayOutputPipeline]];
|
||||
[ce setVertexBuffer:_displayVtxPositionBuffer offset:0 atIndex:0];
|
||||
[ce setVertexBuffer:_displayTexCoordBuffer offset:0 atIndex:1];
|
||||
[ce setVertexBuffer:_cdvPropertiesBuffer offset:0 atIndex:2];
|
||||
pthread_mutex_lock(&_mutexDisplayTextureUpdate);
|
||||
pthread_mutex_lock(&_mutexBufferUpdate);
|
||||
|
||||
// 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<MTLRenderCommandEncoder> ce = [cb renderCommandEncoderWithDescriptor:_outputRenderPassDesc];
|
||||
|
||||
switch (_cdv->GetViewProperties().mode)
|
||||
if (_needEncodeViewport)
|
||||
{
|
||||
case ClientDisplayMode_Main:
|
||||
{
|
||||
if (_cdv->IsSelectedDisplayEnabled(NDSDisplayID_Main))
|
||||
{
|
||||
[ce setFragmentTexture:_texDisplayOutput[NDSDisplayID_Main] atIndex:0];
|
||||
[ce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ClientDisplayMode_Touch:
|
||||
{
|
||||
if (_cdv->IsSelectedDisplayEnabled(NDSDisplayID_Touch))
|
||||
{
|
||||
[ce setFragmentTexture:_texDisplayOutput[NDSDisplayID_Touch] atIndex:0];
|
||||
[ce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:4 vertexCount:4];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ClientDisplayMode_Dual:
|
||||
{
|
||||
const NDSDisplayID majorDisplayID = (_cdv->GetViewProperties().order == ClientDisplayOrder_MainFirst) ? NDSDisplayID_Main : NDSDisplayID_Touch;
|
||||
const size_t majorDisplayVtx = (_cdv->GetViewProperties().order == ClientDisplayOrder_MainFirst) ? 8 : 12;
|
||||
|
||||
switch (_cdv->GetViewProperties().layout)
|
||||
{
|
||||
case ClientDisplayLayout_Hybrid_2_1:
|
||||
case ClientDisplayLayout_Hybrid_16_9:
|
||||
case ClientDisplayLayout_Hybrid_16_10:
|
||||
{
|
||||
if (_cdv->IsSelectedDisplayEnabled(majorDisplayID))
|
||||
{
|
||||
[ce setFragmentTexture:_texDisplayOutput[majorDisplayID] atIndex:0];
|
||||
[ce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:majorDisplayVtx vertexCount:4];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (_cdv->IsSelectedDisplayEnabled(NDSDisplayID_Main))
|
||||
{
|
||||
[ce setFragmentTexture:_texDisplayOutput[NDSDisplayID_Main] atIndex:0];
|
||||
[ce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
|
||||
}
|
||||
|
||||
if (_cdv->IsSelectedDisplayEnabled(NDSDisplayID_Touch))
|
||||
{
|
||||
[ce setFragmentTexture:_texDisplayOutput[NDSDisplayID_Touch] atIndex:0];
|
||||
[ce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:4 vertexCount:4];
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
[ce setViewport:_newViewport];
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the HUD.
|
||||
if (willDrawHUD)
|
||||
{
|
||||
uint8_t isScreenOverlay = 0;
|
||||
|
||||
[ce setRenderPipelineState:[sharedData hudPipeline]];
|
||||
[ce setVertexBuffer:_hudVtxPositionBuffer offset:0 atIndex:0];
|
||||
[ce setVertexBuffer:_hudVtxColorBuffer offset:0 atIndex:1];
|
||||
[ce setVertexBuffer:_hudTexCoordBuffer offset:0 atIndex:2];
|
||||
[ce setVertexBuffer:_cdvPropertiesBuffer offset:0 atIndex:3];
|
||||
[ce setFragmentTexture:[self texHUDCharMap] atIndex:0];
|
||||
|
||||
// First, draw the inputs.
|
||||
if (_cdv->GetHUDShowInput())
|
||||
// Draw the NDS displays.
|
||||
if (_willDrawDisplays)
|
||||
{
|
||||
isScreenOverlay = 1;
|
||||
[ce setRenderPipelineState:[self displayOutputPipeline]];
|
||||
[ce setVertexBuffer:_displayVtxPositionBuffer offset:0 atIndex:0];
|
||||
[ce setVertexBuffer:_displayTexCoordBuffer offset:0 atIndex:1];
|
||||
[ce setVertexBuffer:_cdvPropertiesBuffer offset:0 atIndex:2];
|
||||
|
||||
switch (_cdv->GetViewProperties().mode)
|
||||
{
|
||||
case ClientDisplayMode_Main:
|
||||
{
|
||||
if (_cdv->IsSelectedDisplayEnabled(NDSDisplayID_Main))
|
||||
{
|
||||
[ce setFragmentTexture:_texDisplayOutput[NDSDisplayID_Main] atIndex:0];
|
||||
[ce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ClientDisplayMode_Touch:
|
||||
{
|
||||
if (_cdv->IsSelectedDisplayEnabled(NDSDisplayID_Touch))
|
||||
{
|
||||
[ce setFragmentTexture:_texDisplayOutput[NDSDisplayID_Touch] atIndex:0];
|
||||
[ce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:4 vertexCount:4];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ClientDisplayMode_Dual:
|
||||
{
|
||||
const NDSDisplayID majorDisplayID = (_cdv->GetViewProperties().order == ClientDisplayOrder_MainFirst) ? NDSDisplayID_Main : NDSDisplayID_Touch;
|
||||
const size_t majorDisplayVtx = (_cdv->GetViewProperties().order == ClientDisplayOrder_MainFirst) ? 8 : 12;
|
||||
|
||||
switch (_cdv->GetViewProperties().layout)
|
||||
{
|
||||
case ClientDisplayLayout_Hybrid_2_1:
|
||||
case ClientDisplayLayout_Hybrid_16_9:
|
||||
case ClientDisplayLayout_Hybrid_16_10:
|
||||
{
|
||||
if (_cdv->IsSelectedDisplayEnabled(majorDisplayID))
|
||||
{
|
||||
[ce setFragmentTexture:_texDisplayOutput[majorDisplayID] atIndex:0];
|
||||
[ce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:majorDisplayVtx vertexCount:4];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (_cdv->IsSelectedDisplayEnabled(NDSDisplayID_Main))
|
||||
{
|
||||
[ce setFragmentTexture:_texDisplayOutput[NDSDisplayID_Main] atIndex:0];
|
||||
[ce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
|
||||
}
|
||||
|
||||
if (_cdv->IsSelectedDisplayEnabled(NDSDisplayID_Touch))
|
||||
{
|
||||
[ce setFragmentTexture:_texDisplayOutput[NDSDisplayID_Touch] atIndex:0];
|
||||
[ce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:4 vertexCount:4];
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the HUD.
|
||||
if (_willDrawHUD)
|
||||
{
|
||||
uint8_t isScreenOverlay = 0;
|
||||
|
||||
[ce setRenderPipelineState:[sharedData hudPipeline]];
|
||||
[ce setVertexBuffer:_hudVtxPositionBuffer offset:0 atIndex:0];
|
||||
[ce setVertexBuffer:_hudVtxColorBuffer offset:0 atIndex:1];
|
||||
[ce setVertexBuffer:_hudTexCoordBuffer offset:0 atIndex:2];
|
||||
[ce setVertexBuffer:_cdvPropertiesBuffer offset:0 atIndex:3];
|
||||
[ce setFragmentTexture:[self texHUDCharMap] atIndex:0];
|
||||
|
||||
// First, draw the inputs.
|
||||
if (_willDrawHUDInput)
|
||||
{
|
||||
isScreenOverlay = 1;
|
||||
[ce setVertexBytes:&isScreenOverlay length:sizeof(uint8_t) atIndex:4];
|
||||
[ce setFragmentSamplerState:[sharedData samplerHUDBox] atIndex:0];
|
||||
[ce drawIndexedPrimitives:MTLPrimitiveTypeTriangle
|
||||
indexCount:_hudTouchLineLength * 6
|
||||
indexType:MTLIndexTypeUInt16
|
||||
indexBuffer:[sharedData hudIndexBuffer]
|
||||
indexBufferOffset:(_hudStringLength + HUD_INPUT_ELEMENT_LENGTH) * 6 * sizeof(uint16_t)];
|
||||
|
||||
isScreenOverlay = 0;
|
||||
[ce setVertexBytes:&isScreenOverlay length:sizeof(uint8_t) atIndex:4];
|
||||
[ce setFragmentSamplerState:[sharedData samplerHUDText] atIndex:0];
|
||||
[ce drawIndexedPrimitives:MTLPrimitiveTypeTriangle
|
||||
indexCount:HUD_INPUT_ELEMENT_LENGTH * 6
|
||||
indexType:MTLIndexTypeUInt16
|
||||
indexBuffer:[sharedData hudIndexBuffer]
|
||||
indexBufferOffset:_hudStringLength * 6 * sizeof(uint16_t)];
|
||||
}
|
||||
|
||||
// Next, draw the backing text box.
|
||||
[ce setVertexBytes:&isScreenOverlay length:sizeof(uint8_t) atIndex:4];
|
||||
[ce setFragmentSamplerState:[sharedData samplerHUDBox] atIndex:0];
|
||||
[ce drawIndexedPrimitives:MTLPrimitiveTypeTriangle
|
||||
indexCount:hudTouchLineLength * 6
|
||||
indexCount:6
|
||||
indexType:MTLIndexTypeUInt16
|
||||
indexBuffer:[sharedData hudIndexBuffer]
|
||||
indexBufferOffset:(_cdv->GetHUDString().length() + HUD_INPUT_ELEMENT_LENGTH) * 6 * sizeof(uint16_t)];
|
||||
indexBufferOffset:0];
|
||||
|
||||
isScreenOverlay = 0;
|
||||
[ce setVertexBytes:&isScreenOverlay length:sizeof(uint8_t) atIndex:4];
|
||||
// Finally, draw each character inside the box.
|
||||
[ce setFragmentSamplerState:[sharedData samplerHUDText] atIndex:0];
|
||||
[ce drawIndexedPrimitives:MTLPrimitiveTypeTriangle
|
||||
indexCount:HUD_INPUT_ELEMENT_LENGTH * 6
|
||||
indexCount:(_hudStringLength - 1) * 6
|
||||
indexType:MTLIndexTypeUInt16
|
||||
indexBuffer:[sharedData hudIndexBuffer]
|
||||
indexBufferOffset:_cdv->GetHUDString().length() * 6 * sizeof(uint16_t)];
|
||||
indexBufferOffset:6 * sizeof(uint16_t)];
|
||||
}
|
||||
|
||||
// Next, draw the backing text box.
|
||||
[ce setVertexBytes:&isScreenOverlay length:sizeof(uint8_t) atIndex:4];
|
||||
[ce setFragmentSamplerState:[sharedData samplerHUDBox] atIndex:0];
|
||||
[ce drawIndexedPrimitives:MTLPrimitiveTypeTriangle
|
||||
indexCount:6
|
||||
indexType:MTLIndexTypeUInt16
|
||||
indexBuffer:[sharedData hudIndexBuffer]
|
||||
indexBufferOffset:0];
|
||||
[ce endEncoding];
|
||||
|
||||
// Finally, draw each character inside the box.
|
||||
[ce setFragmentSamplerState:[sharedData samplerHUDText] atIndex:0];
|
||||
[ce drawIndexedPrimitives:MTLPrimitiveTypeTriangle
|
||||
indexCount:(_cdv->GetHUDString().length() - 1) * 6
|
||||
indexType:MTLIndexTypeUInt16
|
||||
indexBuffer:[sharedData hudIndexBuffer]
|
||||
indexBufferOffset:6 * sizeof(uint16_t)];
|
||||
[cb presentDrawable:layerDrawable];
|
||||
[cb addCompletedHandler:^(id<MTLCommandBuffer> block) {
|
||||
pthread_mutex_unlock(&_mutexBufferUpdate);
|
||||
pthread_mutex_unlock(&_mutexDisplayTextureUpdate);
|
||||
}];
|
||||
|
||||
[cb commit];
|
||||
}
|
||||
|
||||
[ce endEncoding];
|
||||
|
||||
[cb presentDrawable:drawable];
|
||||
[cb addCompletedHandler:^(id<MTLCommandBuffer> block) {
|
||||
dispatch_semaphore_signal(availableResources);
|
||||
}];
|
||||
|
||||
[cb commit];
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -1828,6 +1843,7 @@ MacMetalDisplayView::MacMetalDisplayView()
|
|||
_canFilterOnGPU = true;
|
||||
_filtersPreferGPU = true;
|
||||
_willFilterOnGPU = true;
|
||||
_spinlockViewNeedsFlush = OS_SPINLOCK_INIT;
|
||||
|
||||
_mutexProcessPtr = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
|
||||
pthread_mutex_init(_mutexProcessPtr, NULL);
|
||||
|
@ -1839,6 +1855,26 @@ MacMetalDisplayView::~MacMetalDisplayView()
|
|||
free(this->_mutexProcessPtr);
|
||||
}
|
||||
|
||||
bool MacMetalDisplayView::GetViewNeedsFlush()
|
||||
{
|
||||
OSSpinLockLock(&this->_spinlockViewNeedsFlush);
|
||||
const bool viewNeedsFlush = this->_viewNeedsFlush;
|
||||
OSSpinLockUnlock(&this->_spinlockViewNeedsFlush);
|
||||
|
||||
return viewNeedsFlush;
|
||||
}
|
||||
|
||||
void MacMetalDisplayView::SetAllowViewFlushes(bool allowFlushes)
|
||||
{
|
||||
CGDirectDisplayID displayID = (CGDirectDisplayID)this->GetDisplayViewID();
|
||||
MacClientSharedObject *sharedData = this->GetSharedData();
|
||||
|
||||
if (![sharedData isDisplayLinkRunningUsingID:displayID])
|
||||
{
|
||||
[sharedData displayLinkStartUsingID:displayID];
|
||||
}
|
||||
}
|
||||
|
||||
void MacMetalDisplayView::_UpdateNormalSize()
|
||||
{
|
||||
[(DisplayViewMetalLayer *)this->GetFrontendLayer() setNeedsScreenVerticesUpdate:YES];
|
||||
|
@ -1935,13 +1971,29 @@ void MacMetalDisplayView::ProcessDisplays()
|
|||
|
||||
void MacMetalDisplayView::UpdateView()
|
||||
{
|
||||
if (this->_allowViewUpdates)
|
||||
if (!this->_allowViewUpdates || (this->GetNSView() == nil))
|
||||
{
|
||||
@autoreleasepool
|
||||
{
|
||||
[(DisplayViewMetalLayer *)this->GetFrontendLayer() renderToDrawable];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// For every update, ensure that the CVDisplayLink is started so that the update
|
||||
// will eventually get flushed.
|
||||
this->SetAllowViewFlushes(true);
|
||||
|
||||
[(DisplayViewMetalLayer *)this->GetFrontendLayer() updateRenderBuffers];
|
||||
|
||||
OSSpinLockLock(&this->_spinlockViewNeedsFlush);
|
||||
this->_viewNeedsFlush = true;
|
||||
OSSpinLockUnlock(&this->_spinlockViewNeedsFlush);
|
||||
}
|
||||
|
||||
void MacMetalDisplayView::FlushView()
|
||||
{
|
||||
OSSpinLockLock(&this->_spinlockViewNeedsFlush);
|
||||
this->_viewNeedsFlush = false;
|
||||
OSSpinLockUnlock(&this->_spinlockViewNeedsFlush);
|
||||
|
||||
[(DisplayViewMetalLayer *)this->GetFrontendLayer() renderAndFlushDrawable];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <OpenGL/OpenGL.h>
|
||||
#include <libkern/OSAtomic.h>
|
||||
|
||||
#import "DisplayViewCALayer.h"
|
||||
#import "../cocoa_GPU.h"
|
||||
|
@ -67,7 +68,8 @@ protected:
|
|||
NSOpenGLPixelFormat *_nsPixelFormat;
|
||||
CGLContextObj _context;
|
||||
CGLPixelFormatObj _pixelFormat;
|
||||
bool _willRenderToCALayer;
|
||||
|
||||
OSSpinLock _spinlockViewNeedsFlush;
|
||||
|
||||
public:
|
||||
void operator delete(void *ptr);
|
||||
|
@ -80,8 +82,8 @@ public:
|
|||
CGLPixelFormatObj GetPixelFormat() const;
|
||||
CGLContextObj GetContext() const;
|
||||
|
||||
bool GetRenderToCALayer() const;
|
||||
void SetRenderToCALayer(const bool renderToLayer);
|
||||
virtual bool GetViewNeedsFlush();
|
||||
virtual void SetAllowViewFlushes(bool allowFlushes);
|
||||
|
||||
virtual void LoadHUDFont();
|
||||
|
||||
|
@ -97,6 +99,7 @@ public:
|
|||
virtual void LoadDisplays();
|
||||
virtual void ProcessDisplays();
|
||||
virtual void UpdateView();
|
||||
virtual void FlushView();
|
||||
virtual void FinishFrameAtIndex(const u8 bufferIndex);
|
||||
virtual void LockDisplayTextures();
|
||||
virtual void UnlockDisplayTextures();
|
||||
|
|
|
@ -277,8 +277,8 @@ MacOGLDisplayView::MacOGLDisplayView()
|
|||
|
||||
_nsContext = nil;
|
||||
_context = nil;
|
||||
_willRenderToCALayer = false;
|
||||
_allowViewUpdates = false;
|
||||
_spinlockViewNeedsFlush = OS_SPINLOCK_INIT;
|
||||
}
|
||||
|
||||
void MacOGLDisplayView::Init()
|
||||
|
@ -328,14 +328,24 @@ CGLContextObj MacOGLDisplayView::GetContext() const
|
|||
return this->_context;
|
||||
}
|
||||
|
||||
bool MacOGLDisplayView::GetRenderToCALayer() const
|
||||
bool MacOGLDisplayView::GetViewNeedsFlush()
|
||||
{
|
||||
return this->_willRenderToCALayer;
|
||||
OSSpinLockLock(&this->_spinlockViewNeedsFlush);
|
||||
const bool viewNeedsFlush = this->_viewNeedsFlush;
|
||||
OSSpinLockUnlock(&this->_spinlockViewNeedsFlush);
|
||||
|
||||
return viewNeedsFlush;
|
||||
}
|
||||
|
||||
void MacOGLDisplayView::SetRenderToCALayer(const bool renderToLayer)
|
||||
void MacOGLDisplayView::SetAllowViewFlushes(bool allowFlushes)
|
||||
{
|
||||
this->_willRenderToCALayer = renderToLayer;
|
||||
CGDirectDisplayID displayID = (CGDirectDisplayID)this->GetDisplayViewID();
|
||||
MacClientSharedObject *sharedData = this->GetSharedData();
|
||||
|
||||
if (![sharedData isDisplayLinkRunningUsingID:displayID])
|
||||
{
|
||||
[sharedData displayLinkStartUsingID:displayID];
|
||||
}
|
||||
}
|
||||
|
||||
void MacOGLDisplayView::LoadHUDFont()
|
||||
|
@ -408,25 +418,40 @@ void MacOGLDisplayView::ProcessDisplays()
|
|||
|
||||
void MacOGLDisplayView::UpdateView()
|
||||
{
|
||||
if (!this->_allowViewUpdates)
|
||||
if (!this->_allowViewUpdates || (this->GetNSView() == nil))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->_willRenderToCALayer)
|
||||
if (this->GetRenderToCALayer())
|
||||
{
|
||||
this->CALayerDisplay();
|
||||
[[this->GetNSView() layer] setNeedsDisplay];
|
||||
}
|
||||
else
|
||||
{
|
||||
CGLLockContext(this->_context);
|
||||
CGLSetCurrentContext(this->_context);
|
||||
this->RenderViewOGL();
|
||||
CGLFlushDrawable(this->_context);
|
||||
CGLUnlockContext(this->_context);
|
||||
// For every update, ensure that the CVDisplayLink is started so that the update
|
||||
// will eventually get flushed.
|
||||
this->SetAllowViewFlushes(true);
|
||||
|
||||
OSSpinLockLock(&this->_spinlockViewNeedsFlush);
|
||||
this->_viewNeedsFlush = true;
|
||||
OSSpinLockUnlock(&this->_spinlockViewNeedsFlush);
|
||||
}
|
||||
}
|
||||
|
||||
void MacOGLDisplayView::FlushView()
|
||||
{
|
||||
OSSpinLockLock(&this->_spinlockViewNeedsFlush);
|
||||
this->_viewNeedsFlush = false;
|
||||
OSSpinLockUnlock(&this->_spinlockViewNeedsFlush);
|
||||
|
||||
CGLLockContext(this->_context);
|
||||
CGLSetCurrentContext(this->_context);
|
||||
this->RenderViewOGL();
|
||||
CGLFlushDrawable(this->_context);
|
||||
CGLUnlockContext(this->_context);
|
||||
}
|
||||
|
||||
void MacOGLDisplayView::FinishFrameAtIndex(const u8 bufferIndex)
|
||||
{
|
||||
CGLLockContext(this->_context);
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#import "cocoa_firmware.h"
|
||||
#import "cocoa_globals.h"
|
||||
#import "cocoa_input.h"
|
||||
#import "cocoa_output.h"
|
||||
#import "cocoa_rom.h"
|
||||
#import "cocoa_util.h"
|
||||
|
||||
|
|
Loading…
Reference in New Issue