From 89a74e5c3e5b01f6f65209644f039e9e016a3063 Mon Sep 17 00:00:00 2001 From: rogerman Date: Fri, 10 Nov 2017 01:31:50 -0800 Subject: [PATCH] Cocoa Port: Fix a whole slew of synchronization issues in the entire client display system, hopefully improving stability. - Of special note, Metal display views aren't allowed to run on macOS High Sierra because of an assert bug in [id newBufferWithBytesNoCopy:length:options:deallocator:] in this particular version of macOS. Note that Metal display views will continue to work with macOS El Capitan and macOS Sierra. --- .../src/frontend/cocoa/ClientDisplayView.cpp | 17 +- .../src/frontend/cocoa/ClientDisplayView.h | 1 - .../src/frontend/cocoa/OGLDisplayOutput.cpp | 696 ++++++++++---- desmume/src/frontend/cocoa/OGLDisplayOutput.h | 41 +- desmume/src/frontend/cocoa/cocoa_GPU.h | 1 - desmume/src/frontend/cocoa/cocoa_GPU.mm | 78 +- desmume/src/frontend/cocoa/cocoa_output.mm | 6 +- .../cocoa/userinterface/DisplayViewCALayer.h | 4 - .../cocoa/userinterface/DisplayViewCALayer.mm | 11 - .../userinterface/DisplayWindowController.mm | 2 - .../cocoa/userinterface/MacMetalDisplayView.h | 95 +- .../userinterface/MacMetalDisplayView.mm | 907 ++++++++++-------- .../cocoa/userinterface/MacOGLDisplayView.h | 16 +- .../cocoa/userinterface/MacOGLDisplayView.mm | 60 +- desmume/src/frontend/cocoa/utilities.c | 13 + desmume/src/frontend/cocoa/utilities.h | 3 +- 16 files changed, 1204 insertions(+), 747 deletions(-) diff --git a/desmume/src/frontend/cocoa/ClientDisplayView.cpp b/desmume/src/frontend/cocoa/ClientDisplayView.cpp index a0792e732..57d1f3949 100644 --- a/desmume/src/frontend/cocoa/ClientDisplayView.cpp +++ b/desmume/src/frontend/cocoa/ClientDisplayView.cpp @@ -72,8 +72,8 @@ void ClientDisplayPresenter::__InstanceInit(const ClientDisplayPresenterProperti _displaySourceSelect[NDSDisplayID_Main] = ClientDisplaySource_DeterminedByNDS; _displaySourceSelect[NDSDisplayID_Touch] = ClientDisplaySource_DeterminedByNDS; - _isSelectedDisplayEnabled[NDSDisplayID_Main] = true; - _isSelectedDisplayEnabled[NDSDisplayID_Touch] = true; + _isSelectedDisplayEnabled[NDSDisplayID_Main] = false; + _isSelectedDisplayEnabled[NDSDisplayID_Touch] = false; _selectedSourceForDisplay[NDSDisplayID_Main] = NDSDisplayID_Main; _selectedSourceForDisplay[NDSDisplayID_Touch] = NDSDisplayID_Touch; @@ -820,7 +820,7 @@ void ClientDisplayPresenter::LoadDisplays() case ClientDisplaySource_EngineMain: { - if ( (this->_emuDisplayInfo.engineID[NDSDisplayID_Main] == GPUEngineID_Main) && (mainDisplaySrc == ClientDisplaySource_EngineMain) ) + if (this->_emuDisplayInfo.engineID[NDSDisplayID_Main] == GPUEngineID_Main) { this->_selectedSourceForDisplay[NDSDisplayID_Main] = NDSDisplayID_Main; this->_isSelectedDisplayEnabled[NDSDisplayID_Main] = this->_emuDisplayInfo.isDisplayEnabled[NDSDisplayID_Main]; @@ -835,7 +835,7 @@ void ClientDisplayPresenter::LoadDisplays() case ClientDisplaySource_EngineSub: { - if ( (this->_emuDisplayInfo.engineID[NDSDisplayID_Main] == GPUEngineID_Sub) && (mainDisplaySrc == ClientDisplaySource_EngineSub) ) + if (this->_emuDisplayInfo.engineID[NDSDisplayID_Main] == GPUEngineID_Sub) { this->_selectedSourceForDisplay[NDSDisplayID_Main] = NDSDisplayID_Main; this->_isSelectedDisplayEnabled[NDSDisplayID_Main] = this->_emuDisplayInfo.isDisplayEnabled[NDSDisplayID_Main]; @@ -863,7 +863,7 @@ void ClientDisplayPresenter::LoadDisplays() case ClientDisplaySource_EngineMain: { - if ( (this->_emuDisplayInfo.engineID[NDSDisplayID_Touch] == GPUEngineID_Main) && (touchDisplaySrc == ClientDisplaySource_EngineMain) ) + if (this->_emuDisplayInfo.engineID[NDSDisplayID_Touch] == GPUEngineID_Main) { this->_selectedSourceForDisplay[NDSDisplayID_Touch] = NDSDisplayID_Touch; this->_isSelectedDisplayEnabled[NDSDisplayID_Touch] = this->_emuDisplayInfo.isDisplayEnabled[NDSDisplayID_Touch]; @@ -878,7 +878,7 @@ void ClientDisplayPresenter::LoadDisplays() case ClientDisplaySource_EngineSub: { - if ( (this->_emuDisplayInfo.engineID[NDSDisplayID_Touch] == GPUEngineID_Sub) && (touchDisplaySrc == ClientDisplaySource_EngineSub) ) + if (this->_emuDisplayInfo.engineID[NDSDisplayID_Touch] == GPUEngineID_Sub) { this->_selectedSourceForDisplay[NDSDisplayID_Touch] = NDSDisplayID_Touch; this->_isSelectedDisplayEnabled[NDSDisplayID_Touch] = this->_emuDisplayInfo.isDisplayEnabled[NDSDisplayID_Touch]; @@ -960,11 +960,6 @@ void ClientDisplayPresenter::CopyFrameToBuffer(uint32_t *dstBuffer) // Do nothing. This is implementation dependent. } -void ClientDisplayPresenter::FinishFrameAtIndex(const uint8_t bufferIndex) -{ - // Do nothing. This is implementation dependent. -} - const NDSDisplayInfo& ClientDisplayPresenter::GetEmuDisplayInfo() const { return this->_emuDisplayInfo; diff --git a/desmume/src/frontend/cocoa/ClientDisplayView.h b/desmume/src/frontend/cocoa/ClientDisplayView.h index 4064a8c8f..870a177d4 100644 --- a/desmume/src/frontend/cocoa/ClientDisplayView.h +++ b/desmume/src/frontend/cocoa/ClientDisplayView.h @@ -301,7 +301,6 @@ public: virtual void LoadDisplays(); virtual void ProcessDisplays(); virtual void UpdateLayout(); - virtual void FinishFrameAtIndex(const uint8_t bufferIndex); virtual void CopyFrameToBuffer(uint32_t *dstBuffer); diff --git a/desmume/src/frontend/cocoa/OGLDisplayOutput.cpp b/desmume/src/frontend/cocoa/OGLDisplayOutput.cpp index 5ab80f6ea..4fdc72d84 100644 --- a/desmume/src/frontend/cocoa/OGLDisplayOutput.cpp +++ b/desmume/src/frontend/cocoa/OGLDisplayOutput.cpp @@ -4551,6 +4551,9 @@ OGLClientFetchObject::OGLClientFetchObject() pthread_rwlock_init(&_srcCloneRWLock[NDSDisplayID_Main][1], NULL); pthread_rwlock_init(&_srcCloneRWLock[NDSDisplayID_Touch][1], NULL); + pthread_rwlock_init(&_texFetchRWLock[NDSDisplayID_Main], NULL); + pthread_rwlock_init(&_texFetchRWLock[NDSDisplayID_Touch], NULL); + _srcNativeCloneMaster = (uint32_t *)malloc_alignedPage(GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT * 2 * 2 * sizeof(uint32_t)); _srcNativeClone[NDSDisplayID_Main][0] = _srcNativeCloneMaster + (GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT * 0); _srcNativeClone[NDSDisplayID_Touch][0] = _srcNativeCloneMaster + (GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT * 1); @@ -4593,6 +4596,9 @@ OGLClientFetchObject::~OGLClientFetchObject() pthread_rwlock_destroy(&this->_srcCloneRWLock[NDSDisplayID_Touch][0]); pthread_rwlock_destroy(&this->_srcCloneRWLock[NDSDisplayID_Main][1]); pthread_rwlock_destroy(&this->_srcCloneRWLock[NDSDisplayID_Touch][1]); + + pthread_rwlock_destroy(&this->_texFetchRWLock[NDSDisplayID_Main]); + pthread_rwlock_destroy(&this->_texFetchRWLock[NDSDisplayID_Touch]); } OGLContextInfo* OGLClientFetchObject::GetContextInfo() const @@ -4675,6 +4681,21 @@ void OGLClientFetchObject::FetchNativeDisplayToSrcClone(const NDSDisplayID displ } } +void OGLClientFetchObject::FetchTextureWriteLock(const NDSDisplayID displayID) +{ + pthread_rwlock_wrlock(&this->_texFetchRWLock[displayID]); +} + +void OGLClientFetchObject::FetchTextureReadLock(const NDSDisplayID displayID) +{ + pthread_rwlock_rdlock(&this->_texFetchRWLock[displayID]); +} + +void OGLClientFetchObject::FetchTextureUnlock(const NDSDisplayID displayID) +{ + pthread_rwlock_unlock(&this->_texFetchRWLock[displayID]); +} + void OGLClientFetchObject::Init() { glGenTextures(4, &this->_texDisplayFetchNative[0][0]); @@ -4738,6 +4759,9 @@ void OGLClientFetchObject::Init() glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); + this->_texFetch[NDSDisplayID_Main] = this->_texDisplayFetchNative[NDSDisplayID_Main][0]; + this->_texFetch[NDSDisplayID_Touch] = this->_texDisplayFetchNative[NDSDisplayID_Touch][0]; + if (this->_contextInfo->IsShaderSupported()) { SetupHQnxLUTs_OGL(GL_TEXTURE0 + 1, this->_texLQ2xLUT, this->_texHQ2xLUT, this->_texHQ3xLUT, this->_texHQ4xLUT); @@ -4751,15 +4775,28 @@ void OGLClientFetchObject::Init() void OGLClientFetchObject::SetFetchBuffers(const NDSDisplayInfo ¤tDisplayInfo) { + const size_t nativeSize = GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT * currentDisplayInfo.pixelBytes; + const size_t customSize = currentDisplayInfo.customWidth * currentDisplayInfo.customHeight * currentDisplayInfo.pixelBytes; + + this->_fetchDisplayInfo[0] = currentDisplayInfo; + this->_fetchDisplayInfo[1] = currentDisplayInfo; + + this->_fetchDisplayInfo[0].nativeBuffer[NDSDisplayID_Main] = (u8 *)currentDisplayInfo.masterFramebufferHead; + this->_fetchDisplayInfo[0].nativeBuffer[NDSDisplayID_Touch] = (u8 *)currentDisplayInfo.masterFramebufferHead + (nativeSize * 1); + this->_fetchDisplayInfo[0].customBuffer[NDSDisplayID_Main] = (u8 *)currentDisplayInfo.masterFramebufferHead + (nativeSize * 2); + this->_fetchDisplayInfo[0].customBuffer[NDSDisplayID_Touch] = (u8 *)currentDisplayInfo.masterFramebufferHead + (nativeSize * 2) + customSize; + + this->_fetchDisplayInfo[1].nativeBuffer[NDSDisplayID_Main] = (u8 *)this->_fetchDisplayInfo[0].nativeBuffer[NDSDisplayID_Main] + currentDisplayInfo.framebufferSize; + this->_fetchDisplayInfo[1].nativeBuffer[NDSDisplayID_Touch] = (u8 *)this->_fetchDisplayInfo[0].nativeBuffer[NDSDisplayID_Touch] + currentDisplayInfo.framebufferSize; + this->_fetchDisplayInfo[1].customBuffer[NDSDisplayID_Main] = (u8 *)this->_fetchDisplayInfo[0].customBuffer[NDSDisplayID_Main] + currentDisplayInfo.framebufferSize; + this->_fetchDisplayInfo[1].customBuffer[NDSDisplayID_Touch] = (u8 *)this->_fetchDisplayInfo[0].customBuffer[NDSDisplayID_Touch] + currentDisplayInfo.framebufferSize; + #ifdef MSB_FIRST this->_fetchColorFormatOGL = (currentDisplayInfo.pixelBytes == 2) ? GL_UNSIGNED_SHORT_1_5_5_5_REV : GL_UNSIGNED_INT_8_8_8_8; #else this->_fetchColorFormatOGL = (currentDisplayInfo.pixelBytes == 2) ? GL_UNSIGNED_SHORT_1_5_5_5_REV : GL_UNSIGNED_INT_8_8_8_8_REV; #endif - const size_t nativeSize = GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT * currentDisplayInfo.pixelBytes; - const size_t customSize = currentDisplayInfo.customWidth * currentDisplayInfo.customHeight * currentDisplayInfo.pixelBytes; - glFinish(); glTextureRangeAPPLE(GL_TEXTURE_RECTANGLE_ARB, currentDisplayInfo.framebufferSize * 2, currentDisplayInfo.masterFramebufferHead); @@ -4767,35 +4804,35 @@ void OGLClientFetchObject::SetFetchBuffers(const NDSDisplayInfo ¤tDisplayI glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texDisplayFetchNative[NDSDisplayID_Main][0]); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_STORAGE_HINT_APPLE, GL_STORAGE_SHARED_APPLE); - glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, 0, GL_RGBA, this->_fetchColorFormatOGL, (u8 *)currentDisplayInfo.masterFramebufferHead); + glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, 0, GL_RGBA, this->_fetchColorFormatOGL, this->_fetchDisplayInfo[0].nativeBuffer[NDSDisplayID_Main]); glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texDisplayFetchNative[NDSDisplayID_Main][1]); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_STORAGE_HINT_APPLE, GL_STORAGE_SHARED_APPLE); - glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, 0, GL_RGBA, this->_fetchColorFormatOGL, (u8 *)currentDisplayInfo.masterFramebufferHead + currentDisplayInfo.framebufferSize); + glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, 0, GL_RGBA, this->_fetchColorFormatOGL, this->_fetchDisplayInfo[1].nativeBuffer[NDSDisplayID_Main]); glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texDisplayFetchNative[NDSDisplayID_Touch][0]); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_STORAGE_HINT_APPLE, GL_STORAGE_SHARED_APPLE); - glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, 0, GL_RGBA, this->_fetchColorFormatOGL, (u8 *)currentDisplayInfo.masterFramebufferHead + (nativeSize * 1)); + glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, 0, GL_RGBA, this->_fetchColorFormatOGL, this->_fetchDisplayInfo[0].nativeBuffer[NDSDisplayID_Touch]); glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texDisplayFetchNative[NDSDisplayID_Touch][1]); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_STORAGE_HINT_APPLE, GL_STORAGE_SHARED_APPLE); - glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, 0, GL_RGBA, this->_fetchColorFormatOGL, (u8 *)currentDisplayInfo.masterFramebufferHead + (nativeSize * 1) + currentDisplayInfo.framebufferSize); + glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, 0, GL_RGBA, this->_fetchColorFormatOGL, this->_fetchDisplayInfo[1].nativeBuffer[NDSDisplayID_Touch]); glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texDisplayFetchCustom[NDSDisplayID_Main][0]); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_STORAGE_HINT_APPLE, GL_STORAGE_SHARED_APPLE); - glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, currentDisplayInfo.customWidth, currentDisplayInfo.customHeight, 0, GL_RGBA, this->_fetchColorFormatOGL, (u8 *)currentDisplayInfo.masterFramebufferHead + (nativeSize * 2)); + glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, currentDisplayInfo.customWidth, currentDisplayInfo.customHeight, 0, GL_RGBA, this->_fetchColorFormatOGL, this->_fetchDisplayInfo[0].customBuffer[NDSDisplayID_Main]); glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texDisplayFetchCustom[NDSDisplayID_Main][1]); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_STORAGE_HINT_APPLE, GL_STORAGE_SHARED_APPLE); - glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, currentDisplayInfo.customWidth, currentDisplayInfo.customHeight, 0, GL_RGBA, this->_fetchColorFormatOGL, (u8 *)currentDisplayInfo.masterFramebufferHead + (nativeSize * 2) + currentDisplayInfo.framebufferSize); + glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, currentDisplayInfo.customWidth, currentDisplayInfo.customHeight, 0, GL_RGBA, this->_fetchColorFormatOGL, this->_fetchDisplayInfo[1].customBuffer[NDSDisplayID_Main]); glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texDisplayFetchCustom[NDSDisplayID_Touch][0]); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_STORAGE_HINT_APPLE, GL_STORAGE_SHARED_APPLE); - glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, currentDisplayInfo.customWidth, currentDisplayInfo.customHeight, 0, GL_RGBA, this->_fetchColorFormatOGL, (u8 *)currentDisplayInfo.masterFramebufferHead + (nativeSize * 2) + customSize); + glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, currentDisplayInfo.customWidth, currentDisplayInfo.customHeight, 0, GL_RGBA, this->_fetchColorFormatOGL, this->_fetchDisplayInfo[0].customBuffer[NDSDisplayID_Touch]); glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texDisplayFetchCustom[NDSDisplayID_Touch][1]); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_STORAGE_HINT_APPLE, GL_STORAGE_SHARED_APPLE); - glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, currentDisplayInfo.customWidth, currentDisplayInfo.customHeight, 0, GL_RGBA, this->_fetchColorFormatOGL, (u8 *)currentDisplayInfo.masterFramebufferHead + (nativeSize * 2) + customSize + currentDisplayInfo.framebufferSize); + glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, currentDisplayInfo.customWidth, currentDisplayInfo.customHeight, 0, GL_RGBA, this->_fetchColorFormatOGL, this->_fetchDisplayInfo[1].customBuffer[NDSDisplayID_Touch]); glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); @@ -4818,6 +4855,45 @@ void OGLClientFetchObject::SetFetchBuffers(const NDSDisplayInfo ¤tDisplayI pthread_rwlock_unlock(&this->_srcCloneRWLock[NDSDisplayID_Touch][1]); } +void OGLClientFetchObject::FetchFromBufferIndex(const u8 index) +{ + GPUClientFetchObject::FetchFromBufferIndex(index); + glFlush(); + + GLuint texFetchMain = 0; + GLuint texFetchTouch = 0; + const NDSDisplayInfo ¤tDisplayInfo = this->GetFetchDisplayInfoForBufferIndex(index); + const bool isMainEnabled = currentDisplayInfo.isDisplayEnabled[NDSDisplayID_Main]; + const bool isTouchEnabled = currentDisplayInfo.isDisplayEnabled[NDSDisplayID_Touch]; + + if (isMainEnabled) + { + if (!currentDisplayInfo.didPerformCustomRender[NDSDisplayID_Main]) + { + texFetchMain = this->_texDisplayFetchNative[NDSDisplayID_Main][index]; + } + else + { + texFetchMain = this->_texDisplayFetchCustom[NDSDisplayID_Main][index]; + } + } + + if (isTouchEnabled) + { + if (!currentDisplayInfo.didPerformCustomRender[NDSDisplayID_Touch]) + { + texFetchTouch = this->_texDisplayFetchNative[NDSDisplayID_Touch][index]; + } + else + { + texFetchTouch = this->_texDisplayFetchCustom[NDSDisplayID_Touch][index]; + } + } + + this->SetFetchTexture(NDSDisplayID_Main, texFetchMain); + this->SetFetchTexture(NDSDisplayID_Touch, texFetchTouch); +} + void OGLClientFetchObject::_FetchNativeDisplayByID(const NDSDisplayID displayID, const u8 bufferIndex) { pthread_rwlock_wrlock(&this->_srcCloneRWLock[displayID][bufferIndex]); @@ -4840,6 +4916,16 @@ void OGLClientFetchObject::_FetchCustomDisplayByID(const NDSDisplayID displayID, glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, this->_fetchDisplayInfo[bufferIndex].customWidth, this->_fetchDisplayInfo[bufferIndex].customHeight, GL_RGBA, this->_fetchColorFormatOGL, this->_fetchDisplayInfo[bufferIndex].customBuffer[displayID]); } +GLuint OGLClientFetchObject::GetFetchTexture(const NDSDisplayID displayID) +{ + return this->_texFetch[displayID]; +} + +void OGLClientFetchObject::SetFetchTexture(const NDSDisplayID displayID, GLuint texID) +{ + this->_texFetch[displayID] = texID; +} + #pragma mark - OGLVideoOutput::OGLVideoOutput() @@ -4854,6 +4940,12 @@ OGLVideoOutput::OGLVideoOutput() _texCPUFilterDstID[NDSDisplayID_Touch] = 0; _fboFrameCopyID = 0; + _processedFrameInfo.bufferIndex = 0; + _processedFrameInfo.texID[NDSDisplayID_Main] = 0; + _processedFrameInfo.texID[NDSDisplayID_Touch] = 0; + _processedFrameInfo.isMainDisplayProcessed = false; + _processedFrameInfo.isTouchDisplayProcessed = false; + _layerList = new std::vector; _layerList->reserve(8); } @@ -5084,19 +5176,6 @@ void OGLVideoOutput::ProcessDisplays() } } -void OGLVideoOutput::FinishFrameAtIndex(const uint8_t bufferIndex) -{ - for (size_t i = 0; i < _layerList->size(); i++) - { - OGLVideoLayer *theLayer = (*_layerList)[i]; - - if (theLayer->IsVisible()) - { - theLayer->FinishOGL(bufferIndex); - } - } -} - void OGLVideoOutput::CopyFrameToBuffer(uint32_t *dstBuffer) { GLuint texFrameCopyID = 0; @@ -5149,12 +5228,27 @@ void OGLVideoOutput::RenderFrameOGL(bool isRenderingFlipped) } } -void OGLVideoOutput::LockDisplayTextures() +const OGLProcessedFrameInfo& OGLVideoOutput::GetProcessedFrameInfo() +{ + return this->_processedFrameInfo; +} + +void OGLVideoOutput::SetProcessedFrameInfo(const OGLProcessedFrameInfo &processedInfo) +{ + this->_processedFrameInfo = processedInfo; +} + +void OGLVideoOutput::WriteLockEmuFramebuffer(const uint8_t bufferIndex) { // Do nothing. This is implementation dependent. } -void OGLVideoOutput::UnlockDisplayTextures() +void OGLVideoOutput::ReadLockEmuFramebuffer(const uint8_t bufferIndex) +{ + // Do nothing. This is implementation dependent. +} + +void OGLVideoOutput::UnlockEmuFramebuffer(const uint8_t bufferIndex) { // Do nothing. This is implementation dependent. } @@ -6568,8 +6662,10 @@ OGLDisplayLayer::OGLDisplayLayer(OGLVideoOutput *oglVO) _displayTexFilter[0] = GL_NEAREST; _displayTexFilter[1] = GL_NEAREST; - _texVideoOutputID[0] = 0; - _texVideoOutputID[1] = 0; + pthread_rwlock_init(&_cpuFilterRWLock[NDSDisplayID_Main][0], NULL); + pthread_rwlock_init(&_cpuFilterRWLock[NDSDisplayID_Touch][0], NULL); + pthread_rwlock_init(&_cpuFilterRWLock[NDSDisplayID_Main][1], NULL); + pthread_rwlock_init(&_cpuFilterRWLock[NDSDisplayID_Touch][1], NULL); // Set up VBOs glGenBuffersARB(1, &_vboVertexID); @@ -6676,6 +6772,11 @@ OGLDisplayLayer::~OGLDisplayLayer() delete this->_shaderFilter[0]; delete this->_shaderFilter[1]; } + + pthread_rwlock_destroy(&this->_cpuFilterRWLock[NDSDisplayID_Main][0]); + pthread_rwlock_destroy(&this->_cpuFilterRWLock[NDSDisplayID_Touch][0]); + pthread_rwlock_destroy(&this->_cpuFilterRWLock[NDSDisplayID_Main][1]); + pthread_rwlock_destroy(&this->_cpuFilterRWLock[NDSDisplayID_Touch][1]); } void OGLDisplayLayer::_UpdateRotationScaleOGL() @@ -7062,110 +7163,237 @@ void OGLDisplayLayer::LoadNativeDisplayByID_OGL(const NDSDisplayID displayID) OGLClientFetchObject &fetchObjMutable = (OGLClientFetchObject &)this->_output->GetFetchObject(); VideoFilter *vf = this->_output->GetPixelScalerObject(displayID); - fetchObjMutable.CopyFromSrcClone(vf->GetSrcBufferPtr(), displayID, this->_output->GetEmuDisplayInfo().bufferIndex); - } -} - -void OGLDisplayLayer::_ProcessDisplayByID(const NDSDisplayID displayID, GLsizei &inoutWidth, GLsizei &inoutHeight, GLuint &inoutTexID) -{ - VideoFilter *vf = this->_output->GetPixelScalerObject(displayID); - const bool willFilterOnGPU = this->_output->WillFilterOnGPU(); - const bool useDeposterize = this->_output->GetSourceDeposterize(); - - // Source - if (useDeposterize) - { - // For all shader-based filters, we need to temporarily disable GL_UNPACK_CLIENT_STORAGE_APPLE. - // Filtered images are supposed to remain on the GPU for immediate use for further GPU processing, - // so using client-backed buffers for filtered images would simply waste memory here. - glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE); - inoutTexID = this->_filterDeposterize[displayID]->RunFilterOGL(inoutTexID); - glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE); + const uint8_t bufferIndex = fetchObjMutable.GetLastFetchIndex(); - if ((this->_output->GetPixelScaler() != VideoFilterTypeID_None) && !willFilterOnGPU) // Hybrid CPU/GPU-based path (may cause a performance hit on pixel download) - { - this->_filterDeposterize[displayID]->DownloadDstBufferOGL(vf->GetSrcBufferPtr(), 0, vf->GetSrcHeight()); - } - } - - // Pixel scaler - if (this->_output->GetPixelScaler() != VideoFilterTypeID_None) - { - if (willFilterOnGPU) - { - glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE); - inoutTexID = this->_shaderFilter[displayID]->RunFilterOGL(inoutTexID); - glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE); - - inoutWidth = vf->GetDstWidth(); - inoutHeight = vf->GetDstHeight(); - } - else - { - uint32_t *texData = vf->RunFilter(); - inoutTexID = this->_output->GetTexCPUFilterDstID(displayID); - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, inoutTexID); - glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, vf->GetDstWidth(), vf->GetDstHeight(), GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, texData); - - inoutWidth = (GLsizei)vf->GetDstWidth(); - inoutHeight = (GLsizei)vf->GetDstHeight(); - } + pthread_rwlock_wrlock(&this->_cpuFilterRWLock[displayID][bufferIndex]); + fetchObjMutable.CopyFromSrcClone(vf->GetSrcBufferPtr(), displayID, bufferIndex); + pthread_rwlock_unlock(&this->_cpuFilterRWLock[displayID][bufferIndex]); } } void OGLDisplayLayer::ProcessOGL() { - const OGLClientFetchObject &fetchObj = (const OGLClientFetchObject &)this->_output->GetFetchObject(); + OGLClientFetchObject &fetchObj = (OGLClientFetchObject &)this->_output->GetFetchObject(); + const uint8_t bufferIndex = fetchObj.GetLastFetchIndex(); const NDSDisplayInfo &emuDisplayInfo = this->_output->GetEmuDisplayInfo(); const ClientDisplayMode mode = this->_output->GetPresenterProperties().mode; + const bool useDeposterize = this->_output->GetSourceDeposterize(); const NDSDisplayID selectedDisplaySource[2] = { this->_output->GetSelectedDisplaySourceForDisplay(NDSDisplayID_Main), this->_output->GetSelectedDisplaySourceForDisplay(NDSDisplayID_Touch) }; const bool didRenderNative[2] = { !emuDisplayInfo.didPerformCustomRender[selectedDisplaySource[NDSDisplayID_Main]], !emuDisplayInfo.didPerformCustomRender[selectedDisplaySource[NDSDisplayID_Touch]] }; - GLuint texVideoSourceID[2] = { (didRenderNative[NDSDisplayID_Main]) ? fetchObj.GetTexNative(selectedDisplaySource[NDSDisplayID_Main], emuDisplayInfo.bufferIndex) : fetchObj.GetTexCustom(selectedDisplaySource[NDSDisplayID_Main], emuDisplayInfo.bufferIndex), - (didRenderNative[NDSDisplayID_Touch]) ? fetchObj.GetTexNative(selectedDisplaySource[NDSDisplayID_Touch], emuDisplayInfo.bufferIndex) : fetchObj.GetTexCustom(selectedDisplaySource[NDSDisplayID_Touch], emuDisplayInfo.bufferIndex) }; + + GLuint texMain = (selectedDisplaySource[NDSDisplayID_Main] == NDSDisplayID_Main) ? fetchObj.GetFetchTexture(NDSDisplayID_Main) : fetchObj.GetFetchTexture(NDSDisplayID_Touch); + GLuint texTouch = (selectedDisplaySource[NDSDisplayID_Touch] == NDSDisplayID_Touch) ? fetchObj.GetFetchTexture(NDSDisplayID_Touch) : fetchObj.GetFetchTexture(NDSDisplayID_Main); + GLsizei width[2] = { emuDisplayInfo.renderedWidth[selectedDisplaySource[NDSDisplayID_Main]], emuDisplayInfo.renderedWidth[selectedDisplaySource[NDSDisplayID_Touch]] }; GLsizei height[2] = { emuDisplayInfo.renderedHeight[selectedDisplaySource[NDSDisplayID_Main]], emuDisplayInfo.renderedHeight[selectedDisplaySource[NDSDisplayID_Touch]] }; - if (emuDisplayInfo.pixelBytes != 0) + VideoFilter *vfMain = this->_output->GetPixelScalerObject(NDSDisplayID_Main); + VideoFilter *vfTouch = this->_output->GetPixelScalerObject(NDSDisplayID_Touch); + + bool isDisplayProcessedMain = false; + bool isDisplayProcessedTouch = false; + + if ( (emuDisplayInfo.pixelBytes != 0) && (useDeposterize || (this->_output->GetPixelScaler() != VideoFilterTypeID_None)) ) { // Run the video source filters and the pixel scalers const bool willFilterOnGPU = this->_output->WillFilterOnGPU(); - const bool useDeposterize = this->_output->GetSourceDeposterize(); - const bool needProcessDisplay[2] = { (didRenderNative[NDSDisplayID_Main] || !emuDisplayInfo.isCustomSizeRequested) && this->_output->IsSelectedDisplayEnabled(NDSDisplayID_Main) && (mode == ClientDisplayMode_Main || mode == ClientDisplayMode_Dual), - (didRenderNative[NDSDisplayID_Touch] || !emuDisplayInfo.isCustomSizeRequested) && this->_output->IsSelectedDisplayEnabled(NDSDisplayID_Touch) && (mode == ClientDisplayMode_Touch || mode == ClientDisplayMode_Dual) && (selectedDisplaySource[NDSDisplayID_Main] != selectedDisplaySource[NDSDisplayID_Touch]) }; - const bool needsLock = (willFilterOnGPU || useDeposterize) && (needProcessDisplay[NDSDisplayID_Main] || needProcessDisplay[NDSDisplayID_Touch]); + const bool shouldProcessDisplay[2] = { (didRenderNative[NDSDisplayID_Main] || !emuDisplayInfo.isCustomSizeRequested) && this->_output->IsSelectedDisplayEnabled(NDSDisplayID_Main) && (mode == ClientDisplayMode_Main || mode == ClientDisplayMode_Dual), + (didRenderNative[NDSDisplayID_Touch] || !emuDisplayInfo.isCustomSizeRequested) && this->_output->IsSelectedDisplayEnabled(NDSDisplayID_Touch) && (mode == ClientDisplayMode_Touch || mode == ClientDisplayMode_Dual) && (selectedDisplaySource[NDSDisplayID_Main] != selectedDisplaySource[NDSDisplayID_Touch]) }; - if (needsLock) + bool texFetchMainNeedsLock = (useDeposterize || ((this->_output->GetPixelScaler() != VideoFilterTypeID_None) && willFilterOnGPU)) && shouldProcessDisplay[NDSDisplayID_Main]; + bool texFetchTouchNeedsLock = (useDeposterize || ((this->_output->GetPixelScaler() != VideoFilterTypeID_None) && willFilterOnGPU)) && shouldProcessDisplay[NDSDisplayID_Touch]; + bool needsFetchBuffersLock = texFetchMainNeedsLock || texFetchTouchNeedsLock; + + if (needsFetchBuffersLock) { - this->_output->LockDisplayTextures(); + this->_output->ReadLockEmuFramebuffer(bufferIndex); } - if (needProcessDisplay[NDSDisplayID_Main]) + if (useDeposterize) { - this->_ProcessDisplayByID(NDSDisplayID_Main, width[NDSDisplayID_Main], height[NDSDisplayID_Main], texVideoSourceID[NDSDisplayID_Main]); + if (shouldProcessDisplay[NDSDisplayID_Main]) + { + if (texFetchMainNeedsLock) + { + fetchObj.FetchTextureReadLock(NDSDisplayID_Main); + } + + // For all shader-based filters, we need to temporarily disable GL_UNPACK_CLIENT_STORAGE_APPLE. + // Filtered images are supposed to remain on the GPU for immediate use for further GPU processing, + // so using client-backed buffers for filtered images would simply waste memory here. + glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE); + texMain = this->_filterDeposterize[NDSDisplayID_Main]->RunFilterOGL(texMain); + glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE); + + if (texFetchMainNeedsLock) + { + fetchObj.FetchTextureUnlock(NDSDisplayID_Main); + } + + isDisplayProcessedMain = true; + texFetchMainNeedsLock = false; + + if (selectedDisplaySource[NDSDisplayID_Main] == selectedDisplaySource[NDSDisplayID_Touch]) + { + isDisplayProcessedTouch = true; + texFetchTouchNeedsLock = false; + } + } + + if (shouldProcessDisplay[NDSDisplayID_Touch]) + { + if (texFetchTouchNeedsLock) + { + fetchObj.FetchTextureReadLock(NDSDisplayID_Touch); + } + + glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE); + texTouch = this->_filterDeposterize[NDSDisplayID_Touch]->RunFilterOGL(texTouch); + glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE); + + if (texFetchTouchNeedsLock) + { + fetchObj.FetchTextureUnlock(NDSDisplayID_Touch); + } + + isDisplayProcessedTouch = true; + texFetchTouchNeedsLock = false; + } + + if (needsFetchBuffersLock && (!shouldProcessDisplay[NDSDisplayID_Main] || isDisplayProcessedMain) && (!shouldProcessDisplay[NDSDisplayID_Touch] || isDisplayProcessedTouch)) + { + glFinish(); + needsFetchBuffersLock = false; + this->_output->UnlockEmuFramebuffer(bufferIndex); + } } - if (needProcessDisplay[NDSDisplayID_Touch]) + // Run the pixel scalers. First attempt on the GPU. + if ( (this->_output->GetPixelScaler() != VideoFilterTypeID_None) && willFilterOnGPU ) { - this->_ProcessDisplayByID(NDSDisplayID_Touch, width[NDSDisplayID_Touch], height[NDSDisplayID_Touch], texVideoSourceID[NDSDisplayID_Touch]); + if (shouldProcessDisplay[NDSDisplayID_Main]) + { + if (texFetchMainNeedsLock) + { + fetchObj.FetchTextureReadLock(NDSDisplayID_Main); + } + + glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE); + texMain = this->_shaderFilter[NDSDisplayID_Main]->RunFilterOGL(texMain); + glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE); + + if (texFetchMainNeedsLock) + { + fetchObj.FetchTextureUnlock(NDSDisplayID_Main); + } + + width[NDSDisplayID_Main] = (GLsizei)vfMain->GetDstWidth(); + height[NDSDisplayID_Main] = (GLsizei)vfMain->GetDstHeight(); + isDisplayProcessedMain = true; + texFetchMainNeedsLock = false; + + if (selectedDisplaySource[NDSDisplayID_Main] == selectedDisplaySource[NDSDisplayID_Touch]) + { + isDisplayProcessedTouch = true; + texFetchTouchNeedsLock = false; + } + } + + if (shouldProcessDisplay[NDSDisplayID_Touch]) + { + if (texFetchTouchNeedsLock) + { + fetchObj.FetchTextureReadLock(NDSDisplayID_Touch); + } + + glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE); + texTouch = this->_shaderFilter[NDSDisplayID_Touch]->RunFilterOGL(texTouch); + glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE); + + if (texFetchTouchNeedsLock) + { + fetchObj.FetchTextureUnlock(NDSDisplayID_Touch); + } + + width[NDSDisplayID_Touch] = (GLsizei)vfTouch->GetDstWidth(); + height[NDSDisplayID_Touch] = (GLsizei)vfTouch->GetDstHeight(); + isDisplayProcessedTouch = true; + texFetchTouchNeedsLock = false; + } + + if (needsFetchBuffersLock && (!shouldProcessDisplay[NDSDisplayID_Main] || isDisplayProcessedMain) && (!shouldProcessDisplay[NDSDisplayID_Touch] || isDisplayProcessedTouch)) + { + glFinish(); + needsFetchBuffersLock = false; + this->_output->UnlockEmuFramebuffer(bufferIndex); + } } - if (needsLock) + // If the pixel scaler didn't already run on the GPU, then run the pixel scaler on the CPU. + if ( (this->_output->GetPixelScaler() != VideoFilterTypeID_None) && !willFilterOnGPU ) { - this->_output->UnlockDisplayTextures(); + if (useDeposterize) + { + // Hybrid CPU/GPU-based path (may cause a performance hit on pixel download) + if (shouldProcessDisplay[NDSDisplayID_Main]) + { + this->_filterDeposterize[NDSDisplayID_Main]->DownloadDstBufferOGL(vfMain->GetSrcBufferPtr(), 0, vfMain->GetSrcHeight()); + } + + if (shouldProcessDisplay[NDSDisplayID_Touch]) + { + this->_filterDeposterize[NDSDisplayID_Touch]->DownloadDstBufferOGL(vfTouch->GetSrcBufferPtr(), 0, vfTouch->GetSrcHeight()); + } + } + + if (shouldProcessDisplay[NDSDisplayID_Main]) + { + pthread_rwlock_rdlock(&this->_cpuFilterRWLock[NDSDisplayID_Main][bufferIndex]); + vfMain->RunFilter(); + pthread_rwlock_unlock(&this->_cpuFilterRWLock[NDSDisplayID_Main][bufferIndex]); + } + + if (shouldProcessDisplay[NDSDisplayID_Touch]) + { + pthread_rwlock_rdlock(&this->_cpuFilterRWLock[NDSDisplayID_Touch][bufferIndex]); + vfTouch->RunFilter(); + pthread_rwlock_unlock(&this->_cpuFilterRWLock[NDSDisplayID_Touch][bufferIndex]); + } + + if (shouldProcessDisplay[NDSDisplayID_Main]) + { + texMain = this->_output->GetTexCPUFilterDstID(NDSDisplayID_Main); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texMain); + glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, vfMain->GetDstWidth(), vfMain->GetDstHeight(), GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, vfMain->GetDstBufferPtr()); + + width[NDSDisplayID_Main] = (GLsizei)vfMain->GetDstWidth(); + height[NDSDisplayID_Main] = (GLsizei)vfMain->GetDstHeight(); + isDisplayProcessedMain = true; + + if (selectedDisplaySource[NDSDisplayID_Main] == selectedDisplaySource[NDSDisplayID_Touch]) + { + isDisplayProcessedTouch = true; + } + } + + if (shouldProcessDisplay[NDSDisplayID_Touch]) + { + texTouch = this->_output->GetTexCPUFilterDstID(NDSDisplayID_Touch); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texTouch); + glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, vfTouch->GetDstWidth(), vfTouch->GetDstHeight(), GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, vfTouch->GetDstBufferPtr()); + + width[NDSDisplayID_Touch] = (GLsizei)vfTouch->GetDstWidth(); + height[NDSDisplayID_Touch] = (GLsizei)vfTouch->GetDstHeight(); + isDisplayProcessedTouch = true; + } } } // Set the final output texture IDs - this->_texVideoOutputID[NDSDisplayID_Main] = texVideoSourceID[NDSDisplayID_Main]; - - if (selectedDisplaySource[NDSDisplayID_Touch] != selectedDisplaySource[NDSDisplayID_Main]) + if (selectedDisplaySource[NDSDisplayID_Touch] == selectedDisplaySource[NDSDisplayID_Main]) { - this->_texVideoOutputID[NDSDisplayID_Touch] = texVideoSourceID[NDSDisplayID_Touch]; - } - else - { - this->_texVideoOutputID[NDSDisplayID_Touch] = texVideoSourceID[NDSDisplayID_Main]; + texTouch = texMain; width[NDSDisplayID_Touch] = width[NDSDisplayID_Main]; height[NDSDisplayID_Touch] = height[NDSDisplayID_Main]; } @@ -7183,11 +7411,21 @@ void OGLDisplayLayer::ProcessOGL() // OpenGL shader-based filters can modify the viewport, so it needs to be reset here. glViewport(0, 0, this->_output->GetViewportWidth(), this->_output->GetViewportHeight()); + + glFlush(); + + OGLProcessedFrameInfo newFrameInfo; + newFrameInfo.bufferIndex = bufferIndex; + newFrameInfo.isMainDisplayProcessed = isDisplayProcessedMain; + newFrameInfo.isTouchDisplayProcessed = isDisplayProcessedTouch; + newFrameInfo.texID[NDSDisplayID_Main] = texMain; + newFrameInfo.texID[NDSDisplayID_Touch] = texTouch; + + this->_output->SetProcessedFrameInfo(newFrameInfo); } void OGLDisplayLayer::RenderOGL(bool isRenderingFlipped) { - const NDSDisplayInfo &emuDisplayInfo = this->_output->GetEmuDisplayInfo(); const bool isShaderSupported = this->_output->GetContextInfo()->IsShaderSupported(); if (isShaderSupported) @@ -7227,124 +7465,198 @@ void OGLDisplayLayer::RenderOGL(bool isRenderingFlipped) this->_UpdateRotationScaleOGL(); } - if (emuDisplayInfo.pixelBytes != 0) + if (this->_needUpdateVertices) { - if (this->_needUpdateVertices) + this->_UpdateVerticesOGL(); + } + + OGLClientFetchObject &fetchObj = (OGLClientFetchObject &)this->_output->GetFetchObject(); + const NDSDisplayInfo &emuDisplayInfo = this->_output->GetEmuDisplayInfo(); + const float backlightIntensity[2] = { emuDisplayInfo.backlightIntensity[NDSDisplayID_Main], emuDisplayInfo.backlightIntensity[NDSDisplayID_Touch] }; + + const OGLProcessedFrameInfo processedInfo = this->_output->GetProcessedFrameInfo(); + bool texFetchMainNeedsLock = !processedInfo.isMainDisplayProcessed; + bool texFetchTouchNeedsLock = !processedInfo.isTouchDisplayProcessed; + const bool needsFetchBuffersLock = texFetchMainNeedsLock || texFetchTouchNeedsLock; + + if (needsFetchBuffersLock) + { + this->_output->ReadLockEmuFramebuffer(processedInfo.bufferIndex); + } + + glBindVertexArrayDESMUME(this->_vaoMainStatesID); + + switch (this->_output->GetPresenterProperties().mode) + { + case ClientDisplayMode_Main: { - this->_UpdateVerticesOGL(); + if (this->_output->IsSelectedDisplayEnabled(NDSDisplayID_Main)) + { + if (isShaderSupported) + { + glUniform1f(this->_uniformBacklightIntensity, backlightIntensity[NDSDisplayID_Main]); + } + + if (texFetchMainNeedsLock) + { + fetchObj.FetchTextureWriteLock(NDSDisplayID_Main); + } + + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, processedInfo.texID[NDSDisplayID_Main]); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, this->_displayTexFilter[NDSDisplayID_Main]); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, this->_displayTexFilter[NDSDisplayID_Main]); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + if (texFetchMainNeedsLock) + { + glFlush(); + fetchObj.FetchTextureUnlock(NDSDisplayID_Main); + texFetchMainNeedsLock = false; + } + } + break; } - - this->_output->LockDisplayTextures(); - glBindVertexArrayDESMUME(this->_vaoMainStatesID); - - switch (this->_output->GetPresenterProperties().mode) + + case ClientDisplayMode_Touch: { - case ClientDisplayMode_Main: + if (this->_output->IsSelectedDisplayEnabled(NDSDisplayID_Touch)) { - if (this->_output->IsSelectedDisplayEnabled(NDSDisplayID_Main)) + if (isShaderSupported) { - if (isShaderSupported) - { - glUniform1f(this->_uniformBacklightIntensity, emuDisplayInfo.backlightIntensity[NDSDisplayID_Main]); - } - - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texVideoOutputID[NDSDisplayID_Main]); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, this->_displayTexFilter[NDSDisplayID_Main]); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, this->_displayTexFilter[NDSDisplayID_Main]); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glUniform1f(this->_uniformBacklightIntensity, backlightIntensity[NDSDisplayID_Touch]); } - break; - } - case ClientDisplayMode_Touch: - { - if (this->_output->IsSelectedDisplayEnabled(NDSDisplayID_Touch)) + if (texFetchTouchNeedsLock) { - if (isShaderSupported) - { - glUniform1f(this->_uniformBacklightIntensity, emuDisplayInfo.backlightIntensity[NDSDisplayID_Touch]); - } - - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texVideoOutputID[NDSDisplayID_Touch]); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, this->_displayTexFilter[NDSDisplayID_Touch]); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, this->_displayTexFilter[NDSDisplayID_Touch]); - glDrawArrays(GL_TRIANGLE_STRIP, 4, 4); + fetchObj.FetchTextureWriteLock(NDSDisplayID_Touch); } - break; - } - case ClientDisplayMode_Dual: - { - const NDSDisplayID majorDisplayID = (this->_output->GetPresenterProperties().order == ClientDisplayOrder_MainFirst) ? NDSDisplayID_Main : NDSDisplayID_Touch; - const size_t majorDisplayVtx = (this->_output->GetPresenterProperties().order == ClientDisplayOrder_MainFirst) ? 8 : 12; + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, processedInfo.texID[NDSDisplayID_Touch]); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, this->_displayTexFilter[NDSDisplayID_Touch]); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, this->_displayTexFilter[NDSDisplayID_Touch]); + glDrawArrays(GL_TRIANGLE_STRIP, 4, 4); - switch (this->_output->GetPresenterProperties().layout) + if (texFetchTouchNeedsLock) { - case ClientDisplayLayout_Hybrid_2_1: - case ClientDisplayLayout_Hybrid_16_9: - case ClientDisplayLayout_Hybrid_16_10: + glFlush(); + fetchObj.FetchTextureUnlock(NDSDisplayID_Touch); + texFetchTouchNeedsLock = false; + } + } + break; + } + + case ClientDisplayMode_Dual: + { + const NDSDisplayID majorDisplayID = (this->_output->GetPresenterProperties().order == ClientDisplayOrder_MainFirst) ? NDSDisplayID_Main : NDSDisplayID_Touch; + const size_t majorDisplayVtx = (this->_output->GetPresenterProperties().order == ClientDisplayOrder_MainFirst) ? 8 : 12; + + bool texFetchMainAlreadyLocked = false; + bool texFetchTouchAlreadyLocked = false; + + switch (this->_output->GetPresenterProperties().layout) + { + case ClientDisplayLayout_Hybrid_2_1: + case ClientDisplayLayout_Hybrid_16_9: + case ClientDisplayLayout_Hybrid_16_10: + { + if (this->_output->IsSelectedDisplayEnabled(majorDisplayID)) { - if (this->_output->IsSelectedDisplayEnabled(majorDisplayID)) + if (isShaderSupported) { - if (isShaderSupported) - { - glUniform1f(this->_uniformBacklightIntensity, emuDisplayInfo.backlightIntensity[majorDisplayID]); - } - - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texVideoOutputID[majorDisplayID]); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, this->_displayTexFilter[majorDisplayID]); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, this->_displayTexFilter[majorDisplayID]); - glDrawArrays(GL_TRIANGLE_STRIP, majorDisplayVtx, 4); + glUniform1f(this->_uniformBacklightIntensity, backlightIntensity[majorDisplayID]); } - break; - } - default: - break; + const bool texFetchMajorNeedsLock = (majorDisplayID == NDSDisplayID_Main) ? texFetchMainNeedsLock : texFetchTouchNeedsLock; + + if (texFetchMajorNeedsLock) + { + fetchObj.FetchTextureWriteLock(majorDisplayID); + } + + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, processedInfo.texID[majorDisplayID]); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, this->_displayTexFilter[majorDisplayID]); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, this->_displayTexFilter[majorDisplayID]); + glDrawArrays(GL_TRIANGLE_STRIP, majorDisplayVtx, 4); + + if (texFetchMajorNeedsLock) + { + if (majorDisplayID == NDSDisplayID_Main) + { + texFetchMainAlreadyLocked = true; + } + else + { + texFetchTouchAlreadyLocked = true; + } + } + } + break; + } + + default: + break; + } + + if (this->_output->IsSelectedDisplayEnabled(NDSDisplayID_Main)) + { + if (isShaderSupported) + { + glUniform1f(this->_uniformBacklightIntensity, backlightIntensity[NDSDisplayID_Main]); } - if (this->_output->IsSelectedDisplayEnabled(NDSDisplayID_Main)) + if (texFetchMainNeedsLock && !texFetchMainAlreadyLocked) { - if (isShaderSupported) - { - glUniform1f(this->_uniformBacklightIntensity, emuDisplayInfo.backlightIntensity[NDSDisplayID_Main]); - } - - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texVideoOutputID[NDSDisplayID_Main]); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, this->_displayTexFilter[NDSDisplayID_Main]); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, this->_displayTexFilter[NDSDisplayID_Main]); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + fetchObj.FetchTextureWriteLock(NDSDisplayID_Main); } - if (this->_output->IsSelectedDisplayEnabled(NDSDisplayID_Touch)) + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, processedInfo.texID[NDSDisplayID_Main]); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, this->_displayTexFilter[NDSDisplayID_Main]); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, this->_displayTexFilter[NDSDisplayID_Main]); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + if (texFetchMainNeedsLock) { - if (isShaderSupported) - { - glUniform1f(this->_uniformBacklightIntensity, emuDisplayInfo.backlightIntensity[NDSDisplayID_Touch]); - } - - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texVideoOutputID[NDSDisplayID_Touch]); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, this->_displayTexFilter[NDSDisplayID_Touch]); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, this->_displayTexFilter[NDSDisplayID_Touch]); - glDrawArrays(GL_TRIANGLE_STRIP, 4, 4); + glFlush(); + fetchObj.FetchTextureUnlock(NDSDisplayID_Main); + texFetchMainNeedsLock = false; } } + + if (this->_output->IsSelectedDisplayEnabled(NDSDisplayID_Touch)) + { + if (isShaderSupported) + { + glUniform1f(this->_uniformBacklightIntensity, backlightIntensity[NDSDisplayID_Touch]); + } - default: - break; + if (texFetchTouchNeedsLock && !texFetchTouchAlreadyLocked) + { + fetchObj.FetchTextureWriteLock(NDSDisplayID_Touch); + } + + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, processedInfo.texID[NDSDisplayID_Touch]); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, this->_displayTexFilter[NDSDisplayID_Touch]); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, this->_displayTexFilter[NDSDisplayID_Touch]); + glDrawArrays(GL_TRIANGLE_STRIP, 4, 4); + + if (texFetchTouchNeedsLock) + { + glFlush(); + fetchObj.FetchTextureUnlock(NDSDisplayID_Touch); + texFetchTouchNeedsLock = false; + } + } } - - glBindVertexArrayDESMUME(0); - this->_output->UnlockDisplayTextures(); + + default: + break; + } + + glBindVertexArrayDESMUME(0); + + if (needsFetchBuffersLock) + { + this->_output->UnlockEmuFramebuffer(processedInfo.bufferIndex); } } - -void OGLDisplayLayer::FinishOGL(const u8 bufferIndex) -{ - const OGLClientFetchObject &fetchObj = (const OGLClientFetchObject &)this->_output->GetFetchObject(); - - glFinishObjectAPPLE(GL_TEXTURE_RECTANGLE_ARB, fetchObj.GetTexNative(NDSDisplayID_Main, bufferIndex)); - glFinishObjectAPPLE(GL_TEXTURE_RECTANGLE_ARB, fetchObj.GetTexNative(NDSDisplayID_Touch, bufferIndex)); - glFinishObjectAPPLE(GL_TEXTURE_RECTANGLE_ARB, fetchObj.GetTexCustom(NDSDisplayID_Main, bufferIndex)); - glFinishObjectAPPLE(GL_TEXTURE_RECTANGLE_ARB, fetchObj.GetTexCustom(NDSDisplayID_Touch, bufferIndex)); -} diff --git a/desmume/src/frontend/cocoa/OGLDisplayOutput.h b/desmume/src/frontend/cocoa/OGLDisplayOutput.h index 3fa10b2b1..cb27c8060 100644 --- a/desmume/src/frontend/cocoa/OGLDisplayOutput.h +++ b/desmume/src/frontend/cocoa/OGLDisplayOutput.h @@ -49,6 +49,15 @@ enum ShaderSupportTier ShaderSupport_FutureTier = 6, }; +struct OGLProcessedFrameInfo +{ + uint8_t bufferIndex; + GLuint texID[2]; + bool isMainDisplayProcessed; + bool isTouchDisplayProcessed; +}; +typedef struct OGLProcessedFrameInfo OGLProcessedFrameInfo; + class OGLContextInfo { protected: @@ -273,7 +282,6 @@ public: virtual void SetVisibility(const bool visibleState); virtual void RenderOGL(bool isRenderingFlipped) = 0; - virtual void FinishOGL(const u8 bufferIndex) {}; }; class OGLHUDLayer : public OGLVideoLayer @@ -306,8 +314,7 @@ protected: OGLFilter *_filterDeposterize[2]; OGLFilter *_shaderFilter[2]; GLint _displayTexFilter[2]; - - GLuint _texVideoOutputID[2]; + pthread_rwlock_t _cpuFilterRWLock[2][2]; GLuint _vaoMainStatesID; GLuint _vboVertexID; @@ -316,8 +323,6 @@ protected: void _UpdateRotationScaleOGL(); void _UpdateVerticesOGL(); - void _ProcessDisplayByID(const NDSDisplayID displayID, GLsizei &inoutWidth, GLsizei &inoutHeight, GLuint &inoutTexID); - public: OGLDisplayLayer() {}; OGLDisplayLayer(OGLVideoOutput *oglVO); @@ -328,8 +333,8 @@ public: void LoadNativeDisplayByID_OGL(const NDSDisplayID displayID); void ProcessOGL(); + virtual void RenderOGL(bool isRenderingFlipped); - virtual void FinishOGL(const u8 bufferIndex); }; class OGLClientFetchObject : public GPUClientFetchObject @@ -345,10 +350,13 @@ protected: GLuint _texHQ3xLUT; GLuint _texHQ4xLUT; + GLuint _texFetch[2]; + bool _useDirectToCPUFilterPipeline; uint32_t *_srcNativeCloneMaster; uint32_t *_srcNativeClone[2][2]; pthread_rwlock_t _srcCloneRWLock[2][2]; + pthread_rwlock_t _texFetchRWLock[2]; bool _srcCloneNeedsUpdate[2][2]; virtual void _FetchNativeDisplayByID(const NDSDisplayID displayID, const u8 bufferIndex); @@ -372,9 +380,16 @@ public: void CopyFromSrcClone(uint32_t *dstBufferPtr, const NDSDisplayID displayID, const u8 bufferIndex); void FetchNativeDisplayToSrcClone(const NDSDisplayID displayID, const u8 bufferIndex, bool needsLock); + void FetchTextureWriteLock(const NDSDisplayID displayID); + void FetchTextureReadLock(const NDSDisplayID displayID); + void FetchTextureUnlock(const NDSDisplayID displayID); virtual void Init(); virtual void SetFetchBuffers(const NDSDisplayInfo ¤tDisplayInfo); + virtual void FetchFromBufferIndex(const u8 index); + + virtual GLuint GetFetchTexture(const NDSDisplayID displayID); + virtual void SetFetchTexture(const NDSDisplayID displayID, GLuint texID); }; class OGLVideoOutput : public ClientDisplay3DPresenter @@ -389,6 +404,8 @@ protected: GLuint _texCPUFilterDstID[2]; GLuint _fboFrameCopyID; + OGLProcessedFrameInfo _processedFrameInfo; + std::vector *_layerList; void _UpdateViewport(); @@ -428,11 +445,15 @@ public: // Client view interface virtual void ProcessDisplays(); - virtual void FinishFrameAtIndex(const uint8_t bufferIndex); - virtual void CopyFrameToBuffer(uint32_t *dstBuffer);; + virtual void CopyFrameToBuffer(uint32_t *dstBuffer); virtual void RenderFrameOGL(bool isRenderingFlipped); - virtual void LockDisplayTextures(); - virtual void UnlockDisplayTextures(); + + virtual const OGLProcessedFrameInfo& GetProcessedFrameInfo(); + virtual void SetProcessedFrameInfo(const OGLProcessedFrameInfo &processedInfo); + + virtual void WriteLockEmuFramebuffer(const uint8_t bufferIndex); + virtual void ReadLockEmuFramebuffer(const uint8_t bufferIndex); + virtual void UnlockEmuFramebuffer(const uint8_t bufferIndex); }; extern void (*glBindVertexArrayDESMUME)(GLuint id); diff --git a/desmume/src/frontend/cocoa/cocoa_GPU.h b/desmume/src/frontend/cocoa/cocoa_GPU.h index 972e6889a..49b51e477 100644 --- a/desmume/src/frontend/cocoa/cocoa_GPU.h +++ b/desmume/src/frontend/cocoa/cocoa_GPU.h @@ -67,7 +67,6 @@ typedef std::map DisplayLinkFlushTimeLimitMap; - (void) incrementViewsUsingDirectToCPUFiltering; - (void) decrementViewsUsingDirectToCPUFiltering; - (void) pushVideoDataToAllDisplayViews; -- (void) finishAllDisplayViewsAtIndex:(const u8)bufferIndex; - (void) flushAllDisplaysOnDisplayLink:(CVDisplayLinkRef)displayLink timeStamp:(const CVTimeStamp *)timeStamp; - (void) displayLinkStartUsingID:(CGDirectDisplayID)displayID; diff --git a/desmume/src/frontend/cocoa/cocoa_GPU.mm b/desmume/src/frontend/cocoa/cocoa_GPU.mm index 7bbee2b9c..43506643a 100644 --- a/desmume/src/frontend/cocoa/cocoa_GPU.mm +++ b/desmume/src/frontend/cocoa/cocoa_GPU.mm @@ -167,16 +167,21 @@ public: #ifdef ENABLE_APPLE_METAL if (IsOSXVersionSupported(10, 11, 0) && ![[NSUserDefaults standardUserDefaults] boolForKey:@"Debug_DisableMetal"]) { - fetchObject = new MacMetalFetchObject; - - if (fetchObject->GetClientData() == nil) + // macOS v10.13.0 and v10.13.1 are specifically checked for here, because there are + // bugs in these versions of macOS that prevent Metal from working properly. + if (!IsOSXVersion(10, 13, 0) && !IsOSXVersion(10, 13, 1)) { - delete fetchObject; - fetchObject = NULL; - } - else - { - GPU->SetWillPostprocessDisplays(false); + fetchObject = new MacMetalFetchObject; + + if (fetchObject->GetClientData() == nil) + { + delete fetchObject; + fetchObject = NULL; + } + else + { + GPU->SetWillPostprocessDisplays(false); + } } } #endif @@ -189,6 +194,8 @@ public: fetchObject->Init(); gpuEvent->SetFetchObject(fetchObject); + [self clearWithColor:0x8000]; + return self; } @@ -244,15 +251,16 @@ public: - (void) setGpuDimensions:(NSSize)theDimensions { - [[self sharedData] finishAllDisplayViewsAtIndex:0]; - [[self sharedData] finishAllDisplayViewsAtIndex:1]; - gpuEvent->Render3DLock(); gpuEvent->FramebufferLockWrite(); + pthread_rwlock_wrlock([[self sharedData] rwlockFramebufferAtIndex:0]); + pthread_rwlock_wrlock([[self sharedData] rwlockFramebufferAtIndex:1]); GPU->SetCustomFramebufferSize(theDimensions.width, theDimensions.height); fetchObject->SetFetchBuffers(GPU->GetDisplayInfo()); + pthread_rwlock_unlock([[self sharedData] rwlockFramebufferAtIndex:1]); + pthread_rwlock_unlock([[self sharedData] rwlockFramebufferAtIndex:0]); gpuEvent->FramebufferUnlock(); gpuEvent->Render3DUnlock(); } @@ -294,15 +302,16 @@ public: } // Change the color format. - [[self sharedData] finishAllDisplayViewsAtIndex:0]; - [[self sharedData] finishAllDisplayViewsAtIndex:1]; - gpuEvent->Render3DLock(); gpuEvent->FramebufferLockWrite(); + pthread_rwlock_wrlock([[self sharedData] rwlockFramebufferAtIndex:0]); + pthread_rwlock_wrlock([[self sharedData] rwlockFramebufferAtIndex:1]); GPU->SetColorFormat((NDSColorFormat)colorFormat); fetchObject->SetFetchBuffers(GPU->GetDisplayInfo()); + pthread_rwlock_unlock([[self sharedData] rwlockFramebufferAtIndex:1]); + pthread_rwlock_unlock([[self sharedData] rwlockFramebufferAtIndex:0]); gpuEvent->FramebufferUnlock(); gpuEvent->Render3DUnlock(); } @@ -842,8 +851,17 @@ public: - (void) clearWithColor:(const uint16_t)colorBGRA5551 { gpuEvent->FramebufferLockWrite(); + const u8 bufferIndex = GPU->GetDisplayInfo().bufferIndex; + pthread_rwlock_wrlock([[self sharedData] rwlockFramebufferAtIndex:bufferIndex]); + GPU->ClearWithColor(colorBGRA5551); + + pthread_rwlock_unlock([[self sharedData] rwlockFramebufferAtIndex:bufferIndex]); gpuEvent->FramebufferUnlock(); + +#if !defined(PORT_VERSION_OPENEMU) + [[self sharedData] signalFetchAtIndex:bufferIndex]; +#endif } - (void) respondToPauseState:(BOOL)isPaused @@ -1022,30 +1040,6 @@ public: } } -- (void) finishAllDisplayViewsAtIndex:(const u8)bufferIndex -{ - pthread_mutex_t *currentMutex = _mutexOutputList; - - if (currentMutex != NULL) - { - pthread_mutex_lock(currentMutex); - } - - for (CocoaDSOutput *cdsOutput in _cdsOutputList) - { - if ([cdsOutput isKindOfClass:[CocoaDSDisplayVideo class]]) - { - ClientDisplay3DView *cdv = [(CocoaDSDisplayVideo *)cdsOutput clientDisplay3DView]; - cdv->Get3DPresenter()->FinishFrameAtIndex(bufferIndex); - } - } - - if (currentMutex != NULL) - { - pthread_mutex_unlock(currentMutex); - } -} - - (void) flushAllDisplaysOnDisplayLink:(CVDisplayLinkRef)displayLink timeStamp:(const CVTimeStamp *)timeStamp { pthread_mutex_t *currentMutex = _mutexOutputList; @@ -1190,10 +1184,10 @@ public: - (void) runFetchLoop { + pthread_mutex_lock(&_mutexFetchExecute); + do { - pthread_mutex_lock(&_mutexFetchExecute); - while (!_isFetchSignalled) { pthread_cond_wait(&_condSignalFetch, &_mutexFetchExecute); @@ -1202,8 +1196,6 @@ public: GPUFetchObject->FetchFromBufferIndex(_fetchIndex); [self pushVideoDataToAllDisplayViews]; - - pthread_mutex_unlock(&_mutexFetchExecute); } while(true); } diff --git a/desmume/src/frontend/cocoa/cocoa_output.mm b/desmume/src/frontend/cocoa/cocoa_output.mm index b02a363ed..52070fbe0 100644 --- a/desmume/src/frontend/cocoa/cocoa_output.mm +++ b/desmume/src/frontend/cocoa/cocoa_output.mm @@ -517,7 +517,7 @@ _receivedFrameIndex = 0; _currentReceivedFrameIndex = 0; _receivedFrameCount = 0; - + return self; } @@ -1137,10 +1137,6 @@ - (void) handleReloadReprocessRedraw { - GPUClientFetchObject &fetchObjMutable = (GPUClientFetchObject &)_cdv->Get3DPresenter()->GetFetchObject(); - const u8 bufferIndex = fetchObjMutable.GetLastFetchIndex(); - - fetchObjMutable.FetchFromBufferIndex(bufferIndex); _cdv->Get3DPresenter()->LoadDisplays(); _cdv->Get3DPresenter()->ProcessDisplays(); diff --git a/desmume/src/frontend/cocoa/userinterface/DisplayViewCALayer.h b/desmume/src/frontend/cocoa/userinterface/DisplayViewCALayer.h index 913754ede..3effc07e8 100644 --- a/desmume/src/frontend/cocoa/userinterface/DisplayViewCALayer.h +++ b/desmume/src/frontend/cocoa/userinterface/DisplayViewCALayer.h @@ -92,7 +92,6 @@ private: void __InstanceInit(); protected: - NSView *_nsView; CALayer *_caLayer; bool _willRenderToCALayer; @@ -100,9 +99,6 @@ public: MacDisplayLayeredView(); MacDisplayLayeredView(ClientDisplay3DPresenter *thePresenter); - NSView* GetNSView() const; - void SetNSView(NSView *theView); - CALayer* GetCALayer() const; bool GetRenderToCALayer() const; diff --git a/desmume/src/frontend/cocoa/userinterface/DisplayViewCALayer.mm b/desmume/src/frontend/cocoa/userinterface/DisplayViewCALayer.mm index d5c4e2afd..503c6448a 100644 --- a/desmume/src/frontend/cocoa/userinterface/DisplayViewCALayer.mm +++ b/desmume/src/frontend/cocoa/userinterface/DisplayViewCALayer.mm @@ -52,21 +52,10 @@ MacDisplayLayeredView::MacDisplayLayeredView(ClientDisplay3DPresenter *thePresen void MacDisplayLayeredView::__InstanceInit() { - _nsView = nil; _caLayer = nil; _willRenderToCALayer = false; } -NSView* MacDisplayLayeredView::GetNSView() const -{ - return this->_nsView; -} - -void MacDisplayLayeredView::SetNSView(NSView *theView) -{ - this->_nsView = theView; -} - CALayer* MacDisplayLayeredView::GetCALayer() const { return this->_caLayer; diff --git a/desmume/src/frontend/cocoa/userinterface/DisplayWindowController.mm b/desmume/src/frontend/cocoa/userinterface/DisplayWindowController.mm index 4dea476a2..0349b88ad 100644 --- a/desmume/src/frontend/cocoa/userinterface/DisplayWindowController.mm +++ b/desmume/src/frontend/cocoa/userinterface/DisplayWindowController.mm @@ -2055,7 +2055,6 @@ static std::unordered_map _screenMap; // if ([(MetalDisplayViewSharedData *)macSharedData device] != nil) { MacMetalDisplayView *macMTLCDV = new MacMetalDisplayView(macSharedData); - macMTLCDV->SetNSView(self); macMTLCDV->Init(); localLayer = macMTLCDV->GetCALayer(); @@ -2066,7 +2065,6 @@ static std::unordered_map _screenMap; // #endif { MacOGLDisplayView *macOGLCDV = new MacOGLDisplayView(macSharedData); - macOGLCDV->SetNSView(self); macOGLCDV->Init(); localLayer = macOGLCDV->GetCALayer(); diff --git a/desmume/src/frontend/cocoa/userinterface/MacMetalDisplayView.h b/desmume/src/frontend/cocoa/userinterface/MacMetalDisplayView.h index 60e9229e4..13a9e4d14 100644 --- a/desmume/src/frontend/cocoa/userinterface/MacMetalDisplayView.h +++ b/desmume/src/frontend/cocoa/userinterface/MacMetalDisplayView.h @@ -34,6 +34,15 @@ class MacMetalFetchObject; class MacMetalDisplayPresenter; class MacMetalDisplayView; +struct MetalProcessedFrameInfo +{ + uint8_t bufferIndex; + id tex[2]; + bool isMainDisplayProcessed; + bool isTouchDisplayProcessed; +}; +typedef struct MetalProcessedFrameInfo MetalProcessedFrameInfo; + struct DisplayViewShaderProperties { float width; @@ -70,22 +79,22 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties; id _bufMasterBrightMode[2]; id _bufMasterBrightIntensity[2]; - id texDisplayFetch16NativeMain; - id texDisplayFetch16NativeTouch; - id texDisplayFetch32NativeMain; - id texDisplayFetch32NativeTouch; - id texDisplayFetch16CustomMain; - id texDisplayFetch16CustomTouch; - id texDisplayFetch32CustomMain; - id texDisplayFetch32CustomTouch; + id _texDisplayFetch16NativeMain; + id _texDisplayFetch16NativeTouch; + id _texDisplayFetch32NativeMain; + id _texDisplayFetch32NativeTouch; + id _texDisplayPostprocessNativeMain; + id _texDisplayPostprocessNativeTouch; - id texDisplayPostprocessNativeMain; - id texDisplayPostprocessCustomMain; - id texDisplayPostprocessNativeTouch; - id texDisplayPostprocessCustomTouch; + id _texDisplayFetch16CustomMain; + id _texDisplayFetch16CustomTouch; + id _texDisplayFetch32CustomMain; + id _texDisplayFetch32CustomTouch; + id _texDisplayPostprocessCustomMain; + id _texDisplayPostprocessCustomTouch; - id texDisplaySrcTargetMain; - id texDisplaySrcTargetTouch; + id texFetchMain; + id texFetchTouch; id texLQ2xLUT; id texHQ2xLUT; @@ -93,16 +102,13 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties; id texHQ4xLUT; id texCurrentHQnxLUT; - MTLSize fetchThreadsPerGroup; - MTLSize fetchThreadGroupsPerGridNative; - MTLSize fetchThreadGroupsPerGridCustom; + MTLSize _fetchThreadsPerGroup; + MTLSize _fetchThreadGroupsPerGridNative; + MTLSize _fetchThreadGroupsPerGridCustom; MTLSize deposterizeThreadsPerGroup; MTLSize deposterizeThreadGroupsPerGrid; - size_t displayFetchNativeBufferSize; - size_t displayFetchCustomBufferSize; - - pthread_mutex_t _mutexFetch; + uint32_t _isUsingFramebufferDirectly[2][2]; } @property (readonly, nonatomic) id device; @@ -117,22 +123,8 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties; @property (readonly, nonatomic) id hudIndexBuffer; -@property (readonly, nonatomic) id texDisplayFetch16NativeMain; -@property (readonly, nonatomic) id texDisplayFetch16NativeTouch; -@property (readonly, nonatomic) id texDisplayFetch32NativeMain; -@property (readonly, nonatomic) id texDisplayFetch32NativeTouch; -@property (retain) id texDisplayFetch16CustomMain; -@property (retain) id texDisplayFetch16CustomTouch; -@property (retain) id texDisplayFetch32CustomMain; -@property (retain) id texDisplayFetch32CustomTouch; - -@property (retain) id texDisplayPostprocessNativeMain; -@property (retain) id texDisplayPostprocessCustomMain; -@property (retain) id texDisplayPostprocessNativeTouch; -@property (retain) id texDisplayPostprocessCustomTouch; - -@property (retain) id texDisplaySrcTargetMain; -@property (retain) id texDisplaySrcTargetTouch; +@property (retain) id texFetchMain; +@property (retain) id texFetchTouch; @property (readonly, nonatomic) id texLQ2xLUT; @property (readonly, nonatomic) id texHQ2xLUT; @@ -140,16 +132,14 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties; @property (readonly, nonatomic) id texHQ4xLUT; @property (retain) id texCurrentHQnxLUT; -@property (assign) size_t displayFetchNativeBufferSize; -@property (assign) size_t displayFetchCustomBufferSize; - -@property (readonly, nonatomic) MTLSize fetchThreadsPerGroup; -@property (readonly, nonatomic) MTLSize fetchThreadGroupsPerGridNative; -@property (assign) MTLSize fetchThreadGroupsPerGridCustom; @property (readonly, nonatomic) MTLSize deposterizeThreadsPerGroup; @property (readonly, nonatomic) MTLSize deposterizeThreadGroupsPerGrid; +- (void) setUsingFramebufferDirectlyAtIndex:(const u8)index displayID:(NDSDisplayID)displayID state:(bool)theState; +- (bool) isUsingFramebufferDirectlyAtIndex:(const u8)index displayID:(NDSDisplayID)displayID; + - (void) setFetchBuffersWithDisplayInfo:(const NDSDisplayInfo &)dispInfo; +- (void) setFetchTextureBindingsAtIndex:(const u8)index commandBuffer:(id)cb; - (void) fetchFromBufferIndex:(const u8)index; - (void) fetchNativeDisplayByID:(const NDSDisplayID)displayID bufferIndex:(const u8)bufferIndex; - (void) fetchCustomDisplayByID:(const NDSDisplayID)displayID bufferIndex:(const u8)bufferIndex; @@ -174,15 +164,14 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties; id _hudVtxPositionBuffer; id _hudVtxColorBuffer; id _hudTexCoordBuffer; - id bufCPUFilterSrcMain; - id bufCPUFilterSrcTouch; + id _bufCPUFilterSrcMain; + id _bufCPUFilterSrcTouch; id bufCPUFilterDstMain; id bufCPUFilterDstTouch; id _texDisplaySrcDeposterize[2][2]; id texDisplayPixelScaleMain; id texDisplayPixelScaleTouch; - id _texDisplayOutput[2]; id texHUDCharMap; MTLSize _pixelScalerThreadsPerGroup; @@ -193,28 +182,25 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties; BOOL needsScreenVerticesUpdate; BOOL needsHUDVerticesUpdate; - pthread_mutex_t _mutexDisplayTextureUpdate; pthread_mutex_t _mutexBufferUpdate; bool _needEncodeViewport; MTLViewport _newViewport; - bool _willDrawDisplays; bool _willDrawHUD; bool _willDrawHUDInput; size_t _hudStringLength; size_t _hudTouchLineLength; + + MetalProcessedFrameInfo processedFrameInfo; } @property (readonly, nonatomic) ClientDisplay3DPresenter *cdp; @property (assign, nonatomic) MetalDisplayViewSharedData *sharedData; @property (readonly, nonatomic) MTLRenderPassColorAttachmentDescriptor *colorAttachment0Desc; -@property (readonly, nonatomic) pthread_mutex_t *mutexDisplayTextureUpdate; @property (readonly, nonatomic) pthread_mutex_t *mutexBufferUpdate; @property (retain) id pixelScalePipeline; @property (retain) id outputRGBAPipeline; @property (retain) id outputDrawablePipeline; @property (assign) MTLPixelFormat drawableFormat; -@property (retain) id bufCPUFilterSrcMain; -@property (retain) id bufCPUFilterSrcTouch; @property (retain) id bufCPUFilterDstMain; @property (retain) id bufCPUFilterDstTouch; @property (retain) id texDisplayPixelScaleMain; @@ -226,6 +212,7 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties; @property (assign) BOOL needsHUDVerticesUpdate; @property (assign, nonatomic) VideoFilterTypeID pixelScaler; @property (assign, nonatomic) OutputFilterTypeID outputFilter; +@property (assign) MetalProcessedFrameInfo processedFrameInfo; - (id) initWithDisplayPresenter:(MacMetalDisplayPresenter *)thePresenter; - (id) newCommandBuffer; @@ -236,7 +223,9 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties; - (void) updateRenderBuffers; - (void) renderForCommandBuffer:(id)cb outputPipelineState:(id)outputPipelineState - hudPipelineState:(id)hudPipelineState; + hudPipelineState:(id)hudPipelineState + texDisplayMain:(id)texDisplayMain + texDisplayTouch:(id)texDisplayTouch; - (void) renderToBuffer:(uint32_t *)dstBuffer; @end @@ -288,6 +277,7 @@ private: protected: MacMetalDisplayPresenterObject *_presenterObject; pthread_mutex_t _mutexProcessPtr; + pthread_rwlock_t _cpuFilterRWLock[2][2]; virtual void _UpdateNormalSize(); virtual void _UpdateOrder(); @@ -304,6 +294,7 @@ public: MacMetalDisplayPresenterObject* GetPresenterObject() const; pthread_mutex_t* GetMutexProcessPtr(); + pthread_rwlock_t* GetCPUFilterRWLock(const NDSDisplayID displayID, const uint8_t bufferIndex); virtual void Init(); virtual void SetSharedData(MacClientSharedObject *sharedObject); diff --git a/desmume/src/frontend/cocoa/userinterface/MacMetalDisplayView.mm b/desmume/src/frontend/cocoa/userinterface/MacMetalDisplayView.mm index f8f33365a..f297019e8 100644 --- a/desmume/src/frontend/cocoa/userinterface/MacMetalDisplayView.mm +++ b/desmume/src/frontend/cocoa/userinterface/MacMetalDisplayView.mm @@ -33,22 +33,8 @@ @synthesize hudIndexBuffer; -@synthesize texDisplayFetch16NativeMain; -@synthesize texDisplayFetch16NativeTouch; -@synthesize texDisplayFetch32NativeMain; -@synthesize texDisplayFetch32NativeTouch; -@synthesize texDisplayFetch16CustomMain; -@synthesize texDisplayFetch16CustomTouch; -@synthesize texDisplayFetch32CustomMain; -@synthesize texDisplayFetch32CustomTouch; - -@synthesize texDisplayPostprocessNativeMain; -@synthesize texDisplayPostprocessCustomMain; -@synthesize texDisplayPostprocessNativeTouch; -@synthesize texDisplayPostprocessCustomTouch; - -@synthesize texDisplaySrcTargetMain; -@synthesize texDisplaySrcTargetTouch; +@synthesize texFetchMain; +@synthesize texFetchTouch; @synthesize texLQ2xLUT; @synthesize texHQ2xLUT; @@ -56,12 +42,6 @@ @synthesize texHQ4xLUT; @synthesize texCurrentHQnxLUT; -@synthesize displayFetchNativeBufferSize; -@synthesize displayFetchCustomBufferSize; - -@synthesize fetchThreadsPerGroup; -@synthesize fetchThreadGroupsPerGridNative; -@synthesize fetchThreadGroupsPerGridCustom; @synthesize deposterizeThreadsPerGroup; @synthesize deposterizeThreadGroupsPerGrid; @@ -99,15 +79,15 @@ size_t th = [_fetch555Pipeline maxTotalThreadsPerThreadgroup] / tw; - fetchThreadsPerGroup = MTLSizeMake(tw, th, 1); - fetchThreadGroupsPerGridNative = MTLSizeMake(GPU_FRAMEBUFFER_NATIVE_WIDTH / tw, - GPU_FRAMEBUFFER_NATIVE_HEIGHT / th, - 1); + _fetchThreadsPerGroup = MTLSizeMake(tw, th, 1); + _fetchThreadGroupsPerGridNative = MTLSizeMake(GPU_FRAMEBUFFER_NATIVE_WIDTH / tw, + GPU_FRAMEBUFFER_NATIVE_HEIGHT / th, + 1); - fetchThreadGroupsPerGridCustom = fetchThreadGroupsPerGridNative; + _fetchThreadGroupsPerGridCustom = _fetchThreadGroupsPerGridNative; - deposterizeThreadsPerGroup = fetchThreadsPerGroup; - deposterizeThreadGroupsPerGrid = fetchThreadGroupsPerGridNative; + deposterizeThreadsPerGroup = _fetchThreadsPerGroup; + deposterizeThreadGroupsPerGrid = _fetchThreadGroupsPerGridNative; MTLRenderPipelineDescriptor *hudPipelineDesc = [[MTLRenderPipelineDescriptor alloc] init]; [[[hudPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setBlendingEnabled:YES]; @@ -153,8 +133,6 @@ _bufDisplayFetchCustom[NDSDisplayID_Main][1] = nil; _bufDisplayFetchCustom[NDSDisplayID_Touch][0] = nil; _bufDisplayFetchCustom[NDSDisplayID_Touch][1] = nil; - displayFetchNativeBufferSize = 0; - displayFetchCustomBufferSize = 0; _bufMasterBrightMode[NDSDisplayID_Main] = [[device newBufferWithLength:sizeof(uint8_t) * GPU_FRAMEBUFFER_NATIVE_HEIGHT options:MTLResourceStorageModeManaged] retain]; _bufMasterBrightMode[NDSDisplayID_Touch] = [[device newBufferWithLength:sizeof(uint8_t) * GPU_FRAMEBUFFER_NATIVE_HEIGHT options:MTLResourceStorageModeManaged] retain]; @@ -192,10 +170,10 @@ [texDisplayLoad16Desc setCpuCacheMode:MTLCPUCacheModeWriteCombined]; [texDisplayLoad16Desc setUsage:MTLTextureUsageShaderRead]; - texDisplayFetch16NativeMain = [[device newTextureWithDescriptor:texDisplayLoad16Desc] retain]; - texDisplayFetch16NativeTouch = [[device newTextureWithDescriptor:texDisplayLoad16Desc] retain]; - texDisplayFetch16CustomMain = [[device newTextureWithDescriptor:texDisplayLoad16Desc] retain]; - texDisplayFetch16CustomTouch = [[device newTextureWithDescriptor:texDisplayLoad16Desc] retain]; + _texDisplayFetch16NativeMain = [[device newTextureWithDescriptor:texDisplayLoad16Desc] retain]; + _texDisplayFetch16NativeTouch = [[device newTextureWithDescriptor:texDisplayLoad16Desc] retain]; + _texDisplayFetch16CustomMain = [[device newTextureWithDescriptor:texDisplayLoad16Desc] retain]; + _texDisplayFetch16CustomTouch = [[device newTextureWithDescriptor:texDisplayLoad16Desc] retain]; MTLTextureDescriptor *texDisplayLoad32Desc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm width:GPU_FRAMEBUFFER_NATIVE_WIDTH @@ -206,63 +184,67 @@ [texDisplayLoad32Desc setCpuCacheMode:MTLCPUCacheModeWriteCombined]; [texDisplayLoad32Desc setUsage:MTLTextureUsageShaderRead]; - texDisplayFetch32NativeMain = [[device newTextureWithDescriptor:texDisplayLoad32Desc] retain]; - texDisplayFetch32NativeTouch = [[device newTextureWithDescriptor:texDisplayLoad32Desc] retain]; - texDisplayFetch32CustomMain = [[device newTextureWithDescriptor:texDisplayLoad32Desc] retain]; - texDisplayFetch32CustomTouch = [[device newTextureWithDescriptor:texDisplayLoad32Desc] retain]; + _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]; - texDisplayPostprocessCustomTouch = [[device newTextureWithDescriptor:texDisplayLoad32Desc] retain]; + _texDisplayPostprocessNativeMain = [[device newTextureWithDescriptor:texDisplayLoad32Desc] retain]; + _texDisplayPostprocessNativeTouch = [[device newTextureWithDescriptor:texDisplayLoad32Desc] retain]; + _texDisplayPostprocessCustomMain = [[device newTextureWithDescriptor:texDisplayLoad32Desc] retain]; + _texDisplayPostprocessCustomTouch = [[device newTextureWithDescriptor:texDisplayLoad32Desc] retain]; uint32_t *blankBuffer = (uint32_t *)calloc(GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT, sizeof(uint32_t)); const MTLRegion texRegionNative = MTLRegionMake2D(0, 0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT); - [texDisplayFetch32NativeMain replaceRegion:texRegionNative - mipmapLevel:0 - withBytes:blankBuffer - bytesPerRow:GPU_FRAMEBUFFER_NATIVE_WIDTH * sizeof(uint32_t)]; - [texDisplayFetch32NativeTouch replaceRegion:texRegionNative - mipmapLevel:0 - withBytes:blankBuffer - bytesPerRow:GPU_FRAMEBUFFER_NATIVE_WIDTH * sizeof(uint32_t)]; - [texDisplayFetch32CustomMain replaceRegion:texRegionNative - mipmapLevel:0 - withBytes:blankBuffer - bytesPerRow:GPU_FRAMEBUFFER_NATIVE_WIDTH * sizeof(uint32_t)]; - [texDisplayFetch32CustomTouch replaceRegion:texRegionNative - mipmapLevel:0 - withBytes:blankBuffer - bytesPerRow:GPU_FRAMEBUFFER_NATIVE_WIDTH * sizeof(uint32_t)]; + [_texDisplayFetch32NativeMain replaceRegion:texRegionNative + mipmapLevel:0 + withBytes:blankBuffer + bytesPerRow:GPU_FRAMEBUFFER_NATIVE_WIDTH * sizeof(uint32_t)]; + [_texDisplayFetch32NativeTouch replaceRegion:texRegionNative + mipmapLevel:0 + withBytes:blankBuffer + bytesPerRow:GPU_FRAMEBUFFER_NATIVE_WIDTH * sizeof(uint32_t)]; + [_texDisplayFetch32CustomMain replaceRegion:texRegionNative + mipmapLevel:0 + withBytes:blankBuffer + bytesPerRow:GPU_FRAMEBUFFER_NATIVE_WIDTH * sizeof(uint32_t)]; + [_texDisplayFetch32CustomTouch replaceRegion:texRegionNative + mipmapLevel:0 + withBytes:blankBuffer + bytesPerRow:GPU_FRAMEBUFFER_NATIVE_WIDTH * sizeof(uint32_t)]; - [texDisplayPostprocessNativeMain replaceRegion:texRegionNative - mipmapLevel:0 - withBytes:blankBuffer - bytesPerRow:GPU_FRAMEBUFFER_NATIVE_WIDTH * sizeof(uint32_t)]; - [texDisplayPostprocessCustomMain replaceRegion:texRegionNative - mipmapLevel:0 - withBytes:blankBuffer - bytesPerRow:GPU_FRAMEBUFFER_NATIVE_WIDTH * sizeof(uint32_t)]; - [texDisplayPostprocessNativeTouch replaceRegion:texRegionNative - mipmapLevel:0 - withBytes:blankBuffer - bytesPerRow:GPU_FRAMEBUFFER_NATIVE_WIDTH * sizeof(uint32_t)]; - [texDisplayPostprocessCustomTouch replaceRegion:texRegionNative - mipmapLevel:0 - withBytes:blankBuffer - bytesPerRow:GPU_FRAMEBUFFER_NATIVE_WIDTH * sizeof(uint32_t)]; + [_texDisplayPostprocessNativeMain replaceRegion:texRegionNative + mipmapLevel:0 + withBytes:blankBuffer + bytesPerRow:GPU_FRAMEBUFFER_NATIVE_WIDTH * sizeof(uint32_t)]; + [_texDisplayPostprocessNativeTouch replaceRegion:texRegionNative + mipmapLevel:0 + withBytes:blankBuffer + bytesPerRow:GPU_FRAMEBUFFER_NATIVE_WIDTH * sizeof(uint32_t)]; + [_texDisplayPostprocessCustomMain replaceRegion:texRegionNative + mipmapLevel:0 + withBytes:blankBuffer + bytesPerRow:GPU_FRAMEBUFFER_NATIVE_WIDTH * sizeof(uint32_t)]; + [_texDisplayPostprocessCustomTouch replaceRegion:texRegionNative + mipmapLevel:0 + withBytes:blankBuffer + bytesPerRow:GPU_FRAMEBUFFER_NATIVE_WIDTH * sizeof(uint32_t)]; free(blankBuffer); - texDisplaySrcTargetMain = [texDisplayFetch32NativeMain retain]; - texDisplaySrcTargetTouch = [texDisplayFetch32NativeTouch retain]; + texFetchMain = [_texDisplayFetch32NativeMain retain]; + texFetchTouch = [_texDisplayFetch32NativeTouch retain]; + + _isUsingFramebufferDirectly[NDSDisplayID_Main][0] = 1; + _isUsingFramebufferDirectly[NDSDisplayID_Main][1] = 1; + _isUsingFramebufferDirectly[NDSDisplayID_Touch][0] = 1; + _isUsingFramebufferDirectly[NDSDisplayID_Touch][1] = 1; // Set up the HQnx LUT textures. SetupHQnxLUTs_Metal(device, texLQ2xLUT, texHQ2xLUT, texHQ3xLUT, texHQ4xLUT); texCurrentHQnxLUT = nil; _fetchEncoder = nil; - pthread_mutex_init(&_mutexFetch, NULL); return self; } @@ -287,22 +269,22 @@ [_bufMasterBrightIntensity[NDSDisplayID_Main] release]; [_bufMasterBrightIntensity[NDSDisplayID_Touch] release]; - [texDisplayFetch16NativeMain release]; - [texDisplayFetch16NativeTouch release]; - [texDisplayFetch32NativeMain release]; - [texDisplayFetch32NativeTouch release]; - [self setTexDisplayFetch16CustomMain:nil]; - [self setTexDisplayFetch16CustomTouch:nil]; - [self setTexDisplayFetch32CustomMain:nil]; - [self setTexDisplayFetch32CustomTouch:nil]; + [_texDisplayFetch16NativeMain release]; + [_texDisplayFetch16NativeTouch release]; + [_texDisplayFetch32NativeMain release]; + [_texDisplayFetch32NativeTouch release]; + [_texDisplayPostprocessNativeMain release]; + [_texDisplayPostprocessNativeTouch release]; - [self setTexDisplayPostprocessNativeMain:nil]; - [self setTexDisplayPostprocessCustomMain:nil]; - [self setTexDisplayPostprocessNativeTouch:nil]; - [self setTexDisplayPostprocessCustomTouch:nil]; + [_texDisplayFetch16CustomMain release]; + [_texDisplayFetch16CustomTouch release]; + [_texDisplayFetch32CustomMain release]; + [_texDisplayFetch32CustomTouch release]; + [_texDisplayPostprocessCustomMain release]; + [_texDisplayPostprocessCustomTouch release]; - [self setTexDisplaySrcTargetMain:nil]; - [self setTexDisplaySrcTargetTouch:nil]; + [self setTexFetchMain:nil]; + [self setTexFetchTouch:nil]; DeleteHQnxLUTs_Metal(texLQ2xLUT, texHQ2xLUT, texHQ3xLUT, texHQ4xLUT); [self setTexCurrentHQnxLUT:nil]; @@ -319,21 +301,32 @@ [_bufDisplayFetchCustom[NDSDisplayID_Touch][0] release]; [_bufDisplayFetchCustom[NDSDisplayID_Touch][1] release]; - pthread_mutex_destroy(&_mutexFetch); - [super dealloc]; } +- (void) setUsingFramebufferDirectlyAtIndex:(const u8)index displayID:(NDSDisplayID)displayID state:(bool)theState +{ + if (theState) + { + OSAtomicOr32(1, &_isUsingFramebufferDirectly[displayID][index]); + } + else + { + OSAtomicAnd32(0, &_isUsingFramebufferDirectly[displayID][index]); + } +} + +- (bool) isUsingFramebufferDirectlyAtIndex:(const u8)index displayID:(NDSDisplayID)displayID +{ + return (OSAtomicAnd32(1, &_isUsingFramebufferDirectly[displayID][index]) == 1); +} + - (void) setFetchBuffersWithDisplayInfo:(const NDSDisplayInfo &)dispInfo { + const size_t w = dispInfo.customWidth; + const size_t h = dispInfo.customHeight; const size_t nativeSize = GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT * dispInfo.pixelBytes; - const size_t customSize = dispInfo.customWidth * dispInfo.customHeight * dispInfo.pixelBytes; - - id cb = [[self commandQueue] commandBufferWithUnretainedReferences]; - id dummyEncoder = [cb blitCommandEncoder]; - [dummyEncoder endEncoding]; - [cb commit]; - [cb waitUntilCompleted]; + const size_t customSize = w * h * dispInfo.pixelBytes; _bufDisplayFetchNative[NDSDisplayID_Main][0] = [[device newBufferWithBytesNoCopy:(u8 *)dispInfo.masterFramebufferHead length:nativeSize @@ -375,31 +368,54 @@ options:MTLResourceStorageModeManaged deallocator:nil] retain]; - [self setDisplayFetchNativeBufferSize:nativeSize]; - [self setDisplayFetchCustomBufferSize:customSize]; + // If the existing texture size is different than the incoming size, then remake the textures to match the incoming size. + if ( ([_texDisplayFetch32CustomMain width] != w) || ([_texDisplayFetch32CustomMain height] != h) ) + { + MTLTextureDescriptor *texDisplayLoad16Desc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatR16Uint + width:w + height:h + mipmapped:NO]; + [texDisplayLoad16Desc setResourceOptions:MTLResourceStorageModeManaged]; + [texDisplayLoad16Desc setStorageMode:MTLStorageModeManaged]; + [texDisplayLoad16Desc setCpuCacheMode:MTLCPUCacheModeWriteCombined]; + [texDisplayLoad16Desc setUsage:MTLTextureUsageShaderRead]; + + [_texDisplayFetch16CustomMain release]; + _texDisplayFetch16CustomMain = [device newTextureWithDescriptor:texDisplayLoad16Desc]; + [_texDisplayFetch16CustomTouch release]; + _texDisplayFetch16CustomTouch = [device newTextureWithDescriptor:texDisplayLoad16Desc]; + + MTLTextureDescriptor *texDisplayLoad32Desc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm + width:w + height:h + mipmapped:NO]; + [texDisplayLoad32Desc setResourceOptions:MTLResourceStorageModePrivate]; + [texDisplayLoad32Desc setStorageMode:MTLStorageModePrivate]; + [texDisplayLoad32Desc setUsage:MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite]; + + [_texDisplayFetch32CustomMain release]; + _texDisplayFetch32CustomMain = [device newTextureWithDescriptor:texDisplayLoad32Desc]; + [_texDisplayFetch32CustomTouch release]; + _texDisplayFetch32CustomTouch = [device newTextureWithDescriptor:texDisplayLoad32Desc]; + + [_texDisplayPostprocessCustomMain release]; + _texDisplayPostprocessCustomMain = [device newTextureWithDescriptor:texDisplayLoad32Desc]; + [_texDisplayPostprocessCustomTouch release]; + _texDisplayPostprocessCustomTouch = [device newTextureWithDescriptor:texDisplayLoad32Desc]; + + const size_t tw = _fetchThreadsPerGroup.width; + const size_t th = _fetchThreadsPerGroup.height; + _fetchThreadGroupsPerGridCustom = MTLSizeMake((w + tw - 1) / tw, (h + th - 1) / th, 1); + } - cb = [[self commandQueue] commandBufferWithUnretainedReferences]; - dummyEncoder = [cb blitCommandEncoder]; - [dummyEncoder endEncoding]; + id cb = [commandQueue commandBufferWithUnretainedReferences]; + [self setFetchTextureBindingsAtIndex:dispInfo.bufferIndex commandBuffer:cb]; [cb commit]; [cb waitUntilCompleted]; } -- (void) fetchFromBufferIndex:(const u8)index +- (void) setFetchTextureBindingsAtIndex:(const u8)index commandBuffer:(id)cb { - pthread_mutex_lock(&_mutexFetch); - pthread_rwlock_rdlock([self rwlockFramebufferAtIndex:index]); - - id cb = [commandQueue commandBufferWithUnretainedReferences]; - _fetchEncoder = [cb blitCommandEncoder]; - - GPUFetchObject->GPUClientFetchObject::FetchFromBufferIndex(index); - - [_fetchEncoder endEncoding]; - - pthread_rwlock_unlock([self rwlockFramebufferAtIndex:index]); - pthread_mutex_unlock(&_mutexFetch); - id texDisplaySrcTarget[2] = {nil, nil}; const NDSDisplayInfo ¤tDisplayInfo = GPUFetchObject->GetFetchDisplayInfoForBufferIndex(index); const bool isMainEnabled = currentDisplayInfo.isDisplayEnabled[NDSDisplayID_Main]; @@ -411,11 +427,11 @@ { if (!currentDisplayInfo.didPerformCustomRender[NDSDisplayID_Main]) { - texDisplaySrcTarget[NDSDisplayID_Main] = texDisplayFetch32NativeMain; + texDisplaySrcTarget[NDSDisplayID_Main] = _texDisplayFetch32NativeMain; } else { - texDisplaySrcTarget[NDSDisplayID_Main] = texDisplayFetch32CustomMain; + texDisplaySrcTarget[NDSDisplayID_Main] = _texDisplayFetch32CustomMain; } } @@ -423,11 +439,11 @@ { if (!currentDisplayInfo.didPerformCustomRender[NDSDisplayID_Touch]) { - texDisplaySrcTarget[NDSDisplayID_Touch] = texDisplayFetch32NativeTouch; + texDisplaySrcTarget[NDSDisplayID_Touch] = _texDisplayFetch32NativeTouch; } else { - texDisplaySrcTarget[NDSDisplayID_Touch] = texDisplayFetch32CustomTouch; + texDisplaySrcTarget[NDSDisplayID_Touch] = _texDisplayFetch32CustomTouch; } } @@ -454,21 +470,21 @@ if (!currentDisplayInfo.didPerformCustomRender[NDSDisplayID_Main]) { - [cce setTexture:texDisplayFetch16NativeMain atIndex:0]; - [cce setTexture:[self texDisplayPostprocessNativeMain] atIndex:1]; - [cce dispatchThreadgroups:fetchThreadGroupsPerGridNative - threadsPerThreadgroup:fetchThreadsPerGroup]; + [cce setTexture:_texDisplayFetch16NativeMain atIndex:0]; + [cce setTexture:_texDisplayPostprocessNativeMain atIndex:1]; + [cce dispatchThreadgroups:_fetchThreadGroupsPerGridNative + threadsPerThreadgroup:_fetchThreadsPerGroup]; - texDisplaySrcTarget[NDSDisplayID_Main] = [self texDisplayPostprocessNativeMain]; + texDisplaySrcTarget[NDSDisplayID_Main] = _texDisplayPostprocessNativeMain; } else { - [cce setTexture:[self texDisplayFetch16CustomMain] atIndex:0]; - [cce setTexture:[self texDisplayPostprocessCustomMain] atIndex:1]; - [cce dispatchThreadgroups:[self fetchThreadGroupsPerGridCustom] - threadsPerThreadgroup:[self fetchThreadsPerGroup]]; + [cce setTexture:_texDisplayFetch16CustomMain atIndex:0]; + [cce setTexture:_texDisplayPostprocessCustomMain atIndex:1]; + [cce dispatchThreadgroups:_fetchThreadGroupsPerGridCustom + threadsPerThreadgroup:_fetchThreadsPerGroup]; - texDisplaySrcTarget[NDSDisplayID_Main] = [self texDisplayPostprocessCustomMain]; + texDisplaySrcTarget[NDSDisplayID_Main] = _texDisplayPostprocessCustomMain; } } @@ -484,21 +500,21 @@ if (!currentDisplayInfo.didPerformCustomRender[NDSDisplayID_Touch]) { - [cce setTexture:texDisplayFetch16NativeTouch atIndex:0]; - [cce setTexture:[self texDisplayPostprocessNativeTouch] atIndex:1]; - [cce dispatchThreadgroups:fetchThreadGroupsPerGridNative - threadsPerThreadgroup:fetchThreadsPerGroup]; + [cce setTexture:_texDisplayFetch16NativeTouch atIndex:0]; + [cce setTexture:_texDisplayPostprocessNativeTouch atIndex:1]; + [cce dispatchThreadgroups:_fetchThreadGroupsPerGridNative + threadsPerThreadgroup:_fetchThreadsPerGroup]; - texDisplaySrcTarget[NDSDisplayID_Touch] = [self texDisplayPostprocessNativeTouch]; + texDisplaySrcTarget[NDSDisplayID_Touch] = _texDisplayPostprocessNativeTouch; } else { - [cce setTexture:[self texDisplayFetch16CustomTouch] atIndex:0]; - [cce setTexture:[self texDisplayPostprocessCustomTouch] atIndex:1]; - [cce dispatchThreadgroups:[self fetchThreadGroupsPerGridCustom] - threadsPerThreadgroup:[self fetchThreadsPerGroup]]; + [cce setTexture:_texDisplayFetch16CustomTouch atIndex:0]; + [cce setTexture:_texDisplayPostprocessCustomTouch atIndex:1]; + [cce dispatchThreadgroups:_fetchThreadGroupsPerGridCustom + threadsPerThreadgroup:_fetchThreadsPerGroup]; - texDisplaySrcTarget[NDSDisplayID_Touch] = [self texDisplayPostprocessCustomTouch]; + texDisplaySrcTarget[NDSDisplayID_Touch] = _texDisplayPostprocessCustomTouch; } } } @@ -510,21 +526,21 @@ { if (!currentDisplayInfo.didPerformCustomRender[NDSDisplayID_Main]) { - [cce setTexture:texDisplayFetch16NativeMain atIndex:0]; - [cce setTexture:[self texDisplayPostprocessNativeMain] atIndex:1]; - [cce dispatchThreadgroups:fetchThreadGroupsPerGridNative - threadsPerThreadgroup:fetchThreadsPerGroup]; + [cce setTexture:_texDisplayFetch16NativeMain atIndex:0]; + [cce setTexture:_texDisplayPostprocessNativeMain atIndex:1]; + [cce dispatchThreadgroups:_fetchThreadGroupsPerGridNative + threadsPerThreadgroup:_fetchThreadsPerGroup]; - texDisplaySrcTarget[NDSDisplayID_Main] = [self texDisplayPostprocessNativeMain]; + texDisplaySrcTarget[NDSDisplayID_Main] = _texDisplayPostprocessNativeMain; } else { - [cce setTexture:[self texDisplayFetch16CustomMain] atIndex:0]; - [cce setTexture:[self texDisplayPostprocessCustomMain] atIndex:1]; - [cce dispatchThreadgroups:[self fetchThreadGroupsPerGridCustom] - threadsPerThreadgroup:[self fetchThreadsPerGroup]]; + [cce setTexture:_texDisplayFetch16CustomMain atIndex:0]; + [cce setTexture:_texDisplayPostprocessCustomMain atIndex:1]; + [cce dispatchThreadgroups:_fetchThreadGroupsPerGridCustom + threadsPerThreadgroup:_fetchThreadsPerGroup]; - texDisplaySrcTarget[NDSDisplayID_Main] = [self texDisplayPostprocessCustomMain]; + texDisplaySrcTarget[NDSDisplayID_Main] = _texDisplayPostprocessCustomMain; } } @@ -532,21 +548,21 @@ { if (!currentDisplayInfo.didPerformCustomRender[NDSDisplayID_Touch]) { - [cce setTexture:texDisplayFetch16NativeTouch atIndex:0]; - [cce setTexture:[self texDisplayPostprocessNativeTouch] atIndex:1]; - [cce dispatchThreadgroups:fetchThreadGroupsPerGridNative - threadsPerThreadgroup:fetchThreadsPerGroup]; + [cce setTexture:_texDisplayFetch16NativeTouch atIndex:0]; + [cce setTexture:_texDisplayPostprocessNativeTouch atIndex:1]; + [cce dispatchThreadgroups:_fetchThreadGroupsPerGridNative + threadsPerThreadgroup:_fetchThreadsPerGroup]; - texDisplaySrcTarget[NDSDisplayID_Touch] = [self texDisplayPostprocessNativeTouch]; + texDisplaySrcTarget[NDSDisplayID_Touch] = _texDisplayPostprocessNativeTouch; } else { - [cce setTexture:[self texDisplayFetch16CustomTouch] atIndex:0]; - [cce setTexture:[self texDisplayPostprocessCustomTouch] atIndex:1]; - [cce dispatchThreadgroups:[self fetchThreadGroupsPerGridCustom] - threadsPerThreadgroup:[self fetchThreadsPerGroup]]; + [cce setTexture:_texDisplayFetch16CustomTouch atIndex:0]; + [cce setTexture:_texDisplayPostprocessCustomTouch atIndex:1]; + [cce dispatchThreadgroups:_fetchThreadGroupsPerGridCustom + threadsPerThreadgroup:_fetchThreadsPerGroup]; - texDisplaySrcTarget[NDSDisplayID_Touch] = [self texDisplayPostprocessCustomTouch]; + texDisplaySrcTarget[NDSDisplayID_Touch] = _texDisplayPostprocessCustomTouch; } } } @@ -575,23 +591,23 @@ [cce setBuffer:_bufMasterBrightMode[NDSDisplayID_Main] offset:0 atIndex:0]; [cce setBuffer:_bufMasterBrightIntensity[NDSDisplayID_Main] offset:0 atIndex:1]; - if (texDisplaySrcTarget[NDSDisplayID_Main] == texDisplayFetch32NativeMain) + if (texDisplaySrcTarget[NDSDisplayID_Main] == _texDisplayFetch32NativeMain) { - [cce setTexture:texDisplayFetch32NativeMain atIndex:0]; - [cce setTexture:[self texDisplayPostprocessNativeMain] atIndex:1]; - [cce dispatchThreadgroups:fetchThreadGroupsPerGridNative - threadsPerThreadgroup:fetchThreadsPerGroup]; + [cce setTexture:_texDisplayFetch32NativeMain atIndex:0]; + [cce setTexture:_texDisplayPostprocessNativeMain atIndex:1]; + [cce dispatchThreadgroups:_fetchThreadGroupsPerGridNative + threadsPerThreadgroup:_fetchThreadsPerGroup]; - texDisplaySrcTarget[NDSDisplayID_Main] = [self texDisplayPostprocessNativeMain]; + texDisplaySrcTarget[NDSDisplayID_Main] = _texDisplayPostprocessNativeMain; } else { - [cce setTexture:[self texDisplayFetch32CustomMain] atIndex:0]; - [cce setTexture:[self texDisplayPostprocessCustomMain] atIndex:1]; - [cce dispatchThreadgroups:[self fetchThreadGroupsPerGridCustom] - threadsPerThreadgroup:[self fetchThreadsPerGroup]]; + [cce setTexture:_texDisplayFetch32CustomMain atIndex:0]; + [cce setTexture:_texDisplayPostprocessCustomMain atIndex:1]; + [cce dispatchThreadgroups:_fetchThreadGroupsPerGridCustom + threadsPerThreadgroup:_fetchThreadsPerGroup]; - texDisplaySrcTarget[NDSDisplayID_Main] = [self texDisplayPostprocessCustomMain]; + texDisplaySrcTarget[NDSDisplayID_Main] = _texDisplayPostprocessCustomMain; } } @@ -605,23 +621,23 @@ [cce setBuffer:_bufMasterBrightMode[NDSDisplayID_Touch] offset:0 atIndex:0]; [cce setBuffer:_bufMasterBrightIntensity[NDSDisplayID_Touch] offset:0 atIndex:1]; - if (texDisplaySrcTarget[NDSDisplayID_Touch] == texDisplayFetch32NativeTouch) + if (texDisplaySrcTarget[NDSDisplayID_Touch] == _texDisplayFetch32NativeTouch) { - [cce setTexture:texDisplayFetch32NativeTouch atIndex:0]; - [cce setTexture:[self texDisplayPostprocessNativeTouch] atIndex:1]; - [cce dispatchThreadgroups:fetchThreadGroupsPerGridNative - threadsPerThreadgroup:fetchThreadsPerGroup]; + [cce setTexture:_texDisplayFetch32NativeTouch atIndex:0]; + [cce setTexture:_texDisplayPostprocessNativeTouch atIndex:1]; + [cce dispatchThreadgroups:_fetchThreadGroupsPerGridNative + threadsPerThreadgroup:_fetchThreadsPerGroup]; - texDisplaySrcTarget[NDSDisplayID_Touch] = [self texDisplayPostprocessNativeTouch]; + texDisplaySrcTarget[NDSDisplayID_Touch] = _texDisplayPostprocessNativeTouch; } else { - [cce setTexture:[self texDisplayFetch32CustomTouch] atIndex:0]; - [cce setTexture:[self texDisplayPostprocessCustomTouch] atIndex:1]; - [cce dispatchThreadgroups:[self fetchThreadGroupsPerGridCustom] - threadsPerThreadgroup:[self fetchThreadsPerGroup]]; + [cce setTexture:_texDisplayFetch32CustomTouch atIndex:0]; + [cce setTexture:_texDisplayPostprocessCustomTouch atIndex:1]; + [cce dispatchThreadgroups:_fetchThreadGroupsPerGridCustom + threadsPerThreadgroup:_fetchThreadsPerGroup]; - texDisplaySrcTarget[NDSDisplayID_Touch] = [self texDisplayPostprocessCustomTouch]; + texDisplaySrcTarget[NDSDisplayID_Touch] = _texDisplayPostprocessCustomTouch; } } } @@ -630,19 +646,44 @@ [cce endEncoding]; } - [cb commit]; + [self setUsingFramebufferDirectlyAtIndex:index + displayID:NDSDisplayID_Main + state:(texDisplaySrcTarget[NDSDisplayID_Main] == _texDisplayFetch32NativeMain) || (texDisplaySrcTarget[NDSDisplayID_Main] == _texDisplayFetch32CustomMain)]; - [self setTexDisplaySrcTargetMain:texDisplaySrcTarget[NDSDisplayID_Main]]; - [self setTexDisplaySrcTargetTouch:texDisplaySrcTarget[NDSDisplayID_Touch]]; + [self setUsingFramebufferDirectlyAtIndex:index + displayID:NDSDisplayID_Touch + state:(texDisplaySrcTarget[NDSDisplayID_Touch] == _texDisplayFetch32NativeTouch) || (texDisplaySrcTarget[NDSDisplayID_Touch] == _texDisplayFetch32CustomTouch)]; + + [self setTexFetchMain:texDisplaySrcTarget[NDSDisplayID_Main]]; + [self setTexFetchTouch:texDisplaySrcTarget[NDSDisplayID_Touch]]; +} + +- (void) fetchFromBufferIndex:(const u8)index +{ + pthread_rwlock_rdlock([self rwlockFramebufferAtIndex:index]); + + id cb = [commandQueue commandBufferWithUnretainedReferences]; + _fetchEncoder = [cb blitCommandEncoder]; + + GPUFetchObject->GPUClientFetchObject::FetchFromBufferIndex(index); + + [_fetchEncoder endEncoding]; + + [self setFetchTextureBindingsAtIndex:index commandBuffer:cb]; + + [cb addCompletedHandler:^(id block) { + pthread_rwlock_unlock([self rwlockFramebufferAtIndex:index]); + }]; + [cb commit]; } - (void) fetchNativeDisplayByID:(const NDSDisplayID)displayID bufferIndex:(const u8)bufferIndex { const NDSDisplayInfo ¤tDisplayInfo = GPUFetchObject->GetFetchDisplayInfoForBufferIndex(bufferIndex); - id texFetch16 = (displayID == NDSDisplayID_Main) ? texDisplayFetch16NativeMain : texDisplayFetch16NativeTouch; - id texFetch32 = (displayID == NDSDisplayID_Main) ? texDisplayFetch32NativeMain : texDisplayFetch32NativeTouch; - const size_t bufferSize = [self displayFetchNativeBufferSize]; + id texFetch16 = (displayID == NDSDisplayID_Main) ? _texDisplayFetch16NativeMain : _texDisplayFetch16NativeTouch; + id texFetch32 = (displayID == NDSDisplayID_Main) ? _texDisplayFetch32NativeMain : _texDisplayFetch32NativeTouch; + const size_t bufferSize = GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT * currentDisplayInfo.pixelBytes; const id targetSource = (displayID == NDSDisplayID_Main) ? _bufDisplayFetchNative[NDSDisplayID_Main][currentDisplayInfo.bufferIndex] : _bufDisplayFetchNative[NDSDisplayID_Touch][currentDisplayInfo.bufferIndex]; [targetSource didModifyRange:NSMakeRange(0, bufferSize)]; @@ -660,58 +701,10 @@ - (void) fetchCustomDisplayByID:(const NDSDisplayID)displayID bufferIndex:(const u8)bufferIndex { const NDSDisplayInfo ¤tDisplayInfo = GPUFetchObject->GetFetchDisplayInfoForBufferIndex(bufferIndex); - const size_t w = currentDisplayInfo.customWidth; - const size_t h = currentDisplayInfo.customHeight; - id texFetch16 = (displayID == NDSDisplayID_Main) ? [self texDisplayFetch16CustomMain] : [self texDisplayFetch16CustomTouch]; - id texFetch32 = (displayID == NDSDisplayID_Main) ? [self texDisplayFetch32CustomMain] : [self texDisplayFetch32CustomTouch]; - - // If the existing texture size is different than the incoming size, then remake the textures to match the incoming size. - if ( ([texFetch32 width] != w) || ([texFetch32 height] != h) ) - { - MTLTextureDescriptor *texDisplayLoad16Desc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatR16Uint - width:w - height:h - mipmapped:NO]; - [texDisplayLoad16Desc setResourceOptions:MTLResourceStorageModeManaged]; - [texDisplayLoad16Desc setStorageMode:MTLStorageModeManaged]; - [texDisplayLoad16Desc setCpuCacheMode:MTLCPUCacheModeWriteCombined]; - [texDisplayLoad16Desc setUsage:MTLTextureUsageShaderRead]; - - MTLTextureDescriptor *texDisplayLoad32Desc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm - width:w - height:h - mipmapped:NO]; - [texDisplayLoad32Desc setResourceOptions:MTLResourceStorageModePrivate]; - [texDisplayLoad32Desc setStorageMode:MTLStorageModePrivate]; - [texDisplayLoad32Desc setUsage:MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite]; - - if (displayID == NDSDisplayID_Main) - { - [self setTexDisplayFetch16CustomMain:[device newTextureWithDescriptor:texDisplayLoad16Desc]]; - [self setTexDisplayFetch32CustomMain:[device newTextureWithDescriptor:texDisplayLoad32Desc]]; - [self setTexDisplayPostprocessCustomMain:[device newTextureWithDescriptor:texDisplayLoad32Desc]]; - texFetch16 = [self texDisplayFetch16CustomMain]; - texFetch32 = [self texDisplayFetch32CustomMain]; - } - else - { - [self setTexDisplayFetch16CustomTouch:[device newTextureWithDescriptor:texDisplayLoad16Desc]]; - [self setTexDisplayFetch32CustomTouch:[device newTextureWithDescriptor:texDisplayLoad32Desc]]; - [self setTexDisplayPostprocessCustomTouch:[device newTextureWithDescriptor:texDisplayLoad32Desc]]; - texFetch16 = [self texDisplayFetch16CustomTouch]; - texFetch32 = [self texDisplayFetch32CustomTouch]; - } - - const size_t tw = fetchThreadsPerGroup.width; - const size_t th = fetchThreadsPerGroup.height; - - [self setFetchThreadGroupsPerGridCustom:MTLSizeMake((currentDisplayInfo.customWidth + tw - 1) / tw, - (currentDisplayInfo.customHeight + th - 1) / th, - 1)]; - } - - const size_t bufferSize = [self displayFetchCustomBufferSize]; + id texFetch16 = (displayID == NDSDisplayID_Main) ? _texDisplayFetch16CustomMain : _texDisplayFetch16CustomTouch; + id texFetch32 = (displayID == NDSDisplayID_Main) ? _texDisplayFetch32CustomMain : _texDisplayFetch32CustomTouch; + const size_t bufferSize = currentDisplayInfo.customWidth * currentDisplayInfo.customHeight * currentDisplayInfo.pixelBytes; const id targetSource = (displayID == NDSDisplayID_Main) ? _bufDisplayFetchCustom[NDSDisplayID_Main][currentDisplayInfo.bufferIndex] : _bufDisplayFetchCustom[NDSDisplayID_Touch][currentDisplayInfo.bufferIndex]; [targetSource didModifyRange:NSMakeRange(0, bufferSize)]; @@ -733,14 +726,11 @@ @synthesize cdp; @synthesize sharedData; @synthesize colorAttachment0Desc; -@dynamic mutexDisplayTextureUpdate; @dynamic mutexBufferUpdate; @synthesize pixelScalePipeline; @synthesize outputRGBAPipeline; @synthesize outputDrawablePipeline; @synthesize drawableFormat; -@synthesize bufCPUFilterSrcMain; -@synthesize bufCPUFilterSrcTouch; @synthesize bufCPUFilterDstMain; @synthesize bufCPUFilterDstTouch; @synthesize texDisplayPixelScaleMain; @@ -752,6 +742,7 @@ @synthesize needsHUDVerticesUpdate; @dynamic pixelScaler; @dynamic outputFilter; +@synthesize processedFrameInfo; - (id) initWithDisplayPresenter:(MacMetalDisplayPresenter *)thePresenter { @@ -795,14 +786,13 @@ _texDisplaySrcDeposterize[NDSDisplayID_Touch][0] = nil; _texDisplaySrcDeposterize[NDSDisplayID_Main][1] = nil; _texDisplaySrcDeposterize[NDSDisplayID_Touch][1] = nil; - bufCPUFilterSrcMain = nil; - bufCPUFilterSrcTouch = nil; + + _bufCPUFilterSrcMain = nil; + _bufCPUFilterSrcTouch = nil; bufCPUFilterDstMain = nil; bufCPUFilterDstTouch = nil; texDisplayPixelScaleMain = nil; texDisplayPixelScaleTouch = nil; - _texDisplayOutput[0] = nil; - _texDisplayOutput[1] = nil; texHUDCharMap = nil; _pixelScalerThreadsPerGroup = MTLSizeMake(1, 1, 1); @@ -813,7 +803,12 @@ needsScreenVerticesUpdate = YES; needsHUDVerticesUpdate = YES; - pthread_mutex_init(&_mutexDisplayTextureUpdate, NULL); + processedFrameInfo.bufferIndex = 0; + processedFrameInfo.tex[NDSDisplayID_Main] = nil; + processedFrameInfo.tex[NDSDisplayID_Touch] = nil; + processedFrameInfo.isMainDisplayProcessed = false; + processedFrameInfo.isTouchDisplayProcessed = false; + pthread_mutex_init(&_mutexBufferUpdate, NULL); return self; @@ -836,8 +831,8 @@ [_texDisplaySrcDeposterize[NDSDisplayID_Main][1] release]; [_texDisplaySrcDeposterize[NDSDisplayID_Touch][1] release]; - [self setBufCPUFilterSrcMain:nil]; - [self setBufCPUFilterSrcTouch:nil]; + [_bufCPUFilterSrcMain release]; + [_bufCPUFilterSrcTouch release]; [self setBufCPUFilterDstMain:nil]; [self setBufCPUFilterDstTouch:nil]; [self setTexDisplayPixelScaleMain:nil]; @@ -850,17 +845,11 @@ [self setSharedData:nil]; - pthread_mutex_destroy(&_mutexDisplayTextureUpdate); pthread_mutex_destroy(&_mutexBufferUpdate); [super dealloc]; } -- (pthread_mutex_t *) mutexDisplayTextureUpdate -{ - return &_mutexDisplayTextureUpdate; -} - - (pthread_mutex_t *) mutexBufferUpdate { return &_mutexBufferUpdate; @@ -1129,14 +1118,14 @@ [self setTexDisplayPixelScaleMain:[[sharedData device] newTextureWithDescriptor:texDisplayPixelScaleDesc]]; [self setTexDisplayPixelScaleTouch:[[sharedData device] newTextureWithDescriptor:texDisplayPixelScaleDesc]]; - _texDisplayOutput[NDSDisplayID_Main] = [sharedData texDisplayFetch32NativeMain]; - _texDisplayOutput[NDSDisplayID_Touch] = [sharedData texDisplayFetch32NativeTouch]; + processedFrameInfo.tex[NDSDisplayID_Main] = [sharedData texFetchMain]; + processedFrameInfo.tex[NDSDisplayID_Touch] = [sharedData texFetchTouch]; VideoFilter *vfMain = cdp->GetPixelScalerObject(NDSDisplayID_Main); - [self setBufCPUFilterSrcMain:[[sharedData device] newBufferWithBytesNoCopy:vfMain->GetSrcBufferPtr() + _bufCPUFilterSrcMain = [[[sharedData device] newBufferWithBytesNoCopy:vfMain->GetSrcBufferPtr() length:vfMain->GetSrcWidth() * vfMain->GetSrcHeight() * sizeof(uint32_t) - options:MTLResourceStorageModeManaged - deallocator:nil]]; + options:MTLResourceStorageModeManaged + deallocator:nil] retain]; [self setBufCPUFilterDstMain:[[sharedData device] newBufferWithBytesNoCopy:vfMain->GetDstBufferPtr() length:vfMain->GetDstWidth() * vfMain->GetDstHeight() * sizeof(uint32_t) @@ -1144,10 +1133,10 @@ deallocator:nil]]; VideoFilter *vfTouch = cdp->GetPixelScalerObject(NDSDisplayID_Touch); - [self setBufCPUFilterSrcTouch:[[sharedData device] newBufferWithBytesNoCopy:vfTouch->GetSrcBufferPtr() + _bufCPUFilterSrcTouch = [[[sharedData device] newBufferWithBytesNoCopy:vfTouch->GetSrcBufferPtr() length:vfTouch->GetSrcWidth() * vfTouch->GetSrcHeight() * sizeof(uint32_t) options:MTLResourceStorageModeManaged - deallocator:nil]]; + deallocator:nil] retain]; [self setBufCPUFilterDstTouch:[[sharedData device] newBufferWithBytesNoCopy:vfTouch->GetDstBufferPtr() length:vfTouch->GetDstWidth() * vfTouch->GetDstHeight() * sizeof(uint32_t) @@ -1285,30 +1274,17 @@ - (void) processDisplays { - const NDSDisplayInfo &fetchDisplayInfo = cdp->GetEmuDisplayInfo(); + const u8 bufferIndex = [sharedData GPUFetchObject]->GetLastFetchIndex(); + const NDSDisplayInfo &fetchDisplayInfo = [sharedData GPUFetchObject]->GetFetchDisplayInfoForBufferIndex(bufferIndex); const ClientDisplayMode mode = cdp->GetPresenterProperties().mode; const bool useDeposterize = cdp->GetSourceDeposterize(); + const NDSDisplayID selectedDisplaySource[2] = { cdp->GetSelectedDisplaySourceForDisplay(NDSDisplayID_Main), cdp->GetSelectedDisplaySourceForDisplay(NDSDisplayID_Touch) }; + id texMain = (selectedDisplaySource[NDSDisplayID_Main] == NDSDisplayID_Main) ? [sharedData texFetchMain] : [sharedData texFetchTouch]; + id texTouch = (selectedDisplaySource[NDSDisplayID_Touch] == NDSDisplayID_Touch) ? [sharedData texFetchTouch] : [sharedData texFetchMain]; - pthread_mutex_lock(&_mutexDisplayTextureUpdate); - - if (selectedDisplaySource[NDSDisplayID_Main] == NDSDisplayID_Main) - { - _texDisplayOutput[NDSDisplayID_Main] = [sharedData texDisplaySrcTargetMain]; - } - else - { - _texDisplayOutput[NDSDisplayID_Main] = [sharedData texDisplaySrcTargetTouch]; - } - - if (selectedDisplaySource[NDSDisplayID_Touch] == NDSDisplayID_Touch) - { - _texDisplayOutput[NDSDisplayID_Touch] = [sharedData texDisplaySrcTargetTouch]; - } - else - { - _texDisplayOutput[NDSDisplayID_Touch] = [sharedData texDisplaySrcTargetMain]; - } + bool isDisplayProcessedMain = ![sharedData isUsingFramebufferDirectlyAtIndex:bufferIndex displayID:selectedDisplaySource[NDSDisplayID_Main]]; + bool isDisplayProcessedTouch = ![sharedData isUsingFramebufferDirectlyAtIndex:bufferIndex displayID:selectedDisplaySource[NDSDisplayID_Touch]]; if ( (fetchDisplayInfo.pixelBytes != 0) && (useDeposterize || (cdp->GetPixelScaler() != VideoFilterTypeID_None)) ) { @@ -1316,8 +1292,9 @@ const bool shouldProcessDisplay[2] = { (!fetchDisplayInfo.didPerformCustomRender[selectedDisplaySource[NDSDisplayID_Main]] || !fetchDisplayInfo.isCustomSizeRequested) && cdp->IsSelectedDisplayEnabled(NDSDisplayID_Main) && (mode == ClientDisplayMode_Main || mode == ClientDisplayMode_Dual), (!fetchDisplayInfo.didPerformCustomRender[selectedDisplaySource[NDSDisplayID_Touch]] || !fetchDisplayInfo.isCustomSizeRequested) && cdp->IsSelectedDisplayEnabled(NDSDisplayID_Touch) && (mode == ClientDisplayMode_Touch || mode == ClientDisplayMode_Dual) && (selectedDisplaySource[NDSDisplayID_Main] != selectedDisplaySource[NDSDisplayID_Touch]) }; - VideoFilter *vfMain = cdp->GetPixelScalerObject(NDSDisplayID_Main); - VideoFilter *vfTouch = cdp->GetPixelScalerObject(NDSDisplayID_Touch); + bool texFetchMainNeedsLock = (useDeposterize || ((cdp->GetPixelScaler() != VideoFilterTypeID_None) && willFilterOnGPU)) && shouldProcessDisplay[NDSDisplayID_Main]; + bool texFetchTouchNeedsLock = (useDeposterize || ((cdp->GetPixelScaler() != VideoFilterTypeID_None) && willFilterOnGPU)) && shouldProcessDisplay[NDSDisplayID_Touch]; + bool needsFetchBuffersLock = texFetchMainNeedsLock || texFetchTouchNeedsLock; id cb = [self newCommandBuffer]; id cce = [cb computeCommandEncoder]; @@ -1327,9 +1304,14 @@ { [cce setComputePipelineState:[sharedData deposterizePipeline]]; + if (needsFetchBuffersLock) + { + pthread_rwlock_rdlock([sharedData rwlockFramebufferAtIndex:bufferIndex]); + } + if (shouldProcessDisplay[NDSDisplayID_Main]) { - [cce setTexture:_texDisplayOutput[NDSDisplayID_Main] atIndex:0]; + [cce setTexture:texMain atIndex:0]; [cce setTexture:_texDisplaySrcDeposterize[NDSDisplayID_Main][0] atIndex:1]; [cce dispatchThreadgroups:[sharedData deposterizeThreadGroupsPerGrid] threadsPerThreadgroup:[sharedData deposterizeThreadsPerGroup]]; @@ -1339,12 +1321,18 @@ [cce dispatchThreadgroups:[sharedData deposterizeThreadGroupsPerGrid] threadsPerThreadgroup:[sharedData deposterizeThreadsPerGroup]]; - _texDisplayOutput[NDSDisplayID_Main] = _texDisplaySrcDeposterize[NDSDisplayID_Main][1]; + texMain = _texDisplaySrcDeposterize[NDSDisplayID_Main][1]; + isDisplayProcessedMain = true; + + if (selectedDisplaySource[NDSDisplayID_Main] == selectedDisplaySource[NDSDisplayID_Touch]) + { + isDisplayProcessedTouch = true; + } } if (shouldProcessDisplay[NDSDisplayID_Touch]) { - [cce setTexture:_texDisplayOutput[NDSDisplayID_Touch] atIndex:0]; + [cce setTexture:texTouch atIndex:0]; [cce setTexture:_texDisplaySrcDeposterize[NDSDisplayID_Touch][0] atIndex:1]; [cce dispatchThreadgroups:[sharedData deposterizeThreadGroupsPerGrid] threadsPerThreadgroup:[sharedData deposterizeThreadsPerGroup]]; @@ -1354,7 +1342,22 @@ [cce dispatchThreadgroups:[sharedData deposterizeThreadGroupsPerGrid] threadsPerThreadgroup:[sharedData deposterizeThreadsPerGroup]]; - _texDisplayOutput[NDSDisplayID_Touch] = _texDisplaySrcDeposterize[NDSDisplayID_Touch][1]; + texTouch = _texDisplaySrcDeposterize[NDSDisplayID_Touch][1]; + isDisplayProcessedTouch = true; + } + + if (needsFetchBuffersLock) + { + [cce endEncoding]; + [cb addCompletedHandler:^(id block) { + pthread_rwlock_unlock([sharedData rwlockFramebufferAtIndex:bufferIndex]); + }]; + [cb commit]; + + cb = [self newCommandBuffer]; + cce = [cb computeCommandEncoder]; + + needsFetchBuffersLock = !isDisplayProcessedMain || !isDisplayProcessedTouch; } } @@ -1363,24 +1366,48 @@ { [cce setComputePipelineState:[self pixelScalePipeline]]; + if (needsFetchBuffersLock) + { + pthread_rwlock_rdlock([sharedData rwlockFramebufferAtIndex:bufferIndex]); + } + if (shouldProcessDisplay[NDSDisplayID_Main]) { - [cce setTexture:_texDisplayOutput[NDSDisplayID_Main] atIndex:0]; + [cce setTexture:texMain atIndex:0]; [cce setTexture:[self texDisplayPixelScaleMain] atIndex:1]; [cce setTexture:[sharedData texCurrentHQnxLUT] atIndex:2]; [cce dispatchThreadgroups:_pixelScalerThreadGroupsPerGrid threadsPerThreadgroup:_pixelScalerThreadsPerGroup]; - _texDisplayOutput[NDSDisplayID_Main] = [self texDisplayPixelScaleMain]; + texMain = [self texDisplayPixelScaleMain]; + isDisplayProcessedMain = true; + + if (selectedDisplaySource[NDSDisplayID_Main] == selectedDisplaySource[NDSDisplayID_Touch]) + { + isDisplayProcessedTouch = true; + } } if (shouldProcessDisplay[NDSDisplayID_Touch]) { - [cce setTexture:_texDisplayOutput[NDSDisplayID_Touch] atIndex:0]; + [cce setTexture:texTouch atIndex:0]; [cce setTexture:[self texDisplayPixelScaleTouch] atIndex:1]; [cce setTexture:[sharedData texCurrentHQnxLUT] atIndex:2]; [cce dispatchThreadgroups:_pixelScalerThreadGroupsPerGrid threadsPerThreadgroup:_pixelScalerThreadsPerGroup]; - _texDisplayOutput[NDSDisplayID_Touch] = [self texDisplayPixelScaleTouch]; + texTouch = [self texDisplayPixelScaleTouch]; + isDisplayProcessedTouch = true; + } + + if (needsFetchBuffersLock) + { + [cce endEncoding]; + [cb addCompletedHandler:^(id block) { + pthread_rwlock_unlock([sharedData rwlockFramebufferAtIndex:bufferIndex]); + }]; + [cb commit]; + + cb = [self newCommandBuffer]; + cce = [cb computeCommandEncoder]; } } @@ -1389,6 +1416,9 @@ // If the pixel scaler didn't already run on the GPU, then run the pixel scaler on the CPU. if ( (cdp->GetPixelScaler() != VideoFilterTypeID_None) && !willFilterOnGPU ) { + VideoFilter *vfMain = cdp->GetPixelScalerObject(NDSDisplayID_Main); + VideoFilter *vfTouch = cdp->GetPixelScalerObject(NDSDisplayID_Touch); + id bce = [cb blitCommandEncoder]; if (useDeposterize) @@ -1401,12 +1431,12 @@ sourceLevel:0 sourceOrigin:MTLOriginMake(0, 0, 0) sourceSize:MTLSizeMake(vfMain->GetSrcWidth(), vfMain->GetSrcHeight(), 1) - toBuffer:[self bufCPUFilterSrcMain] + toBuffer:_bufCPUFilterSrcMain destinationOffset:0 destinationBytesPerRow:vfMain->GetSrcWidth() * sizeof(uint32_t) destinationBytesPerImage:vfMain->GetSrcWidth() * vfMain->GetSrcHeight() * sizeof(uint32_t)]; - [bce synchronizeResource:[self bufCPUFilterSrcMain]]; + [bce synchronizeResource:_bufCPUFilterSrcMain]; } if (shouldProcessDisplay[NDSDisplayID_Touch]) @@ -1416,12 +1446,12 @@ sourceLevel:0 sourceOrigin:MTLOriginMake(0, 0, 0) sourceSize:MTLSizeMake(vfTouch->GetSrcWidth(), vfTouch->GetSrcHeight(), 1) - toBuffer:[self bufCPUFilterSrcTouch] + toBuffer:_bufCPUFilterSrcTouch destinationOffset:0 destinationBytesPerRow:vfTouch->GetSrcWidth() * sizeof(uint32_t) destinationBytesPerImage:vfTouch->GetSrcWidth() * vfTouch->GetSrcHeight() * sizeof(uint32_t)]; - [bce synchronizeResource:[self bufCPUFilterSrcTouch]]; + [bce synchronizeResource:_bufCPUFilterSrcTouch]; } } @@ -1429,12 +1459,16 @@ if (shouldProcessDisplay[NDSDisplayID_Main]) { + pthread_rwlock_rdlock(((MacMetalDisplayPresenter *)cdp)->GetCPUFilterRWLock(NDSDisplayID_Main, bufferIndex)); vfMain->RunFilter(); + pthread_rwlock_unlock(((MacMetalDisplayPresenter *)cdp)->GetCPUFilterRWLock(NDSDisplayID_Main, bufferIndex)); } if (shouldProcessDisplay[NDSDisplayID_Touch]) { + pthread_rwlock_rdlock(((MacMetalDisplayPresenter *)cdp)->GetCPUFilterRWLock(NDSDisplayID_Touch, bufferIndex)); vfTouch->RunFilter(); + pthread_rwlock_unlock(((MacMetalDisplayPresenter *)cdp)->GetCPUFilterRWLock(NDSDisplayID_Touch, bufferIndex)); } if (shouldProcessDisplay[NDSDisplayID_Main]) @@ -1451,7 +1485,13 @@ destinationLevel:0 destinationOrigin:MTLOriginMake(0, 0, 0)]; - _texDisplayOutput[NDSDisplayID_Main] = [self texDisplayPixelScaleMain]; + texMain = [self texDisplayPixelScaleMain]; + isDisplayProcessedMain = true; + + if (selectedDisplaySource[NDSDisplayID_Main] == selectedDisplaySource[NDSDisplayID_Touch]) + { + isDisplayProcessedTouch = true; + } } if (shouldProcessDisplay[NDSDisplayID_Touch]) @@ -1468,7 +1508,8 @@ destinationLevel:0 destinationOrigin:MTLOriginMake(0, 0, 0)]; - _texDisplayOutput[NDSDisplayID_Touch] = [self texDisplayPixelScaleTouch]; + texTouch = [self texDisplayPixelScaleTouch]; + isDisplayProcessedTouch = true; } pthread_mutex_unlock(((MacMetalDisplayPresenter *)cdp)->GetMutexProcessPtr()); @@ -1481,22 +1522,28 @@ if (selectedDisplaySource[NDSDisplayID_Touch] == selectedDisplaySource[NDSDisplayID_Main]) { - _texDisplayOutput[NDSDisplayID_Touch] = _texDisplayOutput[NDSDisplayID_Main]; + texTouch = texMain; } // Update the texture coordinates - cdp->SetScreenTextureCoordinates((float)[_texDisplayOutput[NDSDisplayID_Main] width], (float)[_texDisplayOutput[NDSDisplayID_Main] height], - (float)[_texDisplayOutput[NDSDisplayID_Touch] width], (float)[_texDisplayOutput[NDSDisplayID_Touch] height], + cdp->SetScreenTextureCoordinates((float)[texMain width], (float)[texMain height], + (float)[texTouch width], (float)[texTouch height], (float *)[_displayTexCoordBuffer contents]); [_displayTexCoordBuffer didModifyRange:NSMakeRange(0, sizeof(float) * (4 * 8))]; - pthread_mutex_unlock(&_mutexDisplayTextureUpdate); + // Update the frame info + MetalProcessedFrameInfo newFrameInfo; + newFrameInfo.bufferIndex = bufferIndex; + newFrameInfo.isMainDisplayProcessed = isDisplayProcessedMain; + newFrameInfo.isTouchDisplayProcessed = isDisplayProcessedTouch; + newFrameInfo.tex[NDSDisplayID_Main] = texMain; + newFrameInfo.tex[NDSDisplayID_Touch] = texTouch; + + [self setProcessedFrameInfo:newFrameInfo]; } - (void) updateRenderBuffers { - const NDSDisplayInfo &displayInfo = cdp->GetEmuDisplayInfo(); - // Set up the view properties. bool didChangeViewProperties = false; bool needEncodeViewport = false; @@ -1540,8 +1587,7 @@ } // Set up the display properties. - bool willDrawDisplays = (displayInfo.pixelBytes != 0); - if (willDrawDisplays && [self needsScreenVerticesUpdate]) + if ([self needsScreenVerticesUpdate]) { cdp->SetScreenVertices((float *)[_displayVtxPositionBuffer contents]); [_displayVtxPositionBuffer didModifyRange:NSMakeRange(0, sizeof(float) * (4 * 8))]; @@ -1606,7 +1652,6 @@ _needEncodeViewport = needEncodeViewport; _newViewport = newViewport; - _willDrawDisplays = willDrawDisplays; _willDrawHUD = willDrawHUD; _willDrawHUDInput = cdp->GetHUDShowInput(); _hudStringLength = cdp->GetHUDString().length(); @@ -1618,6 +1663,8 @@ - (void) renderForCommandBuffer:(id)cb outputPipelineState:(id)outputPipelineState hudPipelineState:(id)hudPipelineState + texDisplayMain:(id)texDisplayMain + texDisplayTouch:(id)texDisplayTouch { id rce = [cb renderCommandEncoderWithDescriptor:_outputRenderPassDesc]; @@ -1627,81 +1674,79 @@ } // Draw the NDS displays. - if (_willDrawDisplays) + const NDSDisplayInfo &displayInfo = cdp->GetEmuDisplayInfo(); + const float backlightIntensity[2] = { displayInfo.backlightIntensity[NDSDisplayID_Main], displayInfo.backlightIntensity[NDSDisplayID_Touch] }; + + [rce setRenderPipelineState:outputPipelineState]; + [rce setVertexBuffer:_displayVtxPositionBuffer offset:0 atIndex:0]; + [rce setVertexBuffer:_displayTexCoordBuffer offset:0 atIndex:1]; + [rce setVertexBuffer:_cdvPropertiesBuffer offset:0 atIndex:2]; + + switch (cdp->GetPresenterProperties().mode) { - const NDSDisplayInfo &displayInfo = cdp->GetEmuDisplayInfo(); - - [rce setRenderPipelineState:outputPipelineState]; - [rce setVertexBuffer:_displayVtxPositionBuffer offset:0 atIndex:0]; - [rce setVertexBuffer:_displayTexCoordBuffer offset:0 atIndex:1]; - [rce setVertexBuffer:_cdvPropertiesBuffer offset:0 atIndex:2]; - - switch (cdp->GetPresenterProperties().mode) + case ClientDisplayMode_Main: { - case ClientDisplayMode_Main: + if (cdp->IsSelectedDisplayEnabled(NDSDisplayID_Main)) { - if (cdp->IsSelectedDisplayEnabled(NDSDisplayID_Main)) - { - [rce setFragmentBytes:&displayInfo.backlightIntensity[NDSDisplayID_Main] length:sizeof(displayInfo.backlightIntensity[NDSDisplayID_Main]) atIndex:0]; - [rce setFragmentTexture:_texDisplayOutput[NDSDisplayID_Main] atIndex:0]; - [rce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4]; - } - break; + [rce setFragmentBytes:&backlightIntensity[NDSDisplayID_Main] length:sizeof(backlightIntensity[NDSDisplayID_Main]) atIndex:0]; + [rce setFragmentTexture:texDisplayMain atIndex:0]; + [rce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4]; } - - case ClientDisplayMode_Touch: - { - if (cdp->IsSelectedDisplayEnabled(NDSDisplayID_Touch)) - { - [rce setFragmentBytes:&displayInfo.backlightIntensity[NDSDisplayID_Touch] length:sizeof(displayInfo.backlightIntensity[NDSDisplayID_Touch]) atIndex:0]; - [rce setFragmentTexture:_texDisplayOutput[NDSDisplayID_Touch] atIndex:0]; - [rce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:4 vertexCount:4]; - } - break; - } - - case ClientDisplayMode_Dual: - { - const NDSDisplayID majorDisplayID = (cdp->GetPresenterProperties().order == ClientDisplayOrder_MainFirst) ? NDSDisplayID_Main : NDSDisplayID_Touch; - const size_t majorDisplayVtx = (cdp->GetPresenterProperties().order == ClientDisplayOrder_MainFirst) ? 8 : 12; - - switch (cdp->GetPresenterProperties().layout) - { - case ClientDisplayLayout_Hybrid_2_1: - case ClientDisplayLayout_Hybrid_16_9: - case ClientDisplayLayout_Hybrid_16_10: - { - if (cdp->IsSelectedDisplayEnabled(majorDisplayID)) - { - [rce setFragmentBytes:&displayInfo.backlightIntensity[majorDisplayID] length:sizeof(displayInfo.backlightIntensity[majorDisplayID]) atIndex:0]; - [rce setFragmentTexture:_texDisplayOutput[majorDisplayID] atIndex:0]; - [rce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:majorDisplayVtx vertexCount:4]; - } - break; - } - - default: - break; - } - - if (cdp->IsSelectedDisplayEnabled(NDSDisplayID_Main)) - { - [rce setFragmentBytes:&displayInfo.backlightIntensity[NDSDisplayID_Main] length:sizeof(displayInfo.backlightIntensity[NDSDisplayID_Main]) atIndex:0]; - [rce setFragmentTexture:_texDisplayOutput[NDSDisplayID_Main] atIndex:0]; - [rce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4]; - } - - if (cdp->IsSelectedDisplayEnabled(NDSDisplayID_Touch)) - { - [rce setFragmentBytes:&displayInfo.backlightIntensity[NDSDisplayID_Touch] length:sizeof(displayInfo.backlightIntensity[NDSDisplayID_Touch]) atIndex:0]; - [rce setFragmentTexture:_texDisplayOutput[NDSDisplayID_Touch] atIndex:0]; - [rce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:4 vertexCount:4]; - } - } - - default: - break; + break; } + + case ClientDisplayMode_Touch: + { + if (cdp->IsSelectedDisplayEnabled(NDSDisplayID_Touch)) + { + [rce setFragmentBytes:&backlightIntensity[NDSDisplayID_Touch] length:sizeof(backlightIntensity[NDSDisplayID_Touch]) atIndex:0]; + [rce setFragmentTexture:texDisplayTouch atIndex:0]; + [rce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:4 vertexCount:4]; + } + break; + } + + case ClientDisplayMode_Dual: + { + const NDSDisplayID majorDisplayID = (cdp->GetPresenterProperties().order == ClientDisplayOrder_MainFirst) ? NDSDisplayID_Main : NDSDisplayID_Touch; + const size_t majorDisplayVtx = (cdp->GetPresenterProperties().order == ClientDisplayOrder_MainFirst) ? 8 : 12; + + switch (cdp->GetPresenterProperties().layout) + { + case ClientDisplayLayout_Hybrid_2_1: + case ClientDisplayLayout_Hybrid_16_9: + case ClientDisplayLayout_Hybrid_16_10: + { + if (cdp->IsSelectedDisplayEnabled(majorDisplayID)) + { + [rce setFragmentBytes:&backlightIntensity[majorDisplayID] length:sizeof(backlightIntensity[majorDisplayID]) atIndex:0]; + [rce setFragmentTexture:((majorDisplayID == NDSDisplayID_Main) ? texDisplayMain : texDisplayTouch) atIndex:0]; + [rce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:majorDisplayVtx vertexCount:4]; + } + break; + } + + default: + break; + } + + if (cdp->IsSelectedDisplayEnabled(NDSDisplayID_Main)) + { + [rce setFragmentBytes:&backlightIntensity[NDSDisplayID_Main] length:sizeof(backlightIntensity[NDSDisplayID_Main]) atIndex:0]; + [rce setFragmentTexture:texDisplayMain atIndex:0]; + [rce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4]; + } + + if (cdp->IsSelectedDisplayEnabled(NDSDisplayID_Touch)) + { + [rce setFragmentBytes:&backlightIntensity[NDSDisplayID_Touch] length:sizeof(backlightIntensity[NDSDisplayID_Touch]) atIndex:0]; + [rce setFragmentTexture:texDisplayTouch atIndex:0]; + [rce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:4 vertexCount:4]; + } + } + + default: + break; } // Draw the HUD. @@ -1777,15 +1822,38 @@ id texRender = [[[sharedData device] newTextureWithDescriptor:texRenderDesc] retain]; id dstMTLBuffer = [[[sharedData device] newBufferWithLength:clientWidth * clientHeight * sizeof(uint32_t) options:MTLResourceStorageModeManaged] retain]; - pthread_mutex_lock(&_mutexDisplayTextureUpdate); + const MetalProcessedFrameInfo processedInfo = [self processedFrameInfo]; + const bool needsFetchBuffersLock = !processedInfo.isMainDisplayProcessed || !processedInfo.isTouchDisplayProcessed; + pthread_mutex_lock(&_mutexBufferUpdate); + if (needsFetchBuffersLock) + { + pthread_rwlock_rdlock([sharedData rwlockFramebufferAtIndex:processedInfo.bufferIndex]); + } + // Now that everything is set up, go ahead and draw everything. [colorAttachment0Desc setTexture:texRender]; id cb = [self newCommandBuffer]; - [self renderForCommandBuffer:cb outputPipelineState:[self outputRGBAPipeline] hudPipelineState:[sharedData hudRGBAPipeline]]; + [self renderForCommandBuffer:cb + outputPipelineState:[self outputRGBAPipeline] + hudPipelineState:[sharedData hudRGBAPipeline] + texDisplayMain:(processedInfo.isMainDisplayProcessed) ? processedInfo.tex[NDSDisplayID_Main] : ((cdp->GetSelectedDisplaySourceForDisplay(NDSDisplayID_Main) == NDSDisplayID_Main) ? [sharedData texFetchMain] : [sharedData texFetchTouch] ) + texDisplayTouch:(processedInfo.isTouchDisplayProcessed) ? processedInfo.tex[NDSDisplayID_Touch] : ((cdp->GetSelectedDisplaySourceForDisplay(NDSDisplayID_Touch) == NDSDisplayID_Touch) ? [sharedData texFetchTouch] : [sharedData texFetchMain] )]; + [cb addCompletedHandler:^(id block) { + if (needsFetchBuffersLock) + { + pthread_rwlock_unlock([sharedData rwlockFramebufferAtIndex:processedInfo.bufferIndex]); + } + + pthread_mutex_unlock(&_mutexBufferUpdate); + }]; + + [cb commit]; + + cb = [self newCommandBuffer]; id bce = [cb blitCommandEncoder]; [bce copyFromTexture:texRender @@ -1801,18 +1869,13 @@ [bce synchronizeResource:dstMTLBuffer]; [bce endEncoding]; - [cb addCompletedHandler:^(id block) { - pthread_mutex_unlock(&_mutexBufferUpdate); - pthread_mutex_unlock(&_mutexDisplayTextureUpdate); - - memcpy(dstBuffer, [dstMTLBuffer contents], clientWidth * clientHeight * sizeof(uint32_t)); - - [texRender release]; - [dstMTLBuffer release]; - }]; - [cb commit]; [cb waitUntilCompleted]; + + memcpy(dstBuffer, [dstMTLBuffer contents], clientWidth * clientHeight * sizeof(uint32_t)); + + [texRender release]; + [dstMTLBuffer release]; } } @@ -1858,8 +1921,15 @@ { @autoreleasepool { - pthread_mutex_lock([presenterObject mutexDisplayTextureUpdate]); + const MetalProcessedFrameInfo processedInfo = [presenterObject processedFrameInfo]; + const bool needsFetchBuffersLock = !processedInfo.isMainDisplayProcessed || !processedInfo.isTouchDisplayProcessed; + pthread_mutex_lock([presenterObject mutexBufferUpdate]); + + if (needsFetchBuffersLock) + { + pthread_rwlock_rdlock([[presenterObject sharedData] rwlockFramebufferAtIndex:processedInfo.bufferIndex]); + } // Now that everything is set up, go ahead and draw everything. id layerDrawable = [self nextDrawable]; @@ -1868,12 +1938,18 @@ [presenterObject renderForCommandBuffer:cb outputPipelineState:[presenterObject outputDrawablePipeline] - hudPipelineState:[[presenterObject sharedData] hudPipeline]]; + hudPipelineState:[[presenterObject sharedData] hudPipeline] + texDisplayMain:(processedInfo.isMainDisplayProcessed) ? processedInfo.tex[NDSDisplayID_Main] : (([presenterObject cdp]->GetSelectedDisplaySourceForDisplay(NDSDisplayID_Main) == NDSDisplayID_Main) ? [[presenterObject sharedData] texFetchMain] : [[presenterObject sharedData] texFetchTouch] ) + texDisplayTouch:(processedInfo.isTouchDisplayProcessed) ? processedInfo.tex[NDSDisplayID_Touch] : (([presenterObject cdp]->GetSelectedDisplaySourceForDisplay(NDSDisplayID_Touch) == NDSDisplayID_Touch) ? [[presenterObject sharedData] texFetchTouch] : [[presenterObject sharedData] texFetchMain] )]; [cb presentDrawable:layerDrawable]; [cb addCompletedHandler:^(id block) { + if (needsFetchBuffersLock) + { + pthread_rwlock_unlock([[presenterObject sharedData] rwlockFramebufferAtIndex:processedInfo.bufferIndex]); + } + pthread_mutex_unlock([presenterObject mutexBufferUpdate]); - pthread_mutex_unlock([presenterObject mutexDisplayTextureUpdate]); }]; [cb commit]; @@ -1942,6 +2018,22 @@ void MacMetalFetchObject::CopyFromSrcClone(uint32_t *dstBufferPtr, const NDSDisp void MacMetalFetchObject::SetFetchBuffers(const NDSDisplayInfo ¤tDisplayInfo) { + const size_t nativeSize = GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT * currentDisplayInfo.pixelBytes; + const size_t customSize = currentDisplayInfo.customWidth * currentDisplayInfo.customHeight * currentDisplayInfo.pixelBytes; + + this->_fetchDisplayInfo[0] = currentDisplayInfo; + this->_fetchDisplayInfo[1] = currentDisplayInfo; + + this->_fetchDisplayInfo[0].nativeBuffer[NDSDisplayID_Main] = (u8 *)currentDisplayInfo.masterFramebufferHead; + this->_fetchDisplayInfo[0].nativeBuffer[NDSDisplayID_Touch] = (u8 *)currentDisplayInfo.masterFramebufferHead + (nativeSize * 1); + this->_fetchDisplayInfo[0].customBuffer[NDSDisplayID_Main] = (u8 *)currentDisplayInfo.masterFramebufferHead + (nativeSize * 2); + this->_fetchDisplayInfo[0].customBuffer[NDSDisplayID_Touch] = (u8 *)currentDisplayInfo.masterFramebufferHead + (nativeSize * 2) + customSize; + + this->_fetchDisplayInfo[1].nativeBuffer[NDSDisplayID_Main] = (u8 *)this->_fetchDisplayInfo[0].nativeBuffer[NDSDisplayID_Main] + currentDisplayInfo.framebufferSize; + this->_fetchDisplayInfo[1].nativeBuffer[NDSDisplayID_Touch] = (u8 *)this->_fetchDisplayInfo[0].nativeBuffer[NDSDisplayID_Touch] + currentDisplayInfo.framebufferSize; + this->_fetchDisplayInfo[1].customBuffer[NDSDisplayID_Main] = (u8 *)this->_fetchDisplayInfo[0].customBuffer[NDSDisplayID_Main] + currentDisplayInfo.framebufferSize; + this->_fetchDisplayInfo[1].customBuffer[NDSDisplayID_Touch] = (u8 *)this->_fetchDisplayInfo[0].customBuffer[NDSDisplayID_Touch] + currentDisplayInfo.framebufferSize; + [(MetalDisplayViewSharedData *)this->_clientData setFetchBuffersWithDisplayInfo:currentDisplayInfo]; } @@ -2001,6 +2093,11 @@ MacMetalDisplayPresenter::~MacMetalDisplayPresenter() [this->_presenterObject release]; pthread_mutex_destroy(&this->_mutexProcessPtr); + + pthread_rwlock_destroy(&this->_cpuFilterRWLock[NDSDisplayID_Main][0]); + pthread_rwlock_destroy(&this->_cpuFilterRWLock[NDSDisplayID_Touch][0]); + pthread_rwlock_destroy(&this->_cpuFilterRWLock[NDSDisplayID_Main][1]); + pthread_rwlock_destroy(&this->_cpuFilterRWLock[NDSDisplayID_Touch][1]); } void MacMetalDisplayPresenter::__InstanceInit(MacClientSharedObject *sharedObject) @@ -2017,6 +2114,11 @@ void MacMetalDisplayPresenter::__InstanceInit(MacClientSharedObject *sharedObjec _presenterObject = [[MacMetalDisplayPresenterObject alloc] initWithDisplayPresenter:this]; pthread_mutex_init(&_mutexProcessPtr, NULL); + + pthread_rwlock_init(&_cpuFilterRWLock[NDSDisplayID_Main][0], NULL); + pthread_rwlock_init(&_cpuFilterRWLock[NDSDisplayID_Touch][0], NULL); + pthread_rwlock_init(&_cpuFilterRWLock[NDSDisplayID_Main][1], NULL); + pthread_rwlock_init(&_cpuFilterRWLock[NDSDisplayID_Touch][1], NULL); } void MacMetalDisplayPresenter::_UpdateNormalSize() @@ -2054,7 +2156,11 @@ void MacMetalDisplayPresenter::_LoadNativeDisplayByID(const NDSDisplayID display MacMetalFetchObject &fetchObjMutable = (MacMetalFetchObject &)this->GetFetchObject(); VideoFilter *vf = this->GetPixelScalerObject(displayID); - fetchObjMutable.CopyFromSrcClone(vf->GetSrcBufferPtr(), displayID, this->GetEmuDisplayInfo().bufferIndex); + const uint8_t bufferIndex = fetchObjMutable.GetLastFetchIndex(); + + pthread_rwlock_wrlock(&this->_cpuFilterRWLock[displayID][bufferIndex]); + fetchObjMutable.CopyFromSrcClone(vf->GetSrcBufferPtr(), displayID, bufferIndex); + pthread_rwlock_unlock(&this->_cpuFilterRWLock[displayID][bufferIndex]); } } @@ -2074,6 +2180,11 @@ pthread_mutex_t* MacMetalDisplayPresenter::GetMutexProcessPtr() return &this->_mutexProcessPtr; } +pthread_rwlock_t* MacMetalDisplayPresenter::GetCPUFilterRWLock(const NDSDisplayID displayID, const uint8_t bufferIndex) +{ + return &this->_cpuFilterRWLock[displayID][bufferIndex]; +} + void MacMetalDisplayPresenter::Init() { [this->_presenterObject setup]; @@ -2180,7 +2291,7 @@ bool MacMetalDisplayView::GetViewNeedsFlush() void MacMetalDisplayView::SetViewNeedsFlush() { - if (!this->_allowViewUpdates || (this->_presenter == nil) || (this->GetNSView() == nil)) + if (!this->_allowViewUpdates || (this->_presenter == nil) || (this->_caLayer == nil)) { return; } diff --git a/desmume/src/frontend/cocoa/userinterface/MacOGLDisplayView.h b/desmume/src/frontend/cocoa/userinterface/MacOGLDisplayView.h index 7db875a55..4b06c9f0a 100644 --- a/desmume/src/frontend/cocoa/userinterface/MacOGLDisplayView.h +++ b/desmume/src/frontend/cocoa/userinterface/MacOGLDisplayView.h @@ -50,6 +50,8 @@ protected: NSOpenGLContext *_nsContext; CGLContextObj _context; + OSSpinLock _spinlockTexFetch[2]; + public: void operator delete(void *ptr); MacOGLClientFetchObject(); @@ -60,6 +62,9 @@ public: virtual void Init(); virtual void SetFetchBuffers(const NDSDisplayInfo ¤tDisplayInfo); virtual void FetchFromBufferIndex(const u8 index); + + virtual GLuint GetFetchTexture(const NDSDisplayID displayID); + virtual void SetFetchTexture(const NDSDisplayID displayID, GLuint texID); }; class MacOGLDisplayPresenter : public OGLVideoOutput, public MacDisplayPresenterInterface @@ -72,6 +77,7 @@ protected: NSOpenGLPixelFormat *_nsPixelFormat; CGLContextObj _context; CGLPixelFormatObj _pixelFormat; + OSSpinLock _spinlockProcessedInfo; public: void operator delete(void *ptr); @@ -97,9 +103,13 @@ public: virtual void LoadDisplays(); virtual void ProcessDisplays(); virtual void CopyFrameToBuffer(uint32_t *dstBuffer); - virtual void FinishFrameAtIndex(const uint8_t bufferIndex); - virtual void LockDisplayTextures(); - virtual void UnlockDisplayTextures(); + + virtual const OGLProcessedFrameInfo& GetProcessedFrameInfo(); + virtual void SetProcessedFrameInfo(const OGLProcessedFrameInfo &processedInfo); + + virtual void WriteLockEmuFramebuffer(const uint8_t bufferIndex); + virtual void ReadLockEmuFramebuffer(const uint8_t bufferIndex); + virtual void UnlockEmuFramebuffer(const uint8_t bufferIndex); }; class MacOGLDisplayView : public MacDisplayLayeredView diff --git a/desmume/src/frontend/cocoa/userinterface/MacOGLDisplayView.mm b/desmume/src/frontend/cocoa/userinterface/MacOGLDisplayView.mm index b3ff019a0..f49fa1706 100644 --- a/desmume/src/frontend/cocoa/userinterface/MacOGLDisplayView.mm +++ b/desmume/src/frontend/cocoa/userinterface/MacOGLDisplayView.mm @@ -62,8 +62,8 @@ - (void)drawInCGLContext:(CGLContextObj)glContext pixelFormat:(CGLPixelFormatObj)pixelFormat forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp { - CGLSetCurrentContext(glContext); CGLLockContext(glContext); + CGLSetCurrentContext(glContext); ((MacOGLDisplayPresenter *)(_cdv->Get3DPresenter()))->RenderFrameOGL(false); [super drawInCGLContext:glContext pixelFormat:pixelFormat forLayerTime:timeInterval displayTime:timeStamp]; CGLUnlockContext(glContext); @@ -156,6 +156,9 @@ MacOGLClientFetchObject::MacOGLClientFetchObject() CGLSetCurrentContext(prevContext); _clientData = [[MacClientSharedObject alloc] init]; + + _spinlockTexFetch[NDSDisplayID_Main] = OS_SPINLOCK_INIT; + _spinlockTexFetch[NDSDisplayID_Touch] = OS_SPINLOCK_INIT; } NSOpenGLContext* MacOGLClientFetchObject::GetNSContext() const @@ -195,12 +198,28 @@ void MacOGLClientFetchObject::FetchFromBufferIndex(const u8 index) CGLLockContext(this->_context); CGLSetCurrentContext(this->_context); - this->GPUClientFetchObject::FetchFromBufferIndex(index); + this->OGLClientFetchObject::FetchFromBufferIndex(index); CGLUnlockContext(this->_context); pthread_rwlock_unlock([sharedViewObject rwlockFramebufferAtIndex:index]); } +GLuint MacOGLClientFetchObject::GetFetchTexture(const NDSDisplayID displayID) +{ + OSSpinLockLock(&this->_spinlockTexFetch[displayID]); + const GLuint texFetchID = this->OGLClientFetchObject::GetFetchTexture(displayID); + OSSpinLockUnlock(&this->_spinlockTexFetch[displayID]); + + return texFetchID; +} + +void MacOGLClientFetchObject::SetFetchTexture(const NDSDisplayID displayID, GLuint texID) +{ + OSSpinLockLock(&this->_spinlockTexFetch[displayID]); + this->OGLClientFetchObject::SetFetchTexture(displayID, texID); + OSSpinLockUnlock(&this->_spinlockTexFetch[displayID]); +} + #pragma mark - void MacOGLDisplayPresenter::operator delete(void *ptr) @@ -275,6 +294,7 @@ void MacOGLDisplayPresenter::__InstanceInit(MacClientSharedObject *sharedObject) _nsContext = nil; _context = nil; + _spinlockProcessedInfo = OS_SPINLOCK_INIT; if (sharedObject != nil) { @@ -394,27 +414,41 @@ void MacOGLDisplayPresenter::CopyFrameToBuffer(uint32_t *dstBuffer) CGLUnlockContext(this->_context); } -void MacOGLDisplayPresenter::FinishFrameAtIndex(const uint8_t bufferIndex) +const OGLProcessedFrameInfo& MacOGLDisplayPresenter::GetProcessedFrameInfo() { - CGLLockContext(this->_context); - CGLSetCurrentContext(this->_context); - this->OGLVideoOutput::FinishFrameAtIndex(bufferIndex); - CGLUnlockContext(this->_context); + OSSpinLockLock(&this->_spinlockProcessedInfo); + const OGLProcessedFrameInfo &processedInfo = this->OGLVideoOutput::GetProcessedFrameInfo(); + OSSpinLockUnlock(&this->_spinlockProcessedInfo); + + return processedInfo; } -void MacOGLDisplayPresenter::LockDisplayTextures() +void MacOGLDisplayPresenter::SetProcessedFrameInfo(const OGLProcessedFrameInfo &processedInfo) +{ + OSSpinLockLock(&this->_spinlockProcessedInfo); + this->OGLVideoOutput::SetProcessedFrameInfo(processedInfo); + OSSpinLockUnlock(&this->_spinlockProcessedInfo); +} + +void MacOGLDisplayPresenter::WriteLockEmuFramebuffer(const uint8_t bufferIndex) +{ + const GPUClientFetchObject &fetchObj = this->GetFetchObject(); + MacClientSharedObject *sharedViewObject = (MacClientSharedObject *)fetchObj.GetClientData(); + + pthread_rwlock_wrlock([sharedViewObject rwlockFramebufferAtIndex:bufferIndex]); +} + +void MacOGLDisplayPresenter::ReadLockEmuFramebuffer(const uint8_t bufferIndex) { const GPUClientFetchObject &fetchObj = this->GetFetchObject(); - const u8 bufferIndex = this->_emuDisplayInfo.bufferIndex; MacClientSharedObject *sharedViewObject = (MacClientSharedObject *)fetchObj.GetClientData(); pthread_rwlock_rdlock([sharedViewObject rwlockFramebufferAtIndex:bufferIndex]); } -void MacOGLDisplayPresenter::UnlockDisplayTextures() +void MacOGLDisplayPresenter::UnlockEmuFramebuffer(const uint8_t bufferIndex) { const GPUClientFetchObject &fetchObj = this->GetFetchObject(); - const u8 bufferIndex = this->_emuDisplayInfo.bufferIndex; MacClientSharedObject *sharedViewObject = (MacClientSharedObject *)fetchObj.GetClientData(); pthread_rwlock_unlock([sharedViewObject rwlockFramebufferAtIndex:bufferIndex]); @@ -460,14 +494,14 @@ bool MacOGLDisplayView::GetViewNeedsFlush() void MacOGLDisplayView::SetViewNeedsFlush() { - if (!this->_allowViewUpdates || (this->_presenter == nil) || (this->GetNSView() == nil)) + if (!this->_allowViewUpdates || (this->_presenter == nil) || (this->_caLayer == nil)) { return; } if (this->GetRenderToCALayer()) { - [[this->GetNSView() layer] setNeedsDisplay]; + [this->_caLayer setNeedsDisplay]; } else { diff --git a/desmume/src/frontend/cocoa/utilities.c b/desmume/src/frontend/cocoa/utilities.c index 7edaec658..9e63aa416 100644 --- a/desmume/src/frontend/cocoa/utilities.c +++ b/desmume/src/frontend/cocoa/utilities.c @@ -119,6 +119,19 @@ bool IsOSXVersionSupported(const unsigned int major, const unsigned int minor, c return result; } +bool IsOSXVersion(const unsigned int major, const unsigned int minor, const unsigned int revision) +{ + bool result = false; + + if (!isSystemVersionAlreadyRead) + { + ReadSystemVersionPListFile(); + } + + result = (isSystemVersionAlreadyRead && (OSXVersionMajor == major) && (OSXVersionMinor == minor) && (OSXVersionRevision == revision)); + return result; +} + /******************************************************************************************** GetNearestPositivePOT() diff --git a/desmume/src/frontend/cocoa/utilities.h b/desmume/src/frontend/cocoa/utilities.h index 6025205b6..6d2044576 100644 --- a/desmume/src/frontend/cocoa/utilities.h +++ b/desmume/src/frontend/cocoa/utilities.h @@ -26,7 +26,8 @@ extern "C" { #endif -bool IsOSXVersionSupported(const unsigned int major, const unsigned int minor, const unsigned int revision); +bool IsOSXVersionSupported(const unsigned int major, const unsigned int minor, const unsigned int revision); +bool IsOSXVersion(const unsigned int major, const unsigned int minor, const unsigned int revision); uint32_t GetNearestPositivePOT(uint32_t value); #ifdef __cplusplus