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.
This commit is contained in:
rogerman 2017-02-22 14:14:22 -08:00
parent b553ff917b
commit 093ce4b05d
13 changed files with 703 additions and 331 deletions

View File

@ -1382,7 +1382,7 @@ void GPUEngineBase::UpdatePropertiesWithoutRender(const u16 l)
} }
} }
void GPUEngineBase::FramebufferPostprocess() void GPUEngineBase::LastLineProcess()
{ {
this->RefreshAffineStartRegs(); this->RefreshAffineStartRegs();
} }
@ -4024,69 +4024,66 @@ void GPUEngineBase::SetWillApplyMasterBrightnessPerScanline(bool willApply)
this->_willApplyMasterBrightnessPerScanline = willApply; this->_willApplyMasterBrightnessPerScanline = willApply;
} }
template <NDSColorFormat OUTPUTFORMAT> void GPUEngineBase::UpdateMasterBrightnessDisplayInfo(NDSDisplayInfo &mutableInfo)
void GPUEngineBase::ApplyMasterBrightness()
{ {
NDSDisplayInfo &dispInfoMutable = (NDSDisplayInfo &)GPU->GetDisplayInfo();
const bool isMasterBrightnessAutoApplied = GPU->GetWillAutoApplyMasterBrightness();
if (this->_willApplyMasterBrightnessPerScanline) if (this->_willApplyMasterBrightnessPerScanline)
{ {
const bool isNativeSize = (this->nativeLineOutputCount == GPU_FRAMEBUFFER_NATIVE_HEIGHT);
bool needsApply = false; bool needsApply = false;
for (size_t line = 0; line < GPU_FRAMEBUFFER_NATIVE_HEIGHT; line++) for (size_t line = 0; line < GPU_FRAMEBUFFER_NATIVE_HEIGHT; line++)
{ {
const GPUEngineCompositorInfo &compInfo = this->_currentCompositorInfo[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)); needsApply = true;
const size_t pixCount = (isNativeSize) ? GPU_FRAMEBUFFER_NATIVE_WIDTH : compInfo.line.pixelCount;
this->ApplyMasterBrightness<OUTPUTFORMAT, false>(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;
}
} }
dispInfoMutable.masterBrightnessMode[this->_targetDisplayID][line] = compInfo.renderState.masterBrightnessMode; mutableInfo.masterBrightnessMode[this->_targetDisplayID][line] = compInfo.renderState.masterBrightnessMode;
dispInfoMutable.masterBrightnessIntensity[this->_targetDisplayID][line] = compInfo.renderState.masterBrightnessIntensity; mutableInfo.masterBrightnessIntensity[this->_targetDisplayID][line] = compInfo.renderState.masterBrightnessIntensity;
} }
dispInfoMutable.needApplyMasterBrightness[this->_targetDisplayID] = dispInfoMutable.needApplyMasterBrightness[this->_targetDisplayID] && needsApply; mutableInfo.needApplyMasterBrightness[this->_targetDisplayID] = needsApply;
} }
else else
{ {
const GPUEngineCompositorInfo &compInfo = this->_currentCompositorInfo[0]; const GPUEngineCompositorInfo &compInfo = this->_currentCompositorInfo[0];
mutableInfo.needApplyMasterBrightness[this->_targetDisplayID] = (compInfo.renderState.masterBrightnessIntensity != 0) && ((compInfo.renderState.masterBrightnessMode == GPUMasterBrightMode_Up) || (compInfo.renderState.masterBrightnessMode == GPUMasterBrightMode_Down));
if (isMasterBrightnessAutoApplied)
{
this->ApplyMasterBrightness<OUTPUTFORMAT, false>(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));
}
for (size_t line = 0; line < GPU_FRAMEBUFFER_NATIVE_HEIGHT; line++) for (size_t line = 0; line < GPU_FRAMEBUFFER_NATIVE_HEIGHT; line++)
{ {
dispInfoMutable.masterBrightnessMode[this->_targetDisplayID][line] = compInfo.renderState.masterBrightnessMode; mutableInfo.masterBrightnessMode[this->_targetDisplayID][line] = compInfo.renderState.masterBrightnessMode;
dispInfoMutable.masterBrightnessIntensity[this->_targetDisplayID][line] = compInfo.renderState.masterBrightnessIntensity; mutableInfo.masterBrightnessIntensity[this->_targetDisplayID][line] = compInfo.renderState.masterBrightnessIntensity;
} }
} }
} }
template <NDSColorFormat OUTPUTFORMAT>
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<OUTPUTFORMAT, false>(dstColorLine,
pixCount,
(GPUMasterBrightMode)displayInfo.masterBrightnessMode[this->_targetDisplayID][line],
displayInfo.masterBrightnessIntensity[this->_targetDisplayID][line]);
}
}
else
{
this->ApplyMasterBrightness<OUTPUTFORMAT, false>(displayInfo.renderedBuffer[this->_targetDisplayID],
displayInfo.renderedWidth[this->_targetDisplayID] * displayInfo.renderedHeight[this->_targetDisplayID],
(GPUMasterBrightMode)displayInfo.masterBrightnessMode[this->_targetDisplayID][0],
displayInfo.masterBrightnessIntensity[this->_targetDisplayID][0]);
}
}
template <NDSColorFormat OUTPUTFORMAT, bool ISFULLINTENSITYHINT> template <NDSColorFormat OUTPUTFORMAT, bool ISFULLINTENSITYHINT>
void GPUEngineBase::ApplyMasterBrightness(void *dst, const size_t pixCount, const GPUMasterBrightMode mode, const u8 intensity) 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; this->renderedBuffer = this->customBuffer;
} }
void GPUEngineBase::ResolveRGB666ToRGB888() void GPUEngineBase::ResolveToCustomFramebuffer(NDSDisplayInfo &mutableInfo)
{ {
ColorspaceConvertBuffer6665To8888<false, false>((u32 *)this->renderedBuffer, (u32 *)this->renderedBuffer, this->renderedWidth * this->renderedHeight); if (mutableInfo.didPerformCustomRender[this->_targetDisplayID])
}
void GPUEngineBase::ResolveToCustomFramebuffer()
{
const NDSDisplayInfo &dispInfo = GPU->GetDisplayInfo();
if (this->nativeLineOutputCount == 0)
{ {
return; 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++) for (size_t y = 0; y < GPU_FRAMEBUFFER_NATIVE_HEIGHT; y++)
{ {
this->_LineColorCopy<false, true, true, false, 2>(this->customBuffer, this->nativeBuffer, y); this->_LineColorCopy<false, true, true, false, 2>(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++) for (size_t y = 0; y < GPU_FRAMEBUFFER_NATIVE_HEIGHT; y++)
{ {
this->_LineColorCopy<false, true, true, false, 4>(this->customBuffer, this->nativeBuffer, y); this->_LineColorCopy<false, true, true, false, 4>(mutableInfo.customBuffer[this->_targetDisplayID], mutableInfo.nativeBuffer[this->_targetDisplayID], y);
} }
} }
} }
else 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() 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; this->_IORegisterMap->DISPCAPCNT.CaptureEnable = 0;
DISP_FIFOreset(); DISP_FIFOreset();
@ -6783,17 +6773,16 @@ GPUSubsystem::GPUSubsystem()
_engineMain = GPUEngineA::Allocate(); _engineMain = GPUEngineA::Allocate();
_engineSub = GPUEngineB::Allocate(); _engineSub = GPUEngineB::Allocate();
_displayMain = new NDSDisplay(NDSDisplayID_Main); _display[NDSDisplayID_Main] = new NDSDisplay(NDSDisplayID_Main);
_displayMain->SetEngine(_engineMain); _display[NDSDisplayID_Main]->SetEngine(_engineMain);
_displayTouch = new NDSDisplay(NDSDisplayID_Touch); _display[NDSDisplayID_Touch] = new NDSDisplay(NDSDisplayID_Touch);
_displayTouch->SetEngine(_engineSub); _display[NDSDisplayID_Touch]->SetEngine(_engineSub);
_videoFrameCount = 0; _videoFrameCount = 0;
_render3DFrameCount = 0; _render3DFrameCount = 0;
_frameNeedsFinish = false; _frameNeedsFinish = false;
_willFrameSkip = false; _willFrameSkip = false;
_willAutoApplyMasterBrightness = true; _willPostprocessDisplays = true;
_willAutoConvertRGB666ToRGB888 = true;
_willAutoResolveToCustomBuffer = true; _willAutoResolveToCustomBuffer = true;
//TODO OSD //TODO OSD
@ -6806,7 +6795,6 @@ GPUSubsystem::GPUSubsystem()
_displayInfo.isCustomSizeRequested = false; _displayInfo.isCustomSizeRequested = false;
_displayInfo.customWidth = GPU_FRAMEBUFFER_NATIVE_WIDTH; _displayInfo.customWidth = GPU_FRAMEBUFFER_NATIVE_WIDTH;
_displayInfo.customHeight = GPU_FRAMEBUFFER_NATIVE_HEIGHT; _displayInfo.customHeight = GPU_FRAMEBUFFER_NATIVE_HEIGHT;
_displayInfo.isMasterBrightnessAutoApplyRequested = true;
_customVRAM = NULL; _customVRAM = NULL;
_customVRAMBlank = NULL; _customVRAMBlank = NULL;
@ -6854,8 +6842,8 @@ GPUSubsystem::~GPUSubsystem()
free_aligned(_gpuDstToSrcSSSE3_u16_8e); free_aligned(_gpuDstToSrcSSSE3_u16_8e);
_gpuDstToSrcSSSE3_u16_8e = NULL; _gpuDstToSrcSSSE3_u16_8e = NULL;
delete _displayMain; delete _display[NDSDisplayID_Main];
delete _displayTouch; delete _display[NDSDisplayID_Touch];
_engineMain->FinalizeAndDeallocate(); _engineMain->FinalizeAndDeallocate();
_engineSub->FinalizeAndDeallocate(); _engineSub->FinalizeAndDeallocate();
@ -6912,8 +6900,8 @@ void GPUSubsystem::Reset()
this->_displayInfo.renderedHeight[NDSDisplayID_Touch] = GPU_FRAMEBUFFER_NATIVE_HEIGHT; this->_displayInfo.renderedHeight[NDSDisplayID_Touch] = GPU_FRAMEBUFFER_NATIVE_HEIGHT;
this->_displayInfo.renderedBuffer[NDSDisplayID_Touch] = this->_displayInfo.nativeBuffer[NDSDisplayID_Touch]; this->_displayInfo.renderedBuffer[NDSDisplayID_Touch] = this->_displayInfo.nativeBuffer[NDSDisplayID_Touch];
this->_displayMain->SetEngineByID(GPUEngineID_Main); this->_display[NDSDisplayID_Main]->SetEngineByID(GPUEngineID_Main);
this->_displayTouch->SetEngineByID(GPUEngineID_Sub); this->_display[NDSDisplayID_Touch]->SetEngineByID(GPUEngineID_Sub);
gfx3d_reset(); gfx3d_reset();
this->_engineMain->Reset(); this->_engineMain->Reset();
@ -6999,14 +6987,14 @@ void GPUSubsystem::UpdateRenderProperties()
this->_engineSub->renderedWidth = GPU_FRAMEBUFFER_NATIVE_WIDTH; this->_engineSub->renderedWidth = GPU_FRAMEBUFFER_NATIVE_WIDTH;
this->_engineSub->renderedHeight = GPU_FRAMEBUFFER_NATIVE_HEIGHT; 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.nativeBuffer[NDSDisplayID_Main] = mainEngine->nativeBuffer;
this->_displayInfo.customBuffer[NDSDisplayID_Main] = mainEngine->customBuffer; this->_displayInfo.customBuffer[NDSDisplayID_Main] = mainEngine->customBuffer;
this->_displayInfo.renderedBuffer[NDSDisplayID_Main] = mainEngine->renderedBuffer; this->_displayInfo.renderedBuffer[NDSDisplayID_Main] = mainEngine->renderedBuffer;
this->_displayInfo.renderedWidth[NDSDisplayID_Main] = mainEngine->renderedWidth; this->_displayInfo.renderedWidth[NDSDisplayID_Main] = mainEngine->renderedWidth;
this->_displayInfo.renderedHeight[NDSDisplayID_Main] = mainEngine->renderedHeight; 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.nativeBuffer[NDSDisplayID_Touch] = touchEngine->nativeBuffer;
this->_displayInfo.customBuffer[NDSDisplayID_Touch] = touchEngine->customBuffer; this->_displayInfo.customBuffer[NDSDisplayID_Touch] = touchEngine->customBuffer;
this->_displayInfo.renderedBuffer[NDSDisplayID_Touch] = touchEngine->renderedBuffer; this->_displayInfo.renderedBuffer[NDSDisplayID_Touch] = touchEngine->renderedBuffer;
@ -7067,11 +7055,6 @@ u32 GPUSubsystem::GetFPSRender3D() const
return this->_render3DFrameCount; return this->_render3DFrameCount;
} }
void GPUSubsystem::SetDisplayDidCustomRender(NDSDisplayID displayID, bool theState)
{
this->_displayInfo.didPerformCustomRender[displayID] = theState;
}
GPUEngineA* GPUSubsystem::GetEngineMain() GPUEngineA* GPUSubsystem::GetEngineMain()
{ {
return this->_engineMain; return this->_engineMain;
@ -7084,12 +7067,12 @@ GPUEngineB* GPUSubsystem::GetEngineSub()
NDSDisplay* GPUSubsystem::GetDisplayMain() NDSDisplay* GPUSubsystem::GetDisplayMain()
{ {
return this->_displayMain; return this->_display[NDSDisplayID_Main];
} }
NDSDisplay* GPUSubsystem::GetDisplayTouch() NDSDisplay* GPUSubsystem::GetDisplayTouch()
{ {
return this->_displayTouch; return this->_display[NDSDisplayID_Touch];
} }
size_t GPUSubsystem::GetCustomFramebufferWidth() const size_t GPUSubsystem::GetCustomFramebufferWidth() const
@ -7275,14 +7258,14 @@ void GPUSubsystem::_AllocateFramebuffers(NDSColorFormat outputFormat, size_t w,
this->_engineMain->SetCustomFramebufferSize(w, h); this->_engineMain->SetCustomFramebufferSize(w, h);
this->_engineSub->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.nativeBuffer[NDSDisplayID_Main] = mainEngine->nativeBuffer;
this->_displayInfo.customBuffer[NDSDisplayID_Main] = mainEngine->customBuffer; this->_displayInfo.customBuffer[NDSDisplayID_Main] = mainEngine->customBuffer;
this->_displayInfo.renderedBuffer[NDSDisplayID_Main] = mainEngine->renderedBuffer; this->_displayInfo.renderedBuffer[NDSDisplayID_Main] = mainEngine->renderedBuffer;
this->_displayInfo.renderedWidth[NDSDisplayID_Main] = mainEngine->renderedWidth; this->_displayInfo.renderedWidth[NDSDisplayID_Main] = mainEngine->renderedWidth;
this->_displayInfo.renderedHeight[NDSDisplayID_Main] = mainEngine->renderedHeight; 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.nativeBuffer[NDSDisplayID_Touch] = touchEngine->nativeBuffer;
this->_displayInfo.customBuffer[NDSDisplayID_Touch] = touchEngine->customBuffer; this->_displayInfo.customBuffer[NDSDisplayID_Touch] = touchEngine->customBuffer;
this->_displayInfo.renderedBuffer[NDSDisplayID_Touch] = touchEngine->renderedBuffer; 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]); 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->_willPostprocessDisplays = willPostprocess;
this->_displayInfo.isMasterBrightnessAutoApplyRequested = willAutoApply;
} }
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<false, false>((u32 *)mutableInfo.renderedBuffer[displayID], (u32 *)mutableInfo.renderedBuffer[displayID], mutableInfo.renderedWidth[displayID] * mutableInfo.renderedHeight[displayID]);
}
if (mutableInfo.needApplyMasterBrightness[displayID])
{
this->_display[displayID]->GetEngine()->ApplyMasterBrightness<NDSColorFormat_BGR888_Rev>(mutableInfo);
}
}
else
{
if (mutableInfo.needApplyMasterBrightness[displayID])
{
switch (mutableInfo.colorFormat)
{
case NDSColorFormat_BGR555_Rev:
this->_display[displayID]->GetEngine()->ApplyMasterBrightness<NDSColorFormat_BGR555_Rev>(mutableInfo);
break;
case NDSColorFormat_BGR666_Rev:
this->_display[displayID]->GetEngine()->ApplyMasterBrightness<NDSColorFormat_BGR666_Rev>(mutableInfo);
break;
case NDSColorFormat_BGR888_Rev:
this->_display[displayID]->GetEngine()->ApplyMasterBrightness<NDSColorFormat_BGR888_Rev>(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 bool GPUSubsystem::GetWillAutoResolveToCustomBuffer() const
@ -7450,8 +7483,8 @@ void GPUSubsystem::RenderLine(const size_t l)
if (l == 191) if (l == 191)
{ {
this->_engineMain->FramebufferPostprocess(); this->_engineMain->LastLineProcess();
this->_engineSub->FramebufferPostprocess(); this->_engineSub->LastLineProcess();
this->_UpdateFPSRender3D(); this->_UpdateFPSRender3D();
@ -7463,55 +7496,35 @@ void GPUSubsystem::RenderLine(const size_t l)
this->_engineSub->ResolveCustomRendering<OUTPUTFORMAT>(); this->_engineSub->ResolveCustomRendering<OUTPUTFORMAT>();
} }
this->_displayInfo.didPerformCustomRender[NDSDisplayID_Main] = (this->_displayMain->GetEngine()->nativeLineOutputCount < GPU_FRAMEBUFFER_NATIVE_HEIGHT); this->_displayInfo.didPerformCustomRender[NDSDisplayID_Main] = (this->_display[NDSDisplayID_Main]->GetEngine()->nativeLineOutputCount < GPU_FRAMEBUFFER_NATIVE_HEIGHT);
this->_displayInfo.renderedBuffer[NDSDisplayID_Main] = this->_displayMain->GetEngine()->renderedBuffer; this->_displayInfo.renderedBuffer[NDSDisplayID_Main] = this->_display[NDSDisplayID_Main]->GetEngine()->renderedBuffer;
this->_displayInfo.renderedWidth[NDSDisplayID_Main] = this->_displayMain->GetEngine()->renderedWidth; this->_displayInfo.renderedWidth[NDSDisplayID_Main] = this->_display[NDSDisplayID_Main]->GetEngine()->renderedWidth;
this->_displayInfo.renderedHeight[NDSDisplayID_Main] = this->_displayMain->GetEngine()->renderedHeight; 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.didPerformCustomRender[NDSDisplayID_Touch] = (this->_display[NDSDisplayID_Touch]->GetEngine()->nativeLineOutputCount < GPU_FRAMEBUFFER_NATIVE_HEIGHT);
this->_displayInfo.renderedBuffer[NDSDisplayID_Touch] = this->_displayTouch->GetEngine()->renderedBuffer; this->_displayInfo.renderedBuffer[NDSDisplayID_Touch] = this->_display[NDSDisplayID_Touch]->GetEngine()->renderedBuffer;
this->_displayInfo.renderedWidth[NDSDisplayID_Touch] = this->_displayTouch->GetEngine()->renderedWidth; this->_displayInfo.renderedWidth[NDSDisplayID_Touch] = this->_display[NDSDisplayID_Touch]->GetEngine()->renderedWidth;
this->_displayInfo.renderedHeight[NDSDisplayID_Touch] = this->_displayTouch->GetEngine()->renderedHeight; this->_displayInfo.renderedHeight[NDSDisplayID_Touch] = this->_display[NDSDisplayID_Touch]->GetEngine()->renderedHeight;
this->_displayInfo.isDisplayEnabled[NDSDisplayID_Main] = CommonSettings.showGpu.main; this->_displayInfo.isDisplayEnabled[NDSDisplayID_Main] = CommonSettings.showGpu.screens[this->_display[NDSDisplayID_Main]->GetEngineID()];
this->_displayInfo.isDisplayEnabled[NDSDisplayID_Touch] = CommonSettings.showGpu.sub; this->_displayInfo.isDisplayEnabled[NDSDisplayID_Touch] = CommonSettings.showGpu.screens[this->_display[NDSDisplayID_Touch]->GetEngineID()];
this->_displayInfo.needApplyMasterBrightness[NDSDisplayID_Main] = !this->_displayInfo.isMasterBrightnessAutoApplyRequested;
this->_displayInfo.needApplyMasterBrightness[NDSDisplayID_Touch] = !this->_displayInfo.isMasterBrightnessAutoApplyRequested;
if (CommonSettings.showGpu.main) this->_displayInfo.needConvertColorFormat[NDSDisplayID_Main] = (OUTPUTFORMAT == NDSColorFormat_BGR666_Rev);
{ this->_displayInfo.needConvertColorFormat[NDSDisplayID_Touch] = (OUTPUTFORMAT == NDSColorFormat_BGR666_Rev);
this->_engineMain->ApplyMasterBrightness<OUTPUTFORMAT>();
}
else
{
if (this->_willAutoApplyMasterBrightness)
{
memset(this->_engineMain->renderedBuffer, 0, this->_engineMain->renderedWidth * this->_engineMain->renderedHeight * this->_displayInfo.pixelBytes);
}
}
if (CommonSettings.showGpu.sub) this->_engineMain->UpdateMasterBrightnessDisplayInfo(this->_displayInfo);
{ this->_engineSub->UpdateMasterBrightnessDisplayInfo(this->_displayInfo);
this->_engineSub->ApplyMasterBrightness<OUTPUTFORMAT>();
}
else
{
if (this->_willAutoApplyMasterBrightness)
{
memset(this->_engineSub->renderedBuffer, 0, this->_engineSub->renderedWidth * this->_engineSub->renderedHeight * this->_displayInfo.pixelBytes);
}
}
if ( (OUTPUTFORMAT == NDSColorFormat_BGR666_Rev) && this->_willAutoConvertRGB666ToRGB888 ) if (this->_willPostprocessDisplays)
{ {
this->_engineMain->ResolveRGB666ToRGB888(); this->PostprocessDisplay(NDSDisplayID_Main, this->_displayInfo);
this->_engineSub->ResolveRGB666ToRGB888(); this->PostprocessDisplay(NDSDisplayID_Touch, this->_displayInfo);
} }
if (this->_willAutoResolveToCustomBuffer) if (this->_willAutoResolveToCustomBuffer)
{ {
this->_engineMain->ResolveToCustomFramebuffer(); this->ResolveDisplayToCustomFramebuffer(NDSDisplayID_Main, this->_displayInfo);
this->_engineSub->ResolveToCustomFramebuffer(); this->ResolveDisplayToCustomFramebuffer(NDSDisplayID_Touch, this->_displayInfo);
} }
} }

View File

@ -1073,28 +1073,19 @@ typedef struct
// Changed by calling GPUSubsystem::SetColorFormat() or GPUSubsystem::SetFramebufferSize(). // Changed by calling GPUSubsystem::SetColorFormat() or GPUSubsystem::SetFramebufferSize().
void *masterFramebufferHead; // Pointer to the head of the master framebuffer memory block that encompasses all buffers. 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(). // Changed by calling GPUEngineBase::SetEnableState().
bool isDisplayEnabled[2]; // Reports that a particular display has been enabled or disabled by the user. 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. u8 bufferIndex; // Index of this frame's buffer set.
void *masterNativeBuffer; // Pointer to the head of the master native buffer. void *masterNativeBuffer; // Pointer to the head of the master native buffer.
void *masterCustomBuffer; // Pointer to the head of the master custom buffer. void *masterCustomBuffer; // Pointer to the head of the master custom buffer.
// If GPUSubsystem::GetWillAutoResolveToCustomBuffer() would return true, or if // If GPUSubsystem::GetWillAutoResolveToCustomBuffer() would return true, or if
// GPUEngineBase::ResolveToCustomFramebuffer() is called, then this buffer is used as the target // GPUSubsystem::ResolveDisplayToCustomFramebuffer() is called, then this buffer is used as the
// buffer for resolving any native-sized renders. // target buffer for resolving any native-sized renders.
void *nativeBuffer[2]; // Pointer to the display's native size framebuffer. void *nativeBuffer[2]; // Pointer to the display's native size framebuffer.
void *customBuffer[2]; // Pointer to the display's custom 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. // true - The display performed a custom-sized render.
// false - The display performed a native-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 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. 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; } NDSDisplayInfo;
#define VRAM_NO_3D_USAGE 0xFF #define VRAM_NO_3D_USAGE 0xFF
@ -1453,7 +1448,7 @@ public:
void ParseAllRegisters(); void ParseAllRegisters();
void UpdatePropertiesWithoutRender(const u16 l); void UpdatePropertiesWithoutRender(const u16 l);
void FramebufferPostprocess(); void LastLineProcess();
u8 vramBlockOBJIndex; u8 vramBlockOBJIndex;
@ -1502,7 +1497,8 @@ public:
bool WillApplyMasterBrightnessPerScanline() const; bool WillApplyMasterBrightnessPerScanline() const;
void SetWillApplyMasterBrightnessPerScanline(bool willApply); void SetWillApplyMasterBrightnessPerScanline(bool willApply);
template<NDSColorFormat OUTPUTFORMAT> void ApplyMasterBrightness(); void UpdateMasterBrightnessDisplayInfo(NDSDisplayInfo &mutableInfo);
template<NDSColorFormat OUTPUTFORMAT> void ApplyMasterBrightness(const NDSDisplayInfo &displayInfo);
template<NDSColorFormat OUTPUTFORMAT, bool ISFULLINTENSITYHINT> void ApplyMasterBrightness(void *dst, const size_t pixCount, const GPUMasterBrightMode mode, const u8 intensity); template<NDSColorFormat OUTPUTFORMAT, bool ISFULLINTENSITYHINT> void ApplyMasterBrightness(void *dst, const size_t pixCount, const GPUMasterBrightMode mode, const u8 intensity);
const BGLayerInfo& GetBGLayerInfoByID(const GPULayerID layerID); const BGLayerInfo& GetBGLayerInfoByID(const GPULayerID layerID);
@ -1519,8 +1515,7 @@ public:
virtual void SetCustomFramebufferSize(size_t w, size_t h); virtual void SetCustomFramebufferSize(size_t w, size_t h);
template<NDSColorFormat OUTPUTFORMAT> void ResolveCustomRendering(); template<NDSColorFormat OUTPUTFORMAT> void ResolveCustomRendering();
void ResolveRGB666ToRGB888(); void ResolveToCustomFramebuffer(NDSDisplayInfo &mutableInfo);
void ResolveToCustomFramebuffer();
void REG_DISPx_pack_test(); void REG_DISPx_pack_test();
}; };
@ -1585,7 +1580,7 @@ public:
bool WillDisplayCapture(const size_t l); bool WillDisplayCapture(const size_t l);
bool VerifyVRAMLineDidChange(const size_t blockID, const size_t l); bool VerifyVRAMLineDidChange(const size_t blockID, const size_t l);
void FramebufferPostprocess(); void LastLineProcess();
virtual void Reset(); virtual void Reset();
@ -1655,15 +1650,13 @@ private:
GPUEngineA *_engineMain; GPUEngineA *_engineMain;
GPUEngineB *_engineSub; GPUEngineB *_engineSub;
NDSDisplay *_displayMain; NDSDisplay *_display[2];
NDSDisplay *_displayTouch;
u32 _videoFrameCount; // Internal variable that increments when a video frame is completed. Resets every 60 video frames. 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. u32 _render3DFrameCount; // The current 3D rendering frame count, saved to this variable once every 60 video frames.
bool _frameNeedsFinish; bool _frameNeedsFinish;
bool _willFrameSkip; bool _willFrameSkip;
bool _willAutoApplyMasterBrightness; bool _willPostprocessDisplays;
bool _willAutoConvertRGB666ToRGB888;
bool _willAutoResolveToCustomBuffer; bool _willAutoResolveToCustomBuffer;
u16 *_customVRAM; u16 *_customVRAM;
u16 *_customVRAMBlank; 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 const NDSDisplayInfo& GetDisplayInfo(); // Frontends need to call this whenever they need to read the video buffers from the emulator core
u32 GetFPSRender3D() const; u32 GetFPSRender3D() const;
void SetDisplayDidCustomRender(NDSDisplayID displayID, bool theState);
GPUEngineA* GetEngineMain(); GPUEngineA* GetEngineMain();
GPUEngineB* GetEngineSub(); GPUEngineB* GetEngineSub();
NDSDisplay* GetDisplayMain(); NDSDisplay* GetDisplayMain();
@ -1709,25 +1700,22 @@ public:
void SetWillFrameSkip(const bool willFrameSkip); void SetWillFrameSkip(const bool willFrameSkip);
void UpdateRenderProperties(); void UpdateRenderProperties();
// By default, the output framebuffer will have the master brightness applied before // By default, the displays will automatically perform certain postprocessing steps on the
// the DidFrameEnd event. The master brightness is applied using the CPU. // CPU before the DidFrameEnd event.
// //
// To turn off this behavior, call SetWillAutoApplyMasterBrightness() and pass a value // To turn off this behavior, call SetWillPostprocessDisplays() and pass a value of "false".
// of "false". This can be useful if the client wants to apply the master brightness // This can be useful if the client wants to perform these postprocessing steps itself, for
// itself, for example, if a client applies it on the GPU. // example, if a client performs them on another thread or 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 SetWillAutoConvertRGB666ToRGB888() and pass a value // If automatic postprocessing is turned off, clients can still manually perform the
// of "false". This can be useful if the client wants to do its own post-processing // postprocessing steps on the CPU by calling PostprocessDisplay().
// 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). // The postprocessing steps that are performed are:
bool GetWillAutoConvertRGB666ToRGB888() const; // - Converting an RGB666 formatted framebuffer to RGB888 format.
void SetWillAutoConvertRGB666ToRGB888(const bool willAutoConvert); // - 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 // 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 // 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 // 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. // the NDS video displays, require that they read from only a single buffer.
// //
// However, if SetWillAutoResolveToCustomBuffer() is passed "false", then the // However, if SetWillAutoResolveToCustomBuffer() is passed "false", then the frontend
// frontend becomes responsible for calling GetDisplayInfo() and reading the native // becomes responsible for calling GetDisplayInfo() and reading the native and custom buffers
// and custom buffers properly for each display. If a single buffer is still needed // properly for each display. If a single buffer is still needed for certain cases, then the
// for certain cases, then the frontend must manually call // frontend must manually call ResolveDisplayToCustomFramebuffer() for each display before
// GPUEngineBase::ResolveToCustomFramebuffer() for each engine before reading the // reading the master custom framebuffer.
// master custom framebuffer.
bool GetWillAutoResolveToCustomBuffer() const; bool GetWillAutoResolveToCustomBuffer() const;
void SetWillAutoResolveToCustomBuffer(const bool willAutoResolve); void SetWillAutoResolveToCustomBuffer(const bool willAutoResolve);
void ResolveDisplayToCustomFramebuffer(const NDSDisplayID displayID, NDSDisplayInfo &mutableInfo);
template<NDSColorFormat OUTPUTFORMAT> void RenderLine(const size_t l); template<NDSColorFormat OUTPUTFORMAT> void RenderLine(const size_t l);
void ClearWithColor(const u16 colorBGRA5551); void ClearWithColor(const u16 colorBGRA5551);

