From 093ce4b05d073d329c41fd62e7e41a9039242bbd Mon Sep 17 00:00:00 2001 From: rogerman Date: Wed, 22 Feb 2017 14:14:22 -0800 Subject: [PATCH] Cocoa Port: The Metal blitter now performs its own display postprocessing instead of letting the GPUSubsystem do it. - Display views now take the Deposterize filter into account when determining the direct-to-CPU-filtering state. - GPUSubsystem now combines the RGB666-to-RGB888 conversions and master brightness steps into a single postprocessing step. - Do some minor code cleanup. --- desmume/src/GPU.cpp | 271 ++++++----- desmume/src/GPU.h | 86 ++-- .../src/frontend/cocoa/OGLDisplayOutput.cpp | 4 +- desmume/src/frontend/cocoa/OGLDisplayOutput.h | 2 +- desmume/src/frontend/cocoa/cocoa_GPU.h | 8 +- desmume/src/frontend/cocoa/cocoa_GPU.mm | 17 +- desmume/src/frontend/cocoa/cocoa_output.mm | 22 +- .../userinterface/DisplayWindowController.mm | 35 +- .../cocoa/userinterface/MacMetalDisplayView.h | 40 +- .../userinterface/MacMetalDisplayView.mm | 440 ++++++++++++++---- .../MacMetalDisplayViewShaders.metal | 102 +++- .../cocoa/userinterface/MacOGLDisplayView.mm | 2 +- .../cocoa/userinterface/appDelegate.mm | 5 +- 13 files changed, 703 insertions(+), 331 deletions(-) diff --git a/desmume/src/GPU.cpp b/desmume/src/GPU.cpp index 33589003c..a51e3bcb8 100644 --- a/desmume/src/GPU.cpp +++ b/desmume/src/GPU.cpp @@ -1382,7 +1382,7 @@ void GPUEngineBase::UpdatePropertiesWithoutRender(const u16 l) } } -void GPUEngineBase::FramebufferPostprocess() +void GPUEngineBase::LastLineProcess() { this->RefreshAffineStartRegs(); } @@ -4024,69 +4024,66 @@ void GPUEngineBase::SetWillApplyMasterBrightnessPerScanline(bool willApply) this->_willApplyMasterBrightnessPerScanline = willApply; } -template -void GPUEngineBase::ApplyMasterBrightness() +void GPUEngineBase::UpdateMasterBrightnessDisplayInfo(NDSDisplayInfo &mutableInfo) { - NDSDisplayInfo &dispInfoMutable = (NDSDisplayInfo &)GPU->GetDisplayInfo(); - const bool isMasterBrightnessAutoApplied = GPU->GetWillAutoApplyMasterBrightness(); - if (this->_willApplyMasterBrightnessPerScanline) { - const bool isNativeSize = (this->nativeLineOutputCount == GPU_FRAMEBUFFER_NATIVE_HEIGHT); bool needsApply = false; for (size_t line = 0; line < GPU_FRAMEBUFFER_NATIVE_HEIGHT; line++) { const GPUEngineCompositorInfo &compInfo = this->_currentCompositorInfo[line]; - if (isMasterBrightnessAutoApplied) + if ( (compInfo.renderState.masterBrightnessIntensity != 0) && ((compInfo.renderState.masterBrightnessMode == GPUMasterBrightMode_Up) || (compInfo.renderState.masterBrightnessMode == GPUMasterBrightMode_Down)) ) { - void *dstColorLine = (isNativeSize) ? ((u8 *)this->nativeBuffer + (compInfo.line.blockOffsetNative * dispInfoMutable.pixelBytes)) : ((u8 *)this->customBuffer + (compInfo.line.blockOffsetCustom * dispInfoMutable.pixelBytes)); - const size_t pixCount = (isNativeSize) ? GPU_FRAMEBUFFER_NATIVE_WIDTH : compInfo.line.pixelCount; - - this->ApplyMasterBrightness(dstColorLine, - pixCount, - compInfo.renderState.masterBrightnessMode, - compInfo.renderState.masterBrightnessIntensity); - } - else - { - if ( (compInfo.renderState.masterBrightnessIntensity != 0) && ((compInfo.renderState.masterBrightnessMode == GPUMasterBrightMode_Up) || (compInfo.renderState.masterBrightnessMode == GPUMasterBrightMode_Down)) ) - { - needsApply = true; - } + needsApply = true; } - dispInfoMutable.masterBrightnessMode[this->_targetDisplayID][line] = compInfo.renderState.masterBrightnessMode; - dispInfoMutable.masterBrightnessIntensity[this->_targetDisplayID][line] = compInfo.renderState.masterBrightnessIntensity; + mutableInfo.masterBrightnessMode[this->_targetDisplayID][line] = compInfo.renderState.masterBrightnessMode; + mutableInfo.masterBrightnessIntensity[this->_targetDisplayID][line] = compInfo.renderState.masterBrightnessIntensity; } - dispInfoMutable.needApplyMasterBrightness[this->_targetDisplayID] = dispInfoMutable.needApplyMasterBrightness[this->_targetDisplayID] && needsApply; + mutableInfo.needApplyMasterBrightness[this->_targetDisplayID] = needsApply; } else { const GPUEngineCompositorInfo &compInfo = this->_currentCompositorInfo[0]; - - if (isMasterBrightnessAutoApplied) - { - this->ApplyMasterBrightness(this->renderedBuffer, - this->renderedWidth * this->renderedHeight, - compInfo.renderState.masterBrightnessMode, - compInfo.renderState.masterBrightnessIntensity); - } - else - { - dispInfoMutable.needApplyMasterBrightness[this->_targetDisplayID] = (compInfo.renderState.masterBrightnessIntensity != 0) && ((compInfo.renderState.masterBrightnessMode == GPUMasterBrightMode_Up) || (compInfo.renderState.masterBrightnessMode == GPUMasterBrightMode_Down)); - } + mutableInfo.needApplyMasterBrightness[this->_targetDisplayID] = (compInfo.renderState.masterBrightnessIntensity != 0) && ((compInfo.renderState.masterBrightnessMode == GPUMasterBrightMode_Up) || (compInfo.renderState.masterBrightnessMode == GPUMasterBrightMode_Down)); for (size_t line = 0; line < GPU_FRAMEBUFFER_NATIVE_HEIGHT; line++) { - dispInfoMutable.masterBrightnessMode[this->_targetDisplayID][line] = compInfo.renderState.masterBrightnessMode; - dispInfoMutable.masterBrightnessIntensity[this->_targetDisplayID][line] = compInfo.renderState.masterBrightnessIntensity; + mutableInfo.masterBrightnessMode[this->_targetDisplayID][line] = compInfo.renderState.masterBrightnessMode; + mutableInfo.masterBrightnessIntensity[this->_targetDisplayID][line] = compInfo.renderState.masterBrightnessIntensity; } } } +template +void GPUEngineBase::ApplyMasterBrightness(const NDSDisplayInfo &displayInfo) +{ + if (this->_willApplyMasterBrightnessPerScanline) + { + for (size_t line = 0; line < GPU_FRAMEBUFFER_NATIVE_HEIGHT; line++) + { + const GPUEngineCompositorInfo &compInfo = this->_currentCompositorInfo[line]; + void *dstColorLine = (!displayInfo.didPerformCustomRender[this->_targetDisplayID]) ? ((u8 *)displayInfo.nativeBuffer[this->_targetDisplayID] + (compInfo.line.blockOffsetNative * displayInfo.pixelBytes)) : ((u8 *)displayInfo.customBuffer[this->_targetDisplayID] + (compInfo.line.blockOffsetCustom * displayInfo.pixelBytes)); + const size_t pixCount = (!displayInfo.didPerformCustomRender[this->_targetDisplayID]) ? GPU_FRAMEBUFFER_NATIVE_WIDTH : compInfo.line.pixelCount; + + this->ApplyMasterBrightness(dstColorLine, + pixCount, + (GPUMasterBrightMode)displayInfo.masterBrightnessMode[this->_targetDisplayID][line], + displayInfo.masterBrightnessIntensity[this->_targetDisplayID][line]); + } + } + else + { + this->ApplyMasterBrightness(displayInfo.renderedBuffer[this->_targetDisplayID], + displayInfo.renderedWidth[this->_targetDisplayID] * displayInfo.renderedHeight[this->_targetDisplayID], + (GPUMasterBrightMode)displayInfo.masterBrightnessMode[this->_targetDisplayID][0], + displayInfo.masterBrightnessIntensity[this->_targetDisplayID][0]); + } +} + template void GPUEngineBase::ApplyMasterBrightness(void *dst, const size_t pixCount, const GPUMasterBrightMode mode, const u8 intensity) { @@ -4951,43 +4948,36 @@ void GPUEngineBase::ResolveCustomRendering() this->renderedBuffer = this->customBuffer; } -void GPUEngineBase::ResolveRGB666ToRGB888() +void GPUEngineBase::ResolveToCustomFramebuffer(NDSDisplayInfo &mutableInfo) { - ColorspaceConvertBuffer6665To8888((u32 *)this->renderedBuffer, (u32 *)this->renderedBuffer, this->renderedWidth * this->renderedHeight); -} - -void GPUEngineBase::ResolveToCustomFramebuffer() -{ - const NDSDisplayInfo &dispInfo = GPU->GetDisplayInfo(); - - if (this->nativeLineOutputCount == 0) + if (mutableInfo.didPerformCustomRender[this->_targetDisplayID]) { return; } - if (dispInfo.isCustomSizeRequested) + if (mutableInfo.isCustomSizeRequested) { - if (dispInfo.pixelBytes == 2) + if (mutableInfo.pixelBytes == 2) { for (size_t y = 0; y < GPU_FRAMEBUFFER_NATIVE_HEIGHT; y++) { - this->_LineColorCopy(this->customBuffer, this->nativeBuffer, y); + this->_LineColorCopy(mutableInfo.customBuffer[this->_targetDisplayID], mutableInfo.nativeBuffer[this->_targetDisplayID], y); } } - else if (dispInfo.pixelBytes == 4) + else if (mutableInfo.pixelBytes == 4) { for (size_t y = 0; y < GPU_FRAMEBUFFER_NATIVE_HEIGHT; y++) { - this->_LineColorCopy(this->customBuffer, this->nativeBuffer, y); + this->_LineColorCopy(mutableInfo.customBuffer[this->_targetDisplayID], mutableInfo.nativeBuffer[this->_targetDisplayID], y); } } } else { - memcpy(this->customBuffer, this->nativeBuffer, GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT * dispInfo.pixelBytes); + memcpy(mutableInfo.customBuffer[this->_targetDisplayID], mutableInfo.nativeBuffer[this->_targetDisplayID], GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT * mutableInfo.pixelBytes); } - GPU->SetDisplayDidCustomRender(this->_targetDisplayID, true); + mutableInfo.didPerformCustomRender[this->_targetDisplayID] = true; } void GPUEngineBase::RefreshAffineStartRegs() @@ -6679,9 +6669,9 @@ void GPUEngineA::_LineLarge8bpp(GPUEngineCompositorInfo &compInfo) } } -void GPUEngineA::FramebufferPostprocess() +void GPUEngineA::LastLineProcess() { - this->GPUEngineBase::FramebufferPostprocess(); + this->GPUEngineBase::LastLineProcess(); this->_IORegisterMap->DISPCAPCNT.CaptureEnable = 0; DISP_FIFOreset(); @@ -6783,17 +6773,16 @@ GPUSubsystem::GPUSubsystem() _engineMain = GPUEngineA::Allocate(); _engineSub = GPUEngineB::Allocate(); - _displayMain = new NDSDisplay(NDSDisplayID_Main); - _displayMain->SetEngine(_engineMain); - _displayTouch = new NDSDisplay(NDSDisplayID_Touch); - _displayTouch->SetEngine(_engineSub); + _display[NDSDisplayID_Main] = new NDSDisplay(NDSDisplayID_Main); + _display[NDSDisplayID_Main]->SetEngine(_engineMain); + _display[NDSDisplayID_Touch] = new NDSDisplay(NDSDisplayID_Touch); + _display[NDSDisplayID_Touch]->SetEngine(_engineSub); _videoFrameCount = 0; _render3DFrameCount = 0; _frameNeedsFinish = false; _willFrameSkip = false; - _willAutoApplyMasterBrightness = true; - _willAutoConvertRGB666ToRGB888 = true; + _willPostprocessDisplays = true; _willAutoResolveToCustomBuffer = true; //TODO OSD @@ -6806,7 +6795,6 @@ GPUSubsystem::GPUSubsystem() _displayInfo.isCustomSizeRequested = false; _displayInfo.customWidth = GPU_FRAMEBUFFER_NATIVE_WIDTH; _displayInfo.customHeight = GPU_FRAMEBUFFER_NATIVE_HEIGHT; - _displayInfo.isMasterBrightnessAutoApplyRequested = true; _customVRAM = NULL; _customVRAMBlank = NULL; @@ -6854,8 +6842,8 @@ GPUSubsystem::~GPUSubsystem() free_aligned(_gpuDstToSrcSSSE3_u16_8e); _gpuDstToSrcSSSE3_u16_8e = NULL; - delete _displayMain; - delete _displayTouch; + delete _display[NDSDisplayID_Main]; + delete _display[NDSDisplayID_Touch]; _engineMain->FinalizeAndDeallocate(); _engineSub->FinalizeAndDeallocate(); @@ -6912,8 +6900,8 @@ void GPUSubsystem::Reset() this->_displayInfo.renderedHeight[NDSDisplayID_Touch] = GPU_FRAMEBUFFER_NATIVE_HEIGHT; this->_displayInfo.renderedBuffer[NDSDisplayID_Touch] = this->_displayInfo.nativeBuffer[NDSDisplayID_Touch]; - this->_displayMain->SetEngineByID(GPUEngineID_Main); - this->_displayTouch->SetEngineByID(GPUEngineID_Sub); + this->_display[NDSDisplayID_Main]->SetEngineByID(GPUEngineID_Main); + this->_display[NDSDisplayID_Touch]->SetEngineByID(GPUEngineID_Sub); gfx3d_reset(); this->_engineMain->Reset(); @@ -6999,14 +6987,14 @@ void GPUSubsystem::UpdateRenderProperties() this->_engineSub->renderedWidth = GPU_FRAMEBUFFER_NATIVE_WIDTH; this->_engineSub->renderedHeight = GPU_FRAMEBUFFER_NATIVE_HEIGHT; - GPUEngineBase *mainEngine = this->_displayMain->GetEngine(); + GPUEngineBase *mainEngine = this->_display[NDSDisplayID_Main]->GetEngine(); this->_displayInfo.nativeBuffer[NDSDisplayID_Main] = mainEngine->nativeBuffer; this->_displayInfo.customBuffer[NDSDisplayID_Main] = mainEngine->customBuffer; this->_displayInfo.renderedBuffer[NDSDisplayID_Main] = mainEngine->renderedBuffer; this->_displayInfo.renderedWidth[NDSDisplayID_Main] = mainEngine->renderedWidth; this->_displayInfo.renderedHeight[NDSDisplayID_Main] = mainEngine->renderedHeight; - GPUEngineBase *touchEngine = this->_displayTouch->GetEngine(); + GPUEngineBase *touchEngine = this->_display[NDSDisplayID_Touch]->GetEngine(); this->_displayInfo.nativeBuffer[NDSDisplayID_Touch] = touchEngine->nativeBuffer; this->_displayInfo.customBuffer[NDSDisplayID_Touch] = touchEngine->customBuffer; this->_displayInfo.renderedBuffer[NDSDisplayID_Touch] = touchEngine->renderedBuffer; @@ -7067,11 +7055,6 @@ u32 GPUSubsystem::GetFPSRender3D() const return this->_render3DFrameCount; } -void GPUSubsystem::SetDisplayDidCustomRender(NDSDisplayID displayID, bool theState) -{ - this->_displayInfo.didPerformCustomRender[displayID] = theState; -} - GPUEngineA* GPUSubsystem::GetEngineMain() { return this->_engineMain; @@ -7084,12 +7067,12 @@ GPUEngineB* GPUSubsystem::GetEngineSub() NDSDisplay* GPUSubsystem::GetDisplayMain() { - return this->_displayMain; + return this->_display[NDSDisplayID_Main]; } NDSDisplay* GPUSubsystem::GetDisplayTouch() { - return this->_displayTouch; + return this->_display[NDSDisplayID_Touch]; } size_t GPUSubsystem::GetCustomFramebufferWidth() const @@ -7275,14 +7258,14 @@ void GPUSubsystem::_AllocateFramebuffers(NDSColorFormat outputFormat, size_t w, this->_engineMain->SetCustomFramebufferSize(w, h); this->_engineSub->SetCustomFramebufferSize(w, h); - GPUEngineBase *mainEngine = this->_displayMain->GetEngine(); + GPUEngineBase *mainEngine = this->_display[NDSDisplayID_Main]->GetEngine(); this->_displayInfo.nativeBuffer[NDSDisplayID_Main] = mainEngine->nativeBuffer; this->_displayInfo.customBuffer[NDSDisplayID_Main] = mainEngine->customBuffer; this->_displayInfo.renderedBuffer[NDSDisplayID_Main] = mainEngine->renderedBuffer; this->_displayInfo.renderedWidth[NDSDisplayID_Main] = mainEngine->renderedWidth; this->_displayInfo.renderedHeight[NDSDisplayID_Main] = mainEngine->renderedHeight; - GPUEngineBase *touchEngine = this->_displayTouch->GetEngine(); + GPUEngineBase *touchEngine = this->_display[NDSDisplayID_Touch]->GetEngine(); this->_displayInfo.nativeBuffer[NDSDisplayID_Touch] = touchEngine->nativeBuffer; this->_displayInfo.customBuffer[NDSDisplayID_Touch] = touchEngine->customBuffer; this->_displayInfo.renderedBuffer[NDSDisplayID_Touch] = touchEngine->renderedBuffer; @@ -7344,25 +7327,75 @@ u16* GPUSubsystem::GetCustomVRAMAddressUsingMappedAddress(const u32 mappedAddr) return (this->GetEngineMain()->GetCustomVRAMBlockPtr(blockID) + (_gpuCaptureLineIndex[blockLine] * this->_displayInfo.customWidth) + _gpuDstPitchIndex[linePixel]); } -bool GPUSubsystem::GetWillAutoApplyMasterBrightness() const +bool GPUSubsystem::GetWillPostprocessDisplays() const { - return this->_willAutoApplyMasterBrightness; + return this->_willPostprocessDisplays; } -void GPUSubsystem::SetWillAutoApplyMasterBrightness(const bool willAutoApply) +void GPUSubsystem::SetWillPostprocessDisplays(const bool willPostprocess) { - this->_willAutoApplyMasterBrightness = willAutoApply; - this->_displayInfo.isMasterBrightnessAutoApplyRequested = willAutoApply; + this->_willPostprocessDisplays = willPostprocess; } -bool GPUSubsystem::GetWillAutoConvertRGB666ToRGB888() const +void GPUSubsystem::PostprocessDisplay(const NDSDisplayID displayID, NDSDisplayInfo &mutableInfo) { - return this->_willAutoConvertRGB666ToRGB888; + if (mutableInfo.isDisplayEnabled[displayID]) + { + if (mutableInfo.colorFormat == NDSColorFormat_BGR666_Rev) + { + if (mutableInfo.needConvertColorFormat[displayID]) + { + ColorspaceConvertBuffer6665To8888((u32 *)mutableInfo.renderedBuffer[displayID], (u32 *)mutableInfo.renderedBuffer[displayID], mutableInfo.renderedWidth[displayID] * mutableInfo.renderedHeight[displayID]); + } + + if (mutableInfo.needApplyMasterBrightness[displayID]) + { + this->_display[displayID]->GetEngine()->ApplyMasterBrightness(mutableInfo); + } + } + else + { + if (mutableInfo.needApplyMasterBrightness[displayID]) + { + switch (mutableInfo.colorFormat) + { + case NDSColorFormat_BGR555_Rev: + this->_display[displayID]->GetEngine()->ApplyMasterBrightness(mutableInfo); + break; + + case NDSColorFormat_BGR666_Rev: + this->_display[displayID]->GetEngine()->ApplyMasterBrightness(mutableInfo); + break; + + case NDSColorFormat_BGR888_Rev: + this->_display[displayID]->GetEngine()->ApplyMasterBrightness(mutableInfo); + break; + + default: + break; + } + } + } + } + else + { + if (mutableInfo.colorFormat == NDSColorFormat_BGR555_Rev) + { + memset(mutableInfo.renderedBuffer[displayID], 0, mutableInfo.renderedWidth[displayID] * mutableInfo.renderedHeight[displayID] * sizeof(u16)); + } + else + { + memset(mutableInfo.renderedBuffer[displayID], 0, mutableInfo.renderedWidth[displayID] * mutableInfo.renderedHeight[displayID] * sizeof(u32)); + } + } + + mutableInfo.needConvertColorFormat[displayID] = false; + mutableInfo.needApplyMasterBrightness[displayID] = false; } -void GPUSubsystem::SetWillAutoConvertRGB666ToRGB888(const bool willAutoConvert) +void GPUSubsystem::ResolveDisplayToCustomFramebuffer(const NDSDisplayID displayID, NDSDisplayInfo &mutableInfo) { - this->_willAutoConvertRGB666ToRGB888 = willAutoConvert; + this->_display[displayID]->GetEngine()->ResolveToCustomFramebuffer(mutableInfo); } bool GPUSubsystem::GetWillAutoResolveToCustomBuffer() const @@ -7450,8 +7483,8 @@ void GPUSubsystem::RenderLine(const size_t l) if (l == 191) { - this->_engineMain->FramebufferPostprocess(); - this->_engineSub->FramebufferPostprocess(); + this->_engineMain->LastLineProcess(); + this->_engineSub->LastLineProcess(); this->_UpdateFPSRender3D(); @@ -7463,55 +7496,35 @@ void GPUSubsystem::RenderLine(const size_t l) this->_engineSub->ResolveCustomRendering(); } - this->_displayInfo.didPerformCustomRender[NDSDisplayID_Main] = (this->_displayMain->GetEngine()->nativeLineOutputCount < GPU_FRAMEBUFFER_NATIVE_HEIGHT); - this->_displayInfo.renderedBuffer[NDSDisplayID_Main] = this->_displayMain->GetEngine()->renderedBuffer; - this->_displayInfo.renderedWidth[NDSDisplayID_Main] = this->_displayMain->GetEngine()->renderedWidth; - this->_displayInfo.renderedHeight[NDSDisplayID_Main] = this->_displayMain->GetEngine()->renderedHeight; + this->_displayInfo.didPerformCustomRender[NDSDisplayID_Main] = (this->_display[NDSDisplayID_Main]->GetEngine()->nativeLineOutputCount < GPU_FRAMEBUFFER_NATIVE_HEIGHT); + this->_displayInfo.renderedBuffer[NDSDisplayID_Main] = this->_display[NDSDisplayID_Main]->GetEngine()->renderedBuffer; + this->_displayInfo.renderedWidth[NDSDisplayID_Main] = this->_display[NDSDisplayID_Main]->GetEngine()->renderedWidth; + this->_displayInfo.renderedHeight[NDSDisplayID_Main] = this->_display[NDSDisplayID_Main]->GetEngine()->renderedHeight; - this->_displayInfo.didPerformCustomRender[NDSDisplayID_Touch] = (this->_displayTouch->GetEngine()->nativeLineOutputCount < GPU_FRAMEBUFFER_NATIVE_HEIGHT); - this->_displayInfo.renderedBuffer[NDSDisplayID_Touch] = this->_displayTouch->GetEngine()->renderedBuffer; - this->_displayInfo.renderedWidth[NDSDisplayID_Touch] = this->_displayTouch->GetEngine()->renderedWidth; - this->_displayInfo.renderedHeight[NDSDisplayID_Touch] = this->_displayTouch->GetEngine()->renderedHeight; + this->_displayInfo.didPerformCustomRender[NDSDisplayID_Touch] = (this->_display[NDSDisplayID_Touch]->GetEngine()->nativeLineOutputCount < GPU_FRAMEBUFFER_NATIVE_HEIGHT); + this->_displayInfo.renderedBuffer[NDSDisplayID_Touch] = this->_display[NDSDisplayID_Touch]->GetEngine()->renderedBuffer; + this->_displayInfo.renderedWidth[NDSDisplayID_Touch] = this->_display[NDSDisplayID_Touch]->GetEngine()->renderedWidth; + this->_displayInfo.renderedHeight[NDSDisplayID_Touch] = this->_display[NDSDisplayID_Touch]->GetEngine()->renderedHeight; - this->_displayInfo.isDisplayEnabled[NDSDisplayID_Main] = CommonSettings.showGpu.main; - this->_displayInfo.isDisplayEnabled[NDSDisplayID_Touch] = CommonSettings.showGpu.sub; - this->_displayInfo.needApplyMasterBrightness[NDSDisplayID_Main] = !this->_displayInfo.isMasterBrightnessAutoApplyRequested; - this->_displayInfo.needApplyMasterBrightness[NDSDisplayID_Touch] = !this->_displayInfo.isMasterBrightnessAutoApplyRequested; + this->_displayInfo.isDisplayEnabled[NDSDisplayID_Main] = CommonSettings.showGpu.screens[this->_display[NDSDisplayID_Main]->GetEngineID()]; + this->_displayInfo.isDisplayEnabled[NDSDisplayID_Touch] = CommonSettings.showGpu.screens[this->_display[NDSDisplayID_Touch]->GetEngineID()]; - if (CommonSettings.showGpu.main) - { - this->_engineMain->ApplyMasterBrightness(); - } - else - { - if (this->_willAutoApplyMasterBrightness) - { - memset(this->_engineMain->renderedBuffer, 0, this->_engineMain->renderedWidth * this->_engineMain->renderedHeight * this->_displayInfo.pixelBytes); - } - } + this->_displayInfo.needConvertColorFormat[NDSDisplayID_Main] = (OUTPUTFORMAT == NDSColorFormat_BGR666_Rev); + this->_displayInfo.needConvertColorFormat[NDSDisplayID_Touch] = (OUTPUTFORMAT == NDSColorFormat_BGR666_Rev); - if (CommonSettings.showGpu.sub) - { - this->_engineSub->ApplyMasterBrightness(); - } - else - { - if (this->_willAutoApplyMasterBrightness) - { - memset(this->_engineSub->renderedBuffer, 0, this->_engineSub->renderedWidth * this->_engineSub->renderedHeight * this->_displayInfo.pixelBytes); - } - } + this->_engineMain->UpdateMasterBrightnessDisplayInfo(this->_displayInfo); + this->_engineSub->UpdateMasterBrightnessDisplayInfo(this->_displayInfo); - if ( (OUTPUTFORMAT == NDSColorFormat_BGR666_Rev) && this->_willAutoConvertRGB666ToRGB888 ) + if (this->_willPostprocessDisplays) { - this->_engineMain->ResolveRGB666ToRGB888(); - this->_engineSub->ResolveRGB666ToRGB888(); + this->PostprocessDisplay(NDSDisplayID_Main, this->_displayInfo); + this->PostprocessDisplay(NDSDisplayID_Touch, this->_displayInfo); } if (this->_willAutoResolveToCustomBuffer) { - this->_engineMain->ResolveToCustomFramebuffer(); - this->_engineSub->ResolveToCustomFramebuffer(); + this->ResolveDisplayToCustomFramebuffer(NDSDisplayID_Main, this->_displayInfo); + this->ResolveDisplayToCustomFramebuffer(NDSDisplayID_Touch, this->_displayInfo); } } diff --git a/desmume/src/GPU.h b/desmume/src/GPU.h index a7b75922a..573822a4c 100644 --- a/desmume/src/GPU.h +++ b/desmume/src/GPU.h @@ -1073,28 +1073,19 @@ typedef struct // Changed by calling GPUSubsystem::SetColorFormat() or GPUSubsystem::SetFramebufferSize(). void *masterFramebufferHead; // Pointer to the head of the master framebuffer memory block that encompasses all buffers. - // Changed by calling GPUSubsystem::SetWillAutoApplyMasterBrightness(). - bool isMasterBrightnessAutoApplyRequested; // Reports the result of GPUSubsystem::GetWillAutoApplyMasterBrightness(). - // true - The emulator itself will apply the master brightness. This is the default option. - // false - The output framebuffer will not have master brightness applied. Clients will need to - // apply the master brightness themselves in a post-processing pass. Clients should use - // the needApplyMasterBrightness, masterBrightnessMode, masterBrightnessIntensity and - // isDisplayEnabled properties to determine how to apply the master brightness on their - // end. - // Changed by calling GPUEngineBase::SetEnableState(). bool isDisplayEnabled[2]; // Reports that a particular display has been enabled or disabled by the user. - // Frame information. These fields will change per frame, depending on how each display was rendered. + // Frame render state information. These fields will change per frame, depending on how each display was rendered. u8 bufferIndex; // Index of this frame's buffer set. void *masterNativeBuffer; // Pointer to the head of the master native buffer. void *masterCustomBuffer; // Pointer to the head of the master custom buffer. // If GPUSubsystem::GetWillAutoResolveToCustomBuffer() would return true, or if - // GPUEngineBase::ResolveToCustomFramebuffer() is called, then this buffer is used as the target - // buffer for resolving any native-sized renders. + // GPUSubsystem::ResolveDisplayToCustomFramebuffer() is called, then this buffer is used as the + // target buffer for resolving any native-sized renders. void *nativeBuffer[2]; // Pointer to the display's native size framebuffer. void *customBuffer[2]; // Pointer to the display's custom size framebuffer. @@ -1107,11 +1098,15 @@ typedef struct // true - The display performed a custom-sized render. // false - The display performed a native-sized render. - bool needApplyMasterBrightness[2]; // Reports if a display still needs to apply the master brightness. This will be true if the - // isMasterBrightnessAutoApplyRequested flag is false and if the NDS has a master brightness - // intensity of non-zero for at least one line. u8 masterBrightnessMode[2][GPU_FRAMEBUFFER_NATIVE_HEIGHT]; // The master brightness mode of each display line. u8 masterBrightnessIntensity[2][GPU_FRAMEBUFFER_NATIVE_HEIGHT]; // The master brightness intensity of each display line. + + + + // Postprocessing information. These fields report the status of each postprocessing step. + // Typically, these fields should be modified whenever GPUSubsystem::PostprocessDisplay() is called. + bool needConvertColorFormat[2]; // Reports if the display still needs to convert its color format from RGB666 to RGB888. + bool needApplyMasterBrightness[2]; // Reports if the display still needs to apply the master brightness. } NDSDisplayInfo; #define VRAM_NO_3D_USAGE 0xFF @@ -1453,7 +1448,7 @@ public: void ParseAllRegisters(); void UpdatePropertiesWithoutRender(const u16 l); - void FramebufferPostprocess(); + void LastLineProcess(); u8 vramBlockOBJIndex; @@ -1502,7 +1497,8 @@ public: bool WillApplyMasterBrightnessPerScanline() const; void SetWillApplyMasterBrightnessPerScanline(bool willApply); - template void ApplyMasterBrightness(); + void UpdateMasterBrightnessDisplayInfo(NDSDisplayInfo &mutableInfo); + template void ApplyMasterBrightness(const NDSDisplayInfo &displayInfo); template void ApplyMasterBrightness(void *dst, const size_t pixCount, const GPUMasterBrightMode mode, const u8 intensity); const BGLayerInfo& GetBGLayerInfoByID(const GPULayerID layerID); @@ -1519,8 +1515,7 @@ public: virtual void SetCustomFramebufferSize(size_t w, size_t h); template void ResolveCustomRendering(); - void ResolveRGB666ToRGB888(); - void ResolveToCustomFramebuffer(); + void ResolveToCustomFramebuffer(NDSDisplayInfo &mutableInfo); void REG_DISPx_pack_test(); }; @@ -1585,7 +1580,7 @@ public: bool WillDisplayCapture(const size_t l); bool VerifyVRAMLineDidChange(const size_t blockID, const size_t l); - void FramebufferPostprocess(); + void LastLineProcess(); virtual void Reset(); @@ -1655,15 +1650,13 @@ private: GPUEngineA *_engineMain; GPUEngineB *_engineSub; - NDSDisplay *_displayMain; - NDSDisplay *_displayTouch; + NDSDisplay *_display[2]; u32 _videoFrameCount; // Internal variable that increments when a video frame is completed. Resets every 60 video frames. u32 _render3DFrameCount; // The current 3D rendering frame count, saved to this variable once every 60 video frames. bool _frameNeedsFinish; bool _willFrameSkip; - bool _willAutoApplyMasterBrightness; - bool _willAutoConvertRGB666ToRGB888; + bool _willPostprocessDisplays; bool _willAutoResolveToCustomBuffer; u16 *_customVRAM; u16 *_customVRAMBlank; @@ -1689,8 +1682,6 @@ public: const NDSDisplayInfo& GetDisplayInfo(); // Frontends need to call this whenever they need to read the video buffers from the emulator core u32 GetFPSRender3D() const; - void SetDisplayDidCustomRender(NDSDisplayID displayID, bool theState); - GPUEngineA* GetEngineMain(); GPUEngineB* GetEngineSub(); NDSDisplay* GetDisplayMain(); @@ -1709,25 +1700,22 @@ public: void SetWillFrameSkip(const bool willFrameSkip); void UpdateRenderProperties(); - // By default, the output framebuffer will have the master brightness applied before - // the DidFrameEnd event. The master brightness is applied using the CPU. + // By default, the displays will automatically perform certain postprocessing steps on the + // CPU before the DidFrameEnd event. // - // To turn off this behavior, call SetWillAutoApplyMasterBrightness() and pass a value - // of "false". This can be useful if the client wants to apply the master brightness - // itself, for example, if a client applies it on the GPU. - bool GetWillAutoApplyMasterBrightness() const; - void SetWillAutoApplyMasterBrightness(const bool willAutoApply); - - // By default, if the output framebuffer is in RGB666 format, then the framebuffers will - // automatically be converted to the much more common RGB888 format. This conversion is - // performed on the CPU. + // To turn off this behavior, call SetWillPostprocessDisplays() and pass a value of "false". + // This can be useful if the client wants to perform these postprocessing steps itself, for + // example, if a client performs them on another thread or on the GPU. // - // To turn off this behavior, call SetWillAutoConvertRGB666ToRGB888() and pass a value - // of "false". This can be useful if the client wants to do its own post-processing - // while the color format is still RGB666, or if the client wants to do its own custom - // conversion (such as converting the framebuffer later on the GPU). - bool GetWillAutoConvertRGB666ToRGB888() const; - void SetWillAutoConvertRGB666ToRGB888(const bool willAutoConvert); + // If automatic postprocessing is turned off, clients can still manually perform the + // postprocessing steps on the CPU by calling PostprocessDisplay(). + // + // The postprocessing steps that are performed are: + // - Converting an RGB666 formatted framebuffer to RGB888 format. + // - Applying the master brightness. + bool GetWillPostprocessDisplays() const; + void SetWillPostprocessDisplays(const bool willPostprocess); + void PostprocessDisplay(const NDSDisplayID displayID, NDSDisplayInfo &mutableInfo); // Normally, the GPUs will automatically resolve their native buffers to the master // custom framebuffer at the end of V-blank so that all rendered graphics are contained @@ -1736,14 +1724,14 @@ public: // Certain functions, such as taking screenshots, as well as many frontends running // the NDS video displays, require that they read from only a single buffer. // - // However, if SetWillAutoResolveToCustomBuffer() is passed "false", then the - // frontend becomes responsible for calling GetDisplayInfo() and reading the native - // and custom buffers properly for each display. If a single buffer is still needed - // for certain cases, then the frontend must manually call - // GPUEngineBase::ResolveToCustomFramebuffer() for each engine before reading the - // master custom framebuffer. + // However, if SetWillAutoResolveToCustomBuffer() is passed "false", then the frontend + // becomes responsible for calling GetDisplayInfo() and reading the native and custom buffers + // properly for each display. If a single buffer is still needed for certain cases, then the + // frontend must manually call ResolveDisplayToCustomFramebuffer() for each display before + // reading the master custom framebuffer. bool GetWillAutoResolveToCustomBuffer() const; void SetWillAutoResolveToCustomBuffer(const bool willAutoResolve); + void ResolveDisplayToCustomFramebuffer(const NDSDisplayID displayID, NDSDisplayInfo &mutableInfo); template void RenderLine(const size_t l); void ClearWithColor(const u16 colorBGRA5551); diff --git a/desmume/src/frontend/cocoa/OGLDisplayOutput.cpp b/desmume/src/frontend/cocoa/OGLDisplayOutput.cpp index 78cebd06b..864d746a4 100644 --- a/desmume/src/frontend/cocoa/OGLDisplayOutput.cpp +++ b/desmume/src/frontend/cocoa/OGLDisplayOutput.cpp @@ -4709,7 +4709,7 @@ bool OGLShaderProgram::LinkOGL() OGLClientFetchObject::OGLClientFetchObject() { _contextInfo = NULL; - _useCPUFilterPipeline = true; + _useDirectToCPUFilterPipeline = true; _fetchColorFormatOGL = GL_UNSIGNED_SHORT_1_5_5_5_REV; pthread_rwlock_init(&_srcCloneRWLock[NDSDisplayID_Main][0], NULL); @@ -4923,7 +4923,7 @@ void OGLClientFetchObject::SetFetchBuffers(const NDSDisplayInfo ¤tDisplayI void OGLClientFetchObject::_FetchNativeDisplayByID(const NDSDisplayID displayID, const u8 bufferIndex) { - if (this->_useCPUFilterPipeline) + if (this->_useDirectToCPUFilterPipeline) { pthread_rwlock_wrlock(&this->_srcCloneRWLock[displayID][bufferIndex]); diff --git a/desmume/src/frontend/cocoa/OGLDisplayOutput.h b/desmume/src/frontend/cocoa/OGLDisplayOutput.h index 578583f4d..b9438a78b 100644 --- a/desmume/src/frontend/cocoa/OGLDisplayOutput.h +++ b/desmume/src/frontend/cocoa/OGLDisplayOutput.h @@ -343,7 +343,7 @@ protected: GLuint _texHQ3xLUT; GLuint _texHQ4xLUT; - bool _useCPUFilterPipeline; + bool _useDirectToCPUFilterPipeline; uint32_t *_srcNativeCloneMaster; uint32_t *_srcNativeClone[2][2]; pthread_rwlock_t _srcCloneRWLock[2][2]; diff --git a/desmume/src/frontend/cocoa/cocoa_GPU.h b/desmume/src/frontend/cocoa/cocoa_GPU.h index ce0142a9c..4d0902946 100644 --- a/desmume/src/frontend/cocoa/cocoa_GPU.h +++ b/desmume/src/frontend/cocoa/cocoa_GPU.h @@ -38,17 +38,17 @@ class GPUEventHandlerOSX; pthread_rwlock_t *_rwlockFramebuffer[2]; pthread_mutex_t *_mutexOutputList; NSMutableArray *_cdsOutputList; - volatile int32_t numberViewsUsingCPUFiltering; + volatile int32_t numberViewsUsingDirectToCPUFiltering; } @property (assign, nonatomic) GPUClientFetchObject *GPUFetchObject; -@property (readonly, nonatomic) int32_t numberViewsUsingCPUFiltering; +@property (readonly, nonatomic) int32_t numberViewsUsingDirectToCPUFiltering; - (const NDSDisplayInfo &) fetchDisplayInfoForIndex:(const u8)bufferIndex; - (pthread_rwlock_t *) rwlockFramebufferAtIndex:(const u8)bufferIndex; - (void) setOutputList:(NSMutableArray *)theOutputList mutex:(pthread_mutex_t *)theMutex; -- (void) incrementViewsUsingCPUFiltering; -- (void) decrementViewsUsingCPUFiltering; +- (void) incrementViewsUsingDirectToCPUFiltering; +- (void) decrementViewsUsingDirectToCPUFiltering; - (void) handleFetchFromBufferIndexAndPushVideo:(NSData *)indexData; - (void) pushVideoDataToAllDisplayViews; - (void) finishAllDisplayViewsAtIndex:(const u8)bufferIndex; diff --git a/desmume/src/frontend/cocoa/cocoa_GPU.mm b/desmume/src/frontend/cocoa/cocoa_GPU.mm index c545f82e7..6f179898c 100644 --- a/desmume/src/frontend/cocoa/cocoa_GPU.mm +++ b/desmume/src/frontend/cocoa/cocoa_GPU.mm @@ -159,11 +159,16 @@ public: if (IsOSXVersionSupported(10, 11, 0) && [[NSUserDefaults standardUserDefaults] boolForKey:@"General_DisplayViewsPreferMetal"]) { fetchObject = new MacMetalFetchObject; + if (fetchObject->GetClientData() == nil) { delete fetchObject; fetchObject = NULL; } + else + { + GPU->SetWillPostprocessDisplays(false); + } } #endif @@ -860,7 +865,7 @@ public: @implementation MacClientSharedObject @synthesize GPUFetchObject; -@synthesize numberViewsUsingCPUFiltering; +@synthesize numberViewsUsingDirectToCPUFiltering; - (id)init { @@ -879,7 +884,7 @@ public: GPUFetchObject = nil; _mutexOutputList = NULL; _cdsOutputList = nil; - numberViewsUsingCPUFiltering = 0; + numberViewsUsingDirectToCPUFiltering = 0; return self; } @@ -962,14 +967,14 @@ public: _mutexOutputList = theMutex; } -- (void) incrementViewsUsingCPUFiltering +- (void) incrementViewsUsingDirectToCPUFiltering { - OSAtomicIncrement32(&numberViewsUsingCPUFiltering); + OSAtomicIncrement32(&numberViewsUsingDirectToCPUFiltering); } -- (void) decrementViewsUsingCPUFiltering +- (void) decrementViewsUsingDirectToCPUFiltering { - OSAtomicDecrement32(&numberViewsUsingCPUFiltering); + OSAtomicDecrement32(&numberViewsUsingDirectToCPUFiltering); } - (void) pushVideoDataToAllDisplayViews diff --git a/desmume/src/frontend/cocoa/cocoa_output.mm b/desmume/src/frontend/cocoa/cocoa_output.mm index 4470e3e19..b7a01fcc6 100644 --- a/desmume/src/frontend/cocoa/cocoa_output.mm +++ b/desmume/src/frontend/cocoa/cocoa_output.mm @@ -678,9 +678,11 @@ - (NSBitmapImageRep *) bitmapImageRep { - const NDSDisplayInfo &dispInfo = GPU->GetDisplayInfo(); - NSUInteger w = (NSUInteger)dispInfo.customWidth; - NSUInteger h = (_cdv->GetMode() == ClientDisplayMode_Dual) ? (NSUInteger)(dispInfo.customHeight * 2) : (NSUInteger)dispInfo.customHeight; + GPUClientFetchObject &fetchObjMutable = (GPUClientFetchObject &)_cdv->GetFetchObject(); + NDSDisplayInfo &displayInfoMutable = (NDSDisplayInfo &)fetchObjMutable.GetFetchDisplayInfoForBufferIndex(fetchObjMutable.GetLastFetchIndex()); + + NSUInteger w = (NSUInteger)displayInfoMutable.customWidth; + NSUInteger h = (_cdv->GetMode() == ClientDisplayMode_Dual) ? (NSUInteger)(displayInfoMutable.customHeight * 2) : (NSUInteger)displayInfoMutable.customHeight; NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL pixelsWide:w @@ -698,19 +700,21 @@ return imageRep; } - void *displayBuffer = dispInfo.masterCustomBuffer; + void *displayBuffer = displayInfoMutable.masterCustomBuffer; uint32_t *bitmapData = (uint32_t *)[imageRep bitmapData]; - pthread_rwlock_rdlock(self.rwlockProducer); + pthread_rwlock_wrlock(self.rwlockProducer); - GPU->GetEngineMain()->ResolveToCustomFramebuffer(); - GPU->GetEngineSub()->ResolveToCustomFramebuffer(); + GPU->PostprocessDisplay(NDSDisplayID_Main, displayInfoMutable); + GPU->PostprocessDisplay(NDSDisplayID_Touch, displayInfoMutable); + GPU->ResolveDisplayToCustomFramebuffer(NDSDisplayID_Main, displayInfoMutable); + GPU->ResolveDisplayToCustomFramebuffer(NDSDisplayID_Touch, displayInfoMutable); - if (dispInfo.pixelBytes == 2) + if (displayInfoMutable.pixelBytes == 2) { ColorspaceConvertBuffer555To8888Opaque((u16 *)displayBuffer, bitmapData, (w * h)); } - else if (dispInfo.pixelBytes == 4) + else if (displayInfoMutable.pixelBytes == 4) { memcpy(bitmapData, displayBuffer, w * h * sizeof(uint32_t)); } diff --git a/desmume/src/frontend/cocoa/userinterface/DisplayWindowController.mm b/desmume/src/frontend/cocoa/userinterface/DisplayWindowController.mm index a6e74a834..8ce1e3e88 100644 --- a/desmume/src/frontend/cocoa/userinterface/DisplayWindowController.mm +++ b/desmume/src/frontend/cocoa/userinterface/DisplayWindowController.mm @@ -1751,9 +1751,9 @@ static std::unordered_map _screenMap; // - (void) setVideoFiltersPreferGPU:(BOOL)theState { - const BOOL oldState = (![[self cdsVideoOutput] willFilterOnGPU] && ([[self cdsVideoOutput] pixelScaler] != VideoFilterTypeID_None)); + const BOOL oldState = ( ![[self cdsVideoOutput] willFilterOnGPU] && ![[self cdsVideoOutput] sourceDeposterize] && ([[self cdsVideoOutput] pixelScaler] != VideoFilterTypeID_None) ); [[self cdsVideoOutput] setVideoFiltersPreferGPU:theState]; - const BOOL newState = (![[self cdsVideoOutput] willFilterOnGPU] && ([[self cdsVideoOutput] pixelScaler] != VideoFilterTypeID_None)); + const BOOL newState = ( ![[self cdsVideoOutput] willFilterOnGPU] && ![[self cdsVideoOutput] sourceDeposterize] && ([[self cdsVideoOutput] pixelScaler] != VideoFilterTypeID_None) ); if (oldState != newState) { @@ -1764,11 +1764,11 @@ static std::unordered_map _screenMap; // if (newState) { - [macSharedData incrementViewsUsingCPUFiltering]; + [macSharedData incrementViewsUsingDirectToCPUFiltering]; } else { - [macSharedData decrementViewsUsingCPUFiltering]; + [macSharedData decrementViewsUsingDirectToCPUFiltering]; } } } @@ -1780,7 +1780,26 @@ static std::unordered_map _screenMap; // - (void) setSourceDeposterize:(BOOL)theState { + const BOOL oldState = ( ![[self cdsVideoOutput] willFilterOnGPU] && ![[self cdsVideoOutput] sourceDeposterize] && ([[self cdsVideoOutput] pixelScaler] != VideoFilterTypeID_None) ); [[self cdsVideoOutput] setSourceDeposterize:theState]; + const BOOL newState = ( ![[self cdsVideoOutput] willFilterOnGPU] && ![[self cdsVideoOutput] sourceDeposterize] && ([[self cdsVideoOutput] pixelScaler] != VideoFilterTypeID_None) ); + + if (oldState != newState) + { + DisplayWindowController *windowController = (DisplayWindowController *)[[self window] delegate]; + CocoaDSCore *cdsCore = (CocoaDSCore *)[[[windowController emuControl] cdsCoreController] content]; + CocoaDSGPU *cdsGPU = [cdsCore cdsGPU]; + MacClientSharedObject *macSharedData = [cdsGPU sharedData]; + + if (newState) + { + [macSharedData incrementViewsUsingDirectToCPUFiltering]; + } + else + { + [macSharedData decrementViewsUsingDirectToCPUFiltering]; + } + } } - (BOOL) sourceDeposterize @@ -1800,9 +1819,9 @@ static std::unordered_map _screenMap; // - (void) setPixelScaler:(NSInteger)filterID { - const BOOL oldState = (![[self cdsVideoOutput] willFilterOnGPU] && ([[self cdsVideoOutput] pixelScaler] != VideoFilterTypeID_None)); + const BOOL oldState = ( ![[self cdsVideoOutput] willFilterOnGPU] && ![[self cdsVideoOutput] sourceDeposterize] && ([[self cdsVideoOutput] pixelScaler] != VideoFilterTypeID_None) ); [[self cdsVideoOutput] setPixelScaler:filterID]; - const BOOL newState = (![[self cdsVideoOutput] willFilterOnGPU] && ([[self cdsVideoOutput] pixelScaler] != VideoFilterTypeID_None)); + const BOOL newState = ( ![[self cdsVideoOutput] willFilterOnGPU] && ![[self cdsVideoOutput] sourceDeposterize] && ([[self cdsVideoOutput] pixelScaler] != VideoFilterTypeID_None) ); if (oldState != newState) { @@ -1813,11 +1832,11 @@ static std::unordered_map _screenMap; // if (newState) { - [macSharedData incrementViewsUsingCPUFiltering]; + [macSharedData incrementViewsUsingDirectToCPUFiltering]; } else { - [macSharedData decrementViewsUsingCPUFiltering]; + [macSharedData decrementViewsUsingDirectToCPUFiltering]; } } } diff --git a/desmume/src/frontend/cocoa/userinterface/MacMetalDisplayView.h b/desmume/src/frontend/cocoa/userinterface/MacMetalDisplayView.h index 196ad9272..4823f437e 100644 --- a/desmume/src/frontend/cocoa/userinterface/MacMetalDisplayView.h +++ b/desmume/src/frontend/cocoa/userinterface/MacMetalDisplayView.h @@ -48,7 +48,10 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties; id commandQueue; id defaultLibrary; - id load16To32Pipeline; + id _fetch555Pipeline; + id _fetch555ConvertOnlyPipeline; + id _fetch666Pipeline; + id _fetch888Pipeline; id deposterizePipeline; id hudPipeline; @@ -61,6 +64,9 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties; id _bufDisplayFetchNative[2][2]; id _bufDisplayFetchCustom[2][2]; + id _bufMasterBrightMode[2]; + id _bufMasterBrightIntensity[2]; + id texDisplayFetch16NativeMain; id texDisplayFetch16NativeTouch; id texDisplayFetch32NativeMain; @@ -70,15 +76,23 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties; id texDisplayFetch32CustomMain; id texDisplayFetch32CustomTouch; + id texDisplayPostprocessNativeMain; + id texDisplayPostprocessCustomMain; + id texDisplayPostprocessNativeTouch; + id texDisplayPostprocessCustomTouch; + + id texDisplaySrcTargetMain; + id texDisplaySrcTargetTouch; + id texLQ2xLUT; id texHQ2xLUT; id texHQ3xLUT; id texHQ4xLUT; id texCurrentHQnxLUT; - MTLSize load16To32ThreadsPerGroup; - MTLSize load16To32ThreadGroupsPerGridNative; - MTLSize load16To32ThreadGroupsPerGridCustom; + MTLSize fetchThreadsPerGroup; + MTLSize fetchThreadGroupsPerGridNative; + MTLSize fetchThreadGroupsPerGridCustom; MTLSize deposterizeThreadsPerGroup; MTLSize deposterizeThreadGroupsPerGrid; @@ -92,7 +106,6 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties; @property (readonly, nonatomic) id commandQueue; @property (readonly, nonatomic) id defaultLibrary; -@property (readonly, nonatomic) id load16To32Pipeline; @property (readonly, nonatomic) id deposterizePipeline; @property (readonly, nonatomic) id hudPipeline; @property (readonly, nonatomic) id samplerHUDBox; @@ -109,6 +122,14 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties; @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 (readonly, nonatomic) id texLQ2xLUT; @property (readonly, nonatomic) id texHQ2xLUT; @property (readonly, nonatomic) id texHQ3xLUT; @@ -118,9 +139,9 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties; @property (assign) size_t displayFetchNativeBufferSize; @property (assign) size_t displayFetchCustomBufferSize; -@property (readonly, nonatomic) MTLSize load16To32ThreadsPerGroup; -@property (readonly, nonatomic) MTLSize load16To32ThreadGroupsPerGridNative; -@property (assign) MTLSize load16To32ThreadGroupsPerGridCustom; +@property (readonly, nonatomic) MTLSize fetchThreadsPerGroup; +@property (readonly, nonatomic) MTLSize fetchThreadGroupsPerGridNative; +@property (assign) MTLSize fetchThreadGroupsPerGridCustom; @property (readonly, nonatomic) MTLSize deposterizeThreadsPerGroup; @property (readonly, nonatomic) MTLSize deposterizeThreadGroupsPerGrid; @@ -128,7 +149,6 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties; - (void) fetchFromBufferIndex:(const u8)index; - (void) fetchNativeDisplayByID:(const NDSDisplayID)displayID bufferIndex:(const u8)bufferIndex; - (void) fetchCustomDisplayByID:(const NDSDisplayID)displayID bufferIndex:(const u8)bufferIndex; -- (void) convertFetch16To32UsingEncoder:(id)cce isMainNative:(BOOL)isMainNative isTouchNative:(BOOL)isTouchNative; @end @@ -201,7 +221,7 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties; class MacMetalFetchObject : public GPUClientFetchObject { protected: - bool _useCPUFilterPipeline; + bool _useDirectToCPUFilterPipeline; uint32_t *_srcNativeCloneMaster; uint32_t *_srcNativeClone[2][2]; pthread_rwlock_t _srcCloneRWLock[2][2]; diff --git a/desmume/src/frontend/cocoa/userinterface/MacMetalDisplayView.mm b/desmume/src/frontend/cocoa/userinterface/MacMetalDisplayView.mm index b4b57257d..67e121d40 100644 --- a/desmume/src/frontend/cocoa/userinterface/MacMetalDisplayView.mm +++ b/desmume/src/frontend/cocoa/userinterface/MacMetalDisplayView.mm @@ -25,7 +25,6 @@ @synthesize commandQueue; @synthesize defaultLibrary; -@synthesize load16To32Pipeline; @synthesize deposterizePipeline; @synthesize hudPipeline; @synthesize samplerHUDBox; @@ -42,6 +41,14 @@ @synthesize texDisplayFetch32CustomMain; @synthesize texDisplayFetch32CustomTouch; +@synthesize texDisplayPostprocessNativeMain; +@synthesize texDisplayPostprocessCustomMain; +@synthesize texDisplayPostprocessNativeTouch; +@synthesize texDisplayPostprocessCustomTouch; + +@synthesize texDisplaySrcTargetMain; +@synthesize texDisplaySrcTargetTouch; + @synthesize texLQ2xLUT; @synthesize texHQ2xLUT; @synthesize texHQ3xLUT; @@ -51,9 +58,9 @@ @synthesize displayFetchNativeBufferSize; @synthesize displayFetchCustomBufferSize; -@synthesize load16To32ThreadsPerGroup; -@synthesize load16To32ThreadGroupsPerGridNative; -@synthesize load16To32ThreadGroupsPerGridCustom; +@synthesize fetchThreadsPerGroup; +@synthesize fetchThreadGroupsPerGridNative; +@synthesize fetchThreadGroupsPerGridCustom; @synthesize deposterizeThreadsPerGroup; @synthesize deposterizeThreadGroupsPerGrid; @@ -77,26 +84,29 @@ commandQueue = [[device newCommandQueue] retain]; defaultLibrary = [[device newDefaultLibrary] retain]; - load16To32Pipeline = [[device newComputePipelineStateWithFunction:[defaultLibrary newFunctionWithName:@"src16_unpack_unorm1555_to_unorm8888"] error:nil] retain]; + _fetch555Pipeline = [[device newComputePipelineStateWithFunction:[defaultLibrary newFunctionWithName:@"nds_fetch555"] error:nil] retain]; + _fetch555ConvertOnlyPipeline = [[device newComputePipelineStateWithFunction:[defaultLibrary newFunctionWithName:@"nds_fetch555ConvertOnly"] error:nil] retain]; + _fetch666Pipeline = [[device newComputePipelineStateWithFunction:[defaultLibrary newFunctionWithName:@"nds_fetch666"] error:nil] retain]; + _fetch888Pipeline = [[device newComputePipelineStateWithFunction:[defaultLibrary newFunctionWithName:@"nds_fetch888"] error:nil] retain]; deposterizePipeline = [[device newComputePipelineStateWithFunction:[defaultLibrary newFunctionWithName:@"src_filter_deposterize"] error:nil] retain]; - size_t tw = GetNearestPositivePOT((uint32_t)[load16To32Pipeline threadExecutionWidth]); - while ( (tw > [load16To32Pipeline threadExecutionWidth]) || (tw > GPU_FRAMEBUFFER_NATIVE_WIDTH) ) + size_t tw = GetNearestPositivePOT((uint32_t)[_fetch555Pipeline threadExecutionWidth]); + while ( (tw > [_fetch555Pipeline threadExecutionWidth]) || (tw > GPU_FRAMEBUFFER_NATIVE_WIDTH) ) { tw >>= 1; } - size_t th = [load16To32Pipeline maxTotalThreadsPerThreadgroup] / tw; + size_t th = [_fetch555Pipeline maxTotalThreadsPerThreadgroup] / tw; - load16To32ThreadsPerGroup = MTLSizeMake(tw, th, 1); - load16To32ThreadGroupsPerGridNative = 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); - load16To32ThreadGroupsPerGridCustom = load16To32ThreadGroupsPerGridNative; + fetchThreadGroupsPerGridCustom = fetchThreadGroupsPerGridNative; - deposterizeThreadsPerGroup = load16To32ThreadsPerGroup; - deposterizeThreadGroupsPerGrid = load16To32ThreadGroupsPerGridNative; + deposterizeThreadsPerGroup = fetchThreadsPerGroup; + deposterizeThreadGroupsPerGrid = fetchThreadGroupsPerGridNative; MTLRenderPipelineDescriptor *hudPipelineDesc = [[MTLRenderPipelineDescriptor alloc] init]; [[[hudPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setPixelFormat:MTLPixelFormatBGRA8Unorm]; @@ -139,6 +149,11 @@ 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]; + _bufMasterBrightIntensity[NDSDisplayID_Main] = [[device newBufferWithLength:sizeof(uint8_t) * GPU_FRAMEBUFFER_NATIVE_HEIGHT options:MTLResourceStorageModeManaged] retain]; + _bufMasterBrightIntensity[NDSDisplayID_Touch] = [[device newBufferWithLength:sizeof(uint8_t) * GPU_FRAMEBUFFER_NATIVE_HEIGHT options:MTLResourceStorageModeManaged] retain]; + // Set up HUD texture samplers. MTLSamplerDescriptor *samplerDesc = [[MTLSamplerDescriptor alloc] init]; [samplerDesc setNormalizedCoordinates:YES]; @@ -189,26 +204,51 @@ texDisplayFetch32CustomMain = [[device newTextureWithDescriptor:texDisplayLoad32Desc] retain]; texDisplayFetch32CustomTouch = [[device newTextureWithDescriptor:texDisplayLoad32Desc] retain]; + texDisplayPostprocessNativeMain = [[device newTextureWithDescriptor:texDisplayLoad32Desc] retain]; + texDisplayPostprocessCustomMain = [[device newTextureWithDescriptor:texDisplayLoad32Desc] retain]; + texDisplayPostprocessNativeTouch = [[device newTextureWithDescriptor:texDisplayLoad32Desc] retain]; + texDisplayPostprocessCustomTouch = [[device newTextureWithDescriptor:texDisplayLoad32Desc] retain]; + uint16_t *blankBuffer = (uint16_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)]; + [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)]; + [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)]; free(blankBuffer); + texDisplaySrcTargetMain = [texDisplayFetch32NativeMain retain]; + texDisplaySrcTargetTouch = [texDisplayFetch32NativeTouch retain]; + // Set up the HQnx LUT textures. SetupHQnxLUTs_Metal(device, texLQ2xLUT, texHQ2xLUT, texHQ3xLUT, texHQ4xLUT); texCurrentHQnxLUT = nil; @@ -225,11 +265,19 @@ [commandQueue release]; [defaultLibrary release]; - [load16To32Pipeline release]; + [_fetch555Pipeline release]; + [_fetch555ConvertOnlyPipeline release]; + [_fetch666Pipeline release]; + [_fetch888Pipeline release]; [deposterizePipeline release]; [hudPipeline release]; [hudIndexBuffer release]; + [_bufMasterBrightMode[NDSDisplayID_Main] release]; + [_bufMasterBrightMode[NDSDisplayID_Touch] release]; + [_bufMasterBrightIntensity[NDSDisplayID_Main] release]; + [_bufMasterBrightIntensity[NDSDisplayID_Touch] release]; + [texDisplayFetch16NativeMain release]; [texDisplayFetch16NativeTouch release]; [texDisplayFetch32NativeMain release]; @@ -239,6 +287,14 @@ [self setTexDisplayFetch32CustomMain:nil]; [self setTexDisplayFetch32CustomTouch:nil]; + [self setTexDisplayPostprocessNativeMain:nil]; + [self setTexDisplayPostprocessCustomMain:nil]; + [self setTexDisplayPostprocessNativeTouch:nil]; + [self setTexDisplayPostprocessCustomTouch:nil]; + + [self setTexDisplaySrcTargetMain:nil]; + [self setTexDisplaySrcTargetTouch:nil]; + DeleteHQnxLUTs_Metal(texLQ2xLUT, texHQ2xLUT, texHQ3xLUT, texHQ4xLUT); [self setTexCurrentHQnxLUT:nil]; @@ -319,10 +375,243 @@ GPUFetchObject->GPUClientFetchObject::FetchFromBufferIndex(index); [_fetchEncoder endEncoding]; - [cb commit]; 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]; + const bool isTouchEnabled = currentDisplayInfo.isDisplayEnabled[NDSDisplayID_Touch]; + + if (isMainEnabled || isTouchEnabled) + { + if (isMainEnabled) + { + if (!currentDisplayInfo.didPerformCustomRender[NDSDisplayID_Main]) + { + texDisplaySrcTarget[NDSDisplayID_Main] = texDisplayFetch32NativeMain; + } + else + { + texDisplaySrcTarget[NDSDisplayID_Main] = texDisplayFetch32CustomMain; + } + } + + if (isTouchEnabled) + { + if (!currentDisplayInfo.didPerformCustomRender[NDSDisplayID_Touch]) + { + texDisplaySrcTarget[NDSDisplayID_Touch] = texDisplayFetch32NativeTouch; + } + else + { + texDisplaySrcTarget[NDSDisplayID_Touch] = texDisplayFetch32CustomTouch; + } + } + + id cce = [cb computeCommandEncoder]; + + if (currentDisplayInfo.colorFormat == NDSColorFormat_BGR555_Rev) + { + // 16-bit textures aren't handled natively in Metal for macOS, so we need to explicitly convert to 32-bit here. + + if (currentDisplayInfo.needConvertColorFormat[NDSDisplayID_Main] || currentDisplayInfo.needConvertColorFormat[NDSDisplayID_Touch] || + currentDisplayInfo.needApplyMasterBrightness[NDSDisplayID_Main] || currentDisplayInfo.needApplyMasterBrightness[NDSDisplayID_Touch]) + { + [cce setComputePipelineState:_fetch555Pipeline]; + + if (isMainEnabled) + { + memcpy([_bufMasterBrightMode[NDSDisplayID_Main] contents], currentDisplayInfo.masterBrightnessMode[NDSDisplayID_Main], sizeof(uint8_t) * GPU_FRAMEBUFFER_NATIVE_HEIGHT); + memcpy([_bufMasterBrightIntensity[NDSDisplayID_Main] contents], currentDisplayInfo.masterBrightnessIntensity[NDSDisplayID_Main], sizeof(uint8_t) * GPU_FRAMEBUFFER_NATIVE_HEIGHT); + [_bufMasterBrightMode[NDSDisplayID_Main] didModifyRange:NSMakeRange(0, sizeof(uint8_t) * GPU_FRAMEBUFFER_NATIVE_HEIGHT)]; + [_bufMasterBrightIntensity[NDSDisplayID_Main] didModifyRange:NSMakeRange(0, sizeof(uint8_t) * GPU_FRAMEBUFFER_NATIVE_HEIGHT)]; + + [cce setBuffer:_bufMasterBrightMode[NDSDisplayID_Main] offset:0 atIndex:0]; + [cce setBuffer:_bufMasterBrightIntensity[NDSDisplayID_Main] offset:0 atIndex:1]; + + if (!currentDisplayInfo.didPerformCustomRender[NDSDisplayID_Main]) + { + [cce setTexture:texDisplayFetch16NativeMain atIndex:0]; + [cce setTexture:[self texDisplayPostprocessNativeMain] atIndex:1]; + [cce dispatchThreadgroups:fetchThreadGroupsPerGridNative + threadsPerThreadgroup:fetchThreadsPerGroup]; + + texDisplaySrcTarget[NDSDisplayID_Main] = [self texDisplayPostprocessNativeMain]; + } + else + { + [cce setTexture:[self texDisplayFetch16CustomMain] atIndex:0]; + [cce setTexture:[self texDisplayPostprocessCustomMain] atIndex:1]; + [cce dispatchThreadgroups:[self fetchThreadGroupsPerGridCustom] + threadsPerThreadgroup:[self fetchThreadsPerGroup]]; + + texDisplaySrcTarget[NDSDisplayID_Main] = [self texDisplayPostprocessCustomMain]; + } + } + + if (isTouchEnabled) + { + memcpy([_bufMasterBrightMode[NDSDisplayID_Touch] contents], currentDisplayInfo.masterBrightnessMode[NDSDisplayID_Touch], sizeof(uint8_t) * GPU_FRAMEBUFFER_NATIVE_HEIGHT); + memcpy([_bufMasterBrightIntensity[NDSDisplayID_Touch] contents], currentDisplayInfo.masterBrightnessIntensity[NDSDisplayID_Touch], sizeof(uint8_t) * GPU_FRAMEBUFFER_NATIVE_HEIGHT); + [_bufMasterBrightMode[NDSDisplayID_Touch] didModifyRange:NSMakeRange(0, sizeof(uint8_t) * GPU_FRAMEBUFFER_NATIVE_HEIGHT)]; + [_bufMasterBrightIntensity[NDSDisplayID_Touch] didModifyRange:NSMakeRange(0, sizeof(uint8_t) * GPU_FRAMEBUFFER_NATIVE_HEIGHT)]; + + [cce setBuffer:_bufMasterBrightMode[NDSDisplayID_Touch] offset:0 atIndex:0]; + [cce setBuffer:_bufMasterBrightIntensity[NDSDisplayID_Touch] offset:0 atIndex:1]; + + if (!currentDisplayInfo.didPerformCustomRender[NDSDisplayID_Touch]) + { + [cce setTexture:texDisplayFetch16NativeTouch atIndex:0]; + [cce setTexture:[self texDisplayPostprocessNativeTouch] atIndex:1]; + [cce dispatchThreadgroups:fetchThreadGroupsPerGridNative + threadsPerThreadgroup:fetchThreadsPerGroup]; + + texDisplaySrcTarget[NDSDisplayID_Touch] = [self texDisplayPostprocessNativeTouch]; + } + else + { + [cce setTexture:[self texDisplayFetch16CustomTouch] atIndex:0]; + [cce setTexture:[self texDisplayPostprocessCustomTouch] atIndex:1]; + [cce dispatchThreadgroups:[self fetchThreadGroupsPerGridCustom] + threadsPerThreadgroup:[self fetchThreadsPerGroup]]; + + texDisplaySrcTarget[NDSDisplayID_Touch] = [self texDisplayPostprocessCustomTouch]; + } + } + } + else + { + [cce setComputePipelineState:_fetch555ConvertOnlyPipeline]; + + if (isMainEnabled) + { + if (!currentDisplayInfo.didPerformCustomRender[NDSDisplayID_Main]) + { + [cce setTexture:texDisplayFetch16NativeMain atIndex:0]; + [cce setTexture:[self texDisplayPostprocessNativeMain] atIndex:1]; + [cce dispatchThreadgroups:fetchThreadGroupsPerGridNative + threadsPerThreadgroup:fetchThreadsPerGroup]; + + texDisplaySrcTarget[NDSDisplayID_Main] = [self texDisplayPostprocessNativeMain]; + } + else + { + [cce setTexture:[self texDisplayFetch16CustomMain] atIndex:0]; + [cce setTexture:[self texDisplayPostprocessCustomMain] atIndex:1]; + [cce dispatchThreadgroups:[self fetchThreadGroupsPerGridCustom] + threadsPerThreadgroup:[self fetchThreadsPerGroup]]; + + texDisplaySrcTarget[NDSDisplayID_Main] = [self texDisplayPostprocessCustomMain]; + } + } + + if (isTouchEnabled) + { + if (!currentDisplayInfo.didPerformCustomRender[NDSDisplayID_Touch]) + { + [cce setTexture:texDisplayFetch16NativeTouch atIndex:0]; + [cce setTexture:[self texDisplayPostprocessNativeTouch] atIndex:1]; + [cce dispatchThreadgroups:fetchThreadGroupsPerGridNative + threadsPerThreadgroup:fetchThreadsPerGroup]; + + texDisplaySrcTarget[NDSDisplayID_Touch] = [self texDisplayPostprocessNativeTouch]; + } + else + { + [cce setTexture:[self texDisplayFetch16CustomTouch] atIndex:0]; + [cce setTexture:[self texDisplayPostprocessCustomTouch] atIndex:1]; + [cce dispatchThreadgroups:[self fetchThreadGroupsPerGridCustom] + threadsPerThreadgroup:[self fetchThreadsPerGroup]]; + + texDisplaySrcTarget[NDSDisplayID_Touch] = [self texDisplayPostprocessCustomTouch]; + } + } + } + } + else + { + if (currentDisplayInfo.needConvertColorFormat[NDSDisplayID_Main] || currentDisplayInfo.needConvertColorFormat[NDSDisplayID_Touch] || + currentDisplayInfo.needApplyMasterBrightness[NDSDisplayID_Main] || currentDisplayInfo.needApplyMasterBrightness[NDSDisplayID_Touch]) + { + if (currentDisplayInfo.colorFormat == NDSColorFormat_BGR666_Rev) + { + [cce setComputePipelineState:_fetch666Pipeline]; + } + else + { + [cce setComputePipelineState:_fetch888Pipeline]; + } + + if (isMainEnabled) + { + memcpy([_bufMasterBrightMode[NDSDisplayID_Main] contents], currentDisplayInfo.masterBrightnessMode[NDSDisplayID_Main], sizeof(uint8_t) * GPU_FRAMEBUFFER_NATIVE_HEIGHT); + memcpy([_bufMasterBrightIntensity[NDSDisplayID_Main] contents], currentDisplayInfo.masterBrightnessIntensity[NDSDisplayID_Main], sizeof(uint8_t) * GPU_FRAMEBUFFER_NATIVE_HEIGHT); + [_bufMasterBrightMode[NDSDisplayID_Main] didModifyRange:NSMakeRange(0, sizeof(uint8_t) * GPU_FRAMEBUFFER_NATIVE_HEIGHT)]; + [_bufMasterBrightIntensity[NDSDisplayID_Main] didModifyRange:NSMakeRange(0, sizeof(uint8_t) * GPU_FRAMEBUFFER_NATIVE_HEIGHT)]; + + [cce setBuffer:_bufMasterBrightMode[NDSDisplayID_Main] offset:0 atIndex:0]; + [cce setBuffer:_bufMasterBrightIntensity[NDSDisplayID_Main] offset:0 atIndex:1]; + + if (!currentDisplayInfo.didPerformCustomRender[NDSDisplayID_Main]) + { + [cce setTexture:texDisplayFetch32NativeMain atIndex:0]; + [cce setTexture:[self texDisplayPostprocessNativeMain] atIndex:1]; + [cce dispatchThreadgroups:fetchThreadGroupsPerGridNative + threadsPerThreadgroup:fetchThreadsPerGroup]; + + texDisplaySrcTarget[NDSDisplayID_Main] = [self texDisplayPostprocessNativeMain]; + } + else + { + [cce setTexture:[self texDisplayFetch32CustomMain] atIndex:0]; + [cce setTexture:[self texDisplayPostprocessCustomMain] atIndex:1]; + [cce dispatchThreadgroups:[self fetchThreadGroupsPerGridCustom] + threadsPerThreadgroup:[self fetchThreadsPerGroup]]; + + texDisplaySrcTarget[NDSDisplayID_Main] = [self texDisplayPostprocessCustomMain]; + } + } + + if (isTouchEnabled) + { + memcpy([_bufMasterBrightMode[NDSDisplayID_Touch] contents], currentDisplayInfo.masterBrightnessMode[NDSDisplayID_Touch], sizeof(uint8_t) * GPU_FRAMEBUFFER_NATIVE_HEIGHT); + memcpy([_bufMasterBrightIntensity[NDSDisplayID_Touch] contents], currentDisplayInfo.masterBrightnessIntensity[NDSDisplayID_Touch], sizeof(uint8_t) * GPU_FRAMEBUFFER_NATIVE_HEIGHT); + [_bufMasterBrightMode[NDSDisplayID_Touch] didModifyRange:NSMakeRange(0, sizeof(uint8_t) * GPU_FRAMEBUFFER_NATIVE_HEIGHT)]; + [_bufMasterBrightIntensity[NDSDisplayID_Touch] didModifyRange:NSMakeRange(0, sizeof(uint8_t) * GPU_FRAMEBUFFER_NATIVE_HEIGHT)]; + + [cce setBuffer:_bufMasterBrightMode[NDSDisplayID_Touch] offset:0 atIndex:0]; + [cce setBuffer:_bufMasterBrightIntensity[NDSDisplayID_Touch] offset:0 atIndex:1]; + + if (!currentDisplayInfo.didPerformCustomRender[NDSDisplayID_Touch]) + { + [cce setTexture:texDisplayFetch32NativeTouch atIndex:0]; + [cce setTexture:[self texDisplayPostprocessNativeTouch] atIndex:1]; + [cce dispatchThreadgroups:fetchThreadGroupsPerGridNative + threadsPerThreadgroup:fetchThreadsPerGroup]; + + texDisplaySrcTarget[NDSDisplayID_Touch] = [self texDisplayPostprocessNativeTouch]; + } + else + { + [cce setTexture:[self texDisplayFetch32CustomTouch] atIndex:0]; + [cce setTexture:[self texDisplayPostprocessCustomTouch] atIndex:1]; + [cce dispatchThreadgroups:[self fetchThreadGroupsPerGridCustom] + threadsPerThreadgroup:[self fetchThreadsPerGroup]]; + + texDisplaySrcTarget[NDSDisplayID_Touch] = [self texDisplayPostprocessCustomTouch]; + } + } + } + } + + [cce endEncoding]; + [cb commit]; + } + + [self setTexDisplaySrcTargetMain:texDisplaySrcTarget[NDSDisplayID_Main]]; + [self setTexDisplaySrcTargetTouch:texDisplaySrcTarget[NDSDisplayID_Touch]]; } - (void) fetchNativeDisplayByID:(const NDSDisplayID)displayID bufferIndex:(const u8)bufferIndex @@ -375,11 +664,11 @@ [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]; } @@ -387,16 +676,17 @@ { [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 = load16To32ThreadsPerGroup.width; - const size_t th = load16To32ThreadsPerGroup.height; + const size_t tw = fetchThreadsPerGroup.width; + const size_t th = fetchThreadsPerGroup.height; - [self setLoad16To32ThreadGroupsPerGridCustom:MTLSizeMake((currentDisplayInfo.customWidth + tw - 1) / tw, - (currentDisplayInfo.customHeight + th - 1) / th, - 1)]; + [self setFetchThreadGroupsPerGridCustom:MTLSizeMake((currentDisplayInfo.customWidth + tw - 1) / tw, + (currentDisplayInfo.customHeight + th - 1) / th, + 1)]; } const size_t bufferSize = [self displayFetchCustomBufferSize]; @@ -414,42 +704,6 @@ destinationOrigin:MTLOriginMake(0, 0, 0)]; } -- (void) convertFetch16To32UsingEncoder:(id)cce isMainNative:(BOOL)isMainNative isTouchNative:(BOOL)isTouchNative -{ - // 16-bit textures aren't handled natively in Metal for macOS, so we need to explicitly convert to 32-bit here. - [cce setComputePipelineState:load16To32Pipeline]; - - if (isMainNative) - { - [cce setTexture:texDisplayFetch16NativeMain atIndex:0]; - [cce setTexture:texDisplayFetch32NativeMain atIndex:1]; - [cce dispatchThreadgroups:load16To32ThreadGroupsPerGridNative - threadsPerThreadgroup:load16To32ThreadsPerGroup]; - } - else - { - [cce setTexture:texDisplayFetch16CustomMain atIndex:0]; - [cce setTexture:texDisplayFetch32CustomMain atIndex:1]; - [cce dispatchThreadgroups:[self load16To32ThreadGroupsPerGridCustom] - threadsPerThreadgroup:[self load16To32ThreadsPerGroup]]; - } - - if (isTouchNative) - { - [cce setTexture:texDisplayFetch16NativeTouch atIndex:0]; - [cce setTexture:texDisplayFetch32NativeTouch atIndex:1]; - [cce dispatchThreadgroups:load16To32ThreadGroupsPerGridNative - threadsPerThreadgroup:load16To32ThreadsPerGroup]; - } - else - { - [cce setTexture:[self texDisplayFetch16CustomTouch] atIndex:0]; - [cce setTexture:[self texDisplayFetch32CustomTouch] atIndex:1]; - [cce dispatchThreadgroups:[self load16To32ThreadGroupsPerGridCustom] - threadsPerThreadgroup:[self load16To32ThreadsPerGroup]]; - } -} - @end @implementation DisplayViewMetalLayer @@ -963,10 +1217,10 @@ const ClientDisplayMode mode = _cdv->GetViewProperties().mode; const bool useDeposterize = _cdv->GetSourceDeposterize(); - _texDisplayOutput[NDSDisplayID_Main] = (!fetchDisplayInfo.didPerformCustomRender[NDSDisplayID_Main]) ? [sharedData texDisplayFetch32NativeMain] : [sharedData texDisplayFetch32CustomMain]; - _texDisplayOutput[NDSDisplayID_Touch] = (!fetchDisplayInfo.didPerformCustomRender[NDSDisplayID_Touch]) ? [sharedData texDisplayFetch32NativeTouch] : [sharedData texDisplayFetch32CustomTouch]; + _texDisplayOutput[NDSDisplayID_Main] = [sharedData texDisplaySrcTargetMain]; + _texDisplayOutput[NDSDisplayID_Touch] = [sharedData texDisplaySrcTargetTouch]; - if (useDeposterize || (_cdv->GetPixelScaler() != VideoFilterTypeID_None) || (fetchDisplayInfo.colorFormat == NDSColorFormat_BGR555_Rev)) + if (useDeposterize || (_cdv->GetPixelScaler() != VideoFilterTypeID_None)) { const bool willFilterOnGPU = _cdv->WillFilterOnGPU(); const bool shouldProcessDisplay[2] = { !fetchDisplayInfo.didPerformCustomRender[NDSDisplayID_Main] && fetchDisplayInfo.isDisplayEnabled[NDSDisplayID_Main] && (mode == ClientDisplayMode_Main || mode == ClientDisplayMode_Dual), @@ -978,13 +1232,6 @@ id cb = [[sharedData commandQueue] commandBufferWithUnretainedReferences]; id cce = [cb computeCommandEncoder]; - if (fetchDisplayInfo.colorFormat == NDSColorFormat_BGR555_Rev) - { - [sharedData convertFetch16To32UsingEncoder:cce - isMainNative:(fetchDisplayInfo.didPerformCustomRender[NDSDisplayID_Main]) ? NO : YES - isTouchNative:(fetchDisplayInfo.didPerformCustomRender[NDSDisplayID_Touch]) ? NO : YES]; - } - // Run the video source filters and the pixel scalers if (useDeposterize) { @@ -992,7 +1239,7 @@ if (shouldProcessDisplay[NDSDisplayID_Main]) { - [cce setTexture:[sharedData texDisplayFetch32NativeMain] atIndex:0]; + [cce setTexture:[sharedData texDisplaySrcTargetMain] atIndex:0]; [cce setTexture:_texDisplaySrcDeposterize[NDSDisplayID_Main][0] atIndex:1]; [cce dispatchThreadgroups:[sharedData deposterizeThreadGroupsPerGrid] threadsPerThreadgroup:[sharedData deposterizeThreadsPerGroup]]; @@ -1007,7 +1254,7 @@ if (shouldProcessDisplay[NDSDisplayID_Touch]) { - [cce setTexture:[sharedData texDisplayFetch32NativeTouch] atIndex:0]; + [cce setTexture:[sharedData texDisplaySrcTargetTouch] atIndex:0]; [cce setTexture:_texDisplaySrcDeposterize[NDSDisplayID_Touch][0] atIndex:1]; [cce dispatchThreadgroups:[sharedData deposterizeThreadGroupsPerGrid] threadsPerThreadgroup:[sharedData deposterizeThreadsPerGroup]]; @@ -1048,17 +1295,15 @@ } [cce endEncoding]; - [cb commit]; - // If the pixel scaler didn't run on the GPU, run the pixel scaler on the CPU after the command buffer commit. + // If the pixel scaler didn't already run on the GPU, then run the pixel scaler on the CPU. if ( (_cdv->GetPixelScaler() != VideoFilterTypeID_None) && !willFilterOnGPU ) { + id bce = [cb blitCommandEncoder]; + if (useDeposterize) { // Hybrid CPU/GPU-based path (may cause a performance hit on pixel download) - id cpuFilterSrcCB = [[sharedData commandQueue] commandBufferWithUnretainedReferences]; - id bce = [cpuFilterSrcCB blitCommandEncoder]; - if (shouldProcessDisplay[NDSDisplayID_Main]) { [bce copyFromTexture:_texDisplaySrcDeposterize[NDSDisplayID_Main][1] @@ -1088,9 +1333,6 @@ [bce synchronizeResource:[self bufCPUFilterSrcTouch]]; } - - [bce endEncoding]; - [cpuFilterSrcCB commit]; } pthread_mutex_lock(_cdv->GetMutexProcessPtr()); @@ -1105,9 +1347,6 @@ vfTouch->RunFilter(); } - id cpuFilterDstCB = [[sharedData commandQueue] commandBufferWithUnretainedReferences]; - id bce = [cpuFilterDstCB blitCommandEncoder]; - if (shouldProcessDisplay[NDSDisplayID_Main]) { [[self bufCPUFilterDstMain] didModifyRange:NSMakeRange(0, vfMain->GetDstWidth() * vfMain->GetDstHeight() * sizeof(uint32_t))]; @@ -1142,11 +1381,12 @@ _texDisplayOutput[NDSDisplayID_Touch] = [self texDisplayPixelScaleTouch]; } - [bce endEncoding]; - [cpuFilterDstCB commit]; - pthread_mutex_unlock(_cdv->GetMutexProcessPtr()); + + [bce endEncoding]; } + + [cb commit]; } // Update the texture coordinates @@ -1347,7 +1587,7 @@ MacMetalFetchObject::MacMetalFetchObject() { - _useCPUFilterPipeline = true; + _useDirectToCPUFilterPipeline = true; pthread_rwlock_init(&_srcCloneRWLock[NDSDisplayID_Main][0], NULL); pthread_rwlock_init(&_srcCloneRWLock[NDSDisplayID_Touch][0], NULL); @@ -1409,24 +1649,26 @@ void MacMetalFetchObject::SetFetchBuffers(const NDSDisplayInfo ¤tDisplayIn void MacMetalFetchObject::FetchFromBufferIndex(const u8 index) { MacClientSharedObject *sharedViewObject = (MacClientSharedObject *)this->_clientData; - this->_useCPUFilterPipeline = ([sharedViewObject numberViewsUsingCPUFiltering] > 0); + this->_useDirectToCPUFilterPipeline = ([sharedViewObject numberViewsUsingDirectToCPUFiltering] > 0); [(MetalDisplayViewSharedData *)this->_clientData fetchFromBufferIndex:index]; } void MacMetalFetchObject::_FetchNativeDisplayByID(const NDSDisplayID displayID, const u8 bufferIndex) { - if (this->_useCPUFilterPipeline) + if (this->_useDirectToCPUFilterPipeline) { + GPU->PostprocessDisplay(displayID, this->_fetchDisplayInfo[bufferIndex]); + pthread_rwlock_wrlock(&this->_srcCloneRWLock[displayID][bufferIndex]); - if (_fetchDisplayInfo[bufferIndex].pixelBytes == 2) + if (this->_fetchDisplayInfo[bufferIndex].pixelBytes == 2) { - ColorspaceConvertBuffer555To8888Opaque((const uint16_t *)_fetchDisplayInfo[bufferIndex].nativeBuffer[displayID], this->_srcNativeClone[displayID][bufferIndex], GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT); + ColorspaceConvertBuffer555To8888Opaque((const uint16_t *)this->_fetchDisplayInfo[bufferIndex].nativeBuffer[displayID], this->_srcNativeClone[displayID][bufferIndex], GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT); } else { - ColorspaceConvertBuffer888XTo8888Opaque((const uint32_t *)_fetchDisplayInfo[bufferIndex].nativeBuffer[displayID], this->_srcNativeClone[displayID][bufferIndex], GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT); + ColorspaceConvertBuffer888XTo8888Opaque((const uint32_t *)this->_fetchDisplayInfo[bufferIndex].nativeBuffer[displayID], this->_srcNativeClone[displayID][bufferIndex], GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT); } pthread_rwlock_unlock(&this->_srcCloneRWLock[displayID][bufferIndex]); diff --git a/desmume/src/frontend/cocoa/userinterface/MacMetalDisplayViewShaders.metal b/desmume/src/frontend/cocoa/userinterface/MacMetalDisplayViewShaders.metal index 9848d0422..a1f0edea6 100644 --- a/desmume/src/frontend/cocoa/userinterface/MacMetalDisplayViewShaders.metal +++ b/desmume/src/frontend/cocoa/userinterface/MacMetalDisplayViewShaders.metal @@ -58,6 +58,8 @@ float DistYCbCr(const float3 pixA, const float3 pixB); bool IsPixEqual(const float3 pixA, const float3 pixB); bool IsBlendingNeeded(const int4 blend); +float3 nds_apply_master_brightness(const float3 inColor, const uchar mode, const float intensity); + constexpr sampler genSampler = sampler(coord::pixel, address::clamp_to_edge, filter::nearest); constexpr sampler outputSamplerBilinear = sampler(coord::pixel, address::clamp_to_edge, filter::linear); @@ -395,22 +397,104 @@ fragment float4 output_filter_lanczos3(const DisplayVtx vtx [[stage_in]], const return float4(outFragment.rgb, 1.0f); } -#pragma mark Conversion Filters +#pragma mark NDS Emulation Functions -//--------------------------------------- -// Input Pixel Mapping: 00 -// -// Output Pixel Mapping: 00 -kernel void src16_unpack_unorm1555_to_unorm8888(const uint2 position [[thread_position_in_grid]], - const texture2d inTexture [[texture(0)]], - texture2d outTexture [[texture(1)]]) +kernel void nds_fetch555(const uint2 position [[thread_position_in_grid]], + const constant uchar *brightnessMode [[buffer(0)]], + const constant uchar *brightnessIntensity [[buffer(1)]], + const texture2d inTexture [[texture(0)]], + texture2d outTexture [[texture(1)]]) +{ + const uint h = inTexture.get_height(); + + if ( (position.x > inTexture.get_width() - 1) || (position.y > h - 1) ) + { + return; + } + + const float4 inColor = unpack_unorm1555_to_unorm8888( (ushort)inTexture.read(position).r ); + float3 outColor = inColor.rgb; + + const uint line = uint(((float)position.y + 0.01f) / ((float)h / 192.0f)); + outColor = nds_apply_master_brightness(outColor, brightnessMode[line], (float)brightnessIntensity[line] / 16.0f); + + outTexture.write(float4(outColor, 1.0f), position); +} + +kernel void nds_fetch555ConvertOnly(const uint2 position [[thread_position_in_grid]], + const texture2d inTexture [[texture(0)]], + texture2d outTexture [[texture(1)]]) { if ( (position.x > inTexture.get_width() - 1) || (position.y > inTexture.get_height() - 1) ) { return; } - outTexture.write( unpack_unorm1555_to_unorm8888( (ushort)inTexture.read(position).r ), position ); + const float4 outColor = unpack_unorm1555_to_unorm8888( (ushort)inTexture.read(position).r ); + outTexture.write(float4(outColor.rgb, 1.0f), position); +} + +kernel void nds_fetch666(const uint2 position [[thread_position_in_grid]], + const constant uchar *brightnessMode [[buffer(0)]], + const constant uchar *brightnessIntensity [[buffer(1)]], + const texture2d inTexture [[texture(0)]], + texture2d outTexture [[texture(1)]]) +{ + const uint h = inTexture.get_height(); + + if ( (position.x > inTexture.get_width() - 1) || (position.y > h - 1) ) + { + return; + } + + const float4 inColor = inTexture.read(position); + float3 outColor = inColor.rgb * float3(255.0f/63.0f); + + const uint line = uint(((float)position.y + 0.01f) / ((float)h / 192.0f)); + outColor = nds_apply_master_brightness(outColor, brightnessMode[line], (float)brightnessIntensity[line] / 16.0f); + + outTexture.write(float4(outColor, 1.0f), position); +} + +kernel void nds_fetch888(const uint2 position [[thread_position_in_grid]], + const constant uchar *brightnessMode [[buffer(0)]], + const constant uchar *brightnessIntensity [[buffer(1)]], + const texture2d inTexture [[texture(0)]], + texture2d outTexture [[texture(1)]]) +{ + const uint h = inTexture.get_height(); + + if ( (position.x > inTexture.get_width() - 1) || (position.y > h - 1) ) + { + return; + } + + const float4 inColor = inTexture.read(position); + float3 outColor = inColor.rgb; + + const uint line = uint(((float)position.y + 0.01f) / ((float)h / 192.0f)); + outColor = nds_apply_master_brightness(outColor, brightnessMode[line], (float)brightnessIntensity[line] / 16.0f); + + outTexture.write(float4(outColor, 1.0f), position); +} + +float3 nds_apply_master_brightness(const float3 inColor, const uchar mode, const float intensity) +{ + switch (mode) + { + case 1: + return (inColor + ((1.0f - inColor) * intensity)); + break; + + case 2: + return (inColor - (inColor * intensity)); + break; + + default: + break; + } + + return inColor; } #pragma mark Source Filters diff --git a/desmume/src/frontend/cocoa/userinterface/MacOGLDisplayView.mm b/desmume/src/frontend/cocoa/userinterface/MacOGLDisplayView.mm index 046f59e31..178a7ac6b 100644 --- a/desmume/src/frontend/cocoa/userinterface/MacOGLDisplayView.mm +++ b/desmume/src/frontend/cocoa/userinterface/MacOGLDisplayView.mm @@ -199,7 +199,7 @@ void MacOGLClientFetchObject::SetFetchBuffers(const NDSDisplayInfo ¤tDispl void MacOGLClientFetchObject::FetchFromBufferIndex(const u8 index) { MacClientSharedObject *sharedViewObject = (MacClientSharedObject *)this->_clientData; - this->_useCPUFilterPipeline = ([sharedViewObject numberViewsUsingCPUFiltering] > 0); + this->_useDirectToCPUFilterPipeline = ([sharedViewObject numberViewsUsingDirectToCPUFiltering] > 0); pthread_rwlock_rdlock([sharedViewObject rwlockFramebufferAtIndex:index]); diff --git a/desmume/src/frontend/cocoa/userinterface/appDelegate.mm b/desmume/src/frontend/cocoa/userinterface/appDelegate.mm index 63ac0b078..461aad793 100644 --- a/desmume/src/frontend/cocoa/userinterface/appDelegate.mm +++ b/desmume/src/frontend/cocoa/userinterface/appDelegate.mm @@ -180,9 +180,8 @@ // Init the DS emulation core. CocoaDSCore *newCore = [[[CocoaDSCore alloc] init] autorelease]; MacClientSharedObject *sharedViewObject = [[newCore cdsGPU] sharedData]; - [NSThread detachNewThreadSelector:@selector(runThread:) toTarget:sharedViewObject withObject:nil]; - // Wait until the SPU is finished starting up. + [NSThread detachNewThreadSelector:@selector(runThread:) toTarget:sharedViewObject withObject:nil]; while ([sharedViewObject thread] == nil) { [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01]]; @@ -206,8 +205,6 @@ // Start up the threads for our outputs. [NSThread detachNewThreadSelector:@selector(runThread:) toTarget:newSpeaker withObject:nil]; - - // Wait until the SPU is finished starting up. while ([newSpeaker thread] == nil) { [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01]];