View File

@ -4709,7 +4709,7 @@ bool OGLShaderProgram::LinkOGL()
OGLClientFetchObject::OGLClientFetchObject() OGLClientFetchObject::OGLClientFetchObject()
{ {
_contextInfo = NULL; _contextInfo = NULL;
_useCPUFilterPipeline = true; _useDirectToCPUFilterPipeline = true;
_fetchColorFormatOGL = GL_UNSIGNED_SHORT_1_5_5_5_REV; _fetchColorFormatOGL = GL_UNSIGNED_SHORT_1_5_5_5_REV;
pthread_rwlock_init(&_srcCloneRWLock[NDSDisplayID_Main][0], NULL); pthread_rwlock_init(&_srcCloneRWLock[NDSDisplayID_Main][0], NULL);
@ -4923,7 +4923,7 @@ void OGLClientFetchObject::SetFetchBuffers(const NDSDisplayInfo &currentDisplayI
void OGLClientFetchObject::_FetchNativeDisplayByID(const NDSDisplayID displayID, const u8 bufferIndex) void OGLClientFetchObject::_FetchNativeDisplayByID(const NDSDisplayID displayID, const u8 bufferIndex)
{ {
if (this->_useCPUFilterPipeline) if (this->_useDirectToCPUFilterPipeline)
{ {
pthread_rwlock_wrlock(&this->_srcCloneRWLock[displayID][bufferIndex]); pthread_rwlock_wrlock(&this->_srcCloneRWLock[displayID][bufferIndex]);

View File

@ -343,7 +343,7 @@ protected:
GLuint _texHQ3xLUT; GLuint _texHQ3xLUT;
GLuint _texHQ4xLUT; GLuint _texHQ4xLUT;
bool _useCPUFilterPipeline; bool _useDirectToCPUFilterPipeline;
uint32_t *_srcNativeCloneMaster; uint32_t *_srcNativeCloneMaster;
uint32_t *_srcNativeClone[2][2]; uint32_t *_srcNativeClone[2][2];
pthread_rwlock_t _srcCloneRWLock[2][2]; pthread_rwlock_t _srcCloneRWLock[2][2];

View File

@ -38,17 +38,17 @@ class GPUEventHandlerOSX;
pthread_rwlock_t *_rwlockFramebuffer[2]; pthread_rwlock_t *_rwlockFramebuffer[2];
pthread_mutex_t *_mutexOutputList; pthread_mutex_t *_mutexOutputList;
NSMutableArray *_cdsOutputList; NSMutableArray *_cdsOutputList;
volatile int32_t numberViewsUsingCPUFiltering; volatile int32_t numberViewsUsingDirectToCPUFiltering;
} }
@property (assign, nonatomic) GPUClientFetchObject *GPUFetchObject; @property (assign, nonatomic) GPUClientFetchObject *GPUFetchObject;
@property (readonly, nonatomic) int32_t numberViewsUsingCPUFiltering; @property (readonly, nonatomic) int32_t numberViewsUsingDirectToCPUFiltering;
- (const NDSDisplayInfo &) fetchDisplayInfoForIndex:(const u8)bufferIndex; - (const NDSDisplayInfo &) fetchDisplayInfoForIndex:(const u8)bufferIndex;
- (pthread_rwlock_t *) rwlockFramebufferAtIndex:(const u8)bufferIndex; - (pthread_rwlock_t *) rwlockFramebufferAtIndex:(const u8)bufferIndex;
- (void) setOutputList:(NSMutableArray *)theOutputList mutex:(pthread_mutex_t *)theMutex; - (void) setOutputList:(NSMutableArray *)theOutputList mutex:(pthread_mutex_t *)theMutex;
- (void) incrementViewsUsingCPUFiltering; - (void) incrementViewsUsingDirectToCPUFiltering;
- (void) decrementViewsUsingCPUFiltering; - (void) decrementViewsUsingDirectToCPUFiltering;
- (void) handleFetchFromBufferIndexAndPushVideo:(NSData *)indexData; - (void) handleFetchFromBufferIndexAndPushVideo:(NSData *)indexData;
- (void) pushVideoDataToAllDisplayViews; - (void) pushVideoDataToAllDisplayViews;
- (void) finishAllDisplayViewsAtIndex:(const u8)bufferIndex; - (void) finishAllDisplayViewsAtIndex:(const u8)bufferIndex;

View File

@ -159,11 +159,16 @@ public:
if (IsOSXVersionSupported(10, 11, 0) && [[NSUserDefaults standardUserDefaults] boolForKey:@"General_DisplayViewsPreferMetal"]) if (IsOSXVersionSupported(10, 11, 0) && [[NSUserDefaults standardUserDefaults] boolForKey:@"General_DisplayViewsPreferMetal"])
{ {
fetchObject = new MacMetalFetchObject; fetchObject = new MacMetalFetchObject;
if (fetchObject->GetClientData() == nil) if (fetchObject->GetClientData() == nil)
{ {
delete fetchObject; delete fetchObject;
fetchObject = NULL; fetchObject = NULL;
} }
else
{
GPU->SetWillPostprocessDisplays(false);
}
} }
#endif #endif
@ -860,7 +865,7 @@ public:
@implementation MacClientSharedObject @implementation MacClientSharedObject
@synthesize GPUFetchObject; @synthesize GPUFetchObject;
@synthesize numberViewsUsingCPUFiltering; @synthesize numberViewsUsingDirectToCPUFiltering;
- (id)init - (id)init
{ {
@ -879,7 +884,7 @@ public:
GPUFetchObject = nil; GPUFetchObject = nil;
_mutexOutputList = NULL; _mutexOutputList = NULL;
_cdsOutputList = nil; _cdsOutputList = nil;
numberViewsUsingCPUFiltering = 0; numberViewsUsingDirectToCPUFiltering = 0;
return self; return self;
} }
@ -962,14 +967,14 @@ public:
_mutexOutputList = theMutex; _mutexOutputList = theMutex;
} }
- (void) incrementViewsUsingCPUFiltering - (void) incrementViewsUsingDirectToCPUFiltering
{ {
OSAtomicIncrement32(&numberViewsUsingCPUFiltering); OSAtomicIncrement32(&numberViewsUsingDirectToCPUFiltering);
} }
- (void) decrementViewsUsingCPUFiltering - (void) decrementViewsUsingDirectToCPUFiltering
{ {
OSAtomicDecrement32(&numberViewsUsingCPUFiltering); OSAtomicDecrement32(&numberViewsUsingDirectToCPUFiltering);
} }
- (void) pushVideoDataToAllDisplayViews - (void) pushVideoDataToAllDisplayViews

View File

@ -678,9 +678,11 @@
- (NSBitmapImageRep *) bitmapImageRep - (NSBitmapImageRep *) bitmapImageRep
{ {
const NDSDisplayInfo &dispInfo = GPU->GetDisplayInfo(); GPUClientFetchObject &fetchObjMutable = (GPUClientFetchObject &)_cdv->GetFetchObject();
NSUInteger w = (NSUInteger)dispInfo.customWidth; NDSDisplayInfo &displayInfoMutable = (NDSDisplayInfo &)fetchObjMutable.GetFetchDisplayInfoForBufferIndex(fetchObjMutable.GetLastFetchIndex());
NSUInteger h = (_cdv->GetMode() == ClientDisplayMode_Dual) ? (NSUInteger)(dispInfo.customHeight * 2) : (NSUInteger)dispInfo.customHeight;
NSUInteger w = (NSUInteger)displayInfoMutable.customWidth;
NSUInteger h = (_cdv->GetMode() == ClientDisplayMode_Dual) ? (NSUInteger)(displayInfoMutable.customHeight * 2) : (NSUInteger)displayInfoMutable.customHeight;
NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
pixelsWide:w pixelsWide:w
@ -698,19 +700,21 @@
return imageRep; return imageRep;
} }
void *displayBuffer = dispInfo.masterCustomBuffer; void *displayBuffer = displayInfoMutable.masterCustomBuffer;
uint32_t *bitmapData = (uint32_t *)[imageRep bitmapData]; uint32_t *bitmapData = (uint32_t *)[imageRep bitmapData];
pthread_rwlock_rdlock(self.rwlockProducer); pthread_rwlock_wrlock(self.rwlockProducer);
GPU->GetEngineMain()->ResolveToCustomFramebuffer(); GPU->PostprocessDisplay(NDSDisplayID_Main, displayInfoMutable);
GPU->GetEngineSub()->ResolveToCustomFramebuffer(); GPU->PostprocessDisplay(NDSDisplayID_Touch, displayInfoMutable);
GPU->ResolveDisplayToCustomFramebuffer(NDSDisplayID_Main, displayInfoMutable);
GPU->ResolveDisplayToCustomFramebuffer(NDSDisplayID_Touch, displayInfoMutable);
if (dispInfo.pixelBytes == 2) if (displayInfoMutable.pixelBytes == 2)
{ {
ColorspaceConvertBuffer555To8888Opaque<false, true>((u16 *)displayBuffer, bitmapData, (w * h)); ColorspaceConvertBuffer555To8888Opaque<false, true>((u16 *)displayBuffer, bitmapData, (w * h));
} }
else if (dispInfo.pixelBytes == 4) else if (displayInfoMutable.pixelBytes == 4)
{ {
memcpy(bitmapData, displayBuffer, w * h * sizeof(uint32_t)); memcpy(bitmapData, displayBuffer, w * h * sizeof(uint32_t));
} }

View File

@ -1751,9 +1751,9 @@ static std::unordered_map<NSScreen *, DisplayWindowController *> _screenMap; //
- (void) setVideoFiltersPreferGPU:(BOOL)theState - (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]; [[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) if (oldState != newState)
{ {
@ -1764,11 +1764,11 @@ static std::unordered_map<NSScreen *, DisplayWindowController *> _screenMap; //
if (newState) if (newState)
{ {
[macSharedData incrementViewsUsingCPUFiltering]; [macSharedData incrementViewsUsingDirectToCPUFiltering];
} }
else else
{ {
[macSharedData decrementViewsUsingCPUFiltering]; [macSharedData decrementViewsUsingDirectToCPUFiltering];
} }
} }
} }
@ -1780,7 +1780,26 @@ static std::unordered_map<NSScreen *, DisplayWindowController *> _screenMap; //
- (void) setSourceDeposterize:(BOOL)theState - (void) setSourceDeposterize:(BOOL)theState
{ {
const BOOL oldState = ( ![[self cdsVideoOutput] willFilterOnGPU] && ![[self cdsVideoOutput] sourceDeposterize] && ([[self cdsVideoOutput] pixelScaler] != VideoFilterTypeID_None) );
[[self cdsVideoOutput] setSourceDeposterize:theState]; [[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 - (BOOL) sourceDeposterize
@ -1800,9 +1819,9 @@ static std::unordered_map<NSScreen *, DisplayWindowController *> _screenMap; //
- (void) setPixelScaler:(NSInteger)filterID - (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]; [[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) if (oldState != newState)
{ {
@ -1813,11 +1832,11 @@ static std::unordered_map<NSScreen *, DisplayWindowController *> _screenMap; //
if (newState) if (newState)
{ {
[macSharedData incrementViewsUsingCPUFiltering]; [macSharedData incrementViewsUsingDirectToCPUFiltering];
} }
else else
{ {
[macSharedData decrementViewsUsingCPUFiltering]; [macSharedData decrementViewsUsingDirectToCPUFiltering];
} }
} }
} }

View File

@ -48,7 +48,10 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties;
id<MTLCommandQueue> commandQueue; id<MTLCommandQueue> commandQueue;
id<MTLLibrary> defaultLibrary; id<MTLLibrary> defaultLibrary;
id<MTLComputePipelineState> load16To32Pipeline; id<MTLComputePipelineState> _fetch555Pipeline;
id<MTLComputePipelineState> _fetch555ConvertOnlyPipeline;
id<MTLComputePipelineState> _fetch666Pipeline;
id<MTLComputePipelineState> _fetch888Pipeline;
id<MTLComputePipelineState> deposterizePipeline; id<MTLComputePipelineState> deposterizePipeline;
id<MTLRenderPipelineState> hudPipeline; id<MTLRenderPipelineState> hudPipeline;
@ -61,6 +64,9 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties;
id<MTLBuffer> _bufDisplayFetchNative[2][2]; id<MTLBuffer> _bufDisplayFetchNative[2][2];
id<MTLBuffer> _bufDisplayFetchCustom[2][2]; id<MTLBuffer> _bufDisplayFetchCustom[2][2];
id<MTLBuffer> _bufMasterBrightMode[2];
id<MTLBuffer> _bufMasterBrightIntensity[2];
id<MTLTexture> texDisplayFetch16NativeMain; id<MTLTexture> texDisplayFetch16NativeMain;
id<MTLTexture> texDisplayFetch16NativeTouch; id<MTLTexture> texDisplayFetch16NativeTouch;
id<MTLTexture> texDisplayFetch32NativeMain; id<MTLTexture> texDisplayFetch32NativeMain;
@ -70,15 +76,23 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties;
id<MTLTexture> texDisplayFetch32CustomMain; id<MTLTexture> texDisplayFetch32CustomMain;
id<MTLTexture> texDisplayFetch32CustomTouch; id<MTLTexture> texDisplayFetch32CustomTouch;
id<MTLTexture> texDisplayPostprocessNativeMain;
id<MTLTexture> texDisplayPostprocessCustomMain;
id<MTLTexture> texDisplayPostprocessNativeTouch;
id<MTLTexture> texDisplayPostprocessCustomTouch;
id<MTLTexture> texDisplaySrcTargetMain;
id<MTLTexture> texDisplaySrcTargetTouch;
id<MTLTexture> texLQ2xLUT; id<MTLTexture> texLQ2xLUT;
id<MTLTexture> texHQ2xLUT; id<MTLTexture> texHQ2xLUT;
id<MTLTexture> texHQ3xLUT; id<MTLTexture> texHQ3xLUT;
id<MTLTexture> texHQ4xLUT; id<MTLTexture> texHQ4xLUT;
id<MTLTexture> texCurrentHQnxLUT; id<MTLTexture> texCurrentHQnxLUT;
MTLSize load16To32ThreadsPerGroup; MTLSize fetchThreadsPerGroup;
MTLSize load16To32ThreadGroupsPerGridNative; MTLSize fetchThreadGroupsPerGridNative;
MTLSize load16To32ThreadGroupsPerGridCustom; MTLSize fetchThreadGroupsPerGridCustom;
MTLSize deposterizeThreadsPerGroup; MTLSize deposterizeThreadsPerGroup;
MTLSize deposterizeThreadGroupsPerGrid; MTLSize deposterizeThreadGroupsPerGrid;
@ -92,7 +106,6 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties;
@property (readonly, nonatomic) id<MTLCommandQueue> commandQueue; @property (readonly, nonatomic) id<MTLCommandQueue> commandQueue;
@property (readonly, nonatomic) id<MTLLibrary> defaultLibrary; @property (readonly, nonatomic) id<MTLLibrary> defaultLibrary;
@property (readonly, nonatomic) id<MTLComputePipelineState> load16To32Pipeline;
@property (readonly, nonatomic) id<MTLComputePipelineState> deposterizePipeline; @property (readonly, nonatomic) id<MTLComputePipelineState> deposterizePipeline;
@property (readonly, nonatomic) id<MTLRenderPipelineState> hudPipeline; @property (readonly, nonatomic) id<MTLRenderPipelineState> hudPipeline;
@property (readonly, nonatomic) id<MTLSamplerState> samplerHUDBox; @property (readonly, nonatomic) id<MTLSamplerState> samplerHUDBox;
@ -109,6 +122,14 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties;
@property (retain) id<MTLTexture> texDisplayFetch32CustomMain; @property (retain) id<MTLTexture> texDisplayFetch32CustomMain;
@property (retain) id<MTLTexture> texDisplayFetch32CustomTouch; @property (retain) id<MTLTexture> texDisplayFetch32CustomTouch;
@property (retain) id<MTLTexture> texDisplayPostprocessNativeMain;
@property (retain) id<MTLTexture> texDisplayPostprocessCustomMain;
@property (retain) id<MTLTexture> texDisplayPostprocessNativeTouch;
@property (retain) id<MTLTexture> texDisplayPostprocessCustomTouch;
@property (retain) id<MTLTexture> texDisplaySrcTargetMain;
@property (retain) id<MTLTexture> texDisplaySrcTargetTouch;
@property (readonly, nonatomic) id<MTLTexture> texLQ2xLUT; @property (readonly, nonatomic) id<MTLTexture> texLQ2xLUT;
@property (readonly, nonatomic) id<MTLTexture> texHQ2xLUT; @property (readonly, nonatomic) id<MTLTexture> texHQ2xLUT;
@property (readonly, nonatomic) id<MTLTexture> texHQ3xLUT; @property (readonly, nonatomic) id<MTLTexture> texHQ3xLUT;
@ -118,9 +139,9 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties;
@property (assign) size_t displayFetchNativeBufferSize; @property (assign) size_t displayFetchNativeBufferSize;
@property (assign) size_t displayFetchCustomBufferSize; @property (assign) size_t displayFetchCustomBufferSize;
@property (readonly, nonatomic) MTLSize load16To32ThreadsPerGroup; @property (readonly, nonatomic) MTLSize fetchThreadsPerGroup;
@property (readonly, nonatomic) MTLSize load16To32ThreadGroupsPerGridNative; @property (readonly, nonatomic) MTLSize fetchThreadGroupsPerGridNative;
@property (assign) MTLSize load16To32ThreadGroupsPerGridCustom; @property (assign) MTLSize fetchThreadGroupsPerGridCustom;
@property (readonly, nonatomic) MTLSize deposterizeThreadsPerGroup; @property (readonly, nonatomic) MTLSize deposterizeThreadsPerGroup;
@property (readonly, nonatomic) MTLSize deposterizeThreadGroupsPerGrid; @property (readonly, nonatomic) MTLSize deposterizeThreadGroupsPerGrid;
@ -128,7 +149,6 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties;
- (void) fetchFromBufferIndex:(const u8)index; - (void) fetchFromBufferIndex:(const u8)index;
- (void) fetchNativeDisplayByID:(const NDSDisplayID)displayID bufferIndex:(const u8)bufferIndex; - (void) fetchNativeDisplayByID:(const NDSDisplayID)displayID bufferIndex:(const u8)bufferIndex;
- (void) fetchCustomDisplayByID:(const NDSDisplayID)displayID bufferIndex:(const u8)bufferIndex; - (void) fetchCustomDisplayByID:(const NDSDisplayID)displayID bufferIndex:(const u8)bufferIndex;
- (void) convertFetch16To32UsingEncoder:(id<MTLComputeCommandEncoder>)cce isMainNative:(BOOL)isMainNative isTouchNative:(BOOL)isTouchNative;
@end @end
@ -201,7 +221,7 @@ typedef DisplayViewShaderProperties DisplayViewShaderProperties;
class MacMetalFetchObject : public GPUClientFetchObject class MacMetalFetchObject : public GPUClientFetchObject
{ {
protected: protected:
bool _useCPUFilterPipeline; bool _useDirectToCPUFilterPipeline;
uint32_t *_srcNativeCloneMaster; uint32_t *_srcNativeCloneMaster;
uint32_t *_srcNativeClone[2][2]; uint32_t *_srcNativeClone[2][2];
pthread_rwlock_t _srcCloneRWLock[2][2]; pthread_rwlock_t _srcCloneRWLock[2][2];

View File

@ -25,7 +25,6 @@
@synthesize commandQueue; @synthesize commandQueue;
@synthesize defaultLibrary; @synthesize defaultLibrary;
@synthesize load16To32Pipeline;
@synthesize deposterizePipeline; @synthesize deposterizePipeline;
@synthesize hudPipeline; @synthesize hudPipeline;
@synthesize samplerHUDBox; @synthesize samplerHUDBox;
@ -42,6 +41,14 @@
@synthesize texDisplayFetch32CustomMain; @synthesize texDisplayFetch32CustomMain;
@synthesize texDisplayFetch32CustomTouch; @synthesize texDisplayFetch32CustomTouch;
@synthesize texDisplayPostprocessNativeMain;
@synthesize texDisplayPostprocessCustomMain;
@synthesize texDisplayPostprocessNativeTouch;
@synthesize texDisplayPostprocessCustomTouch;
@synthesize texDisplaySrcTargetMain;
@synthesize texDisplaySrcTargetTouch;
@synthesize texLQ2xLUT; @synthesize texLQ2xLUT;
@synthesize texHQ2xLUT; @synthesize texHQ2xLUT;
@synthesize texHQ3xLUT; @synthesize texHQ3xLUT;
@ -51,9 +58,9 @@
@synthesize displayFetchNativeBufferSize; @synthesize displayFetchNativeBufferSize;
@synthesize displayFetchCustomBufferSize; @synthesize displayFetchCustomBufferSize;
@synthesize load16To32ThreadsPerGroup; @synthesize fetchThreadsPerGroup;
@synthesize load16To32ThreadGroupsPerGridNative; @synthesize fetchThreadGroupsPerGridNative;
@synthesize load16To32ThreadGroupsPerGridCustom; @synthesize fetchThreadGroupsPerGridCustom;
@synthesize deposterizeThreadsPerGroup; @synthesize deposterizeThreadsPerGroup;
@synthesize deposterizeThreadGroupsPerGrid; @synthesize deposterizeThreadGroupsPerGrid;
@ -77,26 +84,29 @@
commandQueue = [[device newCommandQueue] retain]; commandQueue = [[device newCommandQueue] retain];
defaultLibrary = [[device newDefaultLibrary] 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]; deposterizePipeline = [[device newComputePipelineStateWithFunction:[defaultLibrary newFunctionWithName:@"src_filter_deposterize"] error:nil] retain];
size_t tw = GetNearestPositivePOT((uint32_t)[load16To32Pipeline threadExecutionWidth]); size_t tw = GetNearestPositivePOT((uint32_t)[_fetch555Pipeline threadExecutionWidth]);
while ( (tw > [load16To32Pipeline threadExecutionWidth]) || (tw > GPU_FRAMEBUFFER_NATIVE_WIDTH) ) while ( (tw > [_fetch555Pipeline threadExecutionWidth]) || (tw > GPU_FRAMEBUFFER_NATIVE_WIDTH) )
{ {
tw >>= 1; tw >>= 1;
} }
size_t th = [load16To32Pipeline maxTotalThreadsPerThreadgroup] / tw; size_t th = [_fetch555Pipeline maxTotalThreadsPerThreadgroup] / tw;
load16To32ThreadsPerGroup = MTLSizeMake(tw, th, 1); fetchThreadsPerGroup = MTLSizeMake(tw, th, 1);
load16To32ThreadGroupsPerGridNative = MTLSizeMake(GPU_FRAMEBUFFER_NATIVE_WIDTH / tw, fetchThreadGroupsPerGridNative = MTLSizeMake(GPU_FRAMEBUFFER_NATIVE_WIDTH / tw,
GPU_FRAMEBUFFER_NATIVE_HEIGHT / th, GPU_FRAMEBUFFER_NATIVE_HEIGHT / th,
1); 1);
load16To32ThreadGroupsPerGridCustom = load16To32ThreadGroupsPerGridNative; fetchThreadGroupsPerGridCustom = fetchThreadGroupsPerGridNative;
deposterizeThreadsPerGroup = load16To32ThreadsPerGroup; deposterizeThreadsPerGroup = fetchThreadsPerGroup;
deposterizeThreadGroupsPerGrid = load16To32ThreadGroupsPerGridNative; deposterizeThreadGroupsPerGrid = fetchThreadGroupsPerGridNative;
MTLRenderPipelineDescriptor *hudPipelineDesc = [[MTLRenderPipelineDescriptor alloc] init]; MTLRenderPipelineDescriptor *hudPipelineDesc = [[MTLRenderPipelineDescriptor alloc] init];
[[[hudPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setPixelFormat:MTLPixelFormatBGRA8Unorm]; [[[hudPipelineDesc colorAttachments] objectAtIndexedSubscript:0] setPixelFormat:MTLPixelFormatBGRA8Unorm];
@ -139,6 +149,11 @@
displayFetchNativeBufferSize = 0; displayFetchNativeBufferSize = 0;
displayFetchCustomBufferSize = 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. // Set up HUD texture samplers.
MTLSamplerDescriptor *samplerDesc = [[MTLSamplerDescriptor alloc] init]; MTLSamplerDescriptor *samplerDesc = [[MTLSamplerDescriptor alloc] init];
[samplerDesc setNormalizedCoordinates:YES]; [samplerDesc setNormalizedCoordinates:YES];
@ -189,26 +204,51 @@
texDisplayFetch32CustomMain = [[device newTextureWithDescriptor:texDisplayLoad32Desc] retain]; texDisplayFetch32CustomMain = [[device newTextureWithDescriptor:texDisplayLoad32Desc] retain];
texDisplayFetch32CustomTouch = [[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)); 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); const MTLRegion texRegionNative = MTLRegionMake2D(0, 0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT);
[texDisplayFetch32NativeMain replaceRegion:texRegionNative [texDisplayFetch32NativeMain replaceRegion:texRegionNative
mipmapLevel:0 mipmapLevel:0
withBytes:blankBuffer withBytes:blankBuffer
bytesPerRow:GPU_FRAMEBUFFER_NATIVE_WIDTH * sizeof(uint32_t)]; bytesPerRow:GPU_FRAMEBUFFER_NATIVE_WIDTH * sizeof(uint32_t)];
[texDisplayFetch32NativeTouch replaceRegion:texRegionNative [texDisplayFetch32NativeTouch replaceRegion:texRegionNative
mipmapLevel:0 mipmapLevel:0
withBytes:blankBuffer withBytes:blankBuffer
bytesPerRow:GPU_FRAMEBUFFER_NATIVE_WIDTH * sizeof(uint32_t)]; bytesPerRow:GPU_FRAMEBUFFER_NATIVE_WIDTH * sizeof(uint32_t)];
[texDisplayFetch32CustomMain replaceRegion:texRegionNative [texDisplayFetch32CustomMain replaceRegion:texRegionNative
mipmapLevel:0 mipmapLevel:0
withBytes:blankBuffer withBytes:blankBuffer
bytesPerRow:GPU_FRAMEBUFFER_NATIVE_WIDTH * sizeof(uint32_t)]; bytesPerRow:GPU_FRAMEBUFFER_NATIVE_WIDTH * sizeof(uint32_t)];
[texDisplayFetch32CustomTouch replaceRegion:texRegionNative [texDisplayFetch32CustomTouch replaceRegion:texRegionNative
mipmapLevel:0 mipmapLevel:0
withBytes:blankBuffer withBytes:blankBuffer
bytesPerRow:GPU_FRAMEBUFFER_NATIVE_WIDTH * sizeof(uint32_t)]; 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); free(blankBuffer);
texDisplaySrcTargetMain = [texDisplayFetch32NativeMain retain];
texDisplaySrcTargetTouch = [texDisplayFetch32NativeTouch retain];
// Set up the HQnx LUT textures. // Set up the HQnx LUT textures.
SetupHQnxLUTs_Metal(device, texLQ2xLUT, texHQ2xLUT, texHQ3xLUT, texHQ4xLUT); SetupHQnxLUTs_Metal(device, texLQ2xLUT, texHQ2xLUT, texHQ3xLUT, texHQ4xLUT);
texCurrentHQnxLUT = nil; texCurrentHQnxLUT = nil;
@ -225,11 +265,19 @@
[commandQueue release]; [commandQueue release];
[defaultLibrary release]; [defaultLibrary release];
[load16To32Pipeline release]; [_fetch555Pipeline release];
[_fetch555ConvertOnlyPipeline release];
[_fetch666Pipeline release];
[_fetch888Pipeline release];
[deposterizePipeline release]; [deposterizePipeline release];
[hudPipeline release]; [hudPipeline release];
[hudIndexBuffer release]; [hudIndexBuffer release];
[_bufMasterBrightMode[NDSDisplayID_Main] release];
[_bufMasterBrightMode[NDSDisplayID_Touch] release];
[_bufMasterBrightIntensity[NDSDisplayID_Main] release];
[_bufMasterBrightIntensity[NDSDisplayID_Touch] release];
[texDisplayFetch16NativeMain release]; [texDisplayFetch16NativeMain release];
[texDisplayFetch16NativeTouch release]; [texDisplayFetch16NativeTouch release];
[texDisplayFetch32NativeMain release]; [texDisplayFetch32NativeMain release];
@ -239,6 +287,14 @@
[self setTexDisplayFetch32CustomMain:nil]; [self setTexDisplayFetch32CustomMain:nil];
[self setTexDisplayFetch32CustomTouch: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); DeleteHQnxLUTs_Metal(texLQ2xLUT, texHQ2xLUT, texHQ3xLUT, texHQ4xLUT);
[self setTexCurrentHQnxLUT:nil]; [self setTexCurrentHQnxLUT:nil];
@ -319,10 +375,243 @@
GPUFetchObject->GPUClientFetchObject::FetchFromBufferIndex(index); GPUFetchObject->GPUClientFetchObject::FetchFromBufferIndex(index);
[_fetchEncoder endEncoding]; [_fetchEncoder endEncoding];
[cb commit];
pthread_rwlock_unlock([self rwlockFramebufferAtIndex:index]); pthread_rwlock_unlock([self rwlockFramebufferAtIndex:index]);
pthread_mutex_unlock(&_mutexFetch); pthread_mutex_unlock(&_mutexFetch);
id<MTLTexture> texDisplaySrcTarget[2] = {nil, nil};
const NDSDisplayInfo &currentDisplayInfo = 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<MTLComputeCommandEncoder> 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 - (void) fetchNativeDisplayByID:(const NDSDisplayID)displayID bufferIndex:(const u8)bufferIndex
@ -375,11 +664,11 @@
[texDisplayLoad32Desc setStorageMode:MTLStorageModePrivate]; [texDisplayLoad32Desc setStorageMode:MTLStorageModePrivate];
[texDisplayLoad32Desc setUsage:MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite]; [texDisplayLoad32Desc setUsage:MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite];
if (displayID == NDSDisplayID_Main) if (displayID == NDSDisplayID_Main)
{ {
[self setTexDisplayFetch16CustomMain:[device newTextureWithDescriptor:texDisplayLoad16Desc]]; [self setTexDisplayFetch16CustomMain:[device newTextureWithDescriptor:texDisplayLoad16Desc]];
[self setTexDisplayFetch32CustomMain:[device newTextureWithDescriptor:texDisplayLoad32Desc]]; [self setTexDisplayFetch32CustomMain:[device newTextureWithDescriptor:texDisplayLoad32Desc]];
[self setTexDisplayPostprocessCustomMain:[device newTextureWithDescriptor:texDisplayLoad32Desc]];
texFetch16 = [self texDisplayFetch16CustomMain]; texFetch16 = [self texDisplayFetch16CustomMain];
texFetch32 = [self texDisplayFetch32CustomMain]; texFetch32 = [self texDisplayFetch32CustomMain];
} }
@ -387,16 +676,17 @@
{ {
[self setTexDisplayFetch16CustomTouch:[device newTextureWithDescriptor:texDisplayLoad16Desc]]; [self setTexDisplayFetch16CustomTouch:[device newTextureWithDescriptor:texDisplayLoad16Desc]];
[self setTexDisplayFetch32CustomTouch:[device newTextureWithDescriptor:texDisplayLoad32Desc]]; [self setTexDisplayFetch32CustomTouch:[device newTextureWithDescriptor:texDisplayLoad32Desc]];
[self setTexDisplayPostprocessCustomTouch:[device newTextureWithDescriptor:texDisplayLoad32Desc]];
texFetch16 = [self texDisplayFetch16CustomTouch]; texFetch16 = [self texDisplayFetch16CustomTouch];
texFetch32 = [self texDisplayFetch32CustomTouch]; texFetch32 = [self texDisplayFetch32CustomTouch];
} }
const size_t tw = load16To32ThreadsPerGroup.width; const size_t tw = fetchThreadsPerGroup.width;
const size_t th = load16To32ThreadsPerGroup.height; const size_t th = fetchThreadsPerGroup.height;
[self setLoad16To32ThreadGroupsPerGridCustom:MTLSizeMake((currentDisplayInfo.customWidth + tw - 1) / tw, [self setFetchThreadGroupsPerGridCustom:MTLSizeMake((currentDisplayInfo.customWidth + tw - 1) / tw,
(currentDisplayInfo.customHeight + th - 1) / th, (currentDisplayInfo.customHeight + th - 1) / th,
1)]; 1)];
} }
const size_t bufferSize = [self displayFetchCustomBufferSize]; const size_t bufferSize = [self displayFetchCustomBufferSize];
@ -414,42 +704,6 @@
destinationOrigin:MTLOriginMake(0, 0, 0)]; destinationOrigin:MTLOriginMake(0, 0, 0)];
} }
- (void) convertFetch16To32UsingEncoder:(id<MTLComputeCommandEncoder>)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 @end
@implementation DisplayViewMetalLayer @implementation DisplayViewMetalLayer
@ -963,10 +1217,10 @@
const ClientDisplayMode mode = _cdv->GetViewProperties().mode; const ClientDisplayMode mode = _cdv->GetViewProperties().mode;
const bool useDeposterize = _cdv->GetSourceDeposterize(); const bool useDeposterize = _cdv->GetSourceDeposterize();
_texDisplayOutput[NDSDisplayID_Main] = (!fetchDisplayInfo.didPerformCustomRender[NDSDisplayID_Main]) ? [sharedData texDisplayFetch32NativeMain] : [sharedData texDisplayFetch32CustomMain]; _texDisplayOutput[NDSDisplayID_Main] = [sharedData texDisplaySrcTargetMain];
_texDisplayOutput[NDSDisplayID_Touch] = (!fetchDisplayInfo.didPerformCustomRender[NDSDisplayID_Touch]) ? [sharedData texDisplayFetch32NativeTouch] : [sharedData texDisplayFetch32CustomTouch]; _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 willFilterOnGPU = _cdv->WillFilterOnGPU();
const bool shouldProcessDisplay[2] = { !fetchDisplayInfo.didPerformCustomRender[NDSDisplayID_Main] && fetchDisplayInfo.isDisplayEnabled[NDSDisplayID_Main] && (mode == ClientDisplayMode_Main || mode == ClientDisplayMode_Dual), const bool shouldProcessDisplay[2] = { !fetchDisplayInfo.didPerformCustomRender[NDSDisplayID_Main] && fetchDisplayInfo.isDisplayEnabled[NDSDisplayID_Main] && (mode == ClientDisplayMode_Main || mode == ClientDisplayMode_Dual),
@ -978,13 +1232,6 @@
id<MTLCommandBuffer> cb = [[sharedData commandQueue] commandBufferWithUnretainedReferences]; id<MTLCommandBuffer> cb = [[sharedData commandQueue] commandBufferWithUnretainedReferences];
id<MTLComputeCommandEncoder> cce = [cb computeCommandEncoder]; id<MTLComputeCommandEncoder> 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 // Run the video source filters and the pixel scalers
if (useDeposterize) if (useDeposterize)
{ {
@ -992,7 +1239,7 @@
if (shouldProcessDisplay[NDSDisplayID_Main]) 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 setTexture:_texDisplaySrcDeposterize[NDSDisplayID_Main][0] atIndex:1];
[cce dispatchThreadgroups:[sharedData deposterizeThreadGroupsPerGrid] [cce dispatchThreadgroups:[sharedData deposterizeThreadGroupsPerGrid]
threadsPerThreadgroup:[sharedData deposterizeThreadsPerGroup]]; threadsPerThreadgroup:[sharedData deposterizeThreadsPerGroup]];
@ -1007,7 +1254,7 @@
if (shouldProcessDisplay[NDSDisplayID_Touch]) 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 setTexture:_texDisplaySrcDeposterize[NDSDisplayID_Touch][0] atIndex:1];
[cce dispatchThreadgroups:[sharedData deposterizeThreadGroupsPerGrid] [cce dispatchThreadgroups:[sharedData deposterizeThreadGroupsPerGrid]
threadsPerThreadgroup:[sharedData deposterizeThreadsPerGroup]]; threadsPerThreadgroup:[sharedData deposterizeThreadsPerGroup]];
@ -1048,17 +1295,15 @@
} }
[cce endEncoding]; [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 ) if ( (_cdv->GetPixelScaler() != VideoFilterTypeID_None) && !willFilterOnGPU )
{ {
id<MTLBlitCommandEncoder> bce = [cb blitCommandEncoder];
if (useDeposterize) if (useDeposterize)
{ {
// Hybrid CPU/GPU-based path (may cause a performance hit on pixel download) // Hybrid CPU/GPU-based path (may cause a performance hit on pixel download)
id<MTLCommandBuffer> cpuFilterSrcCB = [[sharedData commandQueue] commandBufferWithUnretainedReferences];
id<MTLBlitCommandEncoder> bce = [cpuFilterSrcCB blitCommandEncoder];
if (shouldProcessDisplay[NDSDisplayID_Main]) if (shouldProcessDisplay[NDSDisplayID_Main])
{ {
[bce copyFromTexture:_texDisplaySrcDeposterize[NDSDisplayID_Main][1] [bce copyFromTexture:_texDisplaySrcDeposterize[NDSDisplayID_Main][1]
@ -1088,9 +1333,6 @@
[bce synchronizeResource:[self bufCPUFilterSrcTouch]]; [bce synchronizeResource:[self bufCPUFilterSrcTouch]];
} }
[bce endEncoding];
[cpuFilterSrcCB commit];
} }
pthread_mutex_lock(_cdv->GetMutexProcessPtr()); pthread_mutex_lock(_cdv->GetMutexProcessPtr());
@ -1105,9 +1347,6 @@
vfTouch->RunFilter(); vfTouch->RunFilter();
} }
id<MTLCommandBuffer> cpuFilterDstCB = [[sharedData commandQueue] commandBufferWithUnretainedReferences];
id<MTLBlitCommandEncoder> bce = [cpuFilterDstCB blitCommandEncoder];
if (shouldProcessDisplay[NDSDisplayID_Main]) if (shouldProcessDisplay[NDSDisplayID_Main])
{ {
[[self bufCPUFilterDstMain] didModifyRange:NSMakeRange(0, vfMain->GetDstWidth() * vfMain->GetDstHeight() * sizeof(uint32_t))]; [[self bufCPUFilterDstMain] didModifyRange:NSMakeRange(0, vfMain->GetDstWidth() * vfMain->GetDstHeight() * sizeof(uint32_t))];
@ -1142,11 +1381,12 @@
_texDisplayOutput[NDSDisplayID_Touch] = [self texDisplayPixelScaleTouch]; _texDisplayOutput[NDSDisplayID_Touch] = [self texDisplayPixelScaleTouch];
} }
[bce endEncoding];
[cpuFilterDstCB commit];
pthread_mutex_unlock(_cdv->GetMutexProcessPtr()); pthread_mutex_unlock(_cdv->GetMutexProcessPtr());
[bce endEncoding];
} }
[cb commit];
} }
// Update the texture coordinates // Update the texture coordinates
@ -1347,7 +1587,7 @@
MacMetalFetchObject::MacMetalFetchObject() MacMetalFetchObject::MacMetalFetchObject()
{ {
_useCPUFilterPipeline = true; _useDirectToCPUFilterPipeline = true;
pthread_rwlock_init(&_srcCloneRWLock[NDSDisplayID_Main][0], NULL); pthread_rwlock_init(&_srcCloneRWLock[NDSDisplayID_Main][0], NULL);
pthread_rwlock_init(&_srcCloneRWLock[NDSDisplayID_Touch][0], NULL); pthread_rwlock_init(&_srcCloneRWLock[NDSDisplayID_Touch][0], NULL);
@ -1409,24 +1649,26 @@ void MacMetalFetchObject::SetFetchBuffers(const NDSDisplayInfo &currentDisplayIn
void MacMetalFetchObject::FetchFromBufferIndex(const u8 index) void MacMetalFetchObject::FetchFromBufferIndex(const u8 index)
{ {
MacClientSharedObject *sharedViewObject = (MacClientSharedObject *)this->_clientData; MacClientSharedObject *sharedViewObject = (MacClientSharedObject *)this->_clientData;
this->_useCPUFilterPipeline = ([sharedViewObject numberViewsUsingCPUFiltering] > 0); this->_useDirectToCPUFilterPipeline = ([sharedViewObject numberViewsUsingDirectToCPUFiltering] > 0);
[(MetalDisplayViewSharedData *)this->_clientData fetchFromBufferIndex:index]; [(MetalDisplayViewSharedData *)this->_clientData fetchFromBufferIndex:index];
} }
void MacMetalFetchObject::_FetchNativeDisplayByID(const NDSDisplayID displayID, const u8 bufferIndex) 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]); pthread_rwlock_wrlock(&this->_srcCloneRWLock[displayID][bufferIndex]);
if (_fetchDisplayInfo[bufferIndex].pixelBytes == 2) if (this->_fetchDisplayInfo[bufferIndex].pixelBytes == 2)
{ {
ColorspaceConvertBuffer555To8888Opaque<false, false>((const uint16_t *)_fetchDisplayInfo[bufferIndex].nativeBuffer[displayID], this->_srcNativeClone[displayID][bufferIndex], GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT); ColorspaceConvertBuffer555To8888Opaque<false, false>((const uint16_t *)this->_fetchDisplayInfo[bufferIndex].nativeBuffer[displayID], this->_srcNativeClone[displayID][bufferIndex], GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT);
} }
else else
{ {
ColorspaceConvertBuffer888XTo8888Opaque<false, false>((const uint32_t *)_fetchDisplayInfo[bufferIndex].nativeBuffer[displayID], this->_srcNativeClone[displayID][bufferIndex], GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT); ColorspaceConvertBuffer888XTo8888Opaque<false, false>((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]); pthread_rwlock_unlock(&this->_srcCloneRWLock[displayID][bufferIndex]);

View File

@ -58,6 +58,8 @@ float DistYCbCr(const float3 pixA, const float3 pixB);
bool IsPixEqual(const float3 pixA, const float3 pixB); bool IsPixEqual(const float3 pixA, const float3 pixB);
bool IsBlendingNeeded(const int4 blend); 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 genSampler = sampler(coord::pixel, address::clamp_to_edge, filter::nearest);
constexpr sampler outputSamplerBilinear = sampler(coord::pixel, address::clamp_to_edge, filter::linear); 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); return float4(outFragment.rgb, 1.0f);
} }
#pragma mark Conversion Filters #pragma mark NDS Emulation Functions
//--------------------------------------- kernel void nds_fetch555(const uint2 position [[thread_position_in_grid]],
// Input Pixel Mapping: 00 const constant uchar *brightnessMode [[buffer(0)]],
// const constant uchar *brightnessIntensity [[buffer(1)]],
// Output Pixel Mapping: 00 const texture2d<ushort, access::read> inTexture [[texture(0)]],
kernel void src16_unpack_unorm1555_to_unorm8888(const uint2 position [[thread_position_in_grid]], texture2d<float, access::write> outTexture [[texture(1)]])
const texture2d<ushort, access::read> inTexture [[texture(0)]], {
texture2d<float, access::write> 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<ushort, access::read> inTexture [[texture(0)]],
texture2d<float, access::write> outTexture [[texture(1)]])
{ {
if ( (position.x > inTexture.get_width() - 1) || (position.y > inTexture.get_height() - 1) ) if ( (position.x > inTexture.get_width() - 1) || (position.y > inTexture.get_height() - 1) )
{ {
return; 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<float, access::read> inTexture [[texture(0)]],
texture2d<float, access::write> 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<float, access::read> inTexture [[texture(0)]],
texture2d<float, access::write> 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 #pragma mark Source Filters

View File

@ -199,7 +199,7 @@ void MacOGLClientFetchObject::SetFetchBuffers(const NDSDisplayInfo &currentDispl
void MacOGLClientFetchObject::FetchFromBufferIndex(const u8 index) void MacOGLClientFetchObject::FetchFromBufferIndex(const u8 index)
{ {
MacClientSharedObject *sharedViewObject = (MacClientSharedObject *)this->_clientData; MacClientSharedObject *sharedViewObject = (MacClientSharedObject *)this->_clientData;
this->_useCPUFilterPipeline = ([sharedViewObject numberViewsUsingCPUFiltering] > 0); this->_useDirectToCPUFilterPipeline = ([sharedViewObject numberViewsUsingDirectToCPUFiltering] > 0);
pthread_rwlock_rdlock([sharedViewObject rwlockFramebufferAtIndex:index]); pthread_rwlock_rdlock([sharedViewObject rwlockFramebufferAtIndex:index]);

View File

@ -180,9 +180,8 @@
// Init the DS emulation core. // Init the DS emulation core.
CocoaDSCore *newCore = [[[CocoaDSCore alloc] init] autorelease]; CocoaDSCore *newCore = [[[CocoaDSCore alloc] init] autorelease];
MacClientSharedObject *sharedViewObject = [[newCore cdsGPU] sharedData]; 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) while ([sharedViewObject thread] == nil)
{ {
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01]]; [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01]];
@ -206,8 +205,6 @@
// Start up the threads for our outputs. // Start up the threads for our outputs.
[NSThread detachNewThreadSelector:@selector(runThread:) toTarget:newSpeaker withObject:nil]; [NSThread detachNewThreadSelector:@selector(runThread:) toTarget:newSpeaker withObject:nil];
// Wait until the SPU is finished starting up.
while ([newSpeaker thread] == nil) while ([newSpeaker thread] == nil)
{ {
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01]]; [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01]];