diff --git a/desmume/src/GPU.cpp b/desmume/src/GPU.cpp index 56964f8fe..a2968937b 100644 --- a/desmume/src/GPU.cpp +++ b/desmume/src/GPU.cpp @@ -162,6 +162,7 @@ bool gpu_loadstate(EMUFILE &is, int size) /*****************************************************************************/ GPUEngineBase::GPUEngineBase() { + _gpuSystem = NULL; _IORegisterMap = NULL; _paletteOBJ = NULL; _targetDisplay = NULL; @@ -272,6 +273,16 @@ GPUEngineBase::~GPUEngineBase() this->_enableColorEffectCustom[GPULayerID_OBJ] = NULL; } +GPUSubsystem* GPUEngineBase::GetGPUSystem() +{ + return this->_gpuSystem; +} + +void GPUEngineBase::SetGPUSystem(GPUSubsystem *theGPU) +{ + this->_gpuSystem = theGPU; +} + void GPUEngineBase::Reset() { this->SetupBuffers(); @@ -424,6 +435,7 @@ void GPUEngineBase::Reset() for (size_t line = 0; line < GPU_VRAM_BLOCK_LINES + 1; line++) { this->_currentCompositorInfo[line].renderState = renderState; + this->_currentCompositorInfo[line].target.lineColor = (this->_targetDisplay->GetColorFormat() == NDSColorFormat_BGR555_Rev) ? (void **)&this->_currentCompositorInfo[line].target.lineColor16 : (void **)&this->_currentCompositorInfo[line].target.lineColor32; } } @@ -1670,8 +1682,8 @@ void GPUEngineBase::_RenderLine_BGExtended(GPUEngineCompositorInfo &compInfo, co const size_t blockID = vramPixel >> 16; const size_t blockLine = (vramPixel >> 8) & 0x000000FF; - GPU->GetEngineMain()->VerifyVRAMLineDidChange(blockID, compInfo.line.indexNative + blockLine); - outUseCustomVRAM = !GPU->GetEngineMain()->IsLineCaptureNative(blockID, compInfo.line.indexNative + blockLine); + this->_gpuSystem->GetEngineMain()->VerifyVRAMLineDidChange(blockID, compInfo.line.indexNative + blockLine); + outUseCustomVRAM = !this->_gpuSystem->GetEngineMain()->IsLineCaptureNative(blockID, compInfo.line.indexNative + blockLine); } } } @@ -2219,7 +2231,7 @@ void GPUEngineBase::_SpriteRenderPerform(GPUEngineCompositorInfo &compInfo, u16 const size_t blockLine = (vramPixel >> 8) & 0x000000FF; const size_t linePixel = vramPixel & 0x000000FF; - if (!GPU->GetEngineMain()->IsLineCaptureNative(blockID, blockLine) && (linePixel == 0)) + if (!this->_gpuSystem->GetEngineMain()->IsLineCaptureNative(blockID, blockLine) && (linePixel == 0)) { this->_vramBlockOBJAddress = objAddress; } @@ -2460,8 +2472,8 @@ void GPUEngineBase::_RenderLine_LayerOBJ(GPUEngineCompositorInfo &compInfo, item const size_t blockID = vramPixel >> 16; const size_t blockLine = (vramPixel >> 8) & 0x000000FF; - GPU->GetEngineMain()->VerifyVRAMLineDidChange(blockID, blockLine); - useCustomVRAM = !GPU->GetEngineMain()->IsLineCaptureNative(blockID, blockLine); + this->_gpuSystem->GetEngineMain()->VerifyVRAMLineDidChange(blockID, blockLine); + useCustomVRAM = !this->_gpuSystem->GetEngineMain()->IsLineCaptureNative(blockID, blockLine); } } @@ -2480,7 +2492,7 @@ void GPUEngineBase::_RenderLine_LayerOBJ(GPUEngineCompositorInfo &compInfo, item { if (useCustomVRAM) { - const void *__restrict vramColorPtr = GPU->GetCustomVRAMAddressUsingMappedAddress(this->_vramBlockOBJAddress, 0); + const void *__restrict vramColorPtr = this->_gpuSystem->GetCustomVRAMAddressUsingMappedAddress(this->_vramBlockOBJAddress, 0); this->_CompositeVRAMLineDeferred(compInfo, vramColorPtr); } else @@ -2527,7 +2539,7 @@ void GPUEngineBase::_RenderLine_LayerOBJ(GPUEngineCompositorInfo &compInfo, item if (useCustomVRAM) { - const void *__restrict vramColorPtr = GPU->GetCustomVRAMAddressUsingMappedAddress(this->_vramBlockOBJAddress, 0); + const void *__restrict vramColorPtr = this->_gpuSystem->GetCustomVRAMAddressUsingMappedAddress(this->_vramBlockOBJAddress, 0); for (size_t line = 0; line < compInfo.line.renderCount; line++) { @@ -2621,6 +2633,7 @@ void GPUEngineBase::TransitionRenderStatesToDisplayInfo(NDSDisplayInfo &mutableI // this work up to the display level instead. This method is used to transition the master // brightness states to the display level so it can be processed as a framebuffer operation. + const NDSDisplayID displayID = this->_targetDisplay->GetDisplayID(); const GPUEngineCompositorInfo &compInfoZero = this->_currentCompositorInfo[0]; bool needApplyMasterBrightness = false; bool masterBrightnessDiffersPerLine = false; @@ -2636,8 +2649,8 @@ void GPUEngineBase::TransitionRenderStatesToDisplayInfo(NDSDisplayInfo &mutableI needApplyMasterBrightness = true; } - mutableInfo.masterBrightnessMode[this->_targetDisplay->GetDisplayID()][line] = compInfo.renderState.masterBrightnessMode; - mutableInfo.masterBrightnessIntensity[this->_targetDisplay->GetDisplayID()][line] = compInfo.renderState.masterBrightnessIntensity; + mutableInfo.masterBrightnessMode[displayID][line] = compInfo.renderState.masterBrightnessMode; + mutableInfo.masterBrightnessIntensity[displayID][line] = compInfo.renderState.masterBrightnessIntensity; // Most games maintain the exact same master brightness values for all 192 lines, so we // can easily apply the master brightness to the entire framebuffer at once, which is @@ -2656,8 +2669,8 @@ void GPUEngineBase::TransitionRenderStatesToDisplayInfo(NDSDisplayInfo &mutableI } } - mutableInfo.masterBrightnessDiffersPerLine[this->_targetDisplay->GetDisplayID()] = masterBrightnessDiffersPerLine; - mutableInfo.needApplyMasterBrightness[this->_targetDisplay->GetDisplayID()] = needApplyMasterBrightness; + mutableInfo.masterBrightnessDiffersPerLine[displayID] = masterBrightnessDiffersPerLine; + mutableInfo.needApplyMasterBrightness[displayID] = needApplyMasterBrightness; } template @@ -2862,7 +2875,7 @@ FORCEINLINE void GPUEngineBase::_RenderLine_LayerBG_Final(GPUEngineCompositorInf { if (useCustomVRAM) { - const void *__restrict vramColorPtr = GPU->GetCustomVRAMAddressUsingMappedAddress(compInfo.renderState.selectedBGLayer->BMPAddress, compInfo.line.blockOffsetCustom); + const void *__restrict vramColorPtr = this->_gpuSystem->GetCustomVRAMAddressUsingMappedAddress(compInfo.renderState.selectedBGLayer->BMPAddress, compInfo.line.blockOffsetCustom); this->_CompositeVRAMLineDeferred(compInfo, vramColorPtr); } else @@ -3108,8 +3121,8 @@ void GPUEngineBase::SetTargetDisplay(NDSDisplay *theDisplay) return; } - this->DisplayDrawBuffersUpdate(); this->_targetDisplay = theDisplay; + this->DisplayDrawBuffersUpdate(); } GPUEngineID GPUEngineBase::GetEngineID() const @@ -3155,7 +3168,7 @@ void GPUEngineBase::AllocateWorkingBuffers(NDSColorFormat requestedColorFormat, for (size_t line = 0; line < GPU_VRAM_BLOCK_LINES + 1; line++) { - this->_currentCompositorInfo[line].line = GPU->GetLineInfoAtIndex(line); + this->_currentCompositorInfo[line].line = this->_gpuSystem->GetLineInfoAtIndex(line); this->_currentCompositorInfo[line].target.lineColor = (this->_targetDisplay->GetColorFormat() == NDSColorFormat_BGR555_Rev) ? (void **)&this->_currentCompositorInfo[line].target.lineColor16 : (void **)&this->_currentCompositorInfo[line].target.lineColor32; } @@ -3235,6 +3248,23 @@ void GPUEngineBase::ParseAllRegisters() this->ParseReg_MASTER_BRIGHT(); } +void* GPUEngineA::operator new(size_t size) +{ + void *newPtr = malloc_alignedPage(size); + if (newPtr == NULL) + { + throw std::bad_alloc(); + } + + memset(newPtr, 0, size); + return newPtr; +} + +void GPUEngineA::operator delete(void *ptr) +{ + free_aligned(ptr); +} + GPUEngineA::GPUEngineA() { _engineID = GPUEngineID_Main; @@ -3284,20 +3314,9 @@ GPUEngineA::~GPUEngineA() free_aligned(this->_captureWorkingB32); } -GPUEngineA* GPUEngineA::Allocate() -{ - return new(malloc_alignedPage(sizeof(GPUEngineA))) GPUEngineA(); -} - -void GPUEngineA::FinalizeAndDeallocate() -{ - this->~GPUEngineA(); - free_aligned(this); -} - void GPUEngineA::Reset() { - this->SetTargetDisplay( GPU->GetDisplayMain() ); + this->SetTargetDisplay( this->_gpuSystem->GetDisplayMain() ); this->GPUEngineBase::Reset(); const size_t customWidth = this->_targetDisplay->GetWidth(); @@ -3421,14 +3440,14 @@ void GPUEngineA::AllocateWorkingBuffers(NDSColorFormat requestedColorFormat, siz if (this->_targetDisplay->GetColorFormat() == NDSColorFormat_BGR888_Rev) { - this->_VRAMCustomBlockPtr[0] = (Color4u8 *)GPU->GetCustomVRAMBuffer(); + this->_VRAMCustomBlockPtr[0] = (Color4u8 *)this->_gpuSystem->GetCustomVRAMBuffer(); this->_VRAMCustomBlockPtr[1] = (Color4u8 *)this->_VRAMCustomBlockPtr[0] + (1 * lineInfo.indexCustom * w); this->_VRAMCustomBlockPtr[2] = (Color4u8 *)this->_VRAMCustomBlockPtr[0] + (2 * lineInfo.indexCustom * w); this->_VRAMCustomBlockPtr[3] = (Color4u8 *)this->_VRAMCustomBlockPtr[0] + (3 * lineInfo.indexCustom * w); } else { - this->_VRAMCustomBlockPtr[0] = (u16 *)GPU->GetCustomVRAMBuffer(); + this->_VRAMCustomBlockPtr[0] = (u16 *)this->_gpuSystem->GetCustomVRAMBuffer(); this->_VRAMCustomBlockPtr[1] = (u16 *)this->_VRAMCustomBlockPtr[0] + (1 * lineInfo.indexCustom * w); this->_VRAMCustomBlockPtr[2] = (u16 *)this->_VRAMCustomBlockPtr[0] + (2 * lineInfo.indexCustom * w); this->_VRAMCustomBlockPtr[3] = (u16 *)this->_VRAMCustomBlockPtr[0] + (3 * lineInfo.indexCustom * w); @@ -3877,8 +3896,8 @@ void GPUEngineA::_RenderLine_DisplayCapture(const GPUEngineCompositorInfo &compI dstCustomOffset -= _gpuVRAMBlockOffset; } - const u16 *vramCustom16 = (u16 *)GPU->GetCustomVRAMBlankBuffer(); - const Color4u8 *vramCustom32 = (Color4u8 *)GPU->GetCustomVRAMBlankBuffer(); + const u16 *vramCustom16 = (u16 *)this->_gpuSystem->GetCustomVRAMBlankBuffer(); + const Color4u8 *vramCustom32 = (Color4u8 *)this->_gpuSystem->GetCustomVRAMBlankBuffer(); if (!willReadNativeVRAM) { @@ -4489,6 +4508,23 @@ void GPUEngineA::LastLineProcess() DISP_FIFOreset(); } +void* GPUEngineB::operator new(size_t size) +{ + void *newPtr = malloc_alignedPage(size); + if (newPtr == NULL) + { + throw std::bad_alloc(); + } + + memset(newPtr, 0, size); + return newPtr; +} + +void GPUEngineB::operator delete(void *ptr) +{ + free_aligned(ptr); +} + GPUEngineB::GPUEngineB() { _engineID = GPUEngineID_Sub; @@ -4503,20 +4539,9 @@ GPUEngineB::~GPUEngineB() { } -GPUEngineB* GPUEngineB::Allocate() -{ - return new(malloc_alignedPage(sizeof(GPUEngineB))) GPUEngineB(); -} - -void GPUEngineB::FinalizeAndDeallocate() -{ - this->~GPUEngineB(); - free_aligned(this); -} - void GPUEngineB::Reset() { - this->SetTargetDisplay( GPU->GetDisplayTouch() ); + this->SetTargetDisplay( this->_gpuSystem->GetDisplayTouch() ); this->GPUEngineBase::Reset(); this->_BGLayer[GPULayerID_BG0].BMPAddress = MMU_BBG; @@ -4634,74 +4659,40 @@ GPUSubsystem::GPUSubsystem() _customVRAM = NULL; _customVRAMBlank = NULL; - _displayInfo.colorFormat = NDSColorFormat_BGR555_Rev; - _displayInfo.pixelBytes = sizeof(u16); - _displayInfo.isCustomSizeRequested = false; - _displayInfo.customWidth = GPU_FRAMEBUFFER_NATIVE_WIDTH; - _displayInfo.customHeight = GPU_FRAMEBUFFER_NATIVE_HEIGHT; - - _displayInfo.framebufferPageSize = ((GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT) + (GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT)) * 2 * _displayInfo.pixelBytes; - _displayInfo.framebufferPageCount = 1; - _masterFramebuffer = malloc_alignedPage(_displayInfo.framebufferPageSize * _displayInfo.framebufferPageCount); - _displayInfo.masterFramebufferHead = _masterFramebuffer; - - _masterWorkingNativeBuffer32 = NULL; + _framebufferColorFormatPending = NDSColorFormat_BGR555_Rev; + _framebufferWidthPending = GPU_FRAMEBUFFER_NATIVE_WIDTH; + _framebufferHeightPending = GPU_FRAMEBUFFER_NATIVE_HEIGHT; + _framebufferPageCountPending = 1; + memset(&_displayInfo, 0, sizeof(_displayInfo)); _displayInfo.isDisplayEnabled[NDSDisplayID_Main] = true; _displayInfo.isDisplayEnabled[NDSDisplayID_Touch] = true; - - _displayInfo.bufferIndex = 0; - _displayInfo.sequenceNumber = 0; - _displayInfo.masterNativeBuffer16 = (u16 *)_masterFramebuffer; - _displayInfo.masterCustomBuffer = (u8 *)_masterFramebuffer + (GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT * 2 * sizeof(u16)); - - _displayInfo.nativeBuffer16[NDSDisplayID_Main] = _displayInfo.masterNativeBuffer16; - _displayInfo.nativeBuffer16[NDSDisplayID_Touch] = _displayInfo.masterNativeBuffer16 + (GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT); - _displayInfo.customBuffer[NDSDisplayID_Main] = _displayInfo.masterCustomBuffer; - _displayInfo.customBuffer[NDSDisplayID_Touch] = (u8 *)_displayInfo.masterCustomBuffer + (GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT * _displayInfo.pixelBytes); - - _displayInfo.renderedWidth[NDSDisplayID_Main] = GPU_FRAMEBUFFER_NATIVE_WIDTH; - _displayInfo.renderedWidth[NDSDisplayID_Touch] = GPU_FRAMEBUFFER_NATIVE_WIDTH; - _displayInfo.renderedHeight[NDSDisplayID_Main] = GPU_FRAMEBUFFER_NATIVE_HEIGHT; - _displayInfo.renderedHeight[NDSDisplayID_Touch] = GPU_FRAMEBUFFER_NATIVE_HEIGHT; - _displayInfo.renderedBuffer[NDSDisplayID_Main] = _displayInfo.nativeBuffer16[NDSDisplayID_Main]; - _displayInfo.renderedBuffer[NDSDisplayID_Touch] = _displayInfo.nativeBuffer16[NDSDisplayID_Touch]; - _displayInfo.engineID[NDSDisplayID_Main] = GPUEngineID_Main; _displayInfo.engineID[NDSDisplayID_Touch] = GPUEngineID_Sub; - - _displayInfo.didPerformCustomRender[NDSDisplayID_Main] = false; - _displayInfo.didPerformCustomRender[NDSDisplayID_Touch] = false; - - _displayInfo.masterBrightnessDiffersPerLine[NDSDisplayID_Main] = false; - _displayInfo.masterBrightnessDiffersPerLine[NDSDisplayID_Touch] = false; - memset(_displayInfo.masterBrightnessMode[NDSDisplayID_Main], GPUMasterBrightMode_Disable, sizeof(_displayInfo.masterBrightnessMode[NDSDisplayID_Main])); - memset(_displayInfo.masterBrightnessMode[NDSDisplayID_Touch], GPUMasterBrightMode_Disable, sizeof(_displayInfo.masterBrightnessMode[NDSDisplayID_Touch])); - memset(_displayInfo.masterBrightnessIntensity[NDSDisplayID_Main], 0, sizeof(_displayInfo.masterBrightnessIntensity[NDSDisplayID_Main])); - memset(_displayInfo.masterBrightnessIntensity[NDSDisplayID_Touch], 0, sizeof(_displayInfo.masterBrightnessIntensity[NDSDisplayID_Touch])); - _displayInfo.backlightIntensity[NDSDisplayID_Main] = 1.0f; _displayInfo.backlightIntensity[NDSDisplayID_Touch] = 1.0f; - _displayInfo.needConvertColorFormat[NDSDisplayID_Main] = false; - _displayInfo.needConvertColorFormat[NDSDisplayID_Touch] = false; - _displayInfo.needApplyMasterBrightness[NDSDisplayID_Main] = false; - _displayInfo.needApplyMasterBrightness[NDSDisplayID_Touch] = false; - ClearWithColor(0x8000); + _masterFramebuffer = NULL; + _masterWorkingNativeBuffer32 = NULL; - _engineMain = GPUEngineA::Allocate(); - _engineSub = GPUEngineB::Allocate(); + _engineMain = new GPUEngineA; + _engineMain->SetGPUSystem(this); + + _engineSub = new GPUEngineB; + _engineSub->SetGPUSystem(this); _display[NDSDisplayID_Main] = new NDSDisplay(NDSDisplayID_Main); _display[NDSDisplayID_Touch] = new NDSDisplay(NDSDisplayID_Touch); _display[NDSDisplayID_Main]->SetEngine(_engineMain); - _display[NDSDisplayID_Main]->SetEngine(_engineSub); + _display[NDSDisplayID_Touch]->SetEngine(_engineSub); _display[NDSDisplayID_Main]->SetDrawBuffers(_displayInfo.nativeBuffer16[NDSDisplayID_Main], NULL, _displayInfo.customBuffer[NDSDisplayID_Main]); _display[NDSDisplayID_Touch]->SetDrawBuffers(_displayInfo.nativeBuffer16[NDSDisplayID_Touch], NULL, _displayInfo.customBuffer[NDSDisplayID_Touch]); gfx3d_init(); + + _ApplyFramebufferSettings(); } GPUSubsystem::~GPUSubsystem() @@ -4735,12 +4726,17 @@ GPUSubsystem::~GPUSubsystem() delete _display[NDSDisplayID_Main]; delete _display[NDSDisplayID_Touch]; - _engineMain->FinalizeAndDeallocate(); - _engineSub->FinalizeAndDeallocate(); + + delete this->_engineMain; + this->_engineMain = NULL; + + delete this->_engineSub; + this->_engineSub = NULL; gfx3d_deinit(); - delete _defaultEventHandler; + delete this->_defaultEventHandler; + this->_defaultEventHandler = NULL; } void GPUSubsystem::_UpdateFPSRender3D() @@ -4960,7 +4956,7 @@ NDSDisplay* GPUSubsystem::GetDisplayTouch() size_t GPUSubsystem::GetFramebufferPageCount() const { - return this->_displayInfo.framebufferPageCount; + return this->_framebufferPageCountPending; } void GPUSubsystem::SetFramebufferPageCount(size_t pageCount) @@ -4970,17 +4966,17 @@ void GPUSubsystem::SetFramebufferPageCount(size_t pageCount) pageCount = MAX_FRAMEBUFFER_PAGES; } - this->_displayInfo.framebufferPageCount = (u32)pageCount; + this->_framebufferPageCountPending = pageCount; } size_t GPUSubsystem::GetCustomFramebufferWidth() const { - return this->_displayInfo.customWidth; + return this->_framebufferWidthPending; } size_t GPUSubsystem::GetCustomFramebufferHeight() const { - return this->_displayInfo.customHeight; + return this->_framebufferHeightPending; } void GPUSubsystem::SetCustomFramebufferSize(size_t w, size_t h) @@ -4990,142 +4986,139 @@ void GPUSubsystem::SetCustomFramebufferSize(size_t w, size_t h) return; } - this->_engineMain->RenderLineClearAsyncFinish(); - this->_engineSub->RenderLineClearAsyncFinish(); - this->AsyncSetupEngineBuffersFinish(); - - const float customWidthScale = (float)w / (float)GPU_FRAMEBUFFER_NATIVE_WIDTH; - const float customHeightScale = (float)h / (float)GPU_FRAMEBUFFER_NATIVE_HEIGHT; - const float newGpuLargestDstLineCount = (size_t)ceilf(customHeightScale); - - u16 *oldGpuDstToSrcIndexPtr = _gpuDstToSrcIndex; - u8 *oldGpuDstToSrcSSSE3_u8_8e = _gpuDstToSrcSSSE3_u8_8e; - u8 *oldGpuDstToSrcSSSE3_u8_16e = _gpuDstToSrcSSSE3_u8_16e; - u8 *oldGpuDstToSrcSSSE3_u16_8e = _gpuDstToSrcSSSE3_u16_8e; - u8 *oldGpuDstToSrcSSSE3_u32_4e = _gpuDstToSrcSSSE3_u32_4e; - - for (u32 srcX = 0, currentPitchCount = 0; srcX < GPU_FRAMEBUFFER_NATIVE_WIDTH; srcX++) - { - const u32 pitch = (u32)ceilf(((float)srcX+1.0f) * customWidthScale) - (float)currentPitchCount; - _gpuDstPitchCount[srcX] = pitch; - _gpuDstPitchIndex[srcX] = currentPitchCount; - currentPitchCount += pitch; - } - - for (size_t line = 0, currentLineCount = 0; line < GPU_VRAM_BLOCK_LINES + 1; line++) - { - const size_t lineCount = (size_t)ceilf((line+1) * customHeightScale) - currentLineCount; - GPUEngineLineInfo &lineInfo = this->_lineInfo[line]; - - lineInfo.indexNative = line; - lineInfo.indexCustom = currentLineCount; - lineInfo.widthCustom = w; - lineInfo.renderCount = lineCount; - lineInfo.pixelCount = lineInfo.widthCustom * lineInfo.renderCount; - lineInfo.blockOffsetNative = lineInfo.indexNative * GPU_FRAMEBUFFER_NATIVE_WIDTH; - lineInfo.blockOffsetCustom = lineInfo.indexCustom * lineInfo.widthCustom; - - currentLineCount += lineCount; - } - - u16 *newGpuDstToSrcIndex = (u16 *)malloc_alignedPage(w * h * sizeof(u16)); - u16 *newGpuDstToSrcPtr = newGpuDstToSrcIndex; - for (size_t y = 0, dstIdx = 0; y < GPU_FRAMEBUFFER_NATIVE_HEIGHT; y++) - { - if (this->_lineInfo[y].renderCount < 1) - { - continue; - } - - for (size_t x = 0; x < GPU_FRAMEBUFFER_NATIVE_WIDTH; x++) - { - for (size_t p = 0; p < _gpuDstPitchCount[x]; p++) - { - newGpuDstToSrcIndex[dstIdx++] = (y * GPU_FRAMEBUFFER_NATIVE_WIDTH) + x; - } - } - - for (size_t l = 1; l < this->_lineInfo[y].renderCount; l++) - { - memcpy(newGpuDstToSrcPtr + (w * l), newGpuDstToSrcPtr, w * sizeof(u16)); - } - - newGpuDstToSrcPtr += (w * this->_lineInfo[y].renderCount); - dstIdx += (w * (this->_lineInfo[y].renderCount - 1)); - } - - u8 *newGpuDstToSrcSSSE3_u8_8e = (u8 *)malloc_alignedPage(w * sizeof(u8)); - u8 *newGpuDstToSrcSSSE3_u8_16e = (u8 *)malloc_alignedPage(w * sizeof(u8)); - u8 *newGpuDstToSrcSSSE3_u16_8e = (u8 *)malloc_alignedPage(w * sizeof(u16)); - u8 *newGpuDstToSrcSSSE3_u32_4e = (u8 *)malloc_alignedPage(w * sizeof(u32)); - - for (size_t i = 0; i < w; i++) - { - const u8 value_u8_4 = newGpuDstToSrcIndex[i] & 0x03; - const u8 value_u8_8 = newGpuDstToSrcIndex[i] & 0x07; - const u8 value_u8_16 = newGpuDstToSrcIndex[i] & 0x0F; - const u8 value_u16 = (value_u8_8 << 1); - const u8 value_u32 = (value_u8_4 << 2); - - newGpuDstToSrcSSSE3_u8_8e[i] = value_u8_8; - newGpuDstToSrcSSSE3_u8_16e[i] = value_u8_16; - - newGpuDstToSrcSSSE3_u16_8e[(i << 1) + 0] = value_u16 + 0; - newGpuDstToSrcSSSE3_u16_8e[(i << 1) + 1] = value_u16 + 1; - - newGpuDstToSrcSSSE3_u32_4e[(i << 2) + 0] = value_u32 + 0; - newGpuDstToSrcSSSE3_u32_4e[(i << 2) + 1] = value_u32 + 1; - newGpuDstToSrcSSSE3_u32_4e[(i << 2) + 2] = value_u32 + 2; - newGpuDstToSrcSSSE3_u32_4e[(i << 2) + 3] = value_u32 + 3; - } - - _gpuLargestDstLineCount = newGpuLargestDstLineCount; - _gpuVRAMBlockOffset = this->_lineInfo[GPU_VRAM_BLOCK_LINES].indexCustom * w; - _gpuDstToSrcIndex = newGpuDstToSrcIndex; - _gpuDstToSrcSSSE3_u8_8e = newGpuDstToSrcSSSE3_u8_8e; - _gpuDstToSrcSSSE3_u8_16e = newGpuDstToSrcSSSE3_u8_16e; - _gpuDstToSrcSSSE3_u16_8e = newGpuDstToSrcSSSE3_u16_8e; - _gpuDstToSrcSSSE3_u32_4e = newGpuDstToSrcSSSE3_u32_4e; - - CurrentRenderer->RenderFinish(); - CurrentRenderer->SetRenderNeedsFinish(false); - - this->_display[NDSDisplayID_Main]->SetDisplaySize(w, h); - this->_display[NDSDisplayID_Touch]->SetDisplaySize(w, h); - - this->_displayInfo.isCustomSizeRequested = ( (w != GPU_FRAMEBUFFER_NATIVE_WIDTH) || (h != GPU_FRAMEBUFFER_NATIVE_HEIGHT) ); - this->_displayInfo.customWidth = (u32)w; - this->_displayInfo.customHeight = (u32)h; - - if (!this->_display[NDSDisplayID_Main]->IsCustomSizeRequested()) - { - this->_engineMain->ResetCaptureLineStates(0); - this->_engineMain->ResetCaptureLineStates(1); - this->_engineMain->ResetCaptureLineStates(2); - this->_engineMain->ResetCaptureLineStates(3); - } - - this->_AllocateFramebuffers(this->_displayInfo.colorFormat, w, h, this->_displayInfo.framebufferPageCount); - - free_aligned(oldGpuDstToSrcIndexPtr); - free_aligned(oldGpuDstToSrcSSSE3_u8_8e); - free_aligned(oldGpuDstToSrcSSSE3_u8_16e); - free_aligned(oldGpuDstToSrcSSSE3_u16_8e); - free_aligned(oldGpuDstToSrcSSSE3_u32_4e); + this->_framebufferWidthPending = w; + this->_framebufferHeightPending = h; } NDSColorFormat GPUSubsystem::GetColorFormat() const { - return this->_displayInfo.colorFormat; + return this->_framebufferColorFormatPending; } void GPUSubsystem::SetColorFormat(const NDSColorFormat outputFormat) { - if (this->_displayInfo.colorFormat == outputFormat) + this->_framebufferColorFormatPending = outputFormat; +} + +void GPUSubsystem::_ApplyFramebufferSettings() +{ + size_t w = this->_framebufferWidthPending; + size_t h = this->_framebufferHeightPending; + NDSColorFormat colorFormat = this->_framebufferColorFormatPending; + size_t pageCount = this->_framebufferPageCountPending; + + const bool didWidthChange = (w != (size_t)this->_displayInfo.customWidth); + const bool didHeightChange = (h != (size_t)this->_displayInfo.customHeight); + const bool didColorFormatChange = (colorFormat != this->_displayInfo.colorFormat); + const bool didPageCountChange = (pageCount != (size_t)this->_displayInfo.framebufferPageCount); + + if (!didWidthChange && !didHeightChange && !didColorFormatChange && !didPageCountChange) { return; } + if (didWidthChange || didHeightChange) + { + const float customWidthScale = (float)w / (float)GPU_FRAMEBUFFER_NATIVE_WIDTH; + const float customHeightScale = (float)h / (float)GPU_FRAMEBUFFER_NATIVE_HEIGHT; + const float newGpuLargestDstLineCount = (size_t)ceilf(customHeightScale); + + u16 *oldGpuDstToSrcIndexPtr = _gpuDstToSrcIndex; + u8 *oldGpuDstToSrcSSSE3_u8_8e = _gpuDstToSrcSSSE3_u8_8e; + u8 *oldGpuDstToSrcSSSE3_u8_16e = _gpuDstToSrcSSSE3_u8_16e; + u8 *oldGpuDstToSrcSSSE3_u16_8e = _gpuDstToSrcSSSE3_u16_8e; + u8 *oldGpuDstToSrcSSSE3_u32_4e = _gpuDstToSrcSSSE3_u32_4e; + + for (u32 srcX = 0, currentPitchCount = 0; srcX < GPU_FRAMEBUFFER_NATIVE_WIDTH; srcX++) + { + const u32 pitch = (u32)ceilf(((float)srcX+1.0f) * customWidthScale) - (float)currentPitchCount; + _gpuDstPitchCount[srcX] = pitch; + _gpuDstPitchIndex[srcX] = currentPitchCount; + currentPitchCount += pitch; + } + + for (size_t line = 0, currentLineCount = 0; line < GPU_VRAM_BLOCK_LINES + 1; line++) + { + const size_t lineCount = (size_t)ceilf((line+1) * customHeightScale) - currentLineCount; + GPUEngineLineInfo &lineInfo = this->_lineInfo[line]; + + lineInfo.indexNative = line; + lineInfo.indexCustom = currentLineCount; + lineInfo.widthCustom = w; + lineInfo.renderCount = lineCount; + lineInfo.pixelCount = lineInfo.widthCustom * lineInfo.renderCount; + lineInfo.blockOffsetNative = lineInfo.indexNative * GPU_FRAMEBUFFER_NATIVE_WIDTH; + lineInfo.blockOffsetCustom = lineInfo.indexCustom * lineInfo.widthCustom; + + currentLineCount += lineCount; + } + + u16 *newGpuDstToSrcIndex = (u16 *)malloc_alignedPage(w * h * sizeof(u16)); + u16 *newGpuDstToSrcPtr = newGpuDstToSrcIndex; + for (size_t y = 0, dstIdx = 0; y < GPU_FRAMEBUFFER_NATIVE_HEIGHT; y++) + { + if (this->_lineInfo[y].renderCount < 1) + { + continue; + } + + for (size_t x = 0; x < GPU_FRAMEBUFFER_NATIVE_WIDTH; x++) + { + for (size_t p = 0; p < _gpuDstPitchCount[x]; p++) + { + newGpuDstToSrcIndex[dstIdx++] = (y * GPU_FRAMEBUFFER_NATIVE_WIDTH) + x; + } + } + + for (size_t l = 1; l < this->_lineInfo[y].renderCount; l++) + { + memcpy(newGpuDstToSrcPtr + (w * l), newGpuDstToSrcPtr, w * sizeof(u16)); + } + + newGpuDstToSrcPtr += (w * this->_lineInfo[y].renderCount); + dstIdx += (w * (this->_lineInfo[y].renderCount - 1)); + } + + u8 *newGpuDstToSrcSSSE3_u8_8e = (u8 *)malloc_alignedPage(w * sizeof(u8)); + u8 *newGpuDstToSrcSSSE3_u8_16e = (u8 *)malloc_alignedPage(w * sizeof(u8)); + u8 *newGpuDstToSrcSSSE3_u16_8e = (u8 *)malloc_alignedPage(w * sizeof(u16)); + u8 *newGpuDstToSrcSSSE3_u32_4e = (u8 *)malloc_alignedPage(w * sizeof(u32)); + + for (size_t i = 0; i < w; i++) + { + const u8 value_u8_4 = newGpuDstToSrcIndex[i] & 0x03; + const u8 value_u8_8 = newGpuDstToSrcIndex[i] & 0x07; + const u8 value_u8_16 = newGpuDstToSrcIndex[i] & 0x0F; + const u8 value_u16 = (value_u8_8 << 1); + const u8 value_u32 = (value_u8_4 << 2); + + newGpuDstToSrcSSSE3_u8_8e[i] = value_u8_8; + newGpuDstToSrcSSSE3_u8_16e[i] = value_u8_16; + + newGpuDstToSrcSSSE3_u16_8e[(i << 1) + 0] = value_u16 + 0; + newGpuDstToSrcSSSE3_u16_8e[(i << 1) + 1] = value_u16 + 1; + + newGpuDstToSrcSSSE3_u32_4e[(i << 2) + 0] = value_u32 + 0; + newGpuDstToSrcSSSE3_u32_4e[(i << 2) + 1] = value_u32 + 1; + newGpuDstToSrcSSSE3_u32_4e[(i << 2) + 2] = value_u32 + 2; + newGpuDstToSrcSSSE3_u32_4e[(i << 2) + 3] = value_u32 + 3; + } + + _gpuLargestDstLineCount = newGpuLargestDstLineCount; + _gpuVRAMBlockOffset = this->_lineInfo[GPU_VRAM_BLOCK_LINES].indexCustom * w; + _gpuDstToSrcIndex = newGpuDstToSrcIndex; + _gpuDstToSrcSSSE3_u8_8e = newGpuDstToSrcSSSE3_u8_8e; + _gpuDstToSrcSSSE3_u8_16e = newGpuDstToSrcSSSE3_u8_16e; + _gpuDstToSrcSSSE3_u16_8e = newGpuDstToSrcSSSE3_u16_8e; + _gpuDstToSrcSSSE3_u32_4e = newGpuDstToSrcSSSE3_u32_4e; + + free_aligned(oldGpuDstToSrcIndexPtr); + free_aligned(oldGpuDstToSrcSSSE3_u8_8e); + free_aligned(oldGpuDstToSrcSSSE3_u8_16e); + free_aligned(oldGpuDstToSrcSSSE3_u16_8e); + free_aligned(oldGpuDstToSrcSSSE3_u32_4e); + } + this->_engineMain->RenderLineClearAsyncFinish(); this->_engineSub->RenderLineClearAsyncFinish(); this->AsyncSetupEngineBuffersFinish(); @@ -5133,13 +5126,10 @@ void GPUSubsystem::SetColorFormat(const NDSColorFormat outputFormat) CurrentRenderer->RenderFinish(); CurrentRenderer->SetRenderNeedsFinish(false); - this->_display[NDSDisplayID_Main]->SetColorFormat(outputFormat); - this->_display[NDSDisplayID_Touch]->SetColorFormat(outputFormat); + const bool didWidthNativeStateChange = ( didWidthChange && ((w == GPU_FRAMEBUFFER_NATIVE_WIDTH) || (this->_displayInfo.customWidth == GPU_FRAMEBUFFER_NATIVE_WIDTH)) ); + const bool didHeightNativeStateChange = ( didHeightChange && ((h == GPU_FRAMEBUFFER_NATIVE_HEIGHT) || (this->_displayInfo.customHeight == GPU_FRAMEBUFFER_NATIVE_HEIGHT)) ); - this->_displayInfo.colorFormat = this->_display[NDSDisplayID_Main]->GetColorFormat(); - this->_displayInfo.pixelBytes = (u32)this->_display[NDSDisplayID_Main]->GetPixelBytes(); - - if (!this->_displayInfo.isCustomSizeRequested) + if (didWidthNativeStateChange || didHeightNativeStateChange) { this->_engineMain->ResetCaptureLineStates(0); this->_engineMain->ResetCaptureLineStates(1); @@ -5147,7 +5137,33 @@ void GPUSubsystem::SetColorFormat(const NDSColorFormat outputFormat) this->_engineMain->ResetCaptureLineStates(3); } - this->_AllocateFramebuffers(this->_displayInfo.colorFormat, this->_displayInfo.customWidth, this->_displayInfo.customHeight, this->_displayInfo.framebufferPageCount); + this->_displayInfo.isCustomSizeRequested = ( (w != GPU_FRAMEBUFFER_NATIVE_WIDTH) || (h != GPU_FRAMEBUFFER_NATIVE_HEIGHT) ); + this->_displayInfo.customWidth = (u32)w; + this->_displayInfo.customHeight = (u32)h; + this->_displayInfo.colorFormat = colorFormat; + this->_displayInfo.pixelBytes = (u32)((colorFormat == NDSColorFormat_BGR555_Rev) ? sizeof(u16) : sizeof(Color4u8)); + this->_displayInfo.framebufferPageCount = (u32)pageCount; + + this->_display[NDSDisplayID_Main]->SetDisplaySize(w, h); + this->_display[NDSDisplayID_Main]->SetColorFormat(colorFormat); + + this->_display[NDSDisplayID_Touch]->SetDisplaySize(w, h); + this->_display[NDSDisplayID_Touch]->SetColorFormat(colorFormat); + + this->_AllocateFramebuffers(colorFormat, w, h, pageCount); + + if (CurrentRenderer != BaseRenderer) + { + if (didColorFormatChange) + { + CurrentRenderer->RequestColorFormat(colorFormat); + } + + if (didWidthChange || didHeightChange) + { + CurrentRenderer->SetFramebufferSize(w, h); + } + } } void GPUSubsystem::_AllocateFramebuffers(NDSColorFormat outputFormat, size_t w, size_t h, size_t pageCount) @@ -5163,7 +5179,6 @@ void GPUSubsystem::_AllocateFramebuffers(NDSColorFormat outputFormat, size_t w, void *newCustomVRAM = NULL; - this->_displayInfo.framebufferPageCount = (u32)pageCount; this->_displayInfo.framebufferPageSize = (u32)( (nativeFramebufferSize * 2) + (customFramebufferSize * 2) ); this->_masterFramebuffer = malloc_alignedPage(this->_displayInfo.framebufferPageSize * this->_displayInfo.framebufferPageCount); @@ -5250,12 +5265,6 @@ void GPUSubsystem::_AllocateFramebuffers(NDSColorFormat outputFormat, size_t w, this->_engineMain->AllocateWorkingBuffers(outputFormat, w, h); this->_engineSub->AllocateWorkingBuffers(outputFormat, w, h); - if (CurrentRenderer != BaseRenderer) - { - CurrentRenderer->RequestColorFormat(outputFormat); - CurrentRenderer->SetFramebufferSize(w, h); - } - free_aligned(oldMasterFramebuffer); free_aligned(oldCustomVRAM); } @@ -5437,13 +5446,16 @@ void GPUSubsystem::RenderLine(const size_t l) this->_event->DidApplyGPUSettingsBegin(); this->_engineMain->ApplySettings(); this->_engineSub->ApplySettings(); - this->_event->DidApplyGPUSettingsEnd(); this->_display[NDSDisplayID_Main]->SetIsEnabled( this->_display[NDSDisplayID_Main]->GetEngine()->GetEnableStateApplied() ); this->_display[NDSDisplayID_Touch]->SetIsEnabled( this->_display[NDSDisplayID_Touch]->GetEngine()->GetEnableStateApplied() ); this->_displayInfo.isDisplayEnabled[NDSDisplayID_Main] = this->_display[NDSDisplayID_Main]->IsEnabled(); this->_displayInfo.isDisplayEnabled[NDSDisplayID_Touch] = this->_display[NDSDisplayID_Touch]->IsEnabled(); + this->_ApplyFramebufferSettings(); + + this->_event->DidApplyGPUSettingsEnd(); + this->_event->DidFrameBegin(l, this->_willFrameSkip, this->_displayInfo.framebufferPageCount, this->_displayInfo.bufferIndex); this->_frameNeedsFinish = true; } @@ -6053,6 +6065,12 @@ void NDSDisplay::__constructor(const NDSDisplayID displayID, GPUEngineBase *theE { _ID = displayID; _gpuEngine = theEngine; + _gpuSystem = NULL; + + if (theEngine != NULL) + { + _gpuSystem = theEngine->GetGPUSystem(); + } for (size_t l = 0; l < GPU_FRAMEBUFFER_NATIVE_HEIGHT; l++) { @@ -6090,7 +6108,17 @@ GPUEngineBase* NDSDisplay::GetEngine() void NDSDisplay::SetEngine(GPUEngineBase *theEngine) { this->_gpuEngine = theEngine; - this->_gpuEngine->SetTargetDisplay(this); + + if (theEngine != NULL) + { + this->_gpuEngine->SetTargetDisplay(this); + this->_gpuSystem = theEngine->GetGPUSystem(); + } + else + { + this->_gpuEngine->SetTargetDisplay(NULL); + this->_gpuSystem = NULL; + } } GPUEngineID NDSDisplay::GetEngineID() @@ -6100,7 +6128,7 @@ GPUEngineID NDSDisplay::GetEngineID() void NDSDisplay::SetEngineByID(const GPUEngineID theID) { - this->SetEngine( (theID == GPUEngineID_Main) ? (GPUEngineBase *)GPU->GetEngineMain() : (GPUEngineBase *)GPU->GetEngineSub() ); + this->SetEngine( (theID == GPUEngineID_Main) ? (GPUEngineBase *)this->_gpuSystem->GetEngineMain() : (GPUEngineBase *)this->_gpuSystem->GetEngineSub() ); } size_t NDSDisplay::GetNativeLineCount() @@ -6169,7 +6197,7 @@ void NDSDisplay::ResolveLinesDisplayedNative() for (size_t y = 0; y < GPU_FRAMEBUFFER_NATIVE_HEIGHT; y++) { - const GPUEngineLineInfo &lineInfo = GPU->GetLineInfoAtIndex(y); + const GPUEngineLineInfo &lineInfo = this->_gpuSystem->GetLineInfoAtIndex(y); if (this->_isLineDisplayNative[y]) { @@ -6188,7 +6216,7 @@ void NDSDisplay::ResolveLinesDisplayedNative() for (size_t y = 0; y < GPU_FRAMEBUFFER_NATIVE_HEIGHT; y++) { - const GPUEngineLineInfo &lineInfo = GPU->GetLineInfoAtIndex(y); + const GPUEngineLineInfo &lineInfo = this->_gpuSystem->GetLineInfoAtIndex(y); if (this->_isLineDisplayNative[y]) { @@ -6251,7 +6279,7 @@ void NDSDisplay::ResolveFramebufferToCustom(NDSDisplayInfo &mutableInfo) for (size_t y = 0; y < GPU_FRAMEBUFFER_NATIVE_HEIGHT; y++) { - const GPUEngineLineInfo &lineInfo = GPU->GetLineInfoAtIndex(y); + const GPUEngineLineInfo &lineInfo = this->_gpuSystem->GetLineInfoAtIndex(y); CopyLineExpandHinted<0x3FFF, true, false, false, 2>(lineInfo, src, dst); src += GPU_FRAMEBUFFER_NATIVE_WIDTH; dst += lineInfo.pixelCount; @@ -6263,7 +6291,7 @@ void NDSDisplay::ResolveFramebufferToCustom(NDSDisplayInfo &mutableInfo) for (size_t y = 0; y < GPU_FRAMEBUFFER_NATIVE_HEIGHT; y++) { - const GPUEngineLineInfo &lineInfo = GPU->GetLineInfoAtIndex(y); + const GPUEngineLineInfo &lineInfo = this->_gpuSystem->GetLineInfoAtIndex(y); CopyLineExpandHinted<0x3FFF, true, false, false, 4>(lineInfo, working, dst); working += GPU_FRAMEBUFFER_NATIVE_WIDTH; dst += lineInfo.pixelCount; @@ -6410,7 +6438,7 @@ void NDSDisplay::ApplyMasterBrightness(const NDSDisplayInfo &displayInfo) // Apply the master brightness as a scanline operation. for (size_t line = 0; line < GPU_FRAMEBUFFER_NATIVE_HEIGHT; line++) { - const GPUEngineLineInfo &lineInfo = GPU->GetLineInfoAtIndex(line); + const GPUEngineLineInfo &lineInfo = this->_gpuSystem->GetLineInfoAtIndex(line); void *dstColorLine = (!this->DidPerformCustomRender()) ? ((u8 *)this->_nativeBuffer16 + (lineInfo.blockOffsetNative * sizeof(u16))) : ((u8 *)this->_customBuffer + (lineInfo.blockOffsetCustom * this->_customPixelBytes)); const size_t pixCount = (!this->DidPerformCustomRender()) ? GPU_FRAMEBUFFER_NATIVE_WIDTH : lineInfo.pixelCount; diff --git a/desmume/src/GPU.h b/desmume/src/GPU.h index bffc23fe2..3f7f75c1a 100755 --- a/desmume/src/GPU.h +++ b/desmume/src/GPU.h @@ -1359,6 +1359,8 @@ typedef struct GPUEngineTargetState target; } GPUEngineCompositorInfo; +class GPUSubsystem; + class GPUEngineBase { protected: @@ -1399,6 +1401,8 @@ protected: CACHE_ALIGN u8 _deferredIndexNative[GPU_FRAMEBUFFER_NATIVE_WIDTH * 4]; CACHE_ALIGN u16 _deferredColorNative[GPU_FRAMEBUFFER_NATIVE_WIDTH * 4]; + GPUSubsystem *_gpuSystem; + bool _needExpandSprColorCustom; u16 *_sprColorCustom; u8 *_sprAlphaCustom; @@ -1536,6 +1540,9 @@ public: GPUEngineBase(); virtual ~GPUEngineBase(); + GPUSubsystem* GetGPUSystem(); + void SetGPUSystem(GPUSubsystem *theGPU); + virtual void Reset(); void SetupBuffers(); @@ -1609,10 +1616,6 @@ public: class GPUEngineA : public GPUEngineBase { -private: - GPUEngineA(); - ~GPUEngineA(); - protected: CACHE_ALIGN u16 _fifoLine16[GPU_FRAMEBUFFER_NATIVE_WIDTH]; CACHE_ALIGN Color4u8 _fifoLine32[GPU_FRAMEBUFFER_NATIVE_WIDTH]; @@ -1671,8 +1674,10 @@ protected: void _HandleDisplayModeMainMemory(const GPUEngineLineInfo &lineInfo); public: - static GPUEngineA* Allocate(); - void FinalizeAndDeallocate(); + static void* operator new(size_t size); + static void operator delete(void *p); + GPUEngineA(); + virtual ~GPUEngineA(); void ParseReg_DISPCAPCNT(); bool IsLineCaptureNative(const size_t blockID, const size_t blockLine); @@ -1697,13 +1702,11 @@ public: class GPUEngineB : public GPUEngineBase { -private: - GPUEngineB(); - ~GPUEngineB(); - public: - static GPUEngineB* Allocate(); - void FinalizeAndDeallocate(); + static void* operator new(size_t size); + static void operator delete(void *p); + GPUEngineB(); + virtual ~GPUEngineB(); virtual void Reset(); @@ -1714,6 +1717,7 @@ class NDSDisplay { private: NDSDisplayID _ID; + GPUSubsystem *_gpuSystem; GPUEngineBase *_gpuEngine; // Native line tracking must be handled at the display level in order to account for @@ -1855,6 +1859,10 @@ private: void *_customVRAM; void *_customVRAMBlank; + NDSColorFormat _framebufferColorFormatPending; + size_t _framebufferWidthPending; + size_t _framebufferHeightPending; + size_t _framebufferPageCountPending; void *_masterFramebuffer; u32 *_masterWorkingNativeBuffer32; @@ -1862,6 +1870,7 @@ private: void _UpdateFPSRender3D(); void _AllocateFramebuffers(NDSColorFormat outputFormat, size_t w, size_t h, size_t pageCount); + void _ApplyFramebufferSettings(); void _DownscaleAndConvertForSavestate(const NDSDisplayID displayID, const void *srcBuffer, u16 *dstBuffer); void _ConvertAndUpscaleForLoadstate(const NDSDisplayID displayID, const u16 *srcBuffer, void *dstBuffer); diff --git a/desmume/src/frontend/cocoa/ClientAudioOutput.cpp b/desmume/src/frontend/cocoa/ClientAudioOutput.cpp index c0f589ed6..75695ae20 100644 --- a/desmume/src/frontend/cocoa/ClientAudioOutput.cpp +++ b/desmume/src/frontend/cocoa/ClientAudioOutput.cpp @@ -191,6 +191,11 @@ ClientAudioOutput::ClientAudioOutput() _spuCallbackStruct.FetchSamples = &SPUFetchSamplesCallback; _spuCallbackStruct.PostProcessSamples = &SPUPostProcessSamples; + if (SNDCoreList[1] == NULL) + { + SNDCoreList[1] = &_spuCallbackStruct; + } + _volume = MAX_VOLUME; _spuAdvancedLogic = true; _interpolationModeID = SPUInterpolation_Cosine; diff --git a/desmume/src/frontend/cocoa/ClientVideoOutput.cpp b/desmume/src/frontend/cocoa/ClientVideoOutput.cpp index 976eb3562..3ba52b809 100644 --- a/desmume/src/frontend/cocoa/ClientVideoOutput.cpp +++ b/desmume/src/frontend/cocoa/ClientVideoOutput.cpp @@ -913,6 +913,28 @@ void ClientDisplayViewOutputManager::SetNDSFrameInfoToAll(const NDSFrameInfo &fr pthread_mutex_unlock(&this->_pendingUnregisterListMutex); } +void ClientDisplayViewOutputManager::GenerateViewListAll(std::vector &outFinalizeList) +{ + // Add all pending outputs to be registered. + pthread_mutex_lock(&this->_pendingRegisterListMutex); + this->_RegisterPending(); + pthread_mutex_unlock(&this->_pendingRegisterListMutex); + + // Remove all pending outputs to be unregistered. + pthread_mutex_lock(&this->_pendingUnregisterListMutex); + this->_UnregisterPending(); + + // Finally, run the outputs. + for (size_t i = 0; i < this->_runList.size(); i++) + { + ClientDisplayViewOutput *runningOutput = (ClientDisplayViewOutput *)this->_runList[i]; + ClientDisplayViewInterface *cdv = (ClientDisplayViewInterface *)runningOutput->GetClientDisplayView(); + outFinalizeList.push_back(cdv); + } + + pthread_mutex_unlock(&this->_pendingUnregisterListMutex); +} + void ClientDisplayViewOutputManager::GenerateFlushListForDisplay(int32_t displayID, std::vector &outFlushList) { // Add all pending outputs to be registered. @@ -1033,3 +1055,16 @@ void ClientGPUFetchObjectMultiDisplayView::FlushMultipleViews(const std::vector< cdv->FinalizeFlush(NULL, timeStampOutput); } } + +void ClientGPUFetchObjectMultiDisplayView::FinalizeAllViews() +{ + std::vector cdvList; + this->_outputManager->GenerateViewListAll(cdvList); + + const size_t listSize = cdvList.size(); + for (size_t i = 0; i < listSize; i++) + { + ClientDisplayViewInterface *cdv = cdvList[i]; + cdv->FinalizeFlush(NULL, 0); + } +} diff --git a/desmume/src/frontend/cocoa/ClientVideoOutput.h b/desmume/src/frontend/cocoa/ClientVideoOutput.h index 8e9f18135..ac3a3c488 100644 --- a/desmume/src/frontend/cocoa/ClientVideoOutput.h +++ b/desmume/src/frontend/cocoa/ClientVideoOutput.h @@ -224,6 +224,7 @@ public: void TakeFrameCountAll(); void SetNDSFrameInfoToAll(const NDSFrameInfo &frameInfo); + void GenerateViewListAll(std::vector &outFinalizeList); void GenerateFlushListForDisplay(int32_t displayID, std::vector &outFlushList); }; @@ -255,6 +256,7 @@ public: void PushVideoDataToAllDisplayViews(); virtual void FlushAllViewsOnDisplay(int32_t displayID, uint64_t timeStampNow, uint64_t timeStampOutput); virtual void FlushMultipleViews(const std::vector &cdvFlushList, uint64_t timeStampNow, uint64_t timeStampOutput); + virtual void FinalizeAllViews(); }; #endif // _CLIENT_OUTPUT_DISPLAY_H_ diff --git a/desmume/src/frontend/cocoa/DeSmuME (Latest).xcodeproj/project.pbxproj b/desmume/src/frontend/cocoa/DeSmuME (Latest).xcodeproj/project.pbxproj index bac8dbe8b..e81ace25d 100755 --- a/desmume/src/frontend/cocoa/DeSmuME (Latest).xcodeproj/project.pbxproj +++ b/desmume/src/frontend/cocoa/DeSmuME (Latest).xcodeproj/project.pbxproj @@ -1534,6 +1534,17 @@ AB5B1D4C21D1F31E00BF0E0F /* MetalRendererCommonShaders.metal in Sources */ = {isa = PBXBuildFile; fileRef = AB5B1D4921D1F31E00BF0E0F /* MetalRendererCommonShaders.metal */; }; AB5B1D4D21D1F31E00BF0E0F /* MetalRendererCommonShaders.metal in Sources */ = {isa = PBXBuildFile; fileRef = AB5B1D4921D1F31E00BF0E0F /* MetalRendererCommonShaders.metal */; }; AB5FDDAC1D62C89E0094617C /* colorspacehandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABBFFF6F1D5F9C52003CD598 /* colorspacehandler.cpp */; }; + AB64DC462E78E3710092D8FC /* cgl_3Demu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB64DC452E78E3710092D8FC /* cgl_3Demu.cpp */; }; + AB64DC472E78E3710092D8FC /* cgl_3Demu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB64DC452E78E3710092D8FC /* cgl_3Demu.cpp */; }; + AB64DC482E78E3710092D8FC /* cgl_3Demu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB64DC452E78E3710092D8FC /* cgl_3Demu.cpp */; }; + AB64DC492E78E3710092D8FC /* cgl_3Demu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB64DC452E78E3710092D8FC /* cgl_3Demu.cpp */; }; + AB64DC4A2E78E3710092D8FC /* cgl_3Demu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB64DC452E78E3710092D8FC /* cgl_3Demu.cpp */; }; + AB64DC4B2E78E3710092D8FC /* cgl_3Demu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB64DC452E78E3710092D8FC /* cgl_3Demu.cpp */; }; + AB64DC4C2E78E3710092D8FC /* cgl_3Demu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB64DC452E78E3710092D8FC /* cgl_3Demu.cpp */; }; + AB64DC4D2E78E3710092D8FC /* cgl_3Demu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB64DC452E78E3710092D8FC /* cgl_3Demu.cpp */; }; + AB64DC4E2E78E3710092D8FC /* cgl_3Demu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB64DC452E78E3710092D8FC /* cgl_3Demu.cpp */; }; + AB64DC4F2E78E3710092D8FC /* cgl_3Demu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB64DC452E78E3710092D8FC /* cgl_3Demu.cpp */; }; + AB64DC502E78E3710092D8FC /* cgl_3Demu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB64DC452E78E3710092D8FC /* cgl_3Demu.cpp */; }; AB68101B187D4AEF0049F2C2 /* Icon_GuitarGrip_Button_Blue_512x512.png in Resources */ = {isa = PBXBuildFile; fileRef = AB681013187D4AEF0049F2C2 /* Icon_GuitarGrip_Button_Blue_512x512.png */; }; AB68101D187D4AEF0049F2C2 /* Icon_GuitarGrip_Button_Green_512x512.png in Resources */ = {isa = PBXBuildFile; fileRef = AB681014187D4AEF0049F2C2 /* Icon_GuitarGrip_Button_Green_512x512.png */; }; AB68101F187D4AEF0049F2C2 /* Icon_GuitarGrip_Button_Red_512x512.png in Resources */ = {isa = PBXBuildFile; fileRef = AB681015187D4AEF0049F2C2 /* Icon_GuitarGrip_Button_Red_512x512.png */; }; @@ -4092,6 +4103,8 @@ AB5B1D4821D1F31D00BF0E0F /* MetalRendererCommonShaders.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MetalRendererCommonShaders.h; sourceTree = ""; }; AB5B1D4921D1F31E00BF0E0F /* MetalRendererCommonShaders.metal */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.metal; path = MetalRendererCommonShaders.metal; sourceTree = ""; }; AB64987B13ECC73800EE7DD2 /* FileTypeInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = FileTypeInfo.plist; sourceTree = ""; }; + AB64DC442E78E3710092D8FC /* cgl_3Demu.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cgl_3Demu.h; sourceTree = ""; }; + AB64DC452E78E3710092D8FC /* cgl_3Demu.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = cgl_3Demu.cpp; sourceTree = ""; }; AB681013187D4AEF0049F2C2 /* Icon_GuitarGrip_Button_Blue_512x512.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Icon_GuitarGrip_Button_Blue_512x512.png; path = images/Icon_GuitarGrip_Button_Blue_512x512.png; sourceTree = ""; }; AB681014187D4AEF0049F2C2 /* Icon_GuitarGrip_Button_Green_512x512.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Icon_GuitarGrip_Button_Green_512x512.png; path = images/Icon_GuitarGrip_Button_Green_512x512.png; sourceTree = ""; }; AB681015187D4AEF0049F2C2 /* Icon_GuitarGrip_Button_Red_512x512.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Icon_GuitarGrip_Button_Red_512x512.png; path = images/Icon_GuitarGrip_Button_Red_512x512.png; sourceTree = ""; }; @@ -4909,6 +4922,7 @@ AB6E3B452E7385710088075E /* ClientFirmwareControl.cpp */, AB11AD871F6757F800CB298E /* ClientInputHandler.cpp */, ABDB1BEE2E66486E002AD9AF /* ClientVideoOutput.cpp */, + AB64DC452E78E3710092D8FC /* cgl_3Demu.cpp */, AB1B9E5F1501A78000464647 /* coreaudiosound.cpp */, AB28625320AE3E9E00EAED43 /* macOS_driver.cpp */, AB23567216C2F6F400DA782E /* macosx_10_5_compat.cpp */, @@ -4926,6 +4940,7 @@ AB6E3B442E7385710088075E /* ClientFirmwareControl.h */, AB11AD881F6757F800CB298E /* ClientInputHandler.h */, ABDB1BED2E66486E002AD9AF /* ClientVideoOutput.h */, + AB64DC442E78E3710092D8FC /* cgl_3Demu.h */, ABA6574914511EC90077E5E9 /* cocoa_cheat.h */, ABD103FE1346652500AF11D1 /* cocoa_core.h */, AB58F32B1364F44B0074C376 /* cocoa_file.h */, @@ -8008,6 +8023,7 @@ 8C43E7B227E3CD0100A35F65 /* cache.cpp in Sources */, 8C43E7B327E3CD0100A35F65 /* fsnitro.cpp in Sources */, 8C43E7B427E3CD0100A35F65 /* fttype1.c in Sources */, + AB64DC492E78E3710092D8FC /* cgl_3Demu.cpp in Sources */, 8C43E7B527E3CD0100A35F65 /* cheatSystem.cpp in Sources */, 8C43E7B627E3CD0100A35F65 /* common.cpp in Sources */, 8C43E7B727E3CD0100A35F65 /* slot1comp_mc.cpp in Sources */, @@ -8212,6 +8228,7 @@ 8C43E90E27E3CD4C00A35F65 /* ftpatent.c in Sources */, 8C43E90F27E3CD4C00A35F65 /* sfnt.c in Sources */, 8C43E91027E3CD4C00A35F65 /* ftfntfmt.c in Sources */, + AB64DC4D2E78E3710092D8FC /* cgl_3Demu.cpp in Sources */, 8C43E91127E3CD4C00A35F65 /* fttype1.c in Sources */, 8C43E91227E3CD4C00A35F65 /* ftmm.c in Sources */, 8C43E91327E3CD4C00A35F65 /* ftfstype.c in Sources */, @@ -8421,6 +8438,7 @@ 8CCD842327E40B730024BDD5 /* armcpu.cpp in Sources */, 8CCD842427E40B730024BDD5 /* bios.cpp in Sources */, 8CCD842527E40B730024BDD5 /* cache.cpp in Sources */, + AB64DC4E2E78E3710092D8FC /* cgl_3Demu.cpp in Sources */, 8CCD842627E40B730024BDD5 /* cheatSystem.cpp in Sources */, 8CCD842727E40B730024BDD5 /* slot2_auto.cpp in Sources */, 8CCD842827E40B730024BDD5 /* ftsystem.c in Sources */, @@ -8783,6 +8801,7 @@ AB36C83D27F2C8AE00C763C8 /* ftdebug.c in Sources */, AB36C83E27F2C8AE00C763C8 /* fttype1.c in Sources */, AB36C83F27F2C8AE00C763C8 /* arm_jit.cpp in Sources */, + AB64DC4B2E78E3710092D8FC /* cgl_3Demu.cpp in Sources */, AB36C84027F2C8AE00C763C8 /* troubleshootingWindowDelegate.mm in Sources */, AB36C84127F2C8AE00C763C8 /* assembler.cpp in Sources */, AB36C84227F2C8AE00C763C8 /* assert.cpp in Sources */, @@ -8947,6 +8966,7 @@ AB7900A4215B84E50082AE82 /* slot1_retail_mcrom_debug.cpp in Sources */, AB7900A5215B84E50082AE82 /* cocoa_slot2.mm in Sources */, AB7900A6215B84E50082AE82 /* slot1_r4.cpp in Sources */, + AB64DC462E78E3710092D8FC /* cgl_3Demu.cpp in Sources */, AB7900A7215B84E50082AE82 /* MacMetalDisplayView.mm in Sources */, AB7900A8215B84E50082AE82 /* slot1_retail_nand.cpp in Sources */, AB7900A9215B84E50082AE82 /* encoding_utf.c in Sources */, @@ -9207,6 +9227,7 @@ AB790216215B84F20082AE82 /* SndOut.cpp in Sources */, AB790217215B84F20082AE82 /* psnames.c in Sources */, AB790218215B84F20082AE82 /* Slot2WindowDelegate.mm in Sources */, + AB64DC472E78E3710092D8FC /* cgl_3Demu.cpp in Sources */, AB790219215B84F20082AE82 /* truetype.c in Sources */, AB79021A215B84F20082AE82 /* SoundTouch.cpp in Sources */, AB79021B215B84F20082AE82 /* slot1_retail_auto.cpp in Sources */, @@ -9418,6 +9439,7 @@ AB2EE12C17D57ED500F68622 /* slot1_retail_mcrom_debug.cpp in Sources */, AB5648FF186E6EA8002740F4 /* cocoa_slot2.mm in Sources */, AB796D2A15CDCBA200C59155 /* slot1_r4.cpp in Sources */, + AB64DC4C2E78E3710092D8FC /* cgl_3Demu.cpp in Sources */, AB78B5C41E384F4F00297FED /* MacMetalDisplayView.mm in Sources */, AB796D2C15CDCBA200C59155 /* slot1_retail_nand.cpp in Sources */, AB35BD8F1DEBF40800844310 /* encoding_utf.c in Sources */, @@ -9678,6 +9700,7 @@ AB8F3CBE1A53AC2600A80BF6 /* SndOut.cpp in Sources */, ABA7315C1BB51A8D00B26147 /* psnames.c in Sources */, AB8F3CBF1A53AC2600A80BF6 /* Slot2WindowDelegate.mm in Sources */, + AB64DC4A2E78E3710092D8FC /* cgl_3Demu.cpp in Sources */, ABFEA8EA1BB4FB3200B08C25 /* truetype.c in Sources */, AB8F3CC01A53AC2600A80BF6 /* SoundTouch.cpp in Sources */, AB8F3CC11A53AC2600A80BF6 /* slot1_retail_auto.cpp in Sources */, @@ -9959,6 +9982,7 @@ AB9038B717C5ED2200F410BD /* slot1comp_mc.cpp in Sources */, AB3A656316CC5438001F5D4A /* cocoa_GPU.mm in Sources */, AB82445D1704AE9A00B8EE20 /* utilities.c in Sources */, + AB64DC4F2E78E3710092D8FC /* cgl_3Demu.cpp in Sources */, AB49B556281707590069F1D7 /* OGLDisplayOutput.cpp in Sources */, ABD10AE91715FCDD00B5729D /* audiosamplegenerator.cpp in Sources */, ABD10AEC1715FCDD00B5729D /* mic_ext.cpp in Sources */, @@ -10067,6 +10091,7 @@ ABC858F528273FEE00A03EA9 /* slot2_rumblepak.cpp in Sources */, ABC858F728273FEE00A03EA9 /* SndOut.cpp in Sources */, ABC858F828273FEE00A03EA9 /* ftpfr.c in Sources */, + AB64DC482E78E3710092D8FC /* cgl_3Demu.cpp in Sources */, ABC858F928273FEE00A03EA9 /* Slot2WindowDelegate.mm in Sources */, ABC858FA28273FEE00A03EA9 /* SoundTouch.cpp in Sources */, ABC858FB28273FEE00A03EA9 /* ftfstype.c in Sources */, @@ -10302,6 +10327,7 @@ ABD2CDA926E05CB000FB15F7 /* slot2_rumblepak.cpp in Sources */, ABD2CDAB26E05CB000FB15F7 /* SndOut.cpp in Sources */, ABD2CDAC26E05CB000FB15F7 /* ftpfr.c in Sources */, + AB64DC502E78E3710092D8FC /* cgl_3Demu.cpp in Sources */, ABD2CDAD26E05CB000FB15F7 /* Slot2WindowDelegate.mm in Sources */, ABD2CDAE26E05CB000FB15F7 /* SoundTouch.cpp in Sources */, ABD2CDAF26E05CB000FB15F7 /* ftfstype.c in Sources */, diff --git a/desmume/src/frontend/cocoa/DeSmuME (XCode 3).xcodeproj/project.pbxproj b/desmume/src/frontend/cocoa/DeSmuME (XCode 3).xcodeproj/project.pbxproj index 8c47100a7..122fc748f 100755 --- a/desmume/src/frontend/cocoa/DeSmuME (XCode 3).xcodeproj/project.pbxproj +++ b/desmume/src/frontend/cocoa/DeSmuME (XCode 3).xcodeproj/project.pbxproj @@ -311,6 +311,11 @@ AB1E5A3D2E73F0AC008AFF9F /* ClientFirmwareControl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB1E5A342E73F0AC008AFF9F /* ClientFirmwareControl.cpp */; }; AB1E5A3E2E73F0AC008AFF9F /* ClientCheatManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB1E5A322E73F0AC008AFF9F /* ClientCheatManager.cpp */; }; AB1E5A3F2E73F0AC008AFF9F /* ClientFirmwareControl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB1E5A342E73F0AC008AFF9F /* ClientFirmwareControl.cpp */; }; + AB1E6DA62E7C63420057B8C9 /* cgl_3Demu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB1E6DA42E7C63420057B8C9 /* cgl_3Demu.cpp */; }; + AB1E6DA72E7C63420057B8C9 /* cgl_3Demu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB1E6DA42E7C63420057B8C9 /* cgl_3Demu.cpp */; }; + AB1E6DA82E7C63420057B8C9 /* cgl_3Demu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB1E6DA42E7C63420057B8C9 /* cgl_3Demu.cpp */; }; + AB1E6DA92E7C63420057B8C9 /* cgl_3Demu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB1E6DA42E7C63420057B8C9 /* cgl_3Demu.cpp */; }; + AB1E6DAA2E7C63420057B8C9 /* cgl_3Demu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB1E6DA42E7C63420057B8C9 /* cgl_3Demu.cpp */; }; AB213D45170CB141006DDB0F /* InputProfileController.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB213D44170CB141006DDB0F /* InputProfileController.mm */; }; AB213D46170CB141006DDB0F /* InputProfileController.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB213D44170CB141006DDB0F /* InputProfileController.mm */; }; AB213D47170CB141006DDB0F /* InputProfileController.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB213D44170CB141006DDB0F /* InputProfileController.mm */; }; @@ -1958,6 +1963,8 @@ AB1E5A332E73F0AC008AFF9F /* ClientCheatManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ClientCheatManager.h; sourceTree = ""; }; AB1E5A342E73F0AC008AFF9F /* ClientFirmwareControl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ClientFirmwareControl.cpp; sourceTree = ""; }; AB1E5A352E73F0AC008AFF9F /* ClientFirmwareControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ClientFirmwareControl.h; sourceTree = ""; }; + AB1E6DA42E7C63420057B8C9 /* cgl_3Demu.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cgl_3Demu.cpp; sourceTree = ""; }; + AB1E6DA52E7C63420057B8C9 /* cgl_3Demu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cgl_3Demu.h; sourceTree = ""; }; AB213D43170CB141006DDB0F /* InputProfileController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InputProfileController.h; sourceTree = ""; }; AB213D44170CB141006DDB0F /* InputProfileController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = InputProfileController.mm; sourceTree = ""; }; AB213E981710D074006DDB0F /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; @@ -2608,6 +2615,7 @@ AB1E5A342E73F0AC008AFF9F /* ClientFirmwareControl.cpp */, ABC04DA11F67A20500EA6ED7 /* ClientInputHandler.cpp */, AB561C012E72AD6E007F88A5 /* ClientVideoOutput.cpp */, + AB1E6DA42E7C63420057B8C9 /* cgl_3Demu.cpp */, ABD0A5341501AA5A0074A094 /* coreaudiosound.cpp */, ABD1267320AE812900EFE1B2 /* macOS_driver.cpp */, ABC04DC91F67A2AC00EA6ED7 /* macosx_10_5_compat.cpp */, @@ -2625,6 +2633,7 @@ AB1E5A352E73F0AC008AFF9F /* ClientFirmwareControl.h */, ABC04DA21F67A20500EA6ED7 /* ClientInputHandler.h */, AB561C022E72AD6E007F88A5 /* ClientVideoOutput.h */, + AB1E6DA52E7C63420057B8C9 /* cgl_3Demu.h */, ABA6574914511EC90077E5E9 /* cocoa_cheat.h */, ABD103FE1346652500AF11D1 /* cocoa_core.h */, AB58F32B1364F44B0074C376 /* cocoa_file.h */, @@ -4920,6 +4929,7 @@ AB1E5A382E73F0AC008AFF9F /* ClientCheatManager.cpp in Sources */, AB1E5A392E73F0AC008AFF9F /* ClientFirmwareControl.cpp in Sources */, AB743E482E766E2E007FB6A2 /* MacCoreAudioOutputEngine.cpp in Sources */, + AB1E6DA72E7C63420057B8C9 /* cgl_3Demu.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5121,6 +5131,7 @@ AB1E5A3A2E73F0AC008AFF9F /* ClientCheatManager.cpp in Sources */, AB1E5A3B2E73F0AC008AFF9F /* ClientFirmwareControl.cpp in Sources */, AB743E492E766E2E007FB6A2 /* MacCoreAudioOutputEngine.cpp in Sources */, + AB1E6DA82E7C63420057B8C9 /* cgl_3Demu.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5352,6 +5363,7 @@ AB1E5A3E2E73F0AC008AFF9F /* ClientCheatManager.cpp in Sources */, AB1E5A3F2E73F0AC008AFF9F /* ClientFirmwareControl.cpp in Sources */, AB743E4B2E766E2E007FB6A2 /* MacCoreAudioOutputEngine.cpp in Sources */, + AB1E6DAA2E7C63420057B8C9 /* cgl_3Demu.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5583,6 +5595,7 @@ AB1E5A3C2E73F0AC008AFF9F /* ClientCheatManager.cpp in Sources */, AB1E5A3D2E73F0AC008AFF9F /* ClientFirmwareControl.cpp in Sources */, AB743E4A2E766E2E007FB6A2 /* MacCoreAudioOutputEngine.cpp in Sources */, + AB1E6DA92E7C63420057B8C9 /* cgl_3Demu.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5784,6 +5797,7 @@ AB1E5A362E73F0AC008AFF9F /* ClientCheatManager.cpp in Sources */, AB1E5A372E73F0AC008AFF9F /* ClientFirmwareControl.cpp in Sources */, AB743E472E766E2E007FB6A2 /* MacCoreAudioOutputEngine.cpp in Sources */, + AB1E6DA62E7C63420057B8C9 /* cgl_3Demu.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5982,6 +5996,7 @@ GCC_ENABLE_FIX_AND_CONTINUE = YES; GCC_FAST_MATH = YES; GCC_FAST_OBJC_DISPATCH = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; GCC_MODEL_TUNING = ""; "GCC_MODEL_TUNING[sdk=macosx10.4][arch=ppc]" = G4; "GCC_MODEL_TUNING[sdk=macosx10.5][arch=ppc64]" = G5; @@ -6044,7 +6059,7 @@ GCC_ENABLE_SUPPLEMENTAL_SSE3_INSTRUCTIONS = YES; "GCC_ENABLE_SUPPLEMENTAL_SSE3_INSTRUCTIONS[arch=i386]" = NO; GCC_FAST_MATH = YES; - GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; GCC_INLINES_ARE_PRIVATE_EXTERN = YES; "GCC_MODEL_PPC64[sdk=macosx10.5][arch=ppc64]" = YES; GCC_MODEL_TUNING = G5; @@ -6054,7 +6069,7 @@ GCC_PREFIX_HEADER = DeSmuME_Prefix.pch; GCC_PREPROCESSOR_DEFINITIONS = NDEBUG; GCC_STRICT_ALIASING = YES; - GCC_SYMBOLS_PRIVATE_EXTERN = YES; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_THREADSAFE_STATICS = NO; GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; GCC_UNROLL_LOOPS = YES; diff --git a/desmume/src/frontend/cocoa/cgl_3Demu.cpp b/desmume/src/frontend/cocoa/cgl_3Demu.cpp new file mode 100644 index 000000000..92ec029f4 --- /dev/null +++ b/desmume/src/frontend/cocoa/cgl_3Demu.cpp @@ -0,0 +1,574 @@ +/* + Copyright (C) 2025 DeSmuME team + + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the this software. If not, see . + */ + +#include "cgl_3Demu.h" + +#include +#include + +#include +#include + +#ifdef MAC_OS_X_VERSION_10_7 + #include "../../OGLRender_3_2.h" +#else + #include "../../OGLRender.h" +#endif + +#include "utilities.h" + +#if !defined(MAC_OS_X_VERSION_10_7) + #define kCGLPFAOpenGLProfile (CGLPixelFormatAttribute)99 + #define kCGLOGLPVersion_Legacy 0x1000 + #define kCGLOGLPVersion_3_2_Core 0x3200 + #define kCGLOGLPVersion_GL3_Core 0x3200 + #define kCGLRPVideoMemoryMegabytes (CGLRendererProperty)131 + #define kCGLRPTextureMemoryMegabytes (CGLRendererProperty)132 +#endif + +#if !defined(MAC_OS_X_VERSION_10_9) + #define kCGLOGLPVersion_GL4_Core 0x4100 +#endif + +#if !defined(MAC_OS_X_VERSION_10_13) + #define kCGLRPRemovable (CGLRendererProperty)142 +#endif + + +int __hostRendererID = -1; +char __hostRendererString[256] = {0}; + +CGLContextObj OSXOpenGLRendererContext = NULL; +CGLContextObj OSXOpenGLRendererContextPrev = NULL; +SILENCE_DEPRECATION_MACOS_10_7( CGLPBufferObj OSXOpenGLRendererPBuffer = NULL ) + +static bool __cgl_initOpenGL(const int requestedProfile) +{ + bool result = false; + CACHE_ALIGN char ctxString[16] = {0}; + + if (requestedProfile == kCGLOGLPVersion_GL4_Core) + { + strncpy(ctxString, "CGL 4.1", sizeof(ctxString)); + } + else if (requestedProfile == kCGLOGLPVersion_3_2_Core) + { + strncpy(ctxString, "CGL 3.2", sizeof(ctxString)); + } + else + { + strncpy(ctxString, "CGL Legacy", sizeof(ctxString)); + } + + if (OSXOpenGLRendererContext != NULL) + { + result = true; + return result; + } + + const bool isHighSierraSupported = IsOSXVersionSupported(10, 13, 0); + const bool isMavericksSupported = (isHighSierraSupported || IsOSXVersionSupported(10, 9, 0)); + const bool isMountainLionSupported = (isMavericksSupported || IsOSXVersionSupported(10, 8, 0)); + const bool isLionSupported = (isMountainLionSupported || IsOSXVersionSupported(10, 7, 0)); + const bool isLeopardSupported = (isLionSupported || IsOSXVersionSupported(10, 5, 0)); + + CGLPixelFormatAttribute attrs[] = { + kCGLPFAColorSize, (CGLPixelFormatAttribute)24, + kCGLPFAAlphaSize, (CGLPixelFormatAttribute)8, + kCGLPFADepthSize, (CGLPixelFormatAttribute)24, + kCGLPFAStencilSize, (CGLPixelFormatAttribute)8, + kCGLPFAOpenGLProfile, (CGLPixelFormatAttribute)0, + kCGLPFAAllowOfflineRenderers, + kCGLPFAAccelerated, + kCGLPFANoRecovery, + (CGLPixelFormatAttribute)0 + }; + + if (requestedProfile == kCGLOGLPVersion_GL4_Core) + { + if (isMavericksSupported) + { + attrs[5] = (CGLPixelFormatAttribute)0; // We'll be using FBOs instead of the default framebuffer. + attrs[7] = (CGLPixelFormatAttribute)0; // We'll be using FBOs instead of the default framebuffer. + attrs[9] = (CGLPixelFormatAttribute)requestedProfile; + } + else + { + fprintf(stderr, "%s: Your version of OS X is too old to support 4.1 Core Profile.\n", ctxString); + return result; + } + } + else if (requestedProfile == kCGLOGLPVersion_3_2_Core) + { + // As of 2021/09/03, testing has shown that macOS v10.7's OpenGL 3.2 shader + // compiler isn't very reliable, and so we're going to require macOS v10.8 + // instead, which at least has a working shader compiler for OpenGL 3.2. + if (isMountainLionSupported) + { + attrs[5] = (CGLPixelFormatAttribute)0; // We'll be using FBOs instead of the default framebuffer. + attrs[7] = (CGLPixelFormatAttribute)0; // We'll be using FBOs instead of the default framebuffer. + attrs[9] = (CGLPixelFormatAttribute)requestedProfile; + } + else + { + fprintf(stderr, "%s: Your version of OS X is too old to support 3.2 Core Profile.\n", ctxString); + return result; + } + } + else if (isLionSupported) + { + attrs[9] = (CGLPixelFormatAttribute)kCGLOGLPVersion_Legacy; + } + else + { + attrs[8] = (CGLPixelFormatAttribute)kCGLPFAAccelerated; + attrs[9] = (CGLPixelFormatAttribute)kCGLPFANoRecovery; + attrs[11] = (CGLPixelFormatAttribute)0; + attrs[12] = (CGLPixelFormatAttribute)0; + } + + CGLError error = kCGLNoError; + CGLPixelFormatObj cglPixFormat = NULL; + CGLContextObj newContext = NULL; + GLint virtualScreenCount = 0; + + CGLChoosePixelFormat(attrs, &cglPixFormat, &virtualScreenCount); + if (cglPixFormat == NULL) + { + if (requestedProfile == kCGLOGLPVersion_GL4_Core) + { + // OpenGL 4.1 Core Profile requires hardware acceleration. Bail if we can't find a renderer that supports both. + fprintf(stderr, "%s: This system has no HW-accelerated renderers that support 4.1 Core Profile.\n", ctxString); + return result; + } + else if (requestedProfile == kCGLOGLPVersion_3_2_Core) + { + // OpenGL 3.2 Core Profile requires hardware acceleration. Bail if we can't find a renderer that supports both. + fprintf(stderr, "%s: This system has no HW-accelerated renderers that support 3.2 Core Profile.\n", ctxString); + return result; + } + + // For Legacy OpenGL, we'll allow fallback to the Apple Software Renderer. + // However, doing this will result in a substantial performance loss. + if (attrs[8] == kCGLPFAAccelerated) + { + attrs[8] = (CGLPixelFormatAttribute)0; + attrs[9] = (CGLPixelFormatAttribute)0; + attrs[10] = (CGLPixelFormatAttribute)0; + } + else + { + attrs[10] = (CGLPixelFormatAttribute)0; + attrs[11] = (CGLPixelFormatAttribute)0; + attrs[12] = (CGLPixelFormatAttribute)0; + } + + error = CGLChoosePixelFormat(attrs, &cglPixFormat, &virtualScreenCount); + if (error != kCGLNoError) + { + // We shouldn't fail at this point, but we're including this to account for all code paths. + fprintf(stderr, "%s: Failed to create the pixel format structure: %i\n", ctxString, (int)error); + return result; + } + else + { + printf("WARNING: No HW-accelerated renderers were found -- falling back to Apple Software Renderer.\n This will result in a substantial performance loss."); + } + } + + // Create the OpenGL context using our pixel format, and then save the default assigned virtual screen. + error = CGLCreateContext(cglPixFormat, NULL, &newContext); + CGLReleasePixelFormat(cglPixFormat); + cglPixFormat = NULL; + + if (error != kCGLNoError) + { + fprintf(stderr, "%s: Failed to create an OpenGL context: %i\n", ctxString, (int)error); + return result; + } + + OSXOpenGLRendererContext = newContext; + GLint defaultVirtualScreen = 0; + CGLGetVirtualScreen(newContext, &defaultVirtualScreen); + + // Retrieve the properties of every renderer available on the system. + CGLRendererInfoObj cglRendererInfo = NULL; + GLint rendererCount = 0; + CGLQueryRendererInfo(0xFFFFFFFF, &cglRendererInfo, &rendererCount); + + ClientRendererInfo *rendererInfo = (ClientRendererInfo *)malloc(sizeof(ClientRendererInfo) * rendererCount); + memset(rendererInfo, 0, sizeof(ClientRendererInfo) * rendererCount); + + if (isLeopardSupported) + { + for (GLint i = 0; i < rendererCount; i++) + { + ClientRendererInfo &info = rendererInfo[i]; + + CGLDescribeRenderer(cglRendererInfo, i, kCGLRPOnline, &(info.online)); + CGLDescribeRenderer(cglRendererInfo, i, kCGLRPDisplayMask, &(info.displayID)); + info.displayID = (GLint)CGOpenGLDisplayMaskToDisplayID(info.displayID); + CGLDescribeRenderer(cglRendererInfo, i, kCGLRPAccelerated, &(info.accelerated)); + CGLDescribeRenderer(cglRendererInfo, i, kCGLRPRendererID, &(info.rendererID)); + + if (isLionSupported) + { + CGLDescribeRenderer(cglRendererInfo, i, kCGLRPVideoMemoryMegabytes, &(info.videoMemoryMB)); + CGLDescribeRenderer(cglRendererInfo, i, kCGLRPTextureMemoryMegabytes, &(info.textureMemoryMB)); + } + else + { + CGLDescribeRenderer(cglRendererInfo, i, kCGLRPVideoMemory, &(info.videoMemoryMB)); + info.videoMemoryMB = (GLint)(((uint32_t)info.videoMemoryMB + 1) >> 20); + CGLDescribeRenderer(cglRendererInfo, i, kCGLRPTextureMemory, &(info.textureMemoryMB)); + info.textureMemoryMB = (GLint)(((uint32_t)info.textureMemoryMB + 1) >> 20); + } + + if (isHighSierraSupported) + { + CGLDescribeRenderer(cglRendererInfo, i, kCGLRPRemovable, &(info.removable)); + } + } + } + else + { + CGLDestroyRendererInfo(cglRendererInfo); + free(rendererInfo); + fprintf(stderr, "%s: Failed to retrieve renderer info - requires Mac OS X v10.5 or later.\n", ctxString); + return result; + } + + CGLDestroyRendererInfo(cglRendererInfo); + cglRendererInfo = NULL; + + // Retrieve the vendor and renderer info from OpenGL. + cgl_beginOpenGL(); + + for (GLint i = 0; i < virtualScreenCount; i++) + { + CGLSetVirtualScreen(newContext, i); + GLint r; + CGLGetParameter(newContext, kCGLCPCurrentRendererID, &r); + + for (int j = 0; j < rendererCount; j++) + { + ClientRendererInfo &info = rendererInfo[j]; + + if (r == info.rendererID) + { + info.virtualScreen = i; + + info.vendorStr = (const char *)glGetString(GL_VENDOR); + if (info.vendorStr != NULL) + { + strncpy(info.vendor, (const char *)info.vendorStr, sizeof(info.vendor)); + } + else if (info.accelerated == 0) + { + strncpy(info.vendor, "Apple Inc.", sizeof(info.vendor)); + } + else + { + strncpy(info.vendor, "UNKNOWN", sizeof(info.vendor)); + } + + info.nameStr = (const char *)glGetString(GL_RENDERER); + if (info.nameStr != NULL) + { + strncpy(info.name, (const char *)info.nameStr, sizeof(info.name)); + } + else if (info.accelerated == 0) + { + strncpy(info.name, "Apple Software Renderer", sizeof(info.name)); + } + else + { + strncpy(info.name, "UNKNOWN", sizeof(info.name)); + } + + } + } + } + + cgl_endOpenGL(); + + // Get the default virtual screen. + strncpy(__hostRendererString, "UNKNOWN", sizeof(__hostRendererString)); + __hostRendererID = -1; + + ClientRendererInfo defaultRendererInfo = rendererInfo[0]; + for (int i = 0; i < rendererCount; i++) + { + if (defaultVirtualScreen == rendererInfo[i].virtualScreen) + { + defaultRendererInfo = rendererInfo[i]; + __hostRendererID = defaultRendererInfo.rendererID; + strncpy(__hostRendererString, (const char *)defaultRendererInfo.name, sizeof(__hostRendererString)); + + if ( (defaultRendererInfo.online == 1) && (defaultRendererInfo.vendorStr != NULL) && (defaultRendererInfo.nameStr != NULL) ) + { + break; + } + } + } + + printf("Default OpenGL Renderer: [0x%08X] %s\n", __hostRendererID, __hostRendererString); + /* + bool isDefaultRunningIntegratedGPU = false; + if ( (defaultRendererInfo.online == 1) && (defaultRendererInfo.vendorStr != NULL) && (defaultRendererInfo.nameStr != NULL) ) + { + const ClientRendererInfo &d = defaultRendererInfo; + isDefaultRunningIntegratedGPU = (strstr(d.name, "GMA 950") != NULL) || + (strstr(d.name, "GMA X3100") != NULL) || + (strstr(d.name, "GeForce 9400M") != NULL) || + (strstr(d.name, "GeForce 320M") != NULL) || + (strstr(d.name, "HD Graphics") != NULL) || + (strstr(d.name, "Iris 5100") != NULL) || + (strstr(d.name, "Iris Plus") != NULL) || + (strstr(d.name, "Iris Pro") != NULL) || + (strstr(d.name, "Iris Graphics") != NULL) || + (strstr(d.name, "UHD Graphics") != NULL); + } + */ +#if defined(DEBUG) && (DEBUG == 1) + // Report information on every renderer. + if (!isLionSupported) + { + printf("WARNING: You are running a macOS version earlier than v10.7.\n Video Memory and Texture Memory reporting is capped\n at 2048 MB on older macOS.\n"); + } + printf("CGL Renderer Count: %i\n", rendererCount); + printf(" Virtual Screen Count: %i\n\n", virtualScreenCount); + + for (int i = 0; i < rendererCount; i++) + { + const ClientRendererInfo &info = rendererInfo[i]; + + printf("Renderer Index: %i\n", i); + printf("Virtual Screen: %i\n", info.virtualScreen); + printf("Vendor: %s\n", info.vendor); + printf("Renderer: %s\n", info.name); + printf("Renderer ID: 0x%08X\n", info.rendererID); + printf("Accelerated: %s\n", (info.accelerated == 1) ? "YES" : "NO"); + printf("Online: %s\n", (info.online == 1) ? "YES" : "NO"); + + if (isHighSierraSupported) + { + printf("Removable: %s\n", (info.removable == 1) ? "YES" : "NO"); + } + else + { + printf("Removable: UNSUPPORTED, Requires High Sierra\n"); + } + + printf("Display ID: 0x%08X\n", info.displayID); + printf("Video Memory: %i MB\n", info.videoMemoryMB); + printf("Texture Memory: %i MB\n\n", info.textureMemoryMB); + } +#endif + + // Search for a better virtual screen that will suit our offscreen rendering better. + // + // At the moment, we are not supporting removable renderers such as eGPUs. Attempting + // to support removable renderers would require a lot more code to handle dynamically + // changing display<-->renderer associations. - rogerman 2025/03/25 + bool wasBetterVirtualScreenFound = false; + + char *modelCString = NULL; + size_t modelStringLen = 0; + + sysctlbyname("hw.model", NULL, &modelStringLen, NULL, 0); + if (modelStringLen > 0) + { + modelCString = (char *)malloc(modelStringLen * sizeof(char)); + sysctlbyname("hw.model", modelCString, &modelStringLen, NULL, 0); + } + + for (int i = 0; i < rendererCount; i++) + { + const ClientRendererInfo &info = rendererInfo[i]; + + if ( (defaultRendererInfo.vendorStr == NULL) || (defaultRendererInfo.nameStr == NULL) || (info.vendorStr == NULL) || (info.nameStr == NULL) ) + { + continue; + } + + wasBetterVirtualScreenFound = (info.accelerated == 1) && + ( ( (modelCString != NULL) && (strstr((const char *)modelCString, "MacBookPro") != NULL) && + ( ( (strstr(defaultRendererInfo.name, "GeForce 9400M") != NULL) && + (strstr(info.name, "GeForce 9600M GT") != NULL) ) || + ( (strstr(defaultRendererInfo.name, "HD Graphics") != NULL) && + ((strstr(info.name, "GeForce GT 330M") != NULL) || + (strstr(info.name, "Radeon HD 6490M") != NULL) || + (strstr(info.name, "Radeon HD 6750M") != NULL) || + (strstr(info.name, "Radeon HD 6770M") != NULL) || + (strstr(info.name, "GeForce GT 650M") != NULL) || + (strstr(info.name, "Radeon Pro 450") != NULL) || + (strstr(info.name, "Radeon Pro 455") != NULL) || + (strstr(info.name, "Radeon Pro 555") != NULL) || + (strstr(info.name, "Radeon Pro 560") != NULL)) ) || + ( (strstr(defaultRendererInfo.name, "Iris Pro") != NULL) && + ((strstr(info.name, "GeForce GT 750M") != NULL) || + (strstr(info.name, "Radeon R9 M370X") != NULL)) ) || + ( (strstr(defaultRendererInfo.name, "UHD Graphics") != NULL) && + ((strstr(info.name, "Radeon Pro 555X") != NULL) || + (strstr(info.name, "Radeon Pro 560X") != NULL) || + (strstr(info.name, "Radeon Pro Vega 16") != NULL) || + (strstr(info.name, "Radeon Pro Vega 20") != NULL) || + (strstr(info.name, "Radeon Pro 5300M") != NULL) || + (strstr(info.name, "Radeon Pro 5500M") != NULL) || + (strstr(info.name, "Radeon Pro 5600M") != NULL)) ) ) ) || + ( (modelCString != NULL) && (strstr((const char *)modelCString, "MacPro6,1") != NULL) && (info.online == 0) && + ((strstr(info.name, "FirePro D300") != NULL) || + (strstr(info.name, "FirePro D500") != NULL) || + (strstr(info.name, "FirePro D700") != NULL)) ) ); + + if (wasBetterVirtualScreenFound) + { + CGLSetVirtualScreen(newContext, info.virtualScreen); + __hostRendererID = info.rendererID; + strncpy(__hostRendererString, (const char *)info.name, sizeof(__hostRendererString)); + printf("Found Better OpenGL Renderer: [0x%08X] %s\n", __hostRendererID, __hostRendererString); + break; + } + } + + // If we couldn't find a better virtual screen for our rendering, then just revert to the default one. + if (!wasBetterVirtualScreenFound) + { + CGLSetVirtualScreen(newContext, defaultVirtualScreen); + } + + // We're done! Report success and return. + printf("%s: OpenGL context creation successful.\n\n", ctxString); + free(rendererInfo); + free(modelCString); + + result = true; + return result; +} + +bool cgl_initOpenGL_StandardAuto() +{ + bool isContextCreated = __cgl_initOpenGL(kCGLOGLPVersion_GL4_Core); + + if (!isContextCreated) + { + isContextCreated = __cgl_initOpenGL(kCGLOGLPVersion_3_2_Core); + } + + if (!isContextCreated) + { + isContextCreated = __cgl_initOpenGL(kCGLOGLPVersion_Legacy); + } + + return isContextCreated; +} + +bool cgl_initOpenGL_LegacyAuto() +{ + return __cgl_initOpenGL(kCGLOGLPVersion_Legacy); +} + +bool cgl_initOpenGL_3_2_CoreProfile() +{ + return __cgl_initOpenGL(kCGLOGLPVersion_3_2_Core); +} + +void cgl_deinitOpenGL() +{ + if (OSXOpenGLRendererContext == NULL) + { + return; + } + + CGLSetCurrentContext(NULL); + SILENCE_DEPRECATION_MACOS_10_7( CGLReleasePBuffer(OSXOpenGLRendererPBuffer) ); + OSXOpenGLRendererPBuffer = NULL; + + CGLReleaseContext(OSXOpenGLRendererContext); + OSXOpenGLRendererContext = NULL; + OSXOpenGLRendererContextPrev = NULL; +} + +bool cgl_beginOpenGL() +{ + OSXOpenGLRendererContextPrev = CGLGetCurrentContext(); + CGLSetCurrentContext(OSXOpenGLRendererContext); + + return true; +} + +void cgl_endOpenGL() +{ +#ifndef PORT_VERSION_OS_X_APP + // The OpenEmu plug-in needs the context reset after 3D rendering since OpenEmu's context + // is assumed to be the default context. However, resetting the context for our standalone + // app can cause problems since the core emulator's context is assumed to be the default + // context. So reset the context for OpenEmu and skip resetting for us. + CGLSetCurrentContext(OSXOpenGLRendererContextPrev); +#endif +} + +bool cgl_framebufferDidResizeCallback(const bool isFBOSupported, size_t w, size_t h) +{ + bool result = false; + + if (isFBOSupported) + { + result = true; + return result; + } + + if (IsOSXVersionSupported(10, 13, 0)) + { + printf("Mac OpenGL: P-Buffers cannot be created on macOS v10.13 High Sierra and later.\n"); + return result; + } + + // Create a PBuffer if FBOs are not supported. + SILENCE_DEPRECATION_MACOS_10_7( CGLPBufferObj newPBuffer = NULL ); + SILENCE_DEPRECATION_MACOS_10_7( CGLError error = CGLCreatePBuffer((GLsizei)w, (GLsizei)h, GL_TEXTURE_2D, GL_RGBA, 0, &newPBuffer) ); + + if ( (newPBuffer == NULL) || (error != kCGLNoError) ) + { + printf("Mac OpenGL: ERROR - Could not create the P-Buffer: %s\n", CGLErrorString(error)); + return result; + } + else + { + GLint virtualScreenID = 0; + CGLGetVirtualScreen(OSXOpenGLRendererContext, &virtualScreenID); + SILENCE_DEPRECATION_MACOS_10_7( CGLSetPBuffer(OSXOpenGLRendererContext, newPBuffer, 0, 0, virtualScreenID) ); + } + + SILENCE_DEPRECATION_MACOS_10_7( CGLPBufferObj oldPBuffer = OSXOpenGLRendererPBuffer ); + OSXOpenGLRendererPBuffer = newPBuffer; + SILENCE_DEPRECATION_MACOS_10_7( CGLReleasePBuffer(oldPBuffer) ); + + result = true; + return result; +} + +int cgl_getHostRendererID() +{ + return __hostRendererID; +} + +const char* cgl_getHostRendererString() +{ + return __hostRendererString; +} diff --git a/desmume/src/frontend/cocoa/cgl_3Demu.h b/desmume/src/frontend/cocoa/cgl_3Demu.h new file mode 100644 index 000000000..1c631a8a8 --- /dev/null +++ b/desmume/src/frontend/cocoa/cgl_3Demu.h @@ -0,0 +1,54 @@ +/* + Copyright (C) 2025 DeSmuME team + + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the this software. If not, see . + */ + +#ifndef _CGL_3DEMU_H_ +#define _CGL_3DEMU_H_ + +#include +#include + +// Struct to hold renderer info +struct ClientRendererInfo +{ + int32_t rendererID; // Renderer ID, used to associate a renderer with a display device or virtual screen + int32_t accelerated; // Hardware acceleration flag, 0 = Software only, 1 = Has hardware acceleration + int32_t displayID; // Display ID, used to associate a display device with a renderer + int32_t online; // Online flag, 0 = No display device associated, 1 = Display device associated + int32_t removable; // Removable flag, used to indicate if the renderer is removable (like an eGPU), 0 = Fixed, 1 = Removable + int32_t virtualScreen; // Virtual screen index, used to associate a virtual screen with a renderer + int32_t videoMemoryMB; // The total amount of VRAM available to this renderer + int32_t textureMemoryMB; // The amount of VRAM available to this renderer for texture usage + char vendor[256]; // C-string copy of the host renderer's vendor + char name[256]; // C-string copy of the host renderer's name + const void *vendorStr; // Pointer to host renderer's vendor string (parsing this is implementation dependent) + const void *nameStr; // Pointer to host renderer's name string (parsing this is implementation dependent) +}; +typedef struct ClientRendererInfo ClientRendererInfo; + +bool cgl_initOpenGL_StandardAuto(); +bool cgl_initOpenGL_LegacyAuto(); +bool cgl_initOpenGL_3_2_CoreProfile(); + +void cgl_deinitOpenGL(); +bool cgl_beginOpenGL(); +void cgl_endOpenGL(); +bool cgl_framebufferDidResizeCallback(bool isFBOSupported, size_t w, size_t h); + +int cgl_getHostRendererID(); +const char* cgl_getHostRendererString(); + +#endif // _CGL_3DEMU_H_ diff --git a/desmume/src/frontend/cocoa/cocoa_GPU.h b/desmume/src/frontend/cocoa/cocoa_GPU.h index 301531c2a..47280f854 100644 --- a/desmume/src/frontend/cocoa/cocoa_GPU.h +++ b/desmume/src/frontend/cocoa/cocoa_GPU.h @@ -81,6 +81,7 @@ protected: semaphore_t _semFramebuffer[MAX_FRAMEBUFFER_PAGES]; volatile ClientDisplayBufferState _framebufferState[MAX_FRAMEBUFFER_PAGES]; + bool _pauseState; uint32_t _threadMessageID; uint8_t _fetchIndex; pthread_t _threadFetch; @@ -92,6 +93,8 @@ public: ~MacGPUFetchObjectAsync(); virtual void Init(); + virtual void SetPauseState(bool theState); + bool GetPauseState(); void SemaphoreFramebufferCreate(); void SemaphoreFramebufferDestroy(); @@ -116,6 +119,7 @@ class MacGPUFetchObjectDisplayLink : public MacGPUFetchObjectAsync, public Clien protected: pthread_mutex_t _mutexDisplayLinkLists; DisplayLinksActiveMap _displayLinksActiveList; + DisplayLinksActiveMap _displayLinksStartedList; DisplayLinkFlushTimeLimitMap _displayLinkFlushTimeList; public: @@ -125,8 +129,10 @@ public: void DisplayLinkStartUsingID(CGDirectDisplayID displayID); void DisplayLinkListUpdate(); - virtual void FlushAllViewsOnDisplayLink(CVDisplayLinkRef displayLink, const CVTimeStamp *timeStampNow, const CVTimeStamp *timeStampOutput); + virtual void FlushAllViewsOnDisplayLink(CVDisplayLinkRef displayLinkRef, const CVTimeStamp *timeStampNow, const CVTimeStamp *timeStampOutput); + // MacGPUEventHandlerAsync methods + virtual void SetPauseState(bool theState); virtual void DoPostFetchActions(); }; @@ -148,11 +154,18 @@ class MacGPUEventHandlerAsync : public GPUEventHandlerDefault private: GPUClientFetchObject *_fetchObject; - pthread_mutex_t _mutexFrame; - pthread_mutex_t _mutex3DRender; + NDSColorFormat _colorFormatPending; + size_t _widthPending; + size_t _heightPending; + size_t _pageCountPending; + + bool _didColorFormatChange; + bool _didWidthChange; + bool _didHeightChange; + bool _didPageCountChange; + pthread_mutex_t _mutexApplyGPUSettings; pthread_mutex_t _mutexApplyRender3DSettings; - bool _render3DNeedsFinish; int _cpuCoreCountRestoreValue; public: @@ -162,17 +175,20 @@ public: GPUClientFetchObject* GetFetchObject() const; void SetFetchObject(GPUClientFetchObject *fetchObject); - void FramebufferLock(); - void FramebufferUnlock(); - void Render3DLock(); - void Render3DUnlock(); + void SetFramebufferPageCount(size_t pageCount); + size_t GetFramebufferPageCount(); + + void SetFramebufferDimensions(size_t w, size_t h); + void GetFramebufferDimensions(size_t &w, size_t &h); + + void SetColorFormat(NDSColorFormat colorFormat); + NDSColorFormat GetColorFormat(); + void ApplyGPUSettingsLock(); void ApplyGPUSettingsUnlock(); void ApplyRender3DSettingsLock(); void ApplyRender3DSettingsUnlock(); - bool GetRender3DNeedsFinish(); - void SetTempThreadCount(int threadCount); #ifdef ENABLE_ASYNC_FETCH @@ -180,22 +196,12 @@ public: virtual void DidFrameEnd(bool isFrameSkipped, const NDSDisplayInfo &latestDisplayInfo); #endif - virtual void DidRender3DBegin(); - virtual void DidRender3DEnd(); virtual void DidApplyGPUSettingsBegin(); virtual void DidApplyGPUSettingsEnd(); virtual void DidApplyRender3DSettingsBegin(); virtual void DidApplyRender3DSettingsEnd(); }; -// This stub version is useful for clients that want to run the entire emulation on a single thread. -class MacGPUEventHandlerAsync_Stub : public MacGPUEventHandlerAsync -{ -public: - virtual void DidRender3DBegin() {}; - virtual void DidRender3DEnd() {}; -}; - @interface CocoaDSGPU : NSObject { UInt32 gpuStateFlags; @@ -205,7 +211,6 @@ public: BOOL isCPUCoreCountAuto; int _render3DThreadsRequested; int _render3DThreadCount; - BOOL _needRestoreRender3DLock; apple_unfairlock_t _unfairlockGpuState; MacGPUEventHandlerAsync *gpuEvent; @@ -257,24 +262,5 @@ public: - (BOOL) gpuStateByBit:(const UInt32)stateBit; - (void) clearWithColor:(const uint16_t)colorBGRA5551; -- (void) respondToPauseState:(BOOL)isPaused; @end - -#ifdef __cplusplus -extern "C" -{ -#endif - -bool cgl_initOpenGL_StandardAuto(); -bool cgl_initOpenGL_LegacyAuto(); -bool cgl_initOpenGL_3_2_CoreProfile(); - -void cgl_deinitOpenGL(); -bool cgl_beginOpenGL(); -void cgl_endOpenGL(); -bool cgl_framebufferDidResizeCallback(const bool isFBOSupported, size_t w, size_t h); - -#ifdef __cplusplus -} -#endif diff --git a/desmume/src/frontend/cocoa/cocoa_GPU.mm b/desmume/src/frontend/cocoa/cocoa_GPU.mm index 422f8dc67..65db9389f 100644 --- a/desmume/src/frontend/cocoa/cocoa_GPU.mm +++ b/desmume/src/frontend/cocoa/cocoa_GPU.mm @@ -17,9 +17,6 @@ #import "cocoa_GPU.h" -#include -#include - #import "cocoa_globals.h" #include "utilities.h" @@ -32,6 +29,8 @@ #include "../../OGLRender.h" #endif +#include "cgl_3Demu.h" + #ifdef PORT_VERSION_OS_X_APP #import "userinterface/CocoaDisplayView.h" #import "userinterface/MacOGLDisplayView.h" @@ -55,9 +54,6 @@ GPU3DInterface *core3DList[GPU_3D_RENDERER_COUNT+1] = { NULL }; -int __hostRendererID = -1; -char __hostRendererString[256] = {0}; - @implementation CocoaDSGPU @dynamic gpuStateFlags; @@ -129,7 +125,6 @@ char __hostRendererString[256] = {0}; isCPUCoreCountAuto = NO; _render3DThreadsRequested = 0; _render3DThreadCount = 0; - _needRestoreRender3DLock = NO; oglrender_init = &cgl_initOpenGL_StandardAuto; oglrender_deinit = &cgl_deinitOpenGL; @@ -142,11 +137,7 @@ char __hostRendererString[256] = {0}; OGLCreateRenderer_3_2_Func = &OGLCreateRenderer_3_2; #endif -#ifdef PORT_VERSION_OS_X_APP gpuEvent = new MacGPUEventHandlerAsync; -#else - gpuEvent = new MacGPUEventHandlerAsync_Stub; -#endif GPU->SetEventHandler(gpuEvent); fetchObject = NULL; @@ -163,7 +154,7 @@ char __hostRendererString[256] = {0}; } else { - GPU->SetFramebufferPageCount(METAL_FETCH_BUFFER_COUNT); + gpuEvent->SetFramebufferPageCount(METAL_FETCH_BUFFER_COUNT); GPU->SetWillPostprocessDisplays(false); } } @@ -177,7 +168,7 @@ char __hostRendererString[256] = {0}; #else fetchObject = new OE_OGLClientFetchObject; #endif - GPU->SetFramebufferPageCount(OPENGL_FETCH_BUFFER_COUNT); + gpuEvent->SetFramebufferPageCount(OPENGL_FETCH_BUFFER_COUNT); } fetchObject->Init(); @@ -259,45 +250,16 @@ char __hostRendererString[256] = {0}; const size_t w = (size_t)(theDimensions.width + 0.01); const size_t h = (size_t)(theDimensions.height + 0.01); - gpuEvent->Render3DLock(); - gpuEvent->FramebufferLock(); - -#ifdef ENABLE_ASYNC_FETCH - const size_t maxPages = GPU->GetDisplayInfo().framebufferPageCount; - for (size_t i = 0; i < maxPages; i++) - { - semaphore_wait( ((MacGPUFetchObjectAsync *)fetchObject)->SemaphoreFramebufferPageAtIndex(i) ); - } -#endif - - GPU->SetCustomFramebufferSize(w, h); - fetchObject->SetFetchBuffers(GPU->GetDisplayInfo()); - -#ifdef ENABLE_ASYNC_FETCH - for (size_t i = maxPages - 1; i < maxPages; i--) - { - semaphore_signal( ((MacGPUFetchObjectAsync *)fetchObject)->SemaphoreFramebufferPageAtIndex(i) ); - } -#endif - - gpuEvent->FramebufferUnlock(); - gpuEvent->Render3DUnlock(); - - if (_needRestoreRender3DLock) - { - _needRestoreRender3DLock = NO; - } + gpuEvent->SetFramebufferDimensions(w, h); } - (NSSize) gpuDimensions { - gpuEvent->Render3DLock(); - gpuEvent->FramebufferLock(); - const NSSize dimensions = NSMakeSize(GPU->GetCustomFramebufferWidth(), GPU->GetCustomFramebufferHeight()); - gpuEvent->FramebufferUnlock(); - gpuEvent->Render3DUnlock(); + size_t w; + size_t h; + gpuEvent->GetFramebufferDimensions(w, h); - return dimensions; + return NSMakeSize((CGFloat)w, (CGFloat)h); } - (void) setGpuScale:(NSUInteger)theScale @@ -325,51 +287,12 @@ char __hostRendererString[256] = {0}; return; } - // Change the color format. - gpuEvent->Render3DLock(); - gpuEvent->FramebufferLock(); - - const NDSDisplayInfo &dispInfo = GPU->GetDisplayInfo(); - - if (dispInfo.colorFormat != (NDSColorFormat)colorFormat) - { -#ifdef ENABLE_ASYNC_FETCH - const size_t maxPages = GPU->GetDisplayInfo().framebufferPageCount; - for (size_t i = 0; i < maxPages; i++) - { - semaphore_wait( ((MacGPUFetchObjectAsync *)fetchObject)->SemaphoreFramebufferPageAtIndex(i) ); - } -#endif - - GPU->SetColorFormat((NDSColorFormat)colorFormat); - fetchObject->SetFetchBuffers(GPU->GetDisplayInfo()); - -#ifdef ENABLE_ASYNC_FETCH - for (size_t i = maxPages - 1; i < maxPages; i--) - { - semaphore_signal( ((MacGPUFetchObjectAsync *)fetchObject)->SemaphoreFramebufferPageAtIndex(i) ); - } -#endif - } - - gpuEvent->FramebufferUnlock(); - gpuEvent->Render3DUnlock(); - - if (_needRestoreRender3DLock) - { - _needRestoreRender3DLock = NO; - } + gpuEvent->SetColorFormat((NDSColorFormat)colorFormat); } - (NSUInteger) gpuColorFormat { - gpuEvent->Render3DLock(); - gpuEvent->FramebufferLock(); - const NSUInteger colorFormat = (NSUInteger)GPU->GetDisplayInfo().colorFormat; - gpuEvent->FramebufferUnlock(); - gpuEvent->Render3DUnlock(); - - return colorFormat; + return (NSUInteger)gpuEvent->GetColorFormat(); } - (void) setRender3DRenderingEngine:(NSInteger)rendererID @@ -441,7 +364,7 @@ char __hostRendererString[256] = {0}; case RENDERID_OPENGL_AUTO: case RENDERID_OPENGL_LEGACY: case RENDERID_OPENGL_3_2: - hostID = (NSInteger)__hostRendererID; + hostID = (NSInteger)cgl_getHostRendererID(); break; case RENDERID_NULL: @@ -474,7 +397,7 @@ char __hostRendererString[256] = {0}; case RENDERID_OPENGL_AUTO: case RENDERID_OPENGL_LEGACY: case RENDERID_OPENGL_3_2: - theName = std::string((const char *)__hostRendererString); + theName = cgl_getHostRendererString(); break; case RENDERID_NULL: @@ -1117,8 +1040,6 @@ char __hostRendererString[256] = {0}; - (void) clearWithColor:(const uint16_t)colorBGRA5551 { - gpuEvent->FramebufferLock(); - #ifdef ENABLE_ASYNC_FETCH const size_t maxPages = GPU->GetDisplayInfo().framebufferPageCount; for (size_t i = 0; i < maxPages; i++) @@ -1134,37 +1055,12 @@ char __hostRendererString[256] = {0}; { semaphore_signal( ((MacGPUFetchObjectAsync *)fetchObject)->SemaphoreFramebufferPageAtIndex(i) ); } -#endif - gpuEvent->FramebufferUnlock(); - -#ifdef ENABLE_ASYNC_FETCH const u8 bufferIndex = GPU->GetDisplayInfo().bufferIndex; ((MacGPUFetchObjectAsync *)fetchObject)->SignalFetchAtIndex(bufferIndex, MESSAGE_FETCH_AND_PERFORM_ACTIONS); #endif } -- (void) respondToPauseState:(BOOL)isPaused -{ - if (isPaused) - { - if (!_needRestoreRender3DLock && gpuEvent->GetRender3DNeedsFinish()) - { - gpuEvent->Render3DUnlock(); - _needRestoreRender3DLock = YES; - } - } - else - { - if (_needRestoreRender3DLock && gpuEvent->GetRender3DNeedsFinish()) - { - gpuEvent->Render3DLock(); - } - - _needRestoreRender3DLock = NO; - } -} - @end #ifdef ENABLE_SHARED_FETCH_OBJECT @@ -1208,6 +1104,7 @@ static void* RunFetchThread(void *arg) MacGPUFetchObjectAsync::MacGPUFetchObjectAsync() { _threadFetch = NULL; + _pauseState = true; _threadMessageID = MESSAGE_NONE; _fetchIndex = 0; pthread_cond_init(&_condSignalFetch, NULL); @@ -1263,6 +1160,16 @@ void MacGPUFetchObjectAsync::Init() } } +void MacGPUFetchObjectAsync::SetPauseState(bool theState) +{ + this->_pauseState = theState; +} + +bool MacGPUFetchObjectAsync::GetPauseState() +{ + return this->_pauseState; +} + void MacGPUFetchObjectAsync::SemaphoreFramebufferCreate() { this->_taskEmulationLoop = mach_task_self(); @@ -1438,7 +1345,7 @@ static void ScreenChangeCallback(CFNotificationCenterRef center, ((MacGPUFetchObjectDisplayLink *)observer)->DisplayLinkListUpdate(); } -static CVReturn MacDisplayLinkCallback(CVDisplayLinkRef displayLink, +static CVReturn MacDisplayLinkCallback(CVDisplayLinkRef displayLinkRef, const CVTimeStamp *inNow, const CVTimeStamp *inOutputTime, CVOptionFlags flagsIn, @@ -1448,7 +1355,7 @@ static CVReturn MacDisplayLinkCallback(CVDisplayLinkRef displayLink, MacGPUFetchObjectDisplayLink *fetchObj = (MacGPUFetchObjectDisplayLink *)displayLinkContext; NSAutoreleasePool *tempPool = [[NSAutoreleasePool alloc] init]; - fetchObj->FlushAllViewsOnDisplayLink(displayLink, inNow, inOutputTime); + fetchObj->FlushAllViewsOnDisplayLink(displayLinkRef, inNow, inOutputTime); [tempPool release]; return kCVReturnSuccess; @@ -1467,6 +1374,7 @@ MacGPUFetchObjectDisplayLink::MacGPUFetchObjectDisplayLink() pthread_mutex_init(&_mutexDisplayLinkLists, NULL); _displayLinksActiveList.clear(); + _displayLinksStartedList.clear(); _displayLinkFlushTimeList.clear(); DisplayLinkListUpdate(); @@ -1496,6 +1404,7 @@ MacGPUFetchObjectDisplayLink::~MacGPUFetchObjectDisplayLink() if (CVDisplayLinkIsRunning(displayLinkRef)) { CVDisplayLinkStop(displayLinkRef); + this->_displayLinksStartedList.erase(displayID); } CVDisplayLinkRelease(displayLinkRef); @@ -1510,18 +1419,19 @@ MacGPUFetchObjectDisplayLink::~MacGPUFetchObjectDisplayLink() void MacGPUFetchObjectDisplayLink::DisplayLinkStartUsingID(CGDirectDisplayID displayID) { - CVDisplayLinkRef displayLink = NULL; + CVDisplayLinkRef displayLinkRef = NULL; pthread_mutex_lock(&this->_mutexDisplayLinkLists); if (this->_displayLinksActiveList.find(displayID) != this->_displayLinksActiveList.end()) { - displayLink = this->_displayLinksActiveList[displayID]; + displayLinkRef = this->_displayLinksActiveList[displayID]; } - if ( (displayLink != NULL) && !CVDisplayLinkIsRunning(displayLink) ) + if ( (displayLinkRef != NULL) && !CVDisplayLinkIsRunning(displayLinkRef) ) { - CVDisplayLinkStart(displayLink); + CVDisplayLinkStart(displayLinkRef); + this->_displayLinksStartedList[displayID] = displayLinkRef; } pthread_mutex_unlock(&this->_mutexDisplayLinkLists); @@ -1570,6 +1480,7 @@ void MacGPUFetchObjectDisplayLink::DisplayLinkListUpdate() if (CVDisplayLinkIsRunning(displayLinkRef)) { CVDisplayLinkStop(displayLinkRef); + this->_displayLinksStartedList.erase(displayID); } CVDisplayLinkRelease(displayLinkRef); @@ -1594,9 +1505,9 @@ void MacGPUFetchObjectDisplayLink::DisplayLinkListUpdate() pthread_mutex_unlock(&this->_mutexDisplayLinkLists); } -void MacGPUFetchObjectDisplayLink::FlushAllViewsOnDisplayLink(CVDisplayLinkRef displayLink, const CVTimeStamp *timeStampNow, const CVTimeStamp *timeStampOutput) +void MacGPUFetchObjectDisplayLink::FlushAllViewsOnDisplayLink(CVDisplayLinkRef displayLinkRef, const CVTimeStamp *timeStampNow, const CVTimeStamp *timeStampOutput) { - CGDirectDisplayID displayID = CVDisplayLinkGetCurrentCGDisplay(displayLink); + CGDirectDisplayID displayID = CVDisplayLinkGetCurrentCGDisplay(displayLinkRef); bool didFlushOccur = false; std::vector cdvFlushList; @@ -1616,7 +1527,43 @@ void MacGPUFetchObjectDisplayLink::FlushAllViewsOnDisplayLink(CVDisplayLinkRef d } else if (timeStampNow->videoTime > this->_displayLinkFlushTimeList[displayID]) { - CVDisplayLinkStop(displayLink); + CVDisplayLinkStop(displayLinkRef); + this->_displayLinksStartedList.erase(displayID); + } +} + +void MacGPUFetchObjectDisplayLink::SetPauseState(bool theState) +{ + if (theState == this->_pauseState) + { + return; + } + + this->_pauseState = theState; + + if (theState) + { + for (DisplayLinksActiveMap::iterator it = this->_displayLinksStartedList.begin(); it != this->_displayLinksStartedList.end(); it++) + { + CVDisplayLinkRef displayLinkRef = it->second; + if ( (displayLinkRef != NULL) && CVDisplayLinkIsRunning(displayLinkRef) ) + { + CVDisplayLinkStop(displayLinkRef); + } + } + + this->FinalizeAllViews(); + } + else + { + for (DisplayLinksActiveMap::iterator it = this->_displayLinksStartedList.begin(); it != this->_displayLinksStartedList.end(); it++) + { + CVDisplayLinkRef displayLinkRef = it->second; + if ( (displayLinkRef != NULL) && !CVDisplayLinkIsRunning(displayLinkRef) ) + { + CVDisplayLinkStart(displayLinkRef); + } + } } } @@ -1632,24 +1579,25 @@ void MacGPUFetchObjectDisplayLink::DoPostFetchActions() MacGPUEventHandlerAsync::MacGPUEventHandlerAsync() { _fetchObject = nil; - _render3DNeedsFinish = false; + + _widthPending = GPU_FRAMEBUFFER_NATIVE_WIDTH; + _heightPending = GPU_FRAMEBUFFER_NATIVE_HEIGHT; + _colorFormatPending = NDSColorFormat_BGR555_Rev; + _pageCountPending = 1; + + _didColorFormatChange = true; + _didWidthChange = true; + _didHeightChange = true; + _didPageCountChange = true; + _cpuCoreCountRestoreValue = 0; - pthread_mutex_init(&_mutexFrame, NULL); - pthread_mutex_init(&_mutex3DRender, NULL); pthread_mutex_init(&_mutexApplyGPUSettings, NULL); pthread_mutex_init(&_mutexApplyRender3DSettings, NULL); } MacGPUEventHandlerAsync::~MacGPUEventHandlerAsync() { - if (this->_render3DNeedsFinish) - { - pthread_mutex_unlock(&this->_mutex3DRender); - } - - pthread_mutex_destroy(&this->_mutexFrame); - pthread_mutex_destroy(&this->_mutex3DRender); pthread_mutex_destroy(&this->_mutexApplyGPUSettings); pthread_mutex_destroy(&this->_mutexApplyRender3DSettings); } @@ -1664,14 +1612,67 @@ void MacGPUEventHandlerAsync::SetFetchObject(GPUClientFetchObject *fetchObject) this->_fetchObject = fetchObject; } +void MacGPUEventHandlerAsync::SetFramebufferPageCount(size_t pageCount) +{ + this->ApplyGPUSettingsLock(); + const NDSDisplayInfo &displayInfo = GPU->GetDisplayInfo(); + this->_didPageCountChange = (pageCount != displayInfo.framebufferPageCount); + this->_pageCountPending = pageCount; + this->ApplyGPUSettingsUnlock(); +} + +size_t MacGPUEventHandlerAsync::GetFramebufferPageCount() +{ + return this->_pageCountPending; +} + +void MacGPUEventHandlerAsync::SetFramebufferDimensions(size_t w, size_t h) +{ + if (w < GPU_FRAMEBUFFER_NATIVE_WIDTH) + { + w = GPU_FRAMEBUFFER_NATIVE_WIDTH; + } + + if (h < GPU_FRAMEBUFFER_NATIVE_HEIGHT) + { + h = GPU_FRAMEBUFFER_NATIVE_HEIGHT; + } + + this->ApplyGPUSettingsLock(); + const NDSDisplayInfo &displayInfo = GPU->GetDisplayInfo(); + this->_didWidthChange = (w != displayInfo.customWidth); + this->_didHeightChange = (h != displayInfo.customHeight); + this->_widthPending = w; + this->_heightPending = h; + this->ApplyGPUSettingsUnlock(); +} + +void MacGPUEventHandlerAsync::GetFramebufferDimensions(size_t &outWidth, size_t &outHeight) +{ + outWidth = this->_widthPending; + outHeight = this->_heightPending; +} + +void MacGPUEventHandlerAsync::SetColorFormat(NDSColorFormat colorFormat) +{ + this->ApplyGPUSettingsLock(); + const NDSDisplayInfo &displayInfo = GPU->GetDisplayInfo(); + this->_didColorFormatChange = (colorFormat != displayInfo.colorFormat); + this->_colorFormatPending = colorFormat; + this->ApplyGPUSettingsUnlock(); +} + +NDSColorFormat MacGPUEventHandlerAsync::GetColorFormat() +{ + return this->_colorFormatPending; +} + #ifdef ENABLE_ASYNC_FETCH void MacGPUEventHandlerAsync::DidFrameBegin(const size_t line, const bool isFrameSkipRequested, const size_t pageCount, u8 &selectedBufferIndexInOut) { MacGPUFetchObjectAsync *asyncFetchObj = (MacGPUFetchObjectAsync *)this->_fetchObject; - this->FramebufferLock(); - if (!isFrameSkipRequested) { if ( (pageCount > 1) && (line == 0) ) @@ -1693,37 +1694,59 @@ void MacGPUEventHandlerAsync::DidFrameEnd(bool isFrameSkipped, const NDSDisplayI asyncFetchObj->SetFetchDisplayInfo(latestDisplayInfo); asyncFetchObj->SetFramebufferState(ClientDisplayBufferState_Ready, latestDisplayInfo.bufferIndex); semaphore_signal( asyncFetchObj->SemaphoreFramebufferPageAtIndex(latestDisplayInfo.bufferIndex) ); - } - - this->FramebufferUnlock(); - - if (!isFrameSkipped) - { asyncFetchObj->SignalFetchAtIndex(latestDisplayInfo.bufferIndex, MESSAGE_FETCH_AND_PERFORM_ACTIONS); } } #endif // ENABLE_ASYNC_FETCH -void MacGPUEventHandlerAsync::DidRender3DBegin() -{ - this->Render3DLock(); - this->_render3DNeedsFinish = true; -} - -void MacGPUEventHandlerAsync::DidRender3DEnd() -{ - this->_render3DNeedsFinish = false; - this->Render3DUnlock(); -} - void MacGPUEventHandlerAsync::DidApplyGPUSettingsBegin() { this->ApplyGPUSettingsLock(); + + if (this->_didWidthChange || this->_didHeightChange || this->_didColorFormatChange || this->_didPageCountChange) + { + MacGPUFetchObjectAsync *asyncFetchObj = (MacGPUFetchObjectAsync *)this->_fetchObject; + asyncFetchObj->SetPauseState(true); + + GPU->SetCustomFramebufferSize(this->_widthPending, this->_heightPending); + GPU->SetColorFormat(this->_colorFormatPending); + GPU->SetFramebufferPageCount(this->_pageCountPending); + } } void MacGPUEventHandlerAsync::DidApplyGPUSettingsEnd() { + if (this->_didWidthChange || this->_didHeightChange || this->_didColorFormatChange || this->_didPageCountChange) + { + const NDSDisplayInfo &displayInfo = GPU->GetDisplayInfo(); + MacGPUFetchObjectAsync *asyncFetchObj = (MacGPUFetchObjectAsync *)this->_fetchObject; + +#ifdef ENABLE_ASYNC_FETCH + const size_t maxPages = displayInfo.framebufferPageCount; + for (size_t i = 0; i < maxPages; i++) + { + semaphore_wait( asyncFetchObj->SemaphoreFramebufferPageAtIndex(i) ); + } +#endif + this->_fetchObject->SetFetchBuffers(displayInfo); + +#ifdef ENABLE_ASYNC_FETCH + for (size_t i = maxPages - 1; i < maxPages; i--) + { + semaphore_signal( asyncFetchObj->SemaphoreFramebufferPageAtIndex(i) ); + } +#endif + asyncFetchObj->SetPauseState(false); + + // Update all the change flags now that settings are applied. + // In theory, all these flags should get cleared. + this->_didWidthChange = (this->_widthPending != displayInfo.customWidth); + this->_didHeightChange = (this->_heightPending != displayInfo.customHeight); + this->_didColorFormatChange = (this->_colorFormatPending != displayInfo.colorFormat); + this->_didPageCountChange = (this->_pageCountPending != displayInfo.framebufferPageCount); + } + this->ApplyGPUSettingsUnlock(); } @@ -1743,26 +1766,6 @@ void MacGPUEventHandlerAsync::DidApplyRender3DSettingsEnd() this->ApplyRender3DSettingsUnlock(); } -void MacGPUEventHandlerAsync::FramebufferLock() -{ - pthread_mutex_lock(&this->_mutexFrame); -} - -void MacGPUEventHandlerAsync::FramebufferUnlock() -{ - pthread_mutex_unlock(&this->_mutexFrame); -} - -void MacGPUEventHandlerAsync::Render3DLock() -{ - pthread_mutex_lock(&this->_mutex3DRender); -} - -void MacGPUEventHandlerAsync::Render3DUnlock() -{ - pthread_mutex_unlock(&this->_mutex3DRender); -} - void MacGPUEventHandlerAsync::ApplyGPUSettingsLock() { pthread_mutex_lock(&this->_mutexApplyGPUSettings); @@ -1783,11 +1786,6 @@ void MacGPUEventHandlerAsync::ApplyRender3DSettingsUnlock() pthread_mutex_unlock(&this->_mutexApplyRender3DSettings); } -bool MacGPUEventHandlerAsync::GetRender3DNeedsFinish() -{ - return this->_render3DNeedsFinish; -} - void MacGPUEventHandlerAsync::SetTempThreadCount(int threadCount) { if (threadCount < 1) @@ -1800,551 +1798,3 @@ void MacGPUEventHandlerAsync::SetTempThreadCount(int threadCount) CommonSettings.num_cores = threadCount; } } - -#pragma mark - - -#if !defined(MAC_OS_X_VERSION_10_7) - #define kCGLPFAOpenGLProfile (CGLPixelFormatAttribute)99 - #define kCGLOGLPVersion_Legacy 0x1000 - #define kCGLOGLPVersion_3_2_Core 0x3200 - #define kCGLOGLPVersion_GL3_Core 0x3200 - #define kCGLRPVideoMemoryMegabytes (CGLRendererProperty)131 - #define kCGLRPTextureMemoryMegabytes (CGLRendererProperty)132 -#endif - -#if !defined(MAC_OS_X_VERSION_10_9) - #define kCGLOGLPVersion_GL4_Core 0x4100 -#endif - -#if !defined(MAC_OS_X_VERSION_10_13) - #define kCGLRPRemovable (CGLRendererProperty)142 -#endif - -CGLContextObj OSXOpenGLRendererContext = NULL; -CGLContextObj OSXOpenGLRendererContextPrev = NULL; -SILENCE_DEPRECATION_MACOS_10_7( CGLPBufferObj OSXOpenGLRendererPBuffer = NULL ) - -// Struct to hold renderer info -struct HostRendererInfo -{ - int32_t rendererID; // Renderer ID, used to associate a renderer with a display device or virtual screen - int32_t accelerated; // Hardware acceleration flag, 0 = Software only, 1 = Has hardware acceleration - int32_t displayID; // Display ID, used to associate a display device with a renderer - int32_t online; // Online flag, 0 = No display device associated, 1 = Display device associated - int32_t removable; // Removable flag, used to indicate if the renderer is removable (like an eGPU), 0 = Fixed, 1 = Removable - int32_t virtualScreen; // Virtual screen index, used to associate a virtual screen with a renderer - int32_t videoMemoryMB; // The total amount of VRAM available to this renderer - int32_t textureMemoryMB; // The amount of VRAM available to this renderer for texture usage - char vendor[256]; // C-string copy of the host renderer's vendor - char name[256]; // C-string copy of the host renderer's name - const void *vendorStr; // Pointer to host renderer's vendor string (parsing this is implementation dependent) - const void *nameStr; // Pointer to host renderer's name string (parsing this is implementation dependent) -}; -typedef struct HostRendererInfo HostRendererInfo; - -static bool __cgl_initOpenGL(const int requestedProfile) -{ - bool result = false; - CACHE_ALIGN char ctxString[16] = {0}; - - if (requestedProfile == kCGLOGLPVersion_GL4_Core) - { - strncpy(ctxString, "CGL 4.1", sizeof(ctxString)); - } - else if (requestedProfile == kCGLOGLPVersion_3_2_Core) - { - strncpy(ctxString, "CGL 3.2", sizeof(ctxString)); - } - else - { - strncpy(ctxString, "CGL Legacy", sizeof(ctxString)); - } - - if (OSXOpenGLRendererContext != NULL) - { - result = true; - return result; - } - - const bool isHighSierraSupported = IsOSXVersionSupported(10, 13, 0); - const bool isMavericksSupported = (isHighSierraSupported || IsOSXVersionSupported(10, 9, 0)); - const bool isMountainLionSupported = (isMavericksSupported || IsOSXVersionSupported(10, 8, 0)); - const bool isLionSupported = (isMountainLionSupported || IsOSXVersionSupported(10, 7, 0)); - const bool isLeopardSupported = (isLionSupported || IsOSXVersionSupported(10, 5, 0)); - - CGLPixelFormatAttribute attrs[] = { - kCGLPFAColorSize, (CGLPixelFormatAttribute)24, - kCGLPFAAlphaSize, (CGLPixelFormatAttribute)8, - kCGLPFADepthSize, (CGLPixelFormatAttribute)24, - kCGLPFAStencilSize, (CGLPixelFormatAttribute)8, - kCGLPFAOpenGLProfile, (CGLPixelFormatAttribute)0, - kCGLPFAAllowOfflineRenderers, - kCGLPFAAccelerated, - kCGLPFANoRecovery, - (CGLPixelFormatAttribute)0 - }; - - if (requestedProfile == kCGLOGLPVersion_GL4_Core) - { - if (isMavericksSupported) - { - attrs[5] = (CGLPixelFormatAttribute)0; // We'll be using FBOs instead of the default framebuffer. - attrs[7] = (CGLPixelFormatAttribute)0; // We'll be using FBOs instead of the default framebuffer. - attrs[9] = (CGLPixelFormatAttribute)requestedProfile; - } - else - { - fprintf(stderr, "%s: Your version of OS X is too old to support 4.1 Core Profile.\n", ctxString); - return result; - } - } - else if (requestedProfile == kCGLOGLPVersion_3_2_Core) - { - // As of 2021/09/03, testing has shown that macOS v10.7's OpenGL 3.2 shader - // compiler isn't very reliable, and so we're going to require macOS v10.8 - // instead, which at least has a working shader compiler for OpenGL 3.2. - if (isMountainLionSupported) - { - attrs[5] = (CGLPixelFormatAttribute)0; // We'll be using FBOs instead of the default framebuffer. - attrs[7] = (CGLPixelFormatAttribute)0; // We'll be using FBOs instead of the default framebuffer. - attrs[9] = (CGLPixelFormatAttribute)requestedProfile; - } - else - { - fprintf(stderr, "%s: Your version of OS X is too old to support 3.2 Core Profile.\n", ctxString); - return result; - } - } - else if (isLionSupported) - { - attrs[9] = (CGLPixelFormatAttribute)kCGLOGLPVersion_Legacy; - } - else - { - attrs[8] = (CGLPixelFormatAttribute)kCGLPFAAccelerated; - attrs[9] = (CGLPixelFormatAttribute)kCGLPFANoRecovery; - attrs[11] = (CGLPixelFormatAttribute)0; - attrs[12] = (CGLPixelFormatAttribute)0; - } - - CGLError error = kCGLNoError; - CGLPixelFormatObj cglPixFormat = NULL; - CGLContextObj newContext = NULL; - GLint virtualScreenCount = 0; - - CGLChoosePixelFormat(attrs, &cglPixFormat, &virtualScreenCount); - if (cglPixFormat == NULL) - { - if (requestedProfile == kCGLOGLPVersion_GL4_Core) - { - // OpenGL 4.1 Core Profile requires hardware acceleration. Bail if we can't find a renderer that supports both. - fprintf(stderr, "%s: This system has no HW-accelerated renderers that support 4.1 Core Profile.\n", ctxString); - return result; - } - else if (requestedProfile == kCGLOGLPVersion_3_2_Core) - { - // OpenGL 3.2 Core Profile requires hardware acceleration. Bail if we can't find a renderer that supports both. - fprintf(stderr, "%s: This system has no HW-accelerated renderers that support 3.2 Core Profile.\n", ctxString); - return result; - } - - // For Legacy OpenGL, we'll allow fallback to the Apple Software Renderer. - // However, doing this will result in a substantial performance loss. - if (attrs[8] == kCGLPFAAccelerated) - { - attrs[8] = (CGLPixelFormatAttribute)0; - attrs[9] = (CGLPixelFormatAttribute)0; - attrs[10] = (CGLPixelFormatAttribute)0; - } - else - { - attrs[10] = (CGLPixelFormatAttribute)0; - attrs[11] = (CGLPixelFormatAttribute)0; - attrs[12] = (CGLPixelFormatAttribute)0; - } - - error = CGLChoosePixelFormat(attrs, &cglPixFormat, &virtualScreenCount); - if (error != kCGLNoError) - { - // We shouldn't fail at this point, but we're including this to account for all code paths. - fprintf(stderr, "%s: Failed to create the pixel format structure: %i\n", ctxString, (int)error); - return result; - } - else - { - printf("WARNING: No HW-accelerated renderers were found -- falling back to Apple Software Renderer.\n This will result in a substantial performance loss."); - } - } - - // Create the OpenGL context using our pixel format, and then save the default assigned virtual screen. - error = CGLCreateContext(cglPixFormat, NULL, &newContext); - CGLReleasePixelFormat(cglPixFormat); - cglPixFormat = NULL; - - if (error != kCGLNoError) - { - fprintf(stderr, "%s: Failed to create an OpenGL context: %i\n", ctxString, (int)error); - return result; - } - - OSXOpenGLRendererContext = newContext; - GLint defaultVirtualScreen = 0; - CGLGetVirtualScreen(newContext, &defaultVirtualScreen); - - // Retrieve the properties of every renderer available on the system. - CGLRendererInfoObj cglRendererInfo = NULL; - GLint rendererCount = 0; - CGLQueryRendererInfo(0xFFFFFFFF, &cglRendererInfo, &rendererCount); - - HostRendererInfo *rendererInfo = (HostRendererInfo *)malloc(sizeof(HostRendererInfo) * rendererCount); - memset(rendererInfo, 0, sizeof(HostRendererInfo) * rendererCount); - - if (isLeopardSupported) - { - for (GLint i = 0; i < rendererCount; i++) - { - HostRendererInfo &info = rendererInfo[i]; - - CGLDescribeRenderer(cglRendererInfo, i, kCGLRPOnline, &(info.online)); - CGLDescribeRenderer(cglRendererInfo, i, kCGLRPDisplayMask, &(info.displayID)); - info.displayID = (GLint)CGOpenGLDisplayMaskToDisplayID(info.displayID); - CGLDescribeRenderer(cglRendererInfo, i, kCGLRPAccelerated, &(info.accelerated)); - CGLDescribeRenderer(cglRendererInfo, i, kCGLRPRendererID, &(info.rendererID)); - - if (isLionSupported) - { - CGLDescribeRenderer(cglRendererInfo, i, kCGLRPVideoMemoryMegabytes, &(info.videoMemoryMB)); - CGLDescribeRenderer(cglRendererInfo, i, kCGLRPTextureMemoryMegabytes, &(info.textureMemoryMB)); - } - else - { - CGLDescribeRenderer(cglRendererInfo, i, kCGLRPVideoMemory, &(info.videoMemoryMB)); - info.videoMemoryMB = (GLint)(((uint32_t)info.videoMemoryMB + 1) >> 20); - CGLDescribeRenderer(cglRendererInfo, i, kCGLRPTextureMemory, &(info.textureMemoryMB)); - info.textureMemoryMB = (GLint)(((uint32_t)info.textureMemoryMB + 1) >> 20); - } - - if (isHighSierraSupported) - { - CGLDescribeRenderer(cglRendererInfo, i, kCGLRPRemovable, &(info.removable)); - } - } - } - else - { - CGLDestroyRendererInfo(cglRendererInfo); - free(rendererInfo); - fprintf(stderr, "%s: Failed to retrieve renderer info - requires Mac OS X v10.5 or later.\n", ctxString); - return result; - } - - CGLDestroyRendererInfo(cglRendererInfo); - cglRendererInfo = NULL; - - // Retrieve the vendor and renderer info from OpenGL. - cgl_beginOpenGL(); - - for (GLint i = 0; i < virtualScreenCount; i++) - { - CGLSetVirtualScreen(newContext, i); - GLint r; - CGLGetParameter(newContext, kCGLCPCurrentRendererID, &r); - - for (int j = 0; j < rendererCount; j++) - { - HostRendererInfo &info = rendererInfo[j]; - - if (r == info.rendererID) - { - info.virtualScreen = i; - - info.vendorStr = (const char *)glGetString(GL_VENDOR); - if (info.vendorStr != NULL) - { - strncpy(info.vendor, (const char *)info.vendorStr, sizeof(info.vendor)); - } - else if (info.accelerated == 0) - { - strncpy(info.vendor, "Apple Inc.", sizeof(info.vendor)); - } - else - { - strncpy(info.vendor, "UNKNOWN", sizeof(info.vendor)); - } - - info.nameStr = (const char *)glGetString(GL_RENDERER); - if (info.nameStr != NULL) - { - strncpy(info.name, (const char *)info.nameStr, sizeof(info.name)); - } - else if (info.accelerated == 0) - { - strncpy(info.name, "Apple Software Renderer", sizeof(info.name)); - } - else - { - strncpy(info.name, "UNKNOWN", sizeof(info.name)); - } - - } - } - } - - cgl_endOpenGL(); - - // Get the default virtual screen. - strncpy(__hostRendererString, "UNKNOWN", sizeof(__hostRendererString)); - __hostRendererID = -1; - - HostRendererInfo defaultRendererInfo = rendererInfo[0]; - for (int i = 0; i < rendererCount; i++) - { - if (defaultVirtualScreen == rendererInfo[i].virtualScreen) - { - defaultRendererInfo = rendererInfo[i]; - __hostRendererID = defaultRendererInfo.rendererID; - strncpy(__hostRendererString, (const char *)defaultRendererInfo.name, sizeof(__hostRendererString)); - - if ( (defaultRendererInfo.online == 1) && (defaultRendererInfo.vendorStr != NULL) && (defaultRendererInfo.nameStr != NULL) ) - { - break; - } - } - } - - printf("Default OpenGL Renderer: [0x%08X] %s\n", __hostRendererID, __hostRendererString); - /* - bool isDefaultRunningIntegratedGPU = false; - if ( (defaultRendererInfo.online == 1) && (defaultRendererInfo.vendorStr != NULL) && (defaultRendererInfo.nameStr != NULL) ) - { - const HostRendererInfo &d = defaultRendererInfo; - isDefaultRunningIntegratedGPU = (strstr(d.name, "GMA 950") != NULL) || - (strstr(d.name, "GMA X3100") != NULL) || - (strstr(d.name, "GeForce 9400M") != NULL) || - (strstr(d.name, "GeForce 320M") != NULL) || - (strstr(d.name, "HD Graphics") != NULL) || - (strstr(d.name, "Iris 5100") != NULL) || - (strstr(d.name, "Iris Plus") != NULL) || - (strstr(d.name, "Iris Pro") != NULL) || - (strstr(d.name, "Iris Graphics") != NULL) || - (strstr(d.name, "UHD Graphics") != NULL); - } - */ -#if defined(DEBUG) && (DEBUG == 1) - // Report information on every renderer. - if (!isLionSupported) - { - printf("WARNING: You are running a macOS version earlier than v10.7.\n Video Memory and Texture Memory reporting is capped\n at 2048 MB on older macOS.\n"); - } - printf("CGL Renderer Count: %i\n", rendererCount); - printf(" Virtual Screen Count: %i\n\n", virtualScreenCount); - - for (int i = 0; i < rendererCount; i++) - { - const HostRendererInfo &info = rendererInfo[i]; - - printf("Renderer Index: %i\n", i); - printf("Virtual Screen: %i\n", info.virtualScreen); - printf("Vendor: %s\n", info.vendor); - printf("Renderer: %s\n", info.name); - printf("Renderer ID: 0x%08X\n", info.rendererID); - printf("Accelerated: %s\n", (info.accelerated == 1) ? "YES" : "NO"); - printf("Online: %s\n", (info.online == 1) ? "YES" : "NO"); - - if (isHighSierraSupported) - { - printf("Removable: %s\n", (info.removable == 1) ? "YES" : "NO"); - } - else - { - printf("Removable: UNSUPPORTED, Requires High Sierra\n"); - } - - printf("Display ID: 0x%08X\n", info.displayID); - printf("Video Memory: %i MB\n", info.videoMemoryMB); - printf("Texture Memory: %i MB\n\n", info.textureMemoryMB); - } -#endif - - // Search for a better virtual screen that will suit our offscreen rendering better. - // - // At the moment, we are not supporting removable renderers such as eGPUs. Attempting - // to support removable renderers would require a lot more code to handle dynamically - // changing display<-->renderer associations. - rogerman 2025/03/25 - bool wasBetterVirtualScreenFound = false; - - char *modelCString = NULL; - size_t modelStringLen = 0; - - sysctlbyname("hw.model", NULL, &modelStringLen, NULL, 0); - if (modelStringLen > 0) - { - modelCString = (char *)malloc(modelStringLen * sizeof(char)); - sysctlbyname("hw.model", modelCString, &modelStringLen, NULL, 0); - } - - for (int i = 0; i < rendererCount; i++) - { - const HostRendererInfo &info = rendererInfo[i]; - - if ( (defaultRendererInfo.vendorStr == NULL) || (defaultRendererInfo.nameStr == NULL) || (info.vendorStr == NULL) || (info.nameStr == NULL) ) - { - continue; - } - - wasBetterVirtualScreenFound = (info.accelerated == 1) && - ( ( (modelCString != NULL) && (strstr((const char *)modelCString, "MacBookPro") != NULL) && - ( ( (strstr(defaultRendererInfo.name, "GeForce 9400M") != NULL) && - (strstr(info.name, "GeForce 9600M GT") != NULL) ) || - ( (strstr(defaultRendererInfo.name, "HD Graphics") != NULL) && - ((strstr(info.name, "GeForce GT 330M") != NULL) || - (strstr(info.name, "Radeon HD 6490M") != NULL) || - (strstr(info.name, "Radeon HD 6750M") != NULL) || - (strstr(info.name, "Radeon HD 6770M") != NULL) || - (strstr(info.name, "GeForce GT 650M") != NULL) || - (strstr(info.name, "Radeon Pro 450") != NULL) || - (strstr(info.name, "Radeon Pro 455") != NULL) || - (strstr(info.name, "Radeon Pro 555") != NULL) || - (strstr(info.name, "Radeon Pro 560") != NULL)) ) || - ( (strstr(defaultRendererInfo.name, "Iris Pro") != NULL) && - ((strstr(info.name, "GeForce GT 750M") != NULL) || - (strstr(info.name, "Radeon R9 M370X") != NULL)) ) || - ( (strstr(defaultRendererInfo.name, "UHD Graphics") != NULL) && - ((strstr(info.name, "Radeon Pro 555X") != NULL) || - (strstr(info.name, "Radeon Pro 560X") != NULL) || - (strstr(info.name, "Radeon Pro Vega 16") != NULL) || - (strstr(info.name, "Radeon Pro Vega 20") != NULL) || - (strstr(info.name, "Radeon Pro 5300M") != NULL) || - (strstr(info.name, "Radeon Pro 5500M") != NULL) || - (strstr(info.name, "Radeon Pro 5600M") != NULL)) ) ) ) || - ( (modelCString != NULL) && (strstr((const char *)modelCString, "MacPro6,1") != NULL) && (info.online == 0) && - ((strstr(info.name, "FirePro D300") != NULL) || - (strstr(info.name, "FirePro D500") != NULL) || - (strstr(info.name, "FirePro D700") != NULL)) ) ); - - if (wasBetterVirtualScreenFound) - { - CGLSetVirtualScreen(newContext, info.virtualScreen); - __hostRendererID = info.rendererID; - strncpy(__hostRendererString, (const char *)info.name, sizeof(__hostRendererString)); - printf("Found Better OpenGL Renderer: [0x%08X] %s\n", __hostRendererID, __hostRendererString); - break; - } - } - - // If we couldn't find a better virtual screen for our rendering, then just revert to the default one. - if (!wasBetterVirtualScreenFound) - { - CGLSetVirtualScreen(newContext, defaultVirtualScreen); - } - - // We're done! Report success and return. - printf("%s: OpenGL context creation successful.\n\n", ctxString); - free(rendererInfo); - free(modelCString); - - result = true; - return result; -} - -bool cgl_initOpenGL_StandardAuto() -{ - bool isContextCreated = __cgl_initOpenGL(kCGLOGLPVersion_GL4_Core); - - if (!isContextCreated) - { - isContextCreated = __cgl_initOpenGL(kCGLOGLPVersion_3_2_Core); - } - - if (!isContextCreated) - { - isContextCreated = __cgl_initOpenGL(kCGLOGLPVersion_Legacy); - } - - return isContextCreated; -} - -bool cgl_initOpenGL_LegacyAuto() -{ - return __cgl_initOpenGL(kCGLOGLPVersion_Legacy); -} - -bool cgl_initOpenGL_3_2_CoreProfile() -{ - return __cgl_initOpenGL(kCGLOGLPVersion_3_2_Core); -} - -void cgl_deinitOpenGL() -{ - if (OSXOpenGLRendererContext == NULL) - { - return; - } - - CGLSetCurrentContext(NULL); - SILENCE_DEPRECATION_MACOS_10_7( CGLReleasePBuffer(OSXOpenGLRendererPBuffer) ); - OSXOpenGLRendererPBuffer = NULL; - - CGLReleaseContext(OSXOpenGLRendererContext); - OSXOpenGLRendererContext = NULL; - OSXOpenGLRendererContextPrev = NULL; -} - -bool cgl_beginOpenGL() -{ - OSXOpenGLRendererContextPrev = CGLGetCurrentContext(); - CGLSetCurrentContext(OSXOpenGLRendererContext); - - return true; -} - -void cgl_endOpenGL() -{ -#ifndef PORT_VERSION_OS_X_APP - // The OpenEmu plug-in needs the context reset after 3D rendering since OpenEmu's context - // is assumed to be the default context. However, resetting the context for our standalone - // app can cause problems since the core emulator's context is assumed to be the default - // context. So reset the context for OpenEmu and skip resetting for us. - CGLSetCurrentContext(OSXOpenGLRendererContextPrev); -#endif -} - -bool cgl_framebufferDidResizeCallback(const bool isFBOSupported, size_t w, size_t h) -{ - bool result = false; - - if (isFBOSupported) - { - result = true; - return result; - } - - if (IsOSXVersionSupported(10, 13, 0)) - { - printf("Mac OpenGL: P-Buffers cannot be created on macOS v10.13 High Sierra and later.\n"); - return result; - } - - // Create a PBuffer if FBOs are not supported. - SILENCE_DEPRECATION_MACOS_10_7( CGLPBufferObj newPBuffer = NULL ); - SILENCE_DEPRECATION_MACOS_10_7( CGLError error = CGLCreatePBuffer((GLsizei)w, (GLsizei)h, GL_TEXTURE_2D, GL_RGBA, 0, &newPBuffer) ); - - if ( (newPBuffer == NULL) || (error != kCGLNoError) ) - { - printf("Mac OpenGL: ERROR - Could not create the P-Buffer: %s\n", CGLErrorString(error)); - return result; - } - else - { - GLint virtualScreenID = 0; - CGLGetVirtualScreen(OSXOpenGLRendererContext, &virtualScreenID); - SILENCE_DEPRECATION_MACOS_10_7( CGLSetPBuffer(OSXOpenGLRendererContext, newPBuffer, 0, 0, virtualScreenID) ); - } - - SILENCE_DEPRECATION_MACOS_10_7( CGLPBufferObj oldPBuffer = OSXOpenGLRendererPBuffer ); - OSXOpenGLRendererPBuffer = newPBuffer; - SILENCE_DEPRECATION_MACOS_10_7( CGLReleasePBuffer(oldPBuffer) ); - - result = true; - return result; -} diff --git a/desmume/src/frontend/cocoa/cocoa_core.mm b/desmume/src/frontend/cocoa/cocoa_core.mm index a45f15efc..3ebd1af0d 100644 --- a/desmume/src/frontend/cocoa/cocoa_core.mm +++ b/desmume/src/frontend/cocoa/cocoa_core.mm @@ -1141,8 +1141,6 @@ static void* RunCoreThread(void *arg) execControl->ApplySettingsOnExecutionLoopStart(); behavior = execControl->GetExecutionBehaviorApplied(); - [cdsGPU respondToPauseState:(behavior == ExecutionBehavior_Pause)]; - while (!(behavior != ExecutionBehavior_Pause && execute)) { pthread_cond_wait(¶m->condThreadExecute, ¶m->mutexThreadExecute); @@ -1152,8 +1150,6 @@ static void* RunCoreThread(void *arg) behavior = execControl->GetExecutionBehaviorApplied(); } - [cdsGPU respondToPauseState:(behavior == ExecutionBehavior_Pause)]; - if ( (lastBehavior == ExecutionBehavior_Run) && (behavior != ExecutionBehavior_Run) ) { lastExecutionWaitBias = executionWaitBias; diff --git a/desmume/src/frontend/cocoa/translations/English.lproj/MainMenu.xib b/desmume/src/frontend/cocoa/translations/English.lproj/MainMenu.xib index 03af3ab01..a3a1c82b9 100644 --- a/desmume/src/frontend/cocoa/translations/English.lproj/MainMenu.xib +++ b/desmume/src/frontend/cocoa/translations/English.lproj/MainMenu.xib @@ -23402,7 +23402,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 YES - + 256 @@ -23410,7 +23410,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 12 {{13, 131}, {240, 173}} - APProfile1 @@ -23423,7 +23422,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{-1, 113}, {78, 14}} - YES 68157504 @@ -23442,7 +23440,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{105, 113}, {12, 17}} - YES 68157504 @@ -23461,7 +23458,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{141, 113}, {12, 17}} - YES 68157504 @@ -23480,7 +23476,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{177, 113}, {12, 17}} - YES 68157504 @@ -23499,7 +23494,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{78, 111}, {30, 19}} - YES -1804599231 @@ -23560,7 +23554,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{114, 111}, {30, 19}} - YES -1804599231 @@ -23621,7 +23614,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{150, 111}, {30, 19}} - YES -1804599231 @@ -23682,7 +23674,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{186, 111}, {30, 19}} - YES -1804599231 @@ -23743,7 +23734,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{-1, 61}, {78, 14}} - YES 68157504 @@ -23762,7 +23752,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{105, 61}, {12, 17}} - YES 68157504 @@ -23781,7 +23770,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{141, 61}, {12, 17}} - YES 68157504 @@ -23800,7 +23788,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{177, 61}, {12, 17}} - YES 68157504 @@ -23819,7 +23806,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{78, 59}, {30, 19}} - YES -1804599231 @@ -23880,7 +23866,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{114, 59}, {30, 19}} - YES -1804599231 @@ -23941,7 +23926,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{150, 59}, {30, 19}} - YES -1804599231 @@ -24002,7 +23986,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{186, 59}, {30, 19}} - YES -1804599231 @@ -24063,7 +24046,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{-1, 34}, {78, 14}} - YES 68157504 @@ -24082,7 +24064,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{105, 34}, {12, 17}} - YES 68157504 @@ -24101,7 +24082,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{141, 34}, {12, 17}} - YES 68157504 @@ -24120,7 +24100,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{177, 34}, {12, 17}} - YES 68157504 @@ -24139,7 +24118,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{78, 32}, {30, 19}} - YES -1804599231 @@ -24200,7 +24178,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{114, 32}, {30, 19}} - YES -1804599231 @@ -24261,7 +24238,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{150, 32}, {30, 19}} - YES -1804599231 @@ -24322,7 +24298,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{186, 32}, {30, 19}} - YES -1804599231 @@ -24383,7 +24358,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{-1, 8}, {78, 14}} - YES 68157504 @@ -24402,7 +24376,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{105, 8}, {12, 17}} - YES 68157504 @@ -24421,7 +24394,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{141, 8}, {12, 17}} - YES 68157504 @@ -24440,7 +24412,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{177, 8}, {12, 17}} - YES 68157504 @@ -24459,7 +24430,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{78, 6}, {30, 19}} - YES -1804599231 @@ -24520,7 +24490,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{114, 6}, {30, 19}} - YES -1804599231 @@ -24581,7 +24550,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{150, 6}, {30, 19}} - YES -1804599231 @@ -24642,7 +24610,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{186, 6}, {30, 19}} - YES -1804599231 @@ -24703,7 +24670,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{1, 86}, {76, 14}} - YES 68157504 @@ -24722,7 +24688,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{93, 86}, {126, 14}} - YES 68157504 @@ -24742,7 +24707,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{75, 81}, {19, 27}} - YES 67895328 @@ -24759,7 +24723,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {{10, 25}, {220, 135}} - Profile 1 @@ -27410,7 +27373,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{105, 305}, {140, 28}} - YES 67108864 @@ -27432,7 +27394,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{109, 331}, {134, 14}} - YES 70254657 @@ -27452,7 +27413,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{17, 331}, {88, 14}} - YES 68157504 @@ -27471,7 +27431,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{53, 9}, {154, 19}} - YES -2080374784 @@ -27493,7 +27452,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{107, 406}, {136, 22}} - YES -2076180416 @@ -27718,7 +27676,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{107, 353}, {136, 22}} - YES -2076180416 @@ -27818,7 +27775,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{17, 36}, {226, 98}} - YES 67108864 @@ -27837,7 +27793,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{110, 381}, {133, 27}} - YES 71303168 @@ -27857,7 +27812,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{17, 358}, {88, 14}} - YES 68157504 @@ -27876,7 +27830,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{17, 385}, {88, 14}} - YES 68157504 @@ -27895,7 +27848,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{17, 411}, {88, 14}} - YES 68157504 @@ -27914,7 +27866,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{17, 457}, {88, 14}} - YES 68157504 @@ -27933,7 +27884,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{17, 483}, {88, 14}} - YES 68157504 @@ -27952,7 +27902,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{110, 434}, {130, 40}} - YES -1805647871 @@ -27973,7 +27922,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{110, 481}, {130, 19}} - YES -1804599231 @@ -27991,8 +27939,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {260, 513} - - NSView @@ -32969,7 +32915,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {1.7976931348623157e+308, 1.7976931348623157e+308} - + 256 @@ -32985,7 +32931,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{18, 13}, {110, 78}} - YES NO 4 @@ -33252,12 +33197,10 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {{1, 1}, {213, 100}} - {{16, 179}, {215, 116}} - {0, 0} 67108864 @@ -33286,7 +33229,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{18, 80}, {154, 38}} - YES NO 2 @@ -33529,7 +33471,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{53, 14}, {100, 58}} - YES NO 3 @@ -33782,12 +33723,10 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {{1, 1}, {213, 128}} - {{16, 31}, {215, 144}} - {0, 0} 67108864 @@ -33816,7 +33755,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{15, 12}, {135, 18}} - YES -2080374784 @@ -33838,12 +33776,10 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {{1, 1}, {213, 38}} - {{16, 299}, {215, 54}} - {0, 0} 67108864 @@ -33872,7 +33808,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{40, 13}, {115, 21}} - YES 67371264 @@ -33895,7 +33830,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{147, 17}, {52, 14}} - YES 68157504 @@ -33967,7 +33901,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {{18, 16}, {16, 16}} - YES 134217728 @@ -33984,12 +33917,10 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {{1, 1}, {213, 46}} - {{16, 357}, {215, 62}} - {0, 0} 67108864 @@ -34010,7 +33941,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{43, 8}, {162, 19}} - YES -2080374784 @@ -34040,7 +33970,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{18, 14}, {128, 38}} - YES NO 2 @@ -34281,12 +34210,10 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {{1, 1}, {213, 62}} - {{16, 423}, {215, 78}} - {0, 0} 67108864 @@ -34304,8 +34231,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {248, 519} - - {{0, 0}, {1920, 1177}} {1.7976931348623157e+308, 1.7976931348623157e+308} @@ -42171,6 +42096,11 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 YES + + CocoaGraphicsController + YES + + isWorking @@ -61123,7 +61053,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 3959 - CocoaDS Sound Controller + Audio Controller 3965 @@ -80217,6 +80147,12 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 + + 12480 + + + Graphics Controller + @@ -83041,6 +82977,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin {{903, 773}, {143, 23}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -86362,7 +86299,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - 12479 + 12480 diff --git a/desmume/src/frontend/cocoa/userinterface/MacOGLDisplayView.h b/desmume/src/frontend/cocoa/userinterface/MacOGLDisplayView.h index 0bb06e7d1..f2a9bc0ef 100644 --- a/desmume/src/frontend/cocoa/userinterface/MacOGLDisplayView.h +++ b/desmume/src/frontend/cocoa/userinterface/MacOGLDisplayView.h @@ -74,6 +74,9 @@ public: void FetchNativeDisplayToSrcClone(const NDSDisplayID displayID, const u8 bufferIndex, bool needsLock); void FetchCustomDisplayToSrcClone(const NDSDisplayID displayID, const u8 bufferIndex, bool needsLock); + // MacGPUEventHandlerAsync methods + virtual void SetPauseState(bool theState); + // GPUClientFetchObject methods virtual void Init(); virtual void SetFetchBuffers(const NDSDisplayInfo ¤tDisplayInfo); diff --git a/desmume/src/frontend/cocoa/userinterface/MacOGLDisplayView.mm b/desmume/src/frontend/cocoa/userinterface/MacOGLDisplayView.mm index 7507d8b41..24803ba4e 100644 --- a/desmume/src/frontend/cocoa/userinterface/MacOGLDisplayView.mm +++ b/desmume/src/frontend/cocoa/userinterface/MacOGLDisplayView.mm @@ -253,6 +253,24 @@ void MacOGLClientFetchObject::FetchCustomDisplayToSrcClone(const NDSDisplayID di sharedData->FetchCustomDisplayToSrcClone(this->_fetchDisplayInfo, displayID, bufferIndex, needsLock); } +void MacOGLClientFetchObject::SetPauseState(bool theState) +{ + if (theState == this->_pauseState) + { + return; + } + + if (theState) + { + CGLContextObj prevContext = CGLGetCurrentContext(); + CGLSetCurrentContext(this->_context); + glFinish(); + CGLSetCurrentContext(prevContext); + } + + this->MacGPUFetchObjectDisplayLink::SetPauseState(theState); +} + void MacOGLClientFetchObject::Init() { MacOGLClientSharedData *sharedData = (MacOGLClientSharedData *)this->_clientData; diff --git a/desmume/src/frontend/modules/osd/agg/agg_osd.cpp b/desmume/src/frontend/modules/osd/agg/agg_osd.cpp index 5534ad0ab..bfa5bda04 100644 --- a/desmume/src/frontend/modules/osd/agg/agg_osd.cpp +++ b/desmume/src/frontend/modules/osd/agg/agg_osd.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2006 yopyop - Copyright (C) 2006-2015 DeSmuME team + Copyright (C) 2006-2025 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -546,6 +546,17 @@ static int previousslot = 0; static char number[10]; static s64 slotTimer=0; +bool HudNeedsDrawStateSlots() +{ + if (HudEditorMode) + { + return true; + } + + s64 fadecounter = 512 - (hudTimer - slotTimer) / 4; //change constant to alter fade speed + return (fadecounter > 0); +} + static void DrawStateSlots(){ const int yloc = calcY(Hud.SavestateSlots.y); //160 diff --git a/desmume/src/frontend/modules/osd/agg/agg_osd.h b/desmume/src/frontend/modules/osd/agg/agg_osd.h index 4077a1eb2..78d2d1790 100644 --- a/desmume/src/frontend/modules/osd/agg/agg_osd.h +++ b/desmume/src/frontend/modules/osd/agg/agg_osd.h @@ -1,6 +1,6 @@ /* Copyright (C) 2006 yopyop - Copyright (C) 2008-2012 DeSmuME team + Copyright (C) 2008-2025 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -80,6 +80,7 @@ public: bool clicked; }; +bool HudNeedsDrawStateSlots(); void EditHud(s32 x, s32 y, HudStruct *hudstruct); void HudClickRelease(HudStruct *hudstruct); diff --git a/desmume/src/frontend/modules/osd/agg/aggdraw.cpp b/desmume/src/frontend/modules/osd/agg/aggdraw.cpp index 50758c8f1..7ce5dddb7 100644 --- a/desmume/src/frontend/modules/osd/agg/aggdraw.cpp +++ b/desmume/src/frontend/modules/osd/agg/aggdraw.cpp @@ -1,7 +1,7 @@ /* The MIT License -Copyright (C) 2009-2010 DeSmuME team +Copyright (C) 2009-2025 DeSmuME team Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -152,13 +152,10 @@ void Agg_init() aggDraw.target = targets[0]; - //if we're single core, we don't want to waste time compositing - //and the more clever compositing isnt supported in non-windows + //if we're single core in Windows, we don't want to waste time compositing #ifdef WIN32 if(CommonSettings.single_core()) aggDraw.hud = aggDraw.screen; - #else - aggDraw.hud = aggDraw.screen; #endif aggDraw.hud->setFont("verdana18_bold"); diff --git a/desmume/src/frontend/posix/codeblocks/desmume.cbp b/desmume/src/frontend/posix/codeblocks/desmume.cbp index 3aa645f7c..a44cd5f06 100644 --- a/desmume/src/frontend/posix/codeblocks/desmume.cbp +++ b/desmume/src/frontend/posix/codeblocks/desmume.cbp @@ -164,6 +164,9 @@ + + + @@ -195,6 +198,9 @@ + + + @@ -222,6 +228,9 @@ + + + @@ -262,6 +271,9 @@ + + + @@ -299,6 +311,9 @@ + + + @@ -310,6 +325,7 @@ + @@ -326,6 +342,9 @@ + + + diff --git a/desmume/src/frontend/posix/gtk/main.cpp b/desmume/src/frontend/posix/gtk/main.cpp index 50e129d00..52171279f 100644 --- a/desmume/src/frontend/posix/gtk/main.cpp +++ b/desmume/src/frontend/posix/gtk/main.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2007 Pascal Giard (evilynux) - Copyright (C) 2006-2024 DeSmuME team + Copyright (C) 2006-2025 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -31,15 +31,16 @@ #include #include #include + #ifdef AGG2D_USE_VECTORFONTS #include #endif #include "types.h" +#include "main.h" #include "firmware.h" #include "NDSSystem.h" #include "driver.h" -#include "GPU.h" #include "SPU.h" #include "../shared/sndsdl.h" #include "../shared/ctrlssdl.h" @@ -106,11 +107,11 @@ extern int _scanline_filter_a, _scanline_filter_b, _scanline_filter_c, _scanline VideoFilter* video; #define GPU_SCALE_FACTOR_MIN 1.0f -#define GPU_SCALE_FACTOR_MAX 10.0f +#define GPU_SCALE_FACTOR_MAX 16.0f float gpu_scale_factor = 1.0f; -int real_framebuffer_width = GPU_FRAMEBUFFER_NATIVE_WIDTH; -int real_framebuffer_height = GPU_FRAMEBUFFER_NATIVE_HEIGHT; + +Gtk3GPUEventHandler *gtk3gpuEvent = NULL; desmume::config::Config config; @@ -197,6 +198,7 @@ static void Modify_PriInterpolation(GSimpleAction *action, GVariant *parameter, static void Modify_Interpolation(GSimpleAction *action, GVariant *parameter, gpointer user_data); static void SetOrientation(GSimpleAction *action, GVariant *parameter, gpointer user_data); static void ToggleLayerVisibility(GSimpleAction *action, GVariant *parameter, gpointer user_data); +static void ToggleHudDisplay(GtkToggleAction* action, gpointer data); #ifdef HAVE_LIBAGG static void HudFps(GSimpleAction *action, GVariant *parameter, gpointer user_data); static void HudInput(GSimpleAction *action, GVariant *parameter, gpointer user_data); @@ -1394,14 +1396,8 @@ static int ConfigureDrawingArea(GtkWidget *widget, GdkEventConfigure *event, gpo return TRUE; } -static inline void gpu_screen_to_rgb(u32* dst) -{ - ColorspaceConvertBuffer555xTo8888Opaque(GPU->GetDisplayInfo().isCustomSizeRequested ? (u16*)(GPU->GetDisplayInfo().masterCustomBuffer) : GPU->GetDisplayInfo().masterNativeBuffer16, - dst, real_framebuffer_width * real_framebuffer_height * 2); -} - static inline void drawScreen(cairo_t* cr, u32* buf, gint w, gint h) { - cairo_surface_t* surf = cairo_image_surface_create_for_data((u8*)buf, CAIRO_FORMAT_RGB24, w, h, w * 4); + cairo_surface_t* surf = cairo_image_surface_create_for_data((u8*)buf, CAIRO_FORMAT_RGB24, w, h, w * sizeof(buf[0])); cairo_set_source_surface(cr, surf, 0, 0); cairo_pattern_set_filter(cairo_get_source(cr), Interpolation); cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_PAD); @@ -1606,17 +1602,59 @@ static gboolean ExposeDrawingArea (GtkWidget *widget, GdkEventExpose *event, gpo return TRUE; } -static void RedrawScreen() { - ColorspaceConvertBuffer555xTo8888Opaque( - GPU->GetDisplayInfo().isCustomSizeRequested ? (u16*)(GPU->GetDisplayInfo().masterCustomBuffer) : GPU->GetDisplayInfo().masterNativeBuffer16, - (uint32_t *)video->GetSrcBufferPtr(), real_framebuffer_width * real_framebuffer_height * 2); +static void RedrawScreen() +{ + gtk3gpuEvent->VideoFetchLock(); + #ifdef HAVE_LIBAGG - aggDraw.hud->setDrawTargetDims((u8*)video->GetSrcBufferPtr(), real_framebuffer_width, real_framebuffer_height * 2, real_framebuffer_width * 4); - osd->update(); - DrawHUD(); - osd->clear(); -#endif + const bool needsHUDDisplay = ( + CommonSettings.hud.ShowInputDisplay || + CommonSettings.hud.ShowGraphicalInputDisplay || + CommonSettings.hud.FpsDisplay || + CommonSettings.hud.FrameCounterDisplay || + CommonSettings.hud.ShowLagFrameCounter || + CommonSettings.hud.ShowMicrophone || + CommonSettings.hud.ShowRTC || + HudEditorMode + ); + + if (needsHUDDisplay) + { + const int w = (int)video->GetSrcWidth(); + const int h = (int)video->GetSrcHeight(); + const double oldGpuScaleFactor = osd->scale; + const double newGpuScaleFactor = ( ((double)w / (double)GPU_FRAMEBUFFER_NATIVE_WIDTH) + ((double)h / (double)(GPU_FRAMEBUFFER_NATIVE_HEIGHT * 2.0)) ) / 2.0; + + if ( ((newGpuScaleFactor + 0.001) < oldGpuScaleFactor) || ((newGpuScaleFactor - 0.001) > oldGpuScaleFactor) ) + { +#ifdef AGG2D_USE_VECTORFONTS + if (vectorFontFile.size() > 0) + { + aggDraw.hud->setVectorFont(vectorFontFile, VECTOR_FONT_BASE_SIZE * newGpuScaleFactor, true); + osd->useVectorFonts = (newGpuScaleFactor >= 1.1f); + } + else + { + osd->useVectorFonts = false; + } +#endif // AGG2D_USE_VECTORFONTS + + Agg_setCustomSize(w, h); + osd->scale = newGpuScaleFactor; + Hud.rescale(oldGpuScaleFactor, newGpuScaleFactor); + HudSaveLayout(); + aggDraw.hud->setDrawTargetDims( (u8 *)video->GetSrcBufferPtr(), w, h, w * sizeof(u32) ); + } + + osd->update(); + DrawHUD(); + osd->clear(); + } +#endif // HAVE_LIBAGG + video->RunFilter(); + gtk3gpuEvent->VideoFetchUnlock(); + gtk_widget_queue_draw(pDrawingArea); } @@ -1628,6 +1666,9 @@ static bool hud_move_started_in_big_screen = false; #ifdef HAVE_LIBAGG static gboolean rotoscaled_hudedit(gint x, gint y, gboolean start) { + const size_t videoWidth = video->GetSrcWidth(); + const size_t videoHeight = video->GetSrcHeight(); + const int scaleFactor = (int)( ( (((float)videoWidth / (float)GPU_FRAMEBUFFER_NATIVE_WIDTH) + ((float)videoHeight / ((float)GPU_FRAMEBUFFER_NATIVE_HEIGHT*2.0f))) / 2.0f ) + 0.5f ); double devX, devY; gint X, Y, topX = -1, topY = -1, botX = -1, botY = -1, hybTopX = -1, hybTopY = -1, hybBotX = -1, hybBotY = -1; static gint startScreen = 0; @@ -1638,15 +1679,15 @@ static gboolean rotoscaled_hudedit(gint x, gint y, gboolean start) devX = x; devY = y; cairo_matrix_transform_point(&nds_screen.topscreen_matrix, &devX, &devY); - topX = devX * gpu_scale_factor; - topY = devY * gpu_scale_factor; + topX = devX * scaleFactor; + topY = devY * scaleFactor; if(hybrid && !nds_screen.swap) { devX = x; devY = y; cairo_matrix_transform_point(&nds_screen.topscreen_matrix_hybrid, &devX, &devY); - hybTopX = devX * gpu_scale_factor; - hybTopY = devY * gpu_scale_factor; + hybTopX = devX * scaleFactor; + hybTopY = devY * scaleFactor; } } @@ -1654,58 +1695,58 @@ static gboolean rotoscaled_hudedit(gint x, gint y, gboolean start) devX = x; devY = y; cairo_matrix_transform_point(&nds_screen.touch_matrix, &devX, &devY); - botX = devX * gpu_scale_factor; - botY = devY * gpu_scale_factor; + botX = devX * scaleFactor; + botY = devY * scaleFactor; if(hybrid && nds_screen.swap) { devX = x; devY = y; cairo_matrix_transform_point(&nds_screen.touch_matrix_hybrid, &devX, &devY); - hybBotX = devX * gpu_scale_factor; - hybBotY = devY * gpu_scale_factor; + hybBotX = devX * scaleFactor; + hybBotY = devY * scaleFactor; } } - if (topX >= 0 && topY >= 0 && topX < real_framebuffer_width && topY < real_framebuffer_height) { + if (topX >= 0 && topY >= 0 && topX < videoWidth && topY < videoHeight) { X = topX; - Y = topY + (osd->swapScreens ? real_framebuffer_height : 0); + Y = topY + (osd->swapScreens ? videoHeight : 0); startScreen = 0; if(start) hud_move_started_in_big_screen = false; - } else if (hybTopX >= 0 && hybTopY >= 0 && hybTopX < real_framebuffer_width && hybTopY < real_framebuffer_height) { + } else if (hybTopX >= 0 && hybTopY >= 0 && hybTopX < videoWidth && hybTopY < videoHeight) { X = hybTopX; Y = hybTopY; startScreen = 0; if(start) hud_move_started_in_big_screen = true; - } else if (botX >= 0 && botY >= 0 && botX < real_framebuffer_width && botY < real_framebuffer_height) { + } else if (botX >= 0 && botY >= 0 && botX < videoWidth && botY < videoHeight) { X = botX; - Y = botY + (osd->swapScreens ? 0 : real_framebuffer_height); + Y = botY + (osd->swapScreens ? 0 : videoHeight); startScreen = 1; if(start) hud_move_started_in_big_screen = false; - } else if (hybBotX >= 0 && hybBotY >= 0 && hybBotX < real_framebuffer_width && hybBotY < real_framebuffer_height) { + } else if (hybBotX >= 0 && hybBotY >= 0 && hybBotX < videoWidth && hybBotY < videoHeight) { X = hybBotX; - Y = hybBotY + real_framebuffer_height; + Y = hybBotY + videoHeight; startScreen = 1; if(start) hud_move_started_in_big_screen = true; } else if (!start) { if (startScreen == 0) { if(!hud_move_started_in_big_screen || !hybrid) { - X = CLAMP(topX, 0, real_framebuffer_width-1); - Y = CLAMP(topY, 0, real_framebuffer_height-1) + (osd->swapScreens ? real_framebuffer_height : 0); + X = CLAMP(topX, 0, videoWidth-1); + Y = CLAMP(topY, 0, videoHeight-1) + (osd->swapScreens ? videoHeight : 0); } else { - X = CLAMP(hybTopX, 0, real_framebuffer_width-1); - Y = CLAMP(hybTopY, 0, real_framebuffer_height-1); + X = CLAMP(hybTopX, 0, videoWidth-1); + Y = CLAMP(hybTopY, 0, videoHeight-1); } } else { if(!hud_move_started_in_big_screen || !hybrid) { - X = CLAMP(botX, 0, real_framebuffer_width-1); - Y = CLAMP(botY, 0, real_framebuffer_height-1) + (osd->swapScreens ? 0 : real_framebuffer_height); + X = CLAMP(botX, 0, videoWidth-1); + Y = CLAMP(botY, 0, videoHeight-1) + (osd->swapScreens ? 0 : videoHeight); } else { - X = CLAMP(hybBotX, 0, real_framebuffer_width-1); - Y = CLAMP(hybBotY, 0, real_framebuffer_height-1) + real_framebuffer_height; + X = CLAMP(hybBotX, 0, videoWidth-1); + Y = CLAMP(hybBotY, 0, videoHeight-1) + videoHeight; } } } else { @@ -2414,7 +2455,7 @@ static void GraphicsSettingsDialog(GSimpleAction *action, GVariant *parameter, g default: break; } - double old_scale_factor = gpu_scale_factor; + gpu_scale_factor = gtk_spin_button_get_value(wGPUScale); if(gpu_scale_factor < GPU_SCALE_FACTOR_MIN) gpu_scale_factor = GPU_SCALE_FACTOR_MIN; @@ -2422,25 +2463,9 @@ static void GraphicsSettingsDialog(GSimpleAction *action, GVariant *parameter, g gpu_scale_factor = GPU_SCALE_FACTOR_MAX; gtk_spin_button_set_value(wGPUScale, gpu_scale_factor); config.gpuScaleFactor = gpu_scale_factor; - real_framebuffer_width = GPU_FRAMEBUFFER_NATIVE_WIDTH * gpu_scale_factor; - real_framebuffer_height = GPU_FRAMEBUFFER_NATIVE_HEIGHT * gpu_scale_factor; - GPU->SetCustomFramebufferSize(real_framebuffer_width, real_framebuffer_height); - video->SetSourceSize(real_framebuffer_width, real_framebuffer_height * 2); -#ifdef HAVE_LIBAGG -#ifdef AGG2D_USE_VECTORFONTS - if(vectorFontFile.size() > 0) - { - aggDraw.hud->setVectorFont(vectorFontFile, VECTOR_FONT_BASE_SIZE * gpu_scale_factor, true); - osd->useVectorFonts=(gpu_scale_factor >= 1.1); - } - else - osd->useVectorFonts=false; -#endif - Agg_setCustomSize(real_framebuffer_width, real_framebuffer_height*2); - osd->scale=gpu_scale_factor; - Hud.rescale(old_scale_factor, gpu_scale_factor); - HudSaveLayout(); -#endif + + gtk3gpuEvent->SetFramebufferDimensions( (size_t)(((float)GPU_FRAMEBUFFER_NATIVE_WIDTH * gpu_scale_factor) + 0.5), (size_t)(((float)GPU_FRAMEBUFFER_NATIVE_HEIGHT * gpu_scale_factor) + 0.5) ); + CommonSettings.GFX3D_Renderer_TextureDeposterize = config.textureDeposterize = gtk_toggle_button_get_active(wPosterize); CommonSettings.GFX3D_Renderer_TextureSmoothing = config.textureSmoothing = gtk_toggle_button_get_active(wSmoothing); CommonSettings.GFX3D_Renderer_TextureScalingFactor = config.textureUpscale = scale; @@ -2497,34 +2522,36 @@ static void ToggleLayerVisibility(GSimpleAction *action, GVariant *parameter, gp static void Printscreen(GSimpleAction *action, GVariant *parameter, gpointer user_data) { + const gint videoWidth = (gint)video->GetSrcWidth(); + const gint videoHeight = (gint)video->GetSrcHeight(); + u8 *screenshotBuffer = (u8 *)malloc_alignedPage(videoWidth * videoHeight * sizeof(u32)); + GdkPixbuf *screenshot; const gchar *dir; gchar *filename = NULL, *filen = NULL; GError *error = NULL; - u8 *rgb = (u8*)malloc(real_framebuffer_width * real_framebuffer_height * 2 * 4); static int seq = 0; gint H, W; - //rgb = (u8 *) malloc(SCREENS_PIXEL_SIZE*SCREEN_BYTES_PER_PIXEL); - //if (!rgb) - // return; - if (nds_screen.rotation_angle == 0 || nds_screen.rotation_angle == 180) { - W = real_framebuffer_width; - H = real_framebuffer_height * 2; + W = videoWidth; + H = videoHeight; } else { - W = real_framebuffer_height * 2; - H = real_framebuffer_width; + W = videoHeight; + H = videoWidth; } - gpu_screen_to_rgb((u32*)rgb); - screenshot = gdk_pixbuf_new_from_data(rgb, + gtk3gpuEvent->VideoFetchLock(); + ColorspaceConvertBuffer888xTo8888Opaque(video->GetSrcBufferPtr(), (u32 *)screenshotBuffer, videoWidth * videoHeight); + gtk3gpuEvent->VideoFetchUnlock(); + + screenshot = gdk_pixbuf_new_from_data(screenshotBuffer, GDK_COLORSPACE_RGB, TRUE, 8, W, H, - W * 4, + W * sizeof(u32), NULL, NULL); @@ -2551,10 +2578,10 @@ static void Printscreen(GSimpleAction *action, GVariant *parameter, gpointer use seq--; } - free(rgb); g_object_unref(screenshot); g_free(filename); g_free(filen); + free_aligned(screenshotBuffer); } #ifdef DESMUME_GTK_FIRMWARE_BROKEN @@ -2909,8 +2936,6 @@ gboolean EmuLoop(gpointer data) desmume_cycle(); /* Emule ! */ _updateDTools(); - avout_x264.updateVideo(GPU->GetDisplayInfo().masterNativeBuffer16); - RedrawScreen(); if (!config.fpslimiter || keys_latch & KEYMASK_(KEY_BOOST - 1)) { if (autoframeskip) { @@ -3400,7 +3425,23 @@ common_gtk_main(GApplication *app, gpointer user_data) // TODO: return a non-zero exit status. g_application_quit(app); } + desmume_init( my_config->disable_sound || !config.audio_enabled); + + gpu_scale_factor = config.gpuScaleFactor; + if(gpu_scale_factor < GPU_SCALE_FACTOR_MIN) + gpu_scale_factor = GPU_SCALE_FACTOR_MIN; + if(gpu_scale_factor > GPU_SCALE_FACTOR_MAX) + gpu_scale_factor = GPU_SCALE_FACTOR_MAX; + config.gpuScaleFactor = gpu_scale_factor; + + gtk3gpuEvent = new Gtk3GPUEventHandler; + GPU->SetEventHandler(gtk3gpuEvent); + gtk3gpuEvent->SetFramebufferDimensions( (size_t)(((float)GPU_FRAMEBUFFER_NATIVE_WIDTH * gpu_scale_factor) + 0.5), (size_t)(((float)GPU_FRAMEBUFFER_NATIVE_HEIGHT * gpu_scale_factor) + 0.5) ); + + const NDSDisplayInfo &dispInfo = GPU->GetDisplayInfo(); + video = new VideoFilter(dispInfo.customWidth, dispInfo.customHeight * 2, VideoFilterTypeID_None, CommonSettings.num_cores); + g_printerr("Using %d threads for video filter.\n", CommonSettings.num_cores); /* Init the hud / osd stuff */ #ifdef HAVE_LIBAGG @@ -3411,7 +3452,23 @@ common_gtk_main(GApplication *app, gpointer user_data) Desmume_InitOnce(); Hud.reset(); osd = new OSDCLASS(-1); -#endif + +#ifdef AGG2D_USE_VECTORFONTS + if (vectorFontFile.size() > 0) + { + aggDraw.hud->setVectorFont(vectorFontFile, VECTOR_FONT_BASE_SIZE, true); + osd->useVectorFonts = false; + } + else + { + osd->useVectorFonts = false; + } +#endif // AGG2D_USE_VECTORFONTS + + Agg_setCustomSize(video->GetSrcWidth(), video->GetSrcHeight()); + osd->scale = 1.0; + aggDraw.hud->setDrawTargetDims( (u8 *)video->GetSrcBufferPtr(), video->GetSrcWidth(), video->GetSrcHeight(), video->GetSrcWidth() * sizeof(u32) ); +#endif // HAVE_LIBAGG /* * Activate the GDB stubs @@ -3465,33 +3522,6 @@ common_gtk_main(GApplication *app, gpointer user_data) memset(&nds_screen, 0, sizeof(nds_screen)); nds_screen.orientation = ORIENT_VERTICAL; - gpu_scale_factor = config.gpuScaleFactor; - if(gpu_scale_factor < GPU_SCALE_FACTOR_MIN) - gpu_scale_factor = GPU_SCALE_FACTOR_MIN; - if(gpu_scale_factor > GPU_SCALE_FACTOR_MAX) - gpu_scale_factor = GPU_SCALE_FACTOR_MAX; - config.gpuScaleFactor = gpu_scale_factor; - real_framebuffer_width = GPU_FRAMEBUFFER_NATIVE_WIDTH * gpu_scale_factor; - real_framebuffer_height = GPU_FRAMEBUFFER_NATIVE_HEIGHT * gpu_scale_factor; - - g_printerr("Using %d threads for video filter.\n", CommonSettings.num_cores); - GPU->SetCustomFramebufferSize(real_framebuffer_width, real_framebuffer_height); - video = new VideoFilter(real_framebuffer_width, real_framebuffer_height * 2, VideoFilterTypeID_None, CommonSettings.num_cores); -#ifdef HAVE_LIBAGG -#ifdef AGG2D_USE_VECTORFONTS - if(vectorFontFile.size() > 0) - { - aggDraw.hud->setVectorFont(vectorFontFile, VECTOR_FONT_BASE_SIZE * gpu_scale_factor, true); - osd->useVectorFonts=(gpu_scale_factor >= 1.1); - } - else - osd->useVectorFonts=false; -#endif - Agg_setCustomSize(real_framebuffer_width, real_framebuffer_height*2); - osd->scale=gpu_scale_factor; - HudLoadLayout(); -#endif - /* Fetch the main elements from the window */ GtkBuilder *builder = gtk_builder_new_from_resource("/org/desmume/DeSmuME/main.ui"); pWindow = GTK_WIDGET(gtk_builder_get_object(builder, "window")); @@ -4111,16 +4141,21 @@ common_gtk_main(GApplication *app, gpointer user_data) } static void Teardown() { - delete video; #ifdef HAVE_LIBAGG HudSaveLayout(); #endif + + delete video; + config.save(); avout_x264.end(); avout_flac.end(); desmume_free(); + delete gtk3gpuEvent; + gtk3gpuEvent = NULL; + #if defined(ENABLE_OPENGL_STANDARD) || defined(ENABLE_OPENGL_ES) #if defined(ENABLE_GLX) glx_deinitOpenGL(); @@ -4238,3 +4273,168 @@ int main (int argc, char *argv[]) Teardown(); return ret; } + +Gtk3GPUEventHandler::Gtk3GPUEventHandler() +{ + _colorFormatPending = NDSColorFormat_BGR666_Rev; + _widthPending = GPU_FRAMEBUFFER_NATIVE_WIDTH; + _heightPending = GPU_FRAMEBUFFER_NATIVE_HEIGHT; + _pageCountPending = GTK3_FRAMEBUFFER_PAGE_COUNT; + + _didColorFormatChange = true; + _didWidthChange = true; + _didHeightChange = true; + _didPageCountChange = true; + + _latestBufferIndex = 0; + + _mutexApplyGPUSettings = slock_new(); + _mutexVideoFetch = slock_new(); + + for (size_t i = 0; i < GTK3_FRAMEBUFFER_PAGE_COUNT; i++) + { + _mutexFramebufferPage[i] = slock_new(); + } +} + +Gtk3GPUEventHandler::~Gtk3GPUEventHandler() +{ + slock_free(this->_mutexApplyGPUSettings); + slock_free(this->_mutexVideoFetch); + + for (size_t i = 0; i < GTK3_FRAMEBUFFER_PAGE_COUNT; i++) + { + slock_free(this->_mutexFramebufferPage[i]); + } +} + +void Gtk3GPUEventHandler::SetFramebufferDimensions(size_t w, size_t h) +{ + if (w < GPU_FRAMEBUFFER_NATIVE_WIDTH) + { + w = GPU_FRAMEBUFFER_NATIVE_WIDTH; + } + + if (h < GPU_FRAMEBUFFER_NATIVE_HEIGHT) + { + h = GPU_FRAMEBUFFER_NATIVE_HEIGHT; + } + + slock_lock(this->_mutexApplyGPUSettings); + + const NDSDisplayInfo &dispInfo = GPU->GetDisplayInfo(); + this->_didWidthChange = (w != dispInfo.customWidth); + this->_didHeightChange = (h != dispInfo.customHeight); + this->_widthPending = w; + this->_heightPending = h; + + slock_unlock(this->_mutexApplyGPUSettings); +} + +void Gtk3GPUEventHandler::GetFramebufferDimensions(size_t &outWidth, size_t &outHeight) +{ + outWidth = this->_widthPending; + outHeight = this->_heightPending; +} + +void Gtk3GPUEventHandler::SetColorFormat(NDSColorFormat colorFormat) +{ + slock_lock(this->_mutexApplyGPUSettings); + const NDSDisplayInfo &dispInfo = GPU->GetDisplayInfo(); + this->_didColorFormatChange = (colorFormat != dispInfo.colorFormat); + this->_colorFormatPending = colorFormat; + slock_unlock(this->_mutexApplyGPUSettings); +} + +NDSColorFormat Gtk3GPUEventHandler::GetColorFormat() +{ + return this->_colorFormatPending; +} + +void Gtk3GPUEventHandler::VideoFetchLock() +{ + slock_lock(this->_mutexVideoFetch); +} + +void Gtk3GPUEventHandler::VideoFetchUnlock() +{ + slock_unlock(this->_mutexVideoFetch); +} + +void Gtk3GPUEventHandler::DidFrameEnd(bool isFrameSkipped, const NDSDisplayInfo &latestDisplayInfo) +{ + if (isFrameSkipped) + { + return; + } + + this->_latestBufferIndex = latestDisplayInfo.bufferIndex; + + slock_lock(this->_mutexFramebufferPage[this->_latestBufferIndex]); + + // TODO: Video file writes only work on fixed 16-bit buffers at the native-size only. + // This currently does not work on custom-sized buffers or any 32-bit color format. + avout_x264.updateVideo(latestDisplayInfo.masterNativeBuffer16); + + this->VideoFetchLock(); + if (latestDisplayInfo.colorFormat == NDSColorFormat_BGR555_Rev) + { + ColorspaceConvertBuffer555xTo8888Opaque( (u16 *)latestDisplayInfo.masterCustomBuffer, (u32 *)video->GetSrcBufferPtr(), latestDisplayInfo.customWidth * latestDisplayInfo.customHeight * 2); + } + else + { + ColorspaceConvertBuffer888xTo8888Opaque( (u32 *)latestDisplayInfo.masterCustomBuffer, (u32 *)video->GetSrcBufferPtr(), latestDisplayInfo.customWidth * latestDisplayInfo.customHeight * 2); + } + this->VideoFetchUnlock(); + + slock_unlock(this->_mutexFramebufferPage[this->_latestBufferIndex]); + + RedrawScreen(); +} + +void Gtk3GPUEventHandler::DidApplyGPUSettingsBegin() +{ + slock_lock(this->_mutexApplyGPUSettings); + + if (this->_didWidthChange || this->_didHeightChange || this->_didColorFormatChange || this->_didPageCountChange) + { + if (this->_didWidthChange || this->_didHeightChange) + { + for (size_t i = 0; i < GTK3_FRAMEBUFFER_PAGE_COUNT; i++) + { + slock_lock(this->_mutexFramebufferPage[i]); + } + } + + GPU->SetCustomFramebufferSize(this->_widthPending, this->_heightPending); + GPU->SetColorFormat(this->_colorFormatPending); + GPU->SetFramebufferPageCount(this->_pageCountPending); + } +} + +void Gtk3GPUEventHandler::DidApplyGPUSettingsEnd() +{ + if (this->_didWidthChange || this->_didHeightChange || this->_didColorFormatChange || this->_didPageCountChange) + { + const NDSDisplayInfo &dispInfo = GPU->GetDisplayInfo(); + + if (this->_didWidthChange || this->_didHeightChange) + { + video->SetSourceSize(dispInfo.customWidth, dispInfo.customHeight * 2); + + for (size_t i = 0; i < GTK3_FRAMEBUFFER_PAGE_COUNT; i++) + { + slock_unlock(this->_mutexFramebufferPage[i]); + } + } + + // Update all the change flags now that settings are applied. + // In theory, all these flags should get cleared. + this->_didWidthChange = (this->_widthPending != dispInfo.customWidth); + this->_didHeightChange = (this->_heightPending != dispInfo.customHeight); + this->_didColorFormatChange = (this->_colorFormatPending != dispInfo.colorFormat); + this->_didPageCountChange = (this->_pageCountPending != dispInfo.framebufferPageCount); + } + + slock_unlock(this->_mutexApplyGPUSettings); +} diff --git a/desmume/src/frontend/posix/gtk/main.h b/desmume/src/frontend/posix/gtk/main.h index 8bb31279e..091d896d9 100644 --- a/desmume/src/frontend/posix/gtk/main.h +++ b/desmume/src/frontend/posix/gtk/main.h @@ -1,7 +1,69 @@ -#ifndef __DESMUME_GTK_MAIN_H__ -#define __DESMUME_GTK_MAIN_H__ - -void Pause(GSimpleAction *action, GVariant *parameter, gpointer user_data); -void Launch(GSimpleAction *action, GVariant *parameter, gpointer user_data); - -#endif + /* + Copyright (C) 2007 Pascal Giard (evilynux) + Copyright (C) 2006-2025 DeSmuME team + + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the this software. If not, see . + */ + +#ifndef __DESMUME_GTK_MAIN_H__ +#define __DESMUME_GTK_MAIN_H__ + +#include "GPU.h" +#include "rthreads/rthreads.h" + +#define GTK3_FRAMEBUFFER_PAGE_COUNT 3 + + +class Gtk3GPUEventHandler : public GPUEventHandlerDefault +{ +protected: + NDSColorFormat _colorFormatPending; + size_t _widthPending; + size_t _heightPending; + size_t _pageCountPending; + + bool _didColorFormatChange; + bool _didWidthChange; + bool _didHeightChange; + bool _didPageCountChange; + + u8 _latestBufferIndex; + + slock_t *_mutexApplyGPUSettings; + slock_t *_mutexVideoFetch; + slock_t *_mutexFramebufferPage[GTK3_FRAMEBUFFER_PAGE_COUNT]; + +public: + Gtk3GPUEventHandler(); + ~Gtk3GPUEventHandler(); + + void SetFramebufferDimensions(size_t w, size_t h); + void GetFramebufferDimensions(size_t &outWidth, size_t &outHeight); + + void SetColorFormat(NDSColorFormat colorFormat); + NDSColorFormat GetColorFormat(); + + void VideoFetchLock(); + void VideoFetchUnlock(); + + // GPUEventHandler methods + virtual void DidFrameEnd(bool isFrameSkipped, const NDSDisplayInfo &latestDisplayInfo); + virtual void DidApplyGPUSettingsBegin(); + virtual void DidApplyGPUSettingsEnd(); +}; + +void Pause(GSimpleAction *action, GVariant *parameter, gpointer user_data); +void Launch(GSimpleAction *action, GVariant *parameter, gpointer user_data); + +#endif diff --git a/desmume/src/frontend/posix/gtk2/config.cpp b/desmume/src/frontend/posix/gtk2/config.cpp index a0e593a5b..127b90571 100644 --- a/desmume/src/frontend/posix/gtk2/config.cpp +++ b/desmume/src/frontend/posix/gtk2/config.cpp @@ -21,9 +21,6 @@ #include "config.h" -using std::string; -using std::vector; - namespace desmume { namespace config { @@ -81,10 +78,10 @@ void value::save() { g_key_file_set_double(this->mKeyFile, this->mSection.c_str(), this->mKey.c_str(), this->mData); } -/* class value */ +/* class value */ template<> -void value::load() { +void value::load() { char* val = g_key_file_get_string(this->mKeyFile, this->mSection.c_str(), this->mKey.c_str(), NULL); if (val != NULL) { this->mData = val; @@ -93,10 +90,29 @@ void value::load() { } template<> -void value::save() { +void value::save() { g_key_file_set_string(this->mKeyFile, this->mSection.c_str(), this->mKey.c_str(), this->mData.c_str()); } +/* class value> */ + +template<> +void value>::load() { + gsize l; + int* val = g_key_file_get_integer_list(this->mKeyFile, this->mSection.c_str(), this->mKey.c_str(), &l, NULL); + if(val) + { + this->mData.resize(l); + std::copy(val, val+l, this->mData.begin()); + g_free(val); + } +} + +template<> +void value>::save() { + g_key_file_set_integer_list(this->mKeyFile, this->mSection.c_str(), this->mKey.c_str(), this->mData.data(), this->mData.size()); +} + /* class Config */ Config::Config() diff --git a/desmume/src/frontend/posix/gtk2/config_opts.h b/desmume/src/frontend/posix/gtk2/config_opts.h index 42ddd8643..65891d8e9 100644 --- a/desmume/src/frontend/posix/gtk2/config_opts.h +++ b/desmume/src/frontend/posix/gtk2/config_opts.h @@ -49,6 +49,7 @@ OPT(hud_input, bool, false, HudDisplay, Input) OPT(hud_graphicalInput, bool, false, HudDisplay, GraphicalInput) OPT(hud_rtc, bool, false, HudDisplay, RTC) OPT(hud_mic, bool, false, HudDisplay, Mic) +OPT(hud_layout, std::vector, std::vector(), HudDisplay, Layout) /* Config */ OPT(fpslimiter, bool, true, Config, FpsLimiter) diff --git a/desmume/src/frontend/posix/gtk2/main.cpp b/desmume/src/frontend/posix/gtk2/main.cpp index dc7a47d45..6315d8d57 100644 --- a/desmume/src/frontend/posix/gtk2/main.cpp +++ b/desmume/src/frontend/posix/gtk2/main.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2007 Pascal Giard (evilynux) - Copyright (C) 2006-2024 DeSmuME team + Copyright (C) 2006-2025 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -31,11 +31,15 @@ #include #include +#ifdef AGG2D_USE_VECTORFONTS +#include +#endif + #include "types.h" +#include "main.h" #include "firmware.h" #include "NDSSystem.h" #include "driver.h" -#include "GPU.h" #include "SPU.h" #include "../shared/sndsdl.h" #include "../shared/ctrlssdl.h" @@ -103,12 +107,11 @@ extern int _scanline_filter_a, _scanline_filter_b, _scanline_filter_c, _scanline VideoFilter* video; #define GPU_SCALE_FACTOR_MIN 1.0f -#define GPU_SCALE_FACTOR_MAX 10.0f +#define GPU_SCALE_FACTOR_MAX 16.0f float gpu_scale_factor = 1.0f; -int real_framebuffer_width = GPU_FRAMEBUFFER_NATIVE_WIDTH; -int real_framebuffer_height = GPU_FRAMEBUFFER_NATIVE_HEIGHT; +Gtk2GPUEventHandler *gtk2gpuEvent = NULL; desmume::config::Config config; @@ -127,6 +130,15 @@ enum { SUB_OBJ }; +#ifdef AGG2D_USE_VECTORFONTS +#define VECTOR_FONT_BASE_SIZE 16 + +static FcConfig* fontConfig; +static std::string vectorFontFile; + +static std::string FindFontFile(const char* fontName, bool bold); +#endif + gboolean EmuLoop(gpointer data); static AVOutX264 avout_x264; @@ -175,6 +187,11 @@ static void SetWinSize(GtkAction *action, GtkRadioAction *current); static void SetOrientation(GtkAction *action, GtkRadioAction *current); static void ToggleLayerVisibility(GtkToggleAction* action, gpointer data); static void ToggleHudDisplay(GtkToggleAction* action, gpointer data); +#ifdef HAVE_LIBAGG +static void HudResetLayout(GSimpleAction *action, GVariant *parameter, gpointer user_data); +static void HudSaveLayout(); +static void HudLoadLayout(); +#endif #ifdef DESMUME_GTK_FIRMWARE_BROKEN static void SelectFirmwareFile(); #endif @@ -1688,14 +1705,8 @@ static int ConfigureDrawingArea(GtkWidget *widget, GdkEventConfigure *event, gpo return TRUE; } -static inline void gpu_screen_to_rgb(u32* dst) -{ - ColorspaceConvertBuffer555xTo8888Opaque(GPU->GetDisplayInfo().isCustomSizeRequested ? (u16*)(GPU->GetDisplayInfo().masterCustomBuffer) : GPU->GetDisplayInfo().masterNativeBuffer16, - dst, real_framebuffer_width * real_framebuffer_height * 2); -} - static inline void drawScreen(cairo_t* cr, u32* buf, gint w, gint h) { - cairo_surface_t* surf = cairo_image_surface_create_for_data((u8*)buf, CAIRO_FORMAT_RGB24, w, h, w * 4); + cairo_surface_t* surf = cairo_image_surface_create_for_data((u8*)buf, CAIRO_FORMAT_RGB24, w, h, w * sizeof(buf[0])); cairo_set_source_surface(cr, surf, 0, 0); cairo_pattern_set_filter(cairo_get_source(cr), Interpolation); cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_PAD); @@ -1815,17 +1826,59 @@ static gboolean ExposeDrawingArea (GtkWidget *widget, GdkEventExpose *event, gpo return TRUE; } -static void RedrawScreen() { - ColorspaceConvertBuffer555xTo8888Opaque( - GPU->GetDisplayInfo().isCustomSizeRequested ? (u16*)(GPU->GetDisplayInfo().masterCustomBuffer) : GPU->GetDisplayInfo().masterNativeBuffer16, - (uint32_t *)video->GetSrcBufferPtr(), real_framebuffer_width * real_framebuffer_height * 2); +static void RedrawScreen() +{ + gtk2gpuEvent->VideoFetchLock(); + #ifdef HAVE_LIBAGG - aggDraw.hud->attach((u8*)video->GetSrcBufferPtr(), real_framebuffer_width, real_framebuffer_height * 2, 1024 * gpu_scale_factor); - osd->update(); - DrawHUD(); - osd->clear(); -#endif + const bool needsHUDDisplay = ( + CommonSettings.hud.ShowInputDisplay || + CommonSettings.hud.ShowGraphicalInputDisplay || + CommonSettings.hud.FpsDisplay || + CommonSettings.hud.FrameCounterDisplay || + CommonSettings.hud.ShowLagFrameCounter || + CommonSettings.hud.ShowMicrophone || + CommonSettings.hud.ShowRTC || + HudEditorMode + ); + + if (needsHUDDisplay) + { + const int w = (int)video->GetSrcWidth(); + const int h = (int)video->GetSrcHeight(); + const double oldGpuScaleFactor = osd->scale; + const double newGpuScaleFactor = ( ((double)w / (double)GPU_FRAMEBUFFER_NATIVE_WIDTH) + ((double)h / (double)(GPU_FRAMEBUFFER_NATIVE_HEIGHT * 2.0)) ) / 2.0; + + if ( ((newGpuScaleFactor + 0.001) < oldGpuScaleFactor) || ((newGpuScaleFactor - 0.001) > oldGpuScaleFactor) ) + { +#ifdef AGG2D_USE_VECTORFONTS + if (vectorFontFile.size() > 0) + { + aggDraw.hud->setVectorFont(vectorFontFile, VECTOR_FONT_BASE_SIZE * newGpuScaleFactor, true); + osd->useVectorFonts = (newGpuScaleFactor >= 1.1f); + } + else + { + osd->useVectorFonts = false; + } +#endif // AGG2D_USE_VECTORFONTS + + Agg_setCustomSize(w, h); + osd->scale = newGpuScaleFactor; + Hud.rescale(oldGpuScaleFactor, newGpuScaleFactor); + HudSaveLayout(); + aggDraw.hud->setDrawTargetDims( (u8 *)video->GetSrcBufferPtr(), w, h, w * sizeof(u32) ); + } + + osd->update(); + DrawHUD(); + osd->clear(); + } +#endif // HAVE_LIBAGG + video->RunFilter(); + gtk2gpuEvent->VideoFetchUnlock(); + gtk_widget_queue_draw(pDrawingArea); } @@ -1834,6 +1887,9 @@ static void RedrawScreen() { #ifdef HAVE_LIBAGG static gboolean rotoscaled_hudedit(gint x, gint y, gboolean start) { + const size_t videoWidth = video->GetSrcWidth(); + const size_t videoHeight = video->GetSrcHeight(); + const int scaleFactor = (int)( ( (((float)videoWidth / (float)GPU_FRAMEBUFFER_NATIVE_WIDTH) + ((float)videoHeight / ((float)GPU_FRAMEBUFFER_NATIVE_HEIGHT*2.0f))) / 2.0f ) + 0.5f ); double devX, devY; gint X, Y, topX = -1, topY = -1, botX = -1, botY = -1; static gint startScreen = 0; @@ -1842,33 +1898,33 @@ static gboolean rotoscaled_hudedit(gint x, gint y, gboolean start) devX = x; devY = y; cairo_matrix_transform_point(&nds_screen.topscreen_matrix, &devX, &devY); - topX = devX; - topY = devY; + topX = devX * scaleFactor; + topY = devY * scaleFactor; } if (nds_screen.orientation != ORIENT_SINGLE || nds_screen.swap) { devX = x; devY = y; cairo_matrix_transform_point(&nds_screen.touch_matrix, &devX, &devY); - botX = devX; - botY = devY; + botX = devX * scaleFactor; + botY = devY * scaleFactor; } - if (topX >= 0 && topY >= 0 && topX < 256 && topY < 192) { + if (topX >= 0 && topY >= 0 && topX < videoWidth && topY < videoHeight) { X = topX; - Y = topY + (nds_screen.swap ? 192 : 0); + Y = topY + (nds_screen.swap ? videoHeight : 0); startScreen = 0; - } else if (botX >= 0 && botY >= 0 && botX < 256 && botY < 192) { + } else if (botX >= 0 && botY >= 0 && botX < videoWidth && botY < videoHeight) { X = botX; - Y = botY + (nds_screen.swap ? 0 : 192); + Y = botY + (nds_screen.swap ? 0 : videoHeight); startScreen = 1; } else if (!start) { if (startScreen == 0) { - X = CLAMP(topX, 0, 255); - Y = CLAMP(topY, 0, 191) + (nds_screen.swap ? 192 : 0); + X = CLAMP(topX, 0, videoWidth-1); + Y = CLAMP(topY, 0, videoHeight-1) + (nds_screen.swap ? videoHeight : 0); } else { - X = CLAMP(botX, 0, 255); - Y = CLAMP(botY, 0, 191) + (nds_screen.swap ? 0 : 192); + X = CLAMP(botX, 0, videoWidth-1); + Y = CLAMP(botY, 0, videoHeight-1) + (nds_screen.swap ? 0 : videoHeight); } } else { LOG("TopX=%d, TopY=%d, BotX=%d, BotY=%d\n", topX, topY, botX, botY); @@ -2695,10 +2751,8 @@ static void GraphicsSettingsDialog() { gpu_scale_factor = GPU_SCALE_FACTOR_MAX; gtk_spin_button_set_value(GTK_SPIN_BUTTON(wGPUScale), gpu_scale_factor); config.gpuScaleFactor = gpu_scale_factor; - real_framebuffer_width = GPU_FRAMEBUFFER_NATIVE_WIDTH * gpu_scale_factor; - real_framebuffer_height = GPU_FRAMEBUFFER_NATIVE_HEIGHT * gpu_scale_factor; - GPU->SetCustomFramebufferSize(real_framebuffer_width, real_framebuffer_height); - video->SetSourceSize(real_framebuffer_width, real_framebuffer_height * 2); + + gtk2gpuEvent->SetFramebufferDimensions( (size_t)(((float)GPU_FRAMEBUFFER_NATIVE_WIDTH * gpu_scale_factor) + 0.5), (size_t)(((float)GPU_FRAMEBUFFER_NATIVE_HEIGHT * gpu_scale_factor) + 0.5) ); CommonSettings.GFX3D_Renderer_TextureDeposterize = config.textureDeposterize = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(wPosterize)); CommonSettings.GFX3D_Renderer_TextureSmoothing = config.textureSmoothing = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(wSmoothing)); @@ -2756,34 +2810,36 @@ static void ToggleLayerVisibility(GtkToggleAction* action, gpointer data) static void Printscreen() { + const gint videoWidth = (gint)video->GetSrcWidth(); + const gint videoHeight = (gint)video->GetSrcHeight(); + u8 *screenshotBuffer = (u8 *)malloc_alignedPage(videoWidth * videoHeight * sizeof(u32)); + GdkPixbuf *screenshot; const gchar *dir; gchar *filename = NULL, *filen = NULL; GError *error = NULL; - u8 *rgb = (u8*)malloc(real_framebuffer_width * real_framebuffer_height * 2 * 4); static int seq = 0; gint H, W; - //rgb = (u8 *) malloc(SCREENS_PIXEL_SIZE*SCREEN_BYTES_PER_PIXEL); - //if (!rgb) - // return; - if (nds_screen.rotation_angle == 0 || nds_screen.rotation_angle == 180) { - W = real_framebuffer_width; - H = real_framebuffer_height * 2; + W = videoWidth; + H = videoHeight; } else { - W = real_framebuffer_height * 2; - H = real_framebuffer_width; + W = videoHeight; + H = videoWidth; } - gpu_screen_to_rgb((u32*)rgb); - screenshot = gdk_pixbuf_new_from_data(rgb, + gtk2gpuEvent->VideoFetchLock(); + ColorspaceConvertBuffer888xTo8888Opaque(video->GetSrcBufferPtr(), (u32 *)screenshotBuffer, videoWidth * videoHeight); + gtk2gpuEvent->VideoFetchUnlock(); + + screenshot = gdk_pixbuf_new_from_data(screenshotBuffer, GDK_COLORSPACE_RGB, TRUE, 8, W, H, - W * 4, + W * sizeof(u32), NULL, NULL); @@ -2810,10 +2866,10 @@ static void Printscreen() seq--; } - free(rgb); g_object_unref(screenshot); g_free(filename); g_free(filen); + free_aligned(screenshotBuffer); } #ifdef DESMUME_GTK_FIRMWARE_BROKEN @@ -3076,8 +3132,6 @@ gboolean EmuLoop(gpointer data) desmume_cycle(); /* Emule ! */ _updateDTools(); - avout_x264.updateVideo(GPU->GetDisplayInfo().masterNativeBuffer16); - RedrawScreen(); if (!config.fpslimiter || keys_latch & KEYMASK_(KEY_BOOST - 1)) { if (autoframeskip) { @@ -3302,6 +3356,8 @@ static void ToggleHudDisplay(GtkToggleAction* action, gpointer data) break; case HUD_DISPLAY_EDITOR: HudEditorMode = active; + if(!active) + HudSaveLayout(); break; default: g_printerr("Unknown HUD toggle %u!", hudId); @@ -3310,6 +3366,60 @@ static void ToggleHudDisplay(GtkToggleAction* action, gpointer data) RedrawScreen(); } +static void HudResetLayout(GSimpleAction *action, GVariant *parameter, gpointer user_data) +{ + Hud.reset(); + HudSaveLayout(); +} + +static void HudSaveCoordsToVector(HudCoordinates* pCoords, int* pDest) +{ + pDest[0] = pCoords->x; + pDest[1] = pCoords->y; + pDest[2] = pCoords->xsize; + pDest[3] = pCoords->ysize; +} + +static void HudLoadCoordsFromVector(HudCoordinates* pCoords, int* pSrc) +{ + pCoords->x=pSrc[0]; + pCoords->y=pSrc[1]; + pCoords->xsize=pSrc[2]; + pCoords->ysize=pSrc[3]; +} + +static void HudSaveLayout() +{ + std::vector vec(8*4); //8 HudCoordinates + HudSaveCoordsToVector(&Hud.SavestateSlots, vec.data()); + HudSaveCoordsToVector(&Hud.FpsDisplay, vec.data()+4); + HudSaveCoordsToVector(&Hud.FrameCounter, vec.data()+8); + HudSaveCoordsToVector(&Hud.InputDisplay, vec.data()+12); + HudSaveCoordsToVector(&Hud.GraphicalInputDisplay, vec.data()+16); + HudSaveCoordsToVector(&Hud.LagFrameCounter, vec.data()+20); + HudSaveCoordsToVector(&Hud.Microphone, vec.data()+24); + HudSaveCoordsToVector(&Hud.RTCDisplay, vec.data()+28); + config.hud_layout = vec; +} + +static void HudLoadLayout() +{ + std::vector vec=config.hud_layout; + if (vec.size()==8*4) + { + HudLoadCoordsFromVector(&Hud.SavestateSlots, vec.data()); + HudLoadCoordsFromVector(&Hud.FpsDisplay, vec.data()+4); + HudLoadCoordsFromVector(&Hud.FrameCounter, vec.data()+8); + HudLoadCoordsFromVector(&Hud.InputDisplay, vec.data()+12); + HudLoadCoordsFromVector(&Hud.GraphicalInputDisplay, vec.data()+16); + HudLoadCoordsFromVector(&Hud.LagFrameCounter, vec.data()+20); + HudLoadCoordsFromVector(&Hud.Microphone, vec.data()+24); + HudLoadCoordsFromVector(&Hud.RTCDisplay, vec.data()+28); + } + else + Hud.reset(); +} + static void desmume_gtk_menu_view_hud (GtkActionGroup *ag) { const struct { @@ -3508,14 +3618,46 @@ common_gtk_main( class configured_features *my_config) SDL_GetError()); return 1; } + desmume_init( my_config->disable_sound || !config.audio_enabled); + gpu_scale_factor = config.gpuScaleFactor; + if(gpu_scale_factor < GPU_SCALE_FACTOR_MIN) + gpu_scale_factor = GPU_SCALE_FACTOR_MIN; + if(gpu_scale_factor > GPU_SCALE_FACTOR_MAX) + gpu_scale_factor = GPU_SCALE_FACTOR_MAX; + config.gpuScaleFactor = gpu_scale_factor; + + gtk2gpuEvent = new Gtk2GPUEventHandler; + GPU->SetEventHandler(gtk2gpuEvent); + gtk2gpuEvent->SetFramebufferDimensions( (size_t)(((float)GPU_FRAMEBUFFER_NATIVE_WIDTH * gpu_scale_factor) + 0.5), (size_t)(((float)GPU_FRAMEBUFFER_NATIVE_HEIGHT * gpu_scale_factor) + 0.5) ); + + const NDSDisplayInfo &dispInfo = GPU->GetDisplayInfo(); + video = new VideoFilter(dispInfo.customWidth, dispInfo.customHeight * 2, VideoFilterTypeID_None, CommonSettings.num_cores); + g_printerr("Using %d threads for video filter.\n", CommonSettings.num_cores); + /* Init the hud / osd stuff */ #ifdef HAVE_LIBAGG Desmume_InitOnce(); Hud.reset(); osd = new OSDCLASS(-1); -#endif + +#ifdef AGG2D_USE_VECTORFONTS + if (vectorFontFile.size() > 0) + { + aggDraw.hud->setVectorFont(vectorFontFile, VECTOR_FONT_BASE_SIZE, true); + osd->useVectorFonts = false; + } + else + { + osd->useVectorFonts = false; + } +#endif // AGG2D_USE_VECTORFONTS + + Agg_setCustomSize(video->GetSrcWidth(), video->GetSrcHeight()); + osd->scale = 1.0; + aggDraw.hud->setDrawTargetDims( (u8 *)video->GetSrcBufferPtr(), video->GetSrcWidth(), video->GetSrcHeight(), video->GetSrcWidth() * sizeof(u32) ); +#endif // HAVE_LIBAGG /* * Activate the GDB stubs @@ -3570,19 +3712,6 @@ common_gtk_main( class configured_features *my_config) memset(&nds_screen, 0, sizeof(nds_screen)); nds_screen.orientation = ORIENT_VERTICAL; - gpu_scale_factor = config.gpuScaleFactor; - if(gpu_scale_factor < GPU_SCALE_FACTOR_MIN) - gpu_scale_factor = GPU_SCALE_FACTOR_MIN; - if(gpu_scale_factor > GPU_SCALE_FACTOR_MAX) - gpu_scale_factor = GPU_SCALE_FACTOR_MAX; - config.gpuScaleFactor = gpu_scale_factor; - real_framebuffer_width = GPU_FRAMEBUFFER_NATIVE_WIDTH * gpu_scale_factor; - real_framebuffer_height = GPU_FRAMEBUFFER_NATIVE_HEIGHT * gpu_scale_factor; - - g_printerr("Using %d threads for video filter.\n", CommonSettings.num_cores); - GPU->SetCustomFramebufferSize(real_framebuffer_width, real_framebuffer_height); - video = new VideoFilter(real_framebuffer_width, real_framebuffer_height * 2, VideoFilterTypeID_None, CommonSettings.num_cores); - /* Create the window */ pWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(pWindow), "DeSmuME"); @@ -3973,6 +4102,10 @@ common_gtk_main( class configured_features *my_config) g_timeout_add(200, OutOfLoopJoyDeviceCheckTimerFunc, 0); /* Main loop */ gtk_main(); + +#ifdef HAVE_LIBAGG + HudSaveLayout(); +#endif delete video; @@ -3982,6 +4115,9 @@ common_gtk_main( class configured_features *my_config) desmume_free(); + delete gtk2gpuEvent; + gtk2gpuEvent = NULL; + #if defined(ENABLE_OPENGL_STANDARD) || defined(ENABLE_OPENGL_ES) #if defined(ENABLE_GLX) glx_deinitOpenGL(); @@ -4012,11 +4148,47 @@ common_gtk_main( class configured_features *my_config) return EXIT_SUCCESS; } +#ifdef AGG2D_USE_VECTORFONTS + +static std::string FindFontFile(const char* fontName, bool bold) +{ + std::string fontFile; + FcPattern* pat = FcNameParse((const FcChar8*)fontName); + if(bold) + FcPatternAddInteger(pat, FC_WEIGHT, FC_WEIGHT_BOLD); + FcConfigSubstitute(fontConfig, pat, FcMatchPattern); + FcDefaultSubstitute(pat); + + // find the font + FcResult res; + FcPattern* font = FcFontMatch(fontConfig, pat, &res); + if (font) + { + FcChar8* file = NULL; + if (FcPatternGetString(font, FC_FILE, 0, &file) == FcResultMatch) + { + // save the file to another std::string + fontFile = (char*)file; + } + FcPatternDestroy(font); + } + FcPatternDestroy(pat); + return fontFile; +} + +#endif int main (int argc, char *argv[]) { configured_features my_config; +#ifdef AGG2D_USE_VECTORFONTS + fontConfig = FcInitLoadConfigAndFonts(); + vectorFontFile = FindFontFile("mono", true); + if(!vectorFontFile.size()) + vectorFontFile = FindFontFile("sans", true); +#endif + // The global menu screws up the window size... unsetenv("UBUNTU_MENUPROXY"); @@ -4062,3 +4234,167 @@ int WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgumen } #endif +Gtk2GPUEventHandler::Gtk2GPUEventHandler() +{ + _colorFormatPending = NDSColorFormat_BGR666_Rev; + _widthPending = GPU_FRAMEBUFFER_NATIVE_WIDTH; + _heightPending = GPU_FRAMEBUFFER_NATIVE_HEIGHT; + _pageCountPending = GTK2_FRAMEBUFFER_PAGE_COUNT; + + _didColorFormatChange = true; + _didWidthChange = true; + _didHeightChange = true; + _didPageCountChange = true; + + _latestBufferIndex = 0; + + _mutexApplyGPUSettings = slock_new(); + _mutexVideoFetch = slock_new(); + + for (size_t i = 0; i < GTK2_FRAMEBUFFER_PAGE_COUNT; i++) + { + _mutexFramebufferPage[i] = slock_new(); + } +} + +Gtk2GPUEventHandler::~Gtk2GPUEventHandler() +{ + slock_free(this->_mutexApplyGPUSettings); + slock_free(this->_mutexVideoFetch); + + for (size_t i = 0; i < GTK2_FRAMEBUFFER_PAGE_COUNT; i++) + { + slock_free(this->_mutexFramebufferPage[i]); + } +} + +void Gtk2GPUEventHandler::SetFramebufferDimensions(size_t w, size_t h) +{ + if (w < GPU_FRAMEBUFFER_NATIVE_WIDTH) + { + w = GPU_FRAMEBUFFER_NATIVE_WIDTH; + } + + if (h < GPU_FRAMEBUFFER_NATIVE_HEIGHT) + { + h = GPU_FRAMEBUFFER_NATIVE_HEIGHT; + } + + slock_lock(this->_mutexApplyGPUSettings); + + const NDSDisplayInfo &dispInfo = GPU->GetDisplayInfo(); + this->_didWidthChange = (w != dispInfo.customWidth); + this->_didHeightChange = (h != dispInfo.customHeight); + this->_widthPending = w; + this->_heightPending = h; + + slock_unlock(this->_mutexApplyGPUSettings); +} + +void Gtk2GPUEventHandler::GetFramebufferDimensions(size_t &outWidth, size_t &outHeight) +{ + outWidth = this->_widthPending; + outHeight = this->_heightPending; +} + +void Gtk2GPUEventHandler::SetColorFormat(NDSColorFormat colorFormat) +{ + slock_lock(this->_mutexApplyGPUSettings); + const NDSDisplayInfo &dispInfo = GPU->GetDisplayInfo(); + this->_didColorFormatChange = (colorFormat != dispInfo.colorFormat); + this->_colorFormatPending = colorFormat; + slock_unlock(this->_mutexApplyGPUSettings); +} + +NDSColorFormat Gtk2GPUEventHandler::GetColorFormat() +{ + return this->_colorFormatPending; +} + +void Gtk2GPUEventHandler::VideoFetchLock() +{ + slock_lock(this->_mutexVideoFetch); +} + +void Gtk2GPUEventHandler::VideoFetchUnlock() +{ + slock_unlock(this->_mutexVideoFetch); +} + +void Gtk2GPUEventHandler::DidFrameEnd(bool isFrameSkipped, const NDSDisplayInfo &latestDisplayInfo) +{ + if (isFrameSkipped) + { + return; + } + + this->_latestBufferIndex = latestDisplayInfo.bufferIndex; + + slock_lock(this->_mutexFramebufferPage[this->_latestBufferIndex]); + + // TODO: Video file writes only work on fixed 16-bit buffers at the native-size only. + // This currently does not work on custom-sized buffers or any 32-bit color format. + avout_x264.updateVideo(latestDisplayInfo.masterNativeBuffer16); + + this->VideoFetchLock(); + if (latestDisplayInfo.colorFormat == NDSColorFormat_BGR555_Rev) + { + ColorspaceConvertBuffer555xTo8888Opaque( (u16 *)latestDisplayInfo.masterCustomBuffer, (u32 *)video->GetSrcBufferPtr(), latestDisplayInfo.customWidth * latestDisplayInfo.customHeight * 2); + } + else + { + ColorspaceConvertBuffer888xTo8888Opaque( (u32 *)latestDisplayInfo.masterCustomBuffer, (u32 *)video->GetSrcBufferPtr(), latestDisplayInfo.customWidth * latestDisplayInfo.customHeight * 2); + } + this->VideoFetchUnlock(); + + slock_unlock(this->_mutexFramebufferPage[this->_latestBufferIndex]); + + RedrawScreen(); +} + +void Gtk2GPUEventHandler::DidApplyGPUSettingsBegin() +{ + slock_lock(this->_mutexApplyGPUSettings); + + if (this->_didWidthChange || this->_didHeightChange || this->_didColorFormatChange || this->_didPageCountChange) + { + if (this->_didWidthChange || this->_didHeightChange) + { + for (size_t i = 0; i < GTK2_FRAMEBUFFER_PAGE_COUNT; i++) + { + slock_lock(this->_mutexFramebufferPage[i]); + } + } + + GPU->SetCustomFramebufferSize(this->_widthPending, this->_heightPending); + GPU->SetColorFormat(this->_colorFormatPending); + GPU->SetFramebufferPageCount(this->_pageCountPending); + } +} + +void Gtk2GPUEventHandler::DidApplyGPUSettingsEnd() +{ + if (this->_didWidthChange || this->_didHeightChange || this->_didColorFormatChange || this->_didPageCountChange) + { + const NDSDisplayInfo &dispInfo = GPU->GetDisplayInfo(); + + if (this->_didWidthChange || this->_didHeightChange) + { + video->SetSourceSize(dispInfo.customWidth, dispInfo.customHeight * 2); + + for (size_t i = 0; i < GTK2_FRAMEBUFFER_PAGE_COUNT; i++) + { + slock_unlock(this->_mutexFramebufferPage[i]); + } + } + + // Update all the change flags now that settings are applied. + // In theory, all these flags should get cleared. + this->_didWidthChange = (this->_widthPending != dispInfo.customWidth); + this->_didHeightChange = (this->_heightPending != dispInfo.customHeight); + this->_didColorFormatChange = (this->_colorFormatPending != dispInfo.colorFormat); + this->_didPageCountChange = (this->_pageCountPending != dispInfo.framebufferPageCount); + } + + slock_unlock(this->_mutexApplyGPUSettings); +} diff --git a/desmume/src/frontend/posix/gtk2/main.h b/desmume/src/frontend/posix/gtk2/main.h index b64706d67..986d1edaf 100644 --- a/desmume/src/frontend/posix/gtk2/main.h +++ b/desmume/src/frontend/posix/gtk2/main.h @@ -1,7 +1,69 @@ -#ifndef __DESMUME_GTK_MAIN_H__ -#define __DESMUME_GTK_MAIN_H__ - -void Pause(); -void Launch(); - -#endif + /* + Copyright (C) 2007 Pascal Giard (evilynux) + Copyright (C) 2006-2025 DeSmuME team + + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the this software. If not, see . + */ + +#ifndef __DESMUME_GTK_MAIN_H__ +#define __DESMUME_GTK_MAIN_H__ + +#include "GPU.h" +#include "rthreads/rthreads.h" + +#define GTK2_FRAMEBUFFER_PAGE_COUNT 3 + + +class Gtk2GPUEventHandler : public GPUEventHandlerDefault +{ +protected: + NDSColorFormat _colorFormatPending; + size_t _widthPending; + size_t _heightPending; + size_t _pageCountPending; + + bool _didColorFormatChange; + bool _didWidthChange; + bool _didHeightChange; + bool _didPageCountChange; + + u8 _latestBufferIndex; + + slock_t *_mutexApplyGPUSettings; + slock_t *_mutexVideoFetch; + slock_t *_mutexFramebufferPage[GTK2_FRAMEBUFFER_PAGE_COUNT]; + +public: + Gtk2GPUEventHandler(); + ~Gtk2GPUEventHandler(); + + void SetFramebufferDimensions(size_t w, size_t h); + void GetFramebufferDimensions(size_t &outWidth, size_t &outHeight); + + void SetColorFormat(NDSColorFormat colorFormat); + NDSColorFormat GetColorFormat(); + + void VideoFetchLock(); + void VideoFetchUnlock(); + + // GPUEventHandler methods + virtual void DidFrameEnd(bool isFrameSkipped, const NDSDisplayInfo &latestDisplayInfo); + virtual void DidApplyGPUSettingsBegin(); + virtual void DidApplyGPUSettingsEnd(); +}; + +void Pause(); +void Launch(); + +#endif diff --git a/desmume/src/frontend/windows/display.cpp b/desmume/src/frontend/windows/display.cpp index c5ee7c139..e2d17f786 100644 --- a/desmume/src/frontend/windows/display.cpp +++ b/desmume/src/frontend/windows/display.cpp @@ -1,5 +1,5 @@ /* -Copyright (C) 2018-2024 DeSmuME team +Copyright (C) 2018-2025 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,6 +21,7 @@ along with the this software. If not, see . #include #include "main.h" +#include "aviout.h" #include "windriver.h" #include "winutil.h" @@ -30,6 +31,7 @@ DDRAW ddraw; GLDISPLAY gldisplay; u32 displayMethod; +Win32GPUEventHandler* WinGPUEvent = NULL; VideoInfo video; int gpu_bpp = 18; @@ -69,26 +71,11 @@ bool PadToInteger = false; float screenSizeRatio = 1.0f; bool vCenterResizedScr = true; -//triple buffering logic -struct DisplayBuffer -{ - DisplayBuffer() - : buffer(NULL) - , size(0) - { - } - u32* buffer; - size_t size; //[256*192*4]; -} displayBuffers[3]; - -volatile int currDisplayBuffer = -1; -volatile int newestDisplayBuffer = -2; -slock_t *display_mutex = NULL; sthread_t *display_thread = NULL; +volatile bool displayNeedsBufferUpdates = true; volatile bool display_die = false; HANDLE display_wakeup_event = INVALID_HANDLE_VALUE; HANDLE display_done_event = INVALID_HANDLE_VALUE; -DWORD display_done_timeout = 500; int displayPostponeType = 0; DWORD displayPostponeUntil = ~0; @@ -199,11 +186,10 @@ RECT CalculateDisplayLayoutWrapper(RECT rcClient, int targetWidth, int targetHei return rc; } -template static void doRotate(void* dst) +template static void doRotate(u32 *__restrict src, u8 *__restrict dst) { - u8* buffer = (u8*)dst; + u8 *__restrict buffer = dst; int size = video.size(); - u32* src = (u32*)video.finalBuffer(); int width = video.width; int height = video.height; int pitch = ddraw.surfDescBack.lPitch; @@ -359,37 +345,21 @@ static void OGL_DrawTexture(RECT* srcRects, RECT* dstRects) } glEnd(); } -static void OGL_DoDisplay() +static void OGL_DoDisplay(NDSColorFormat colorFormat, int videoWidth, int videoHeight, bool useSecondaryVideoBuffer, u8 bufferIndex, void* srcFramebuffer, u32* srcHUD) { if (!gldisplay.begin(MainWindow->getHWnd())) return; - //the ds screen fills the texture entirely, so we dont have garbage at edge to worry about, - //but we need to make sure this is clamped for when filtering is selected - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - if (gldisplay.filter) - { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } - else - { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - } - RECT rc; HWND hwnd = MainWindow->getHWnd(); GetClientRect(hwnd, &rc); - int width = rc.right - rc.left; - int height = rc.bottom - rc.top; + int windowWidth = rc.right - rc.left; + int windowHeight = rc.bottom - rc.top; - glViewport(0, 0, width, height); + glViewport(0, 0, windowWidth, windowHeight); glMatrixMode(GL_PROJECTION); glLoadIdentity(); - glOrtho(0.0f, (float)width, (float)height, 0.0f, -100.0f, 100.0f); + glOrtho(0.0f, (float)windowWidth, (float)windowHeight, 0.0f, -100.0f, 100.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); @@ -405,8 +375,8 @@ static void OGL_DoDisplay() ScreenToClient(hwnd, (LPPOINT)&dr[i].left); ScreenToClient(hwnd, (LPPOINT)&dr[i].right); } - dr[2].bottom = height - dr[2].bottom; - dr[2].top = height - dr[2].top; + dr[2].bottom = windowHeight - dr[2].bottom; + dr[2].top = windowHeight - dr[2].top; RECT srcRects[2]; const bool isMainGPUFirst = (GPU->GetDisplayInfo().engineID[NDSDisplayID_Main] == GPUEngineID_Main); @@ -442,25 +412,46 @@ static void OGL_DoDisplay() // ); glEnable(GL_TEXTURE_2D); + gldisplay.applyOutputFilterOGL(); + + if (!useSecondaryVideoBuffer) + { + WinGPUEvent->VideoFetchLock(); + } + + glBindTexture(GL_TEXTURE_2D, gldisplay.getTexVideoID(bufferIndex)); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, (GLsizei)videoWidth, (GLsizei)videoHeight, (useSecondaryVideoBuffer) ? GL_BGRA : GL_RGBA, (colorFormat == NDSColorFormat_BGR555_Rev) ? GL_UNSIGNED_SHORT_1_5_5_5_REV : GL_UNSIGNED_INT_8_8_8_8_REV, srcFramebuffer); + + if (!useSecondaryVideoBuffer) + { + WinGPUEvent->VideoFetchUnlock(); + } + // draw DS display - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, video.width, video.height, 0, GL_BGRA, GL_UNSIGNED_BYTE, video.finalBuffer()); OGL_DrawTexture(srcRects, dr); // draw HUD - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_BLEND); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT * 2, 0, GL_BGRA, GL_UNSIGNED_BYTE, aggDraw.hud->buf().buf()); - OGL_DrawTexture(srcRects, dr); - glDisable(GL_BLEND); + if (srcHUD != NULL) + { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + + glBindTexture(GL_TEXTURE_2D, gldisplay.getTexHudID(bufferIndex)); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT * 2, GL_BGRA, GL_UNSIGNED_BYTE, srcHUD); + + OGL_DrawTexture(srcRects, dr); + glDisable(GL_BLEND); + } gldisplay.showPage(); gldisplay.end(); } -static void DD_DoDisplay() + +static void DD_DoDisplay(u32* srcFramebuffer, int videoWidth, int videoHeight) { - if (ddraw.surfDescBack.dwWidth != video.rotatedwidth() || ddraw.surfDescBack.dwHeight != video.rotatedheight()) - ddraw.createBackSurface(video.rotatedwidth(), video.rotatedheight()); + if ( (ddraw.surfDescBack.dwWidth != videoWidth) || (ddraw.surfDescBack.dwHeight != videoHeight) ) + ddraw.createBackSurface(videoWidth, videoHeight); if (!ddraw.lock()) return; char* buffer = (char*)ddraw.surfDescBack.lpSurface; @@ -468,16 +459,16 @@ static void DD_DoDisplay() switch (ddraw.surfDescBack.ddpfPixelFormat.dwRGBBitCount) { case 32: - doRotate(ddraw.surfDescBack.lpSurface); + doRotate(srcFramebuffer, (u8*)ddraw.surfDescBack.lpSurface); break; case 24: - doRotate(ddraw.surfDescBack.lpSurface); + doRotate(srcFramebuffer, (u8*)ddraw.surfDescBack.lpSurface); break; case 16: if (ddraw.surfDescBack.ddpfPixelFormat.dwGBitMask != 0x3E0) - doRotate(ddraw.surfDescBack.lpSurface); + doRotate(srcFramebuffer, (u8*)ddraw.surfDescBack.lpSurface); else - doRotate(ddraw.surfDescBack.lpSurface); + doRotate(srcFramebuffer, (u8*)ddraw.surfDescBack.lpSurface); break; case 0: break; @@ -579,48 +570,19 @@ static void DD_DoDisplay() } } -void displayProc() -{ - slock_lock(display_mutex); - - //find a buffer to display - int todo = newestDisplayBuffer; - bool alreadyDisplayed = (todo == currDisplayBuffer); - - slock_unlock(display_mutex); - - //something new to display: - if (!alreadyDisplayed) { - //start displaying a new buffer - currDisplayBuffer = todo; - video.srcBuffer = (u8*)displayBuffers[currDisplayBuffer].buffer; - video.srcBufferSize = displayBuffers[currDisplayBuffer].size; - } - DoDisplay(); -} void displayThread(void *arg) { do { - if ((MainWindow == NULL) || IsMinimized(MainWindow->getHWnd())) - { - WaitForSingleObject(display_wakeup_event, INFINITE); - } - else if ((emu_paused || !execute || !romloaded) && (!HudEditorMode && !CommonSettings.hud.ShowInputDisplay && !CommonSettings.hud.ShowGraphicalInputDisplay)) - { - WaitForSingleObject(display_wakeup_event, 250); - } - else - { - WaitForSingleObject(display_wakeup_event, 10); - } + DWORD waitTime = ( (emu_paused || !execute || !romloaded) && HudNeedsDrawStateSlots() ) ? 16 : INFINITE; + WaitForSingleObject(display_wakeup_event, waitTime); if (display_die) { break; } - displayProc(); + DoDisplay(); SetEvent(display_done_event); } while (!display_die); } @@ -634,40 +596,18 @@ static void DoDisplay_DrawHud() void Display() { - const NDSDisplayInfo &dispInfo = GPU->GetDisplayInfo(); - if (CommonSettings.single_core()) { - video.srcBuffer = (u8*)dispInfo.masterCustomBuffer; - video.srcBufferSize = dispInfo.customWidth * dispInfo.customHeight * dispInfo.pixelBytes * 2; DoDisplay(); } else { if (display_thread == NULL) { - display_mutex = slock_new(); display_thread = sthread_create(&displayThread, nullptr); } - slock_lock(display_mutex); - - if (int diff = (currDisplayBuffer + 1) % 3 - newestDisplayBuffer) - newestDisplayBuffer += diff; - else newestDisplayBuffer = (currDisplayBuffer + 2) % 3; - - DisplayBuffer& db = displayBuffers[newestDisplayBuffer]; - size_t targetSize = dispInfo.customWidth * dispInfo.customHeight * dispInfo.pixelBytes * 2; - if (db.size != targetSize) - { - free_aligned(db.buffer); - db.buffer = (u32*)malloc_alignedPage(targetSize); - db.size = targetSize; - } - memcpy(db.buffer, dispInfo.masterCustomBuffer, targetSize); - - slock_unlock(display_mutex); - + WaitForSingleObject(display_done_event, WIN32_MAX_FRAME_WAIT_TIME); SetEvent(display_wakeup_event); } } @@ -675,59 +615,123 @@ void Display() //does a single display work unit. only to be used from the display thread void DoDisplay() { - Lock lock(win_backbuffer_sync); + const NDSDisplayInfo& dispInfo = GPU->GetDisplayInfo(); + video.srcBuffer = (u8*)dispInfo.masterCustomBuffer; + video.srcBufferSize = dispInfo.customWidth * dispInfo.customHeight * dispInfo.pixelBytes * 2; + + const bool isRunningDirectDraw = (displayMethod == DISPMETHOD_DDRAW_HW) || (displayMethod == DISPMETHOD_DDRAW_SW); + const bool needsVideoFiltering = (video.currentfilter != video.NONE); + const bool needsBacklightApply = (dispInfo.backlightIntensity[NDSDisplayID_Main] < 1.0f) || (dispInfo.backlightIntensity[NDSDisplayID_Touch] < 1.0f); + + const bool needsHUDDrawing = ( + CommonSettings.hud.ShowInputDisplay || + CommonSettings.hud.ShowGraphicalInputDisplay || + CommonSettings.hud.FpsDisplay || + CommonSettings.hud.FrameCounterDisplay || + CommonSettings.hud.ShowLagFrameCounter || + CommonSettings.hud.ShowMicrophone || + CommonSettings.hud.ShowRTC || + HudEditorMode || + HudNeedsDrawStateSlots() || + AnyLuaActive() + ); + + bool useSecondaryVideoBuffer = false; if (displayPostponeType && !displayNoPostponeNext && (displayPostponeType < 0 || timeGetTime() < displayPostponeUntil)) return; displayNoPostponeNext = false; - //we have to do a copy here because we're about to draw the OSD onto it. bummer. - if (gpu_bpp == 15) - ColorspaceConvertBuffer555xTo8888Opaque((u16 *)video.srcBuffer, video.buffer, video.srcBufferSize / 2); - else - ColorspaceConvertBuffer888xTo8888Opaque((u32*)video.srcBuffer, video.buffer, video.srcBufferSize / 4); - - //some games use the backlight for fading effects - const size_t pixCount = video.prefilterWidth * video.prefilterHeight / 2; - const NDSDisplayInfo &displayInfo = GPU->GetDisplayInfo(); - ColorspaceApplyIntensityToBuffer32(video.buffer, pixCount, displayInfo.backlightIntensity[NDSDisplayID_Main]); - ColorspaceApplyIntensityToBuffer32(video.buffer + pixCount, pixCount, displayInfo.backlightIntensity[NDSDisplayID_Touch]); - - // Lua draws to the HUD buffer, so clear it here instead of right before redrawing the HUD. - aggDraw.hud->clear(); - if (AnyLuaActive()) + if (displayNeedsBufferUpdates) { - if (sthread_isself(display_thread)) + video.ResizeBuffers(); + + if (!isRunningDirectDraw) { - InvokeOnMainThread((void(*)(DWORD)) - CallRegisteredLuaFunctions, LUACALL_AFTEREMULATIONGUI); - } - else - { - CallRegisteredLuaFunctions(LUACALL_AFTEREMULATIONGUI); + if ( gldisplay.begin(MainWindow->getHWnd()) ) + { + gldisplay.initVideoTexture(dispInfo.colorFormat, video.width, video.height); + gldisplay.end(); + } } + + displayNeedsBufferUpdates = false; } - // draw hud - DoDisplay_DrawHud(); - if (displayMethod == DISPMETHOD_DDRAW_HW || displayMethod == DISPMETHOD_DDRAW_SW) + if (isRunningDirectDraw || needsVideoFiltering || needsBacklightApply) { + //we have to do a copy here because we're about to draw the OSD onto it. bummer. + WinGPUEvent->VideoFetchLock(); + + if (dispInfo.colorFormat == NDSColorFormat_BGR555_Rev) + ColorspaceConvertBuffer555xTo8888Opaque((u16*)video.srcBuffer, video.buffer, video.srcBufferSize / sizeof(u16)); + else + ColorspaceConvertBuffer888xTo8888Opaque((u32*)video.srcBuffer, video.buffer, video.srcBufferSize / sizeof(u32)); + + WinGPUEvent->VideoFetchUnlock(); + + //some games use the backlight for fading effects + const size_t pixCount = video.prefilterWidth * video.prefilterHeight / 2; + ColorspaceApplyIntensityToBuffer32(video.buffer, pixCount, dispInfo.backlightIntensity[NDSDisplayID_Main]); + ColorspaceApplyIntensityToBuffer32(video.buffer + pixCount, pixCount, dispInfo.backlightIntensity[NDSDisplayID_Touch]); + + useSecondaryVideoBuffer = true; + } + + aggDraw.hud->clear(); + + if (needsHUDDrawing) + { + if (AnyLuaActive()) + { + if (sthread_isself(display_thread)) + { + InvokeOnMainThread((void(*)(DWORD)) + CallRegisteredLuaFunctions, LUACALL_AFTEREMULATIONGUI); + } + else + { + CallRegisteredLuaFunctions(LUACALL_AFTEREMULATIONGUI); + } + } + + // draw hud + DoDisplay_DrawHud(); + // DirectDraw doesn't support alpha blending, so we must scale and overlay the HUD ourselves. - T_AGG_RGBA target((u8*)video.buffer, video.prefilterWidth, video.prefilterHeight, video.prefilterWidth * 4); - target.transformImage(aggDraw.hud->image(), 0, 0, video.prefilterWidth, video.prefilterHeight); + if (isRunningDirectDraw) + { + T_AGG_RGBA target((u8*)video.buffer, video.prefilterWidth, video.prefilterHeight, video.prefilterWidth * sizeof(u32)); + target.transformImage(aggDraw.hud->image(), 0, 0, video.prefilterWidth, video.prefilterHeight); + } } //apply user's filter - video.filter(); + if (needsVideoFiltering) + { + video.filter(); + } - if (displayMethod == DISPMETHOD_DDRAW_HW || displayMethod == DISPMETHOD_DDRAW_SW) + if (isRunningDirectDraw) { gldisplay.kill(); - DD_DoDisplay(); + + u32* srcFramebuffer = (needsVideoFiltering) ? (u32*)video.filteredbuffer : (u32*)video.buffer; + DD_DoDisplay(srcFramebuffer, video.rotatedwidth(), video.rotatedheight()); } else { - OGL_DoDisplay(); + u32* srcHUD = (needsHUDDrawing) ? (u32*)aggDraw.hud->buf().buf() : NULL; + + if (useSecondaryVideoBuffer) + { + void* srcFramebuffer = (needsVideoFiltering) ? video.filteredbuffer : video.buffer; + OGL_DoDisplay(NDSColorFormat_BGR888_Rev, video.width, video.height, true, dispInfo.bufferIndex, srcFramebuffer, srcHUD); + } + else + { + OGL_DoDisplay(dispInfo.colorFormat, dispInfo.customWidth, dispInfo.customHeight * 2, false, dispInfo.bufferIndex, dispInfo.masterCustomBuffer, srcHUD); + } } } @@ -739,6 +743,74 @@ void KillDisplay() sthread_join(display_thread); } +void SetDisplayNeedsBufferUpdates() +{ + displayNeedsBufferUpdates = true; +} + +void UpdateScreenRects() +{ + if (video.layout == 1) + { + // Main screen + MainScreenSrcRect.left = 0; + MainScreenSrcRect.top = 0; + MainScreenSrcRect.right = video.width; + MainScreenSrcRect.bottom = video.height / 2; + + // Sub screen + SubScreenSrcRect.left = 0; + SubScreenSrcRect.top = video.height / 2; + SubScreenSrcRect.right = video.width; + SubScreenSrcRect.bottom = video.height; + } + else if (video.layout == 2) + { + // Main screen + MainScreenSrcRect.left = 0; + MainScreenSrcRect.top = 0; + MainScreenSrcRect.right = video.width; + MainScreenSrcRect.bottom = video.height / 2; + + // Sub screen + SubScreenSrcRect.left = 0; + SubScreenSrcRect.top = video.height / 2; + SubScreenSrcRect.right = video.width; + SubScreenSrcRect.bottom = video.height; + } + else + { + if ((video.rotation == 90) || (video.rotation == 270)) + { + // Main screen + MainScreenSrcRect.left = 0; + MainScreenSrcRect.top = 0; + MainScreenSrcRect.right = video.height / 2; + MainScreenSrcRect.bottom = video.width; + + // Sub screen + SubScreenSrcRect.left = video.height / 2; + SubScreenSrcRect.top = 0; + SubScreenSrcRect.right = video.height; + SubScreenSrcRect.bottom = video.width; + } + else + { + // Main screen + MainScreenSrcRect.left = 0; + MainScreenSrcRect.top = 0; + MainScreenSrcRect.right = video.width; + MainScreenSrcRect.bottom = video.height / 2; + + // Sub screen + SubScreenSrcRect.left = 0; + SubScreenSrcRect.top = video.height / 2; + SubScreenSrcRect.right = video.width; + SubScreenSrcRect.bottom = video.height; + } + } +} + void UpdateWndRects(HWND hwnd, RECT* newClientRect) { POINT ptClient; @@ -986,7 +1058,7 @@ void SetLayerMasks(int mainEngineMask, int subEngineMask) const int mask = core == 0 ? mainEngineMask : subEngineMask; for (size_t layer = 0; layer < numLayers; layer++) { - const bool newLayerState = (mask >> layer) & 0x01 != 0; + const bool newLayerState = ((mask >> layer) & 0x01) != 0; if (newLayerState != CommonSettings.dispLayers[core][layer]) { gpu->SetLayerEnableState(layer, newLayerState); @@ -995,3 +1067,183 @@ void SetLayerMasks(int mainEngineMask, int subEngineMask) } } } + +Win32GPUEventHandler::Win32GPUEventHandler() +{ + _colorFormatPending = NDSColorFormat_BGR666_Rev; + _widthPending = GPU_FRAMEBUFFER_NATIVE_WIDTH; + _heightPending = GPU_FRAMEBUFFER_NATIVE_HEIGHT; + _pageCountPending = WIN32_FRAMEBUFFER_COUNT; + _scaleFactorIntegerPending = 1; + + _didColorFormatChange = true; + _didWidthChange = true; + _didHeightChange = true; + _didPageCountChange = true; + + _inProcessBufferIndex = 0; + _latestAvailableBufferIndex = 0; + _currentLockedPageIndex = 0; + + _mutexApplyGPUSettings = slock_new(); + _mutexVideoFetch = slock_new(); + + for (size_t i = 0; i < WIN32_FRAMEBUFFER_COUNT; i++) + { + _mutexFramebufferPage[i] = slock_new(); + } +} + +Win32GPUEventHandler::~Win32GPUEventHandler() +{ + slock_free(this->_mutexApplyGPUSettings); + slock_free(this->_mutexVideoFetch); + + for (size_t i = 0; i < WIN32_FRAMEBUFFER_COUNT; i++) + { + slock_free(this->_mutexFramebufferPage[i]); + } +} + +void Win32GPUEventHandler::SetFramebufferDimensions(size_t w, size_t h) +{ + if (w < GPU_FRAMEBUFFER_NATIVE_WIDTH) + { + w = GPU_FRAMEBUFFER_NATIVE_WIDTH; + } + + if (h < GPU_FRAMEBUFFER_NATIVE_HEIGHT) + { + h = GPU_FRAMEBUFFER_NATIVE_HEIGHT; + } + + slock_lock(this->_mutexApplyGPUSettings); + + const NDSDisplayInfo& dispInfo = GPU->GetDisplayInfo(); + this->_didWidthChange = (w != dispInfo.customWidth); + this->_didHeightChange = (h != dispInfo.customHeight); + this->_widthPending = w; + this->_heightPending = h; + this->_scaleFactorIntegerPending = ((w / GPU_FRAMEBUFFER_NATIVE_WIDTH) + (h / GPU_FRAMEBUFFER_NATIVE_HEIGHT)) / 2; + + slock_unlock(this->_mutexApplyGPUSettings); +} + +void Win32GPUEventHandler::GetFramebufferDimensions(size_t& outWidth, size_t& outHeight) +{ + outWidth = this->_widthPending; + outHeight = this->_heightPending; +} + +void Win32GPUEventHandler::SetFramebufferDimensionsByScaleFactorInteger(size_t scaleFactor) +{ + const size_t w = GPU_FRAMEBUFFER_NATIVE_WIDTH * scaleFactor; + const size_t h = GPU_FRAMEBUFFER_NATIVE_HEIGHT * scaleFactor; + this->SetFramebufferDimensions(w, h); +} + +size_t Win32GPUEventHandler::GetFramebufferDimensionsByScaleFactorInteger() +{ + return this->_scaleFactorIntegerPending; +} + +void Win32GPUEventHandler::SetColorFormat(NDSColorFormat colorFormat) +{ + slock_lock(this->_mutexApplyGPUSettings); + const NDSDisplayInfo& dispInfo = GPU->GetDisplayInfo(); + this->_didColorFormatChange = (colorFormat != dispInfo.colorFormat); + this->_colorFormatPending = colorFormat; + slock_unlock(this->_mutexApplyGPUSettings); +} + +NDSColorFormat Win32GPUEventHandler::GetColorFormat() +{ + return this->_colorFormatPending; +} + +void Win32GPUEventHandler::VideoFetchLock() +{ + slock_lock(this->_mutexFramebufferPage[this->_latestAvailableBufferIndex]); + this->_currentLockedPageIndex = this->_latestAvailableBufferIndex; +} + +void Win32GPUEventHandler::VideoFetchUnlock() +{ + slock_unlock(this->_mutexFramebufferPage[this->_currentLockedPageIndex]); +} + +void Win32GPUEventHandler::DidFrameBegin(const size_t line, const bool isFrameSkipRequested, const size_t pageCount, u8& selectedBufferIndexInOut) +{ + this->GPUEventHandlerDefault::DidFrameBegin(line, isFrameSkipRequested, pageCount, selectedBufferIndexInOut); + + if (!isFrameSkipRequested) + { + slock_lock(this->_mutexFramebufferPage[selectedBufferIndexInOut]); + this->_inProcessBufferIndex = selectedBufferIndexInOut; + } +} + +void Win32GPUEventHandler::DidFrameEnd(bool isFrameSkipped, const NDSDisplayInfo& latestDisplayInfo) +{ + if (isFrameSkipped) + { + return; + } + + this->_latestAvailableBufferIndex = latestDisplayInfo.bufferIndex; + DRV_AviVideoUpdate(latestDisplayInfo); + slock_unlock(this->_mutexFramebufferPage[this->_inProcessBufferIndex]); + + Display(); +} + +void Win32GPUEventHandler::DidApplyGPUSettingsBegin() +{ + slock_lock(this->_mutexApplyGPUSettings); + + if (this->_didWidthChange || this->_didHeightChange || this->_didColorFormatChange || this->_didPageCountChange) + { + WaitForSingleObject(display_done_event, WIN32_MAX_FRAME_WAIT_TIME); + + if (this->_didWidthChange || this->_didHeightChange) + { + for (size_t i = 0; i < WIN32_FRAMEBUFFER_COUNT; i++) + { + slock_lock(this->_mutexFramebufferPage[i]); + } + } + + GPU->SetCustomFramebufferSize(this->_widthPending, this->_heightPending); + GPU->SetColorFormat(this->_colorFormatPending); + GPU->SetFramebufferPageCount(this->_pageCountPending); + } +} + +void Win32GPUEventHandler::DidApplyGPUSettingsEnd() +{ + if (this->_didWidthChange || this->_didHeightChange || this->_didColorFormatChange || this->_didPageCountChange) + { + const NDSDisplayInfo& dispInfo = GPU->GetDisplayInfo(); + + if (this->_didWidthChange || this->_didHeightChange) + { + video.SetPrescale(((dispInfo.customWidth / GPU_FRAMEBUFFER_NATIVE_WIDTH) + (dispInfo.customHeight / GPU_FRAMEBUFFER_NATIVE_HEIGHT)) / 2, 1); + UpdateScreenRects(); + SetDisplayNeedsBufferUpdates(); + + for (size_t i = 0; i < WIN32_FRAMEBUFFER_COUNT; i++) + { + slock_unlock(this->_mutexFramebufferPage[i]); + } + } + + // Update all the change flags now that settings are applied. + // In theory, all these flags should get cleared. + this->_didWidthChange = (this->_widthPending != dispInfo.customWidth); + this->_didHeightChange = (this->_heightPending != dispInfo.customHeight); + this->_didColorFormatChange = (this->_colorFormatPending != dispInfo.colorFormat); + this->_didPageCountChange = (this->_pageCountPending != dispInfo.framebufferPageCount); + } + + slock_unlock(this->_mutexApplyGPUSettings); +} diff --git a/desmume/src/frontend/windows/display.h b/desmume/src/frontend/windows/display.h index 1c099c06e..ad7569171 100644 --- a/desmume/src/frontend/windows/display.h +++ b/desmume/src/frontend/windows/display.h @@ -1,5 +1,5 @@ /* -Copyright (C) 2018 DeSmuME team +Copyright (C) 2018-2025 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -30,6 +30,54 @@ along with the this software. If not, see . #include "ddraw.h" #include "ogl_display.h" +#define WIN32_FRAMEBUFFER_COUNT 3 +#define WIN32_MAX_FRAME_WAIT_TIME 333 // Maximum time in milliseconds to wait for a video frame to render to a window before starting a new frame. + + +class Win32GPUEventHandler : public GPUEventHandlerDefault +{ +protected: + NDSColorFormat _colorFormatPending; + size_t _widthPending; + size_t _heightPending; + size_t _pageCountPending; + size_t _scaleFactorIntegerPending; + + bool _didColorFormatChange; + bool _didWidthChange; + bool _didHeightChange; + bool _didPageCountChange; + + u8 _inProcessBufferIndex; + u8 _latestAvailableBufferIndex; + u8 _currentLockedPageIndex; + + slock_t *_mutexApplyGPUSettings; + slock_t *_mutexVideoFetch; + slock_t *_mutexFramebufferPage[WIN32_FRAMEBUFFER_COUNT]; + +public: + Win32GPUEventHandler(); + ~Win32GPUEventHandler(); + + void SetFramebufferDimensions(size_t w, size_t h); + void GetFramebufferDimensions(size_t& outWidth, size_t& outHeight); + void SetFramebufferDimensionsByScaleFactorInteger(size_t scaleFactor); + size_t GetFramebufferDimensionsByScaleFactorInteger(); + + void SetColorFormat(NDSColorFormat colorFormat); + NDSColorFormat GetColorFormat(); + + void VideoFetchLock(); + void VideoFetchUnlock(); + + // GPUEventHandler methods + virtual void DidFrameBegin(const size_t line, const bool isFrameSkipRequested, const size_t pageCount, u8& selectedBufferIndexInOut); + virtual void DidFrameEnd(bool isFrameSkipped, const NDSDisplayInfo& latestDisplayInfo); + virtual void DidApplyGPUSettingsBegin(); + virtual void DidApplyGPUSettingsEnd(); +}; + extern DDRAW ddraw; extern GLDISPLAY gldisplay; extern u32 displayMethod; @@ -37,6 +85,7 @@ const u32 DISPMETHOD_DDRAW_HW = 1; const u32 DISPMETHOD_DDRAW_SW = 2; const u32 DISPMETHOD_OPENGL = 3; +extern Win32GPUEventHandler* WinGPUEvent; extern int gpu_bpp; extern int emu_paused; @@ -46,7 +95,6 @@ extern int lastskiprate; extern VideoInfo video; extern RECT FullScreenRect, MainScreenRect, SubScreenRect, GapRect; -extern RECT MainScreenSrcRect, SubScreenSrcRect; const int kGapNone = 0; const int kGapBorder = 5; const int kGapNDS = 64; // extremely tilted (but some games seem to use this value) @@ -62,10 +110,8 @@ extern bool vCenterResizedScr; extern bool SeparationBorderDrag; extern int ScreenGapColor; -extern slock_t *display_mutex; extern HANDLE display_wakeup_event; extern HANDLE display_done_event; -extern DWORD display_done_timeout; extern int displayPostponeType; extern DWORD displayPostponeUntil; @@ -93,6 +139,7 @@ extern int scanline_filter_d; void Display(); void DoDisplay(); void KillDisplay(); +void SetDisplayNeedsBufferUpdates(); void GetNdsScreenRect(RECT* r); @@ -103,6 +150,7 @@ FORCEINLINE void ServiceDisplayThreadInvocations() _ServiceDisplayThreadInvocation(); } +void UpdateScreenRects(); void UpdateWndRects(HWND hwnd, RECT* newClientRect = NULL); void TwiddleLayer(UINT ctlid, int core, int layer); void SetLayerMasks(int mainEngineMask, int subEngineMask); diff --git a/desmume/src/frontend/windows/hotkey.cpp b/desmume/src/frontend/windows/hotkey.cpp index 5ad32691a..7e1fe34c2 100644 --- a/desmume/src/frontend/windows/hotkey.cpp +++ b/desmume/src/frontend/windows/hotkey.cpp @@ -3,7 +3,7 @@ licensed under the terms supplied at the end of this file (for the terms are very long!) Differences from that baseline version are: - Copyright (C) 2009-2024 DeSmuME team + Copyright (C) 2009-2025 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -366,13 +366,25 @@ void HK_StylusAutoHoldKeyDown(int, bool justPressed) { NDS_setTouchPos((u16)winLastTouch.x, (u16)winLastTouch.y); else if (!userTouchesScreen) NDS_releaseTouch(); + + if ((emu_paused || !execute || !romloaded) && (HudEditorMode || CommonSettings.hud.ShowInputDisplay || CommonSettings.hud.ShowGraphicalInputDisplay)) + { + Display(); + } } void HK_AutoHoldClearKeyDown(int, bool justPressed) { ClearAutoHold(); StylusAutoHoldPressed = false; if (!userTouchesScreen) + { NDS_releaseTouch(); + + if ((emu_paused || !execute || !romloaded) && (HudEditorMode || CommonSettings.hud.ShowInputDisplay || CommonSettings.hud.ShowGraphicalInputDisplay)) + { + Display(); + } + } } extern VideoInfo video; diff --git a/desmume/src/frontend/windows/main.cpp b/desmume/src/frontend/windows/main.cpp index 5f9b4f8c6..412273426 100644 --- a/desmume/src/frontend/windows/main.cpp +++ b/desmume/src/frontend/windows/main.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2006 Theo Berkau - Copyright (C) 2006-2024 DeSmuME team + Copyright (C) 2006-2025 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -317,14 +317,11 @@ extern bool killStylusOffScreen; extern LRESULT CALLBACK RamSearchProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); void InitRamSearch(); -void FilterUpdate(HWND hwnd, bool user=true); +void SetWindowMagnificationFilter(HWND hwnd, int filterID, bool user=true); CRITICAL_SECTION win_execute_sync; volatile int win_sound_samplecounter = 0; -CRITICAL_SECTION win_backbuffer_sync; -volatile bool backbuffer_invalidate = false; - Lock::Lock() : m_cs(&win_execute_sync) { EnterCriticalSection(m_cs); } Lock::Lock(CRITICAL_SECTION& cs) : m_cs(&cs) { EnterCriticalSection(m_cs); } Lock::~Lock() { LeaveCriticalSection(m_cs); } @@ -452,19 +449,6 @@ unsigned short windowSize = 0; bool fsWindow = false; bool autoHideCursor = false; -class GPUEventHandlerWindows : public GPUEventHandlerDefault -{ -public: - virtual void DidFrameEnd(bool isFrameSkipped, const NDSDisplayInfo &latestDisplayInfo) - { - if (isFrameSkipped) - { - return; - } - - DRV_AviVideoUpdate(latestDisplayInfo); - } -}; class WinPCapInterface : public ClientPCapInterface { @@ -515,8 +499,6 @@ public: } }; -GPUEventHandlerWindows *WinGPUEvent = NULL; - LRESULT CALLBACK HUDFontSettingsDlgProc(HWND hw, UINT msg, WPARAM wp, LPARAM lp); LRESULT CALLBACK GFX3DSettingsDlgProc(HWND hw, UINT msg, WPARAM wp, LPARAM lp); LRESULT CALLBACK SoundSettingsDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); @@ -673,7 +655,7 @@ void ScaleScreen(float factor, bool user) factor = 2.5f; //don't incorporate prescale into these calculations - factor /= video.prescaleHD; + factor /= (float)WinGPUEvent->GetFramebufferDimensionsByScaleFactorInteger(); if (video.layout == 0) MainWindow->setClientSize((int)(video.rotatedwidthgap() * factor), (int)(video.rotatedheightgap() * factor)); @@ -1301,7 +1283,6 @@ static void StepRunLoop_Paused() // periodically update single-core OSD when paused and in the foreground if(CommonSettings.single_core() && GetActiveWindow() == mainLoopData.hwnd) { - video.srcBuffer = (u8*)GPU->GetDisplayInfo().masterCustomBuffer; DoDisplay(); } @@ -1314,14 +1295,6 @@ static void StepRunLoop_User() Hud.fps = mainLoopData.fps; Hud.fps3d = GPU->GetFPSRender3D(); - - if (mainLoopData.framesskipped == 0) - { - WaitForSingleObject(display_done_event, display_done_timeout); - Display(); - } - ResetEvent(display_done_event); - mainLoopData.fps3d = Hud.fps3d; mainLoopData.toolframecount++; @@ -1888,12 +1861,12 @@ static void RefreshMicSettings() static void SyncGpuBpp() { //either of these works. 666 must be packed as 888 - if(gpu_bpp == 18) - GPU->SetColorFormat(NDSColorFormat_BGR666_Rev); + if (gpu_bpp == 18) + WinGPUEvent->SetColorFormat(NDSColorFormat_BGR666_Rev); else if(gpu_bpp == 15) - GPU->SetColorFormat(NDSColorFormat_BGR555_Rev); + WinGPUEvent->SetColorFormat(NDSColorFormat_BGR555_Rev); else - GPU->SetColorFormat(NDSColorFormat_BGR888_Rev); + WinGPUEvent->SetColorFormat(NDSColorFormat_BGR888_Rev); } static BOOL OpenCoreSystemCP(const char* filename_syscp) @@ -1916,6 +1889,10 @@ int _main() dwMainThread = GetCurrentThreadId(); + oglrender_init = &windows_opengl_init; + oglrender_beginOpenGL = &wgl_beginOpenGL; + oglrender_endOpenGL = &wgl_endOpenGL; + //enable opengl 3.2 driver in this port OGLLoadEntryPoints_3_2_Func = OGLLoadEntryPoints_3_2; OGLCreateRenderer_3_2_Func = OGLCreateRenderer_3_2; @@ -1943,10 +1920,9 @@ int _main() LoadWinPCap(isPCapSupported); driver = new WinDriver(); - WinGPUEvent = new GPUEventHandlerWindows; + WinGPUEvent = new Win32GPUEventHandler; InitializeCriticalSection(&win_execute_sync); - InitializeCriticalSection(&win_backbuffer_sync); InitializeCriticalSection(&display_invoke_handler_cs); display_invoke_ready_event = CreateEvent(NULL, TRUE, FALSE, NULL); display_invoke_done_event = CreateEvent(NULL, FALSE, FALSE, NULL); @@ -1955,10 +1931,6 @@ int _main() // struct configured_features my_config; - oglrender_init = &windows_opengl_init; - oglrender_beginOpenGL = &wgl_beginOpenGL; - oglrender_endOpenGL = &wgl_endOpenGL; - //try and detect this for users who don't specify it on the commandline //(can't say I really blame them) //this helps give a substantial speedup for singlecore users @@ -1991,7 +1963,9 @@ int _main() if(GetPrivateProfileBool("Display", "Show Menu In Fullscreen Mode", false, IniName)) style |= DWS_FS_MENU; if (GetPrivateProfileBool("Display", "Non-exclusive Fullscreen Mode", false, IniName)) style |= DWS_FS_WINDOW; - gldisplay.filter = GetPrivateProfileBool("Video","Display Method Filter", false, IniName); + bool useOutputFilter = GetPrivateProfileBool("Video","Display Method Filter", false, IniName); + gldisplay.setUseOutputFilter(useOutputFilter); + if(GetPrivateProfileBool("Video","VSync", false, IniName)) style |= DWS_VSYNC; displayMethod = GetPrivateProfileInt("Video","Display Method", DISPMETHOD_DDRAW_HW, IniName); @@ -2122,6 +2096,13 @@ int _main() boffo[i] = emu_desmume_name_and_version[i]; boffo[len] = 0; + osd = new OSDCLASS(-1); + + NDS_Init(); + GPU->SetEventHandler(WinGPUEvent); + video.SetPrescale(1, 1); + SetDisplayNeedsBufferUpdates(); + MainWindow = new WINCLASS(L"DeSmuME", hAppInst); if (!MainWindow->createW(boffo, WndX, WndY, video.width,video.height+video.screengap, WS_CAPTION | WS_SYSMENU | WS_SIZEBOX | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, @@ -2132,6 +2113,26 @@ int _main() exit(-1); } + switch (displayMethod) + { + case DISPMETHOD_OPENGL: + break; + + case DISPMETHOD_DDRAW_HW: + case DISPMETHOD_DDRAW_SW: + default: + { + HWND hwnd = MainWindow->getHWnd(); + ddraw.systemMemory = (displayMethod != DISPMETHOD_DDRAW_HW); + u32 res = ddraw.create(hwnd); + if (res != 0) + { + MessageBox(hwnd, DDerrors[res], EMU_DESMUME_NAME_AND_VERSION(), MB_OK | MB_ICONERROR); + } + break; + } + } + //disable wacky stylus stuff //TODO - we are obliged to call GlobalDeleteAtom GlobalAddAtom(MICROSOFT_TABLETPENSERVICE_PROPERTY); @@ -2278,12 +2279,6 @@ int _main() CommonSettings.WifiBridgeDeviceID = GetPrivateProfileInt("Wifi", "BridgeAdapter", 0, IniName); - osd = new OSDCLASS(-1); - - NDS_Init(); - - GPU->SetEventHandler(WinGPUEvent); - WinPCapInterface *winpcapInterface = (isPCapSupported) ? new WinPCapInterface : NULL; wifiHandler->SetPCapInterface(winpcapInterface); wifiHandler->SetSocketsSupported(isSocketsSupported); @@ -2301,8 +2296,7 @@ int _main() CommonSettings.GFX3D_Renderer_TextureScalingFactor = (cmdline.texture_upscale != -1) ? cmdline.texture_upscale : GetValid3DIntSetting("TextureScalingFactor", 1, possibleTexScale, 3); int newPrescaleHD = (cmdline.gpu_resolution_multiplier != -1) ? cmdline.gpu_resolution_multiplier : GetPrivateProfileInt("3D", "PrescaleHD", 1, IniName); - video.SetPrescale(newPrescaleHD, 1); - GPU->SetCustomFramebufferSize(GPU_FRAMEBUFFER_NATIVE_WIDTH*video.prescaleHD, GPU_FRAMEBUFFER_NATIVE_HEIGHT*video.prescaleHD); + WinGPUEvent->SetFramebufferDimensionsByScaleFactorInteger(newPrescaleHD); SyncGpuBpp(); GPU->ClearWithColor(0xFFFFFF); @@ -2447,10 +2441,10 @@ int _main() CommonSettings.UseExtFirmwareSettings = GetPrivateProfileBool("Firmware", "UseExtFirmwareSettings", false, IniName); GetPrivateProfileString("Firmware", "FirmwareFile", "firmware.bin", CommonSettings.ExtFirmwarePath, 256, IniName); CommonSettings.BootFromFirmware = GetPrivateProfileBool("Firmware", "BootFromFirmware", false, IniName); - - video.setfilter(GetPrivateProfileInt("Video", "Filter", video.NONE, IniName)); - FilterUpdate(MainWindow->getHWnd(),false); - + + UINT magFilterID = GetPrivateProfileInt("Video", "Filter", video.NONE, IniName); + SetWindowMagnificationFilter(MainWindow->getHWnd(), (int)magFilterID, false); + // Read the firmware settings from the init file CommonSettings.fwConfig.favoriteColor = GetPrivateProfileInt("Firmware","favColor", 10, IniName); CommonSettings.fwConfig.birthdayMonth = GetPrivateProfileInt("Firmware","bMonth", 7, IniName); @@ -2663,70 +2657,6 @@ int GetValid3DIntSetting(char *settingName, const int defVal, const int arrName[ return defVal; } -void UpdateScreenRects() -{ - if (video.layout == 1) - { - // Main screen - MainScreenSrcRect.left = 0; - MainScreenSrcRect.top = 0; - MainScreenSrcRect.right = video.width; - MainScreenSrcRect.bottom = video.height/2; - - // Sub screen - SubScreenSrcRect.left = 0; - SubScreenSrcRect.top = video.height/2; - SubScreenSrcRect.right = video.width; - SubScreenSrcRect.bottom = video.height; - } - else - if (video.layout == 2) - { - // Main screen - MainScreenSrcRect.left = 0; - MainScreenSrcRect.top = 0; - MainScreenSrcRect.right = video.width; - MainScreenSrcRect.bottom = video.height/2; - - // Sub screen - SubScreenSrcRect.left = 0; - SubScreenSrcRect.top = video.height/2; - SubScreenSrcRect.right = video.width; - SubScreenSrcRect.bottom = video.height; - } - else - { - if((video.rotation == 90) || (video.rotation == 270)) - { - // Main screen - MainScreenSrcRect.left = 0; - MainScreenSrcRect.top = 0; - MainScreenSrcRect.right = video.height/2; - MainScreenSrcRect.bottom = video.width; - - // Sub screen - SubScreenSrcRect.left = video.height/2; - SubScreenSrcRect.top = 0; - SubScreenSrcRect.right = video.height; - SubScreenSrcRect.bottom = video.width; - } - else - { - // Main screen - MainScreenSrcRect.left = 0; - MainScreenSrcRect.top = 0; - MainScreenSrcRect.right = video.width; - MainScreenSrcRect.bottom = video.height/2; - - // Sub screen - SubScreenSrcRect.left = 0; - SubScreenSrcRect.top = video.height/2; - SubScreenSrcRect.right = video.width; - SubScreenSrcRect.bottom = video.height; - } - } -} - // re-run the aspect ratio calculations if enabled void FixAspectRatio() { @@ -2788,7 +2718,6 @@ void SetRotate(HWND hwnd, int rot, bool user) if (maximized) RestoreWindow(hwnd); { - Lock lock (win_backbuffer_sync); RECT rc; int oldrot = video.rotation; @@ -3557,8 +3486,11 @@ void RunConfig(CONFIGSCREEN which) NDS_UnPause(); } -void FilterUpdate(HWND hwnd, bool user) +void SetWindowMagnificationFilter(HWND hwnd, int filterID, bool user) { + video.setfilter(filterID); + SetDisplayNeedsBufferUpdates(); + u32 style = GetStyle(); bool maximized = IsZoomed(hwnd) || fsWindow; if (maximized) @@ -3825,7 +3757,7 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM MainWindow->checkMenu(ID_DISPLAYMETHOD_DIRECTDRAWHW, displayMethod == DISPMETHOD_DDRAW_HW); MainWindow->checkMenu(ID_DISPLAYMETHOD_DIRECTDRAWSW, displayMethod == DISPMETHOD_DDRAW_SW); MainWindow->checkMenu(ID_DISPLAYMETHOD_OPENGL, displayMethod == DISPMETHOD_OPENGL); - MainWindow->checkMenu(ID_DISPLAYMETHOD_FILTER, gldisplay.filter); + MainWindow->checkMenu(ID_DISPLAYMETHOD_FILTER, gldisplay.useOutputFilter()); MainWindow->checkMenu(IDC_BACKGROUNDPAUSE, lostFocusPause); MainWindow->checkMenu(IDC_BACKGROUNDINPUT, allowBackgroundInput); @@ -4005,10 +3937,6 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM case WM_SIZING: { - { - Lock lock(win_backbuffer_sync); - backbuffer_invalidate = true; - } bool fullscreen = false; InvalidateRect(hwnd, NULL, FALSE); @@ -4138,6 +4066,10 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM case WM_KEYDOWN: //MainWindowToolbar->Show(false); input_acquire(); + if ((emu_paused || !execute || !romloaded) && (HudEditorMode || CommonSettings.hud.ShowInputDisplay || CommonSettings.hud.ShowGraphicalInputDisplay)) + { + Display(); + } if(wParam != VK_PAUSE) break; @@ -4195,6 +4127,10 @@ DOKEYDOWN: } } input_acquire(); + if ((emu_paused || !execute || !romloaded) && (HudEditorMode || CommonSettings.hud.ShowInputDisplay || CommonSettings.hud.ShowGraphicalInputDisplay)) + { + Display(); + } if(wParam != VK_PAUSE) break; case WM_SYSKEYUP: @@ -4209,10 +4145,6 @@ DOKEYDOWN: break; case WM_SIZE: - { - Lock lock(win_backbuffer_sync); - backbuffer_invalidate = true; - } switch(wParam) { case SIZE_MINIMIZED: @@ -4261,7 +4193,7 @@ DOKEYDOWN: UpdateWndRects(hwnd); MainWindowToolbar->OnSize(); - SetEvent(display_wakeup_event); + Display(); } break; } @@ -4275,16 +4207,12 @@ DOKEYDOWN: if(!romloaded) { - //ugh, dont do this when creating the window. in case we're using ddraw display method, ddraw wont be setup yet - if(ddraw.handle) - Display(); + Display(); } else { if(CommonSettings.single_core()) { - const NDSDisplayInfo &dispInfo = GPU->GetDisplayInfo(); - video.srcBuffer = (u8*)dispInfo.masterCustomBuffer; DoDisplay(); } } @@ -4469,6 +4397,11 @@ DOKEYDOWN: else NDS_setTouchPos(x, y); + if ((emu_paused || !execute || !romloaded) && (HudEditorMode || CommonSettings.hud.ShowInputDisplay || CommonSettings.hud.ShowGraphicalInputDisplay)) + { + Display(); + } + winLastTouch.x = x; winLastTouch.y = y; userTouchesScreen = true; @@ -4482,7 +4415,14 @@ DOKEYDOWN: HudClickRelease(&Hud); } if (!StylusAutoHoldPressed) + { NDS_releaseTouch(); + + if ((emu_paused || !execute || !romloaded) && (HudEditorMode || CommonSettings.hud.ShowInputDisplay || CommonSettings.hud.ShowGraphicalInputDisplay)) + { + Display(); + } + } userTouchesScreen = false; return 0; @@ -4496,7 +4436,14 @@ DOKEYDOWN: ReleaseCapture(); HudClickRelease(&Hud); if (!StylusAutoHoldPressed) + { NDS_releaseTouch(); + + if ((emu_paused || !execute || !romloaded) && (HudEditorMode || CommonSettings.hud.ShowInputDisplay || CommonSettings.hud.ShowGraphicalInputDisplay)) + { + Display(); + } + } userTouchesScreen = false; return 0; @@ -4609,158 +4556,70 @@ DOKEYDOWN: break; #endif case IDM_RENDER_NORMAL: - { - Lock lock (win_backbuffer_sync); - video.setfilter(video.NONE); - FilterUpdate(hwnd); - } + SetWindowMagnificationFilter(hwnd, video.NONE); break; case IDM_RENDER_LQ2X: - { - Lock lock (win_backbuffer_sync); - video.setfilter(video.LQ2X); - FilterUpdate(hwnd); - } + SetWindowMagnificationFilter(hwnd, video.LQ2X); break; case IDM_RENDER_LQ2XS: - { - Lock lock (win_backbuffer_sync); - video.setfilter(video.LQ2XS); - FilterUpdate(hwnd); - } + SetWindowMagnificationFilter(hwnd, video.LQ2XS); break; case IDM_RENDER_HQ2X: - { - Lock lock (win_backbuffer_sync); - video.setfilter(video.HQ2X); - FilterUpdate(hwnd); - } + SetWindowMagnificationFilter(hwnd, video.HQ2X); break; case IDM_RENDER_HQ4X: - { - Lock lock (win_backbuffer_sync); - video.setfilter(video.HQ4X); - FilterUpdate(hwnd); - } + SetWindowMagnificationFilter(hwnd, video.HQ4X); break; case IDM_RENDER_HQ2XS: - { - Lock lock (win_backbuffer_sync); - video.setfilter(video.HQ2XS); - FilterUpdate(hwnd); - } + SetWindowMagnificationFilter(hwnd, video.HQ2XS); break; case IDM_RENDER_2XSAI: - { - Lock lock (win_backbuffer_sync); - video.setfilter(video._2XSAI); - FilterUpdate(hwnd); - } + SetWindowMagnificationFilter(hwnd, video._2XSAI); break; case IDM_RENDER_SUPER2XSAI: - { - Lock lock (win_backbuffer_sync); - video.setfilter(video.SUPER2XSAI); - FilterUpdate(hwnd); - } + SetWindowMagnificationFilter(hwnd, video.SUPER2XSAI); break; case IDM_RENDER_SUPEREAGLE: - { - Lock lock (win_backbuffer_sync); - video.setfilter(video.SUPEREAGLE); - FilterUpdate(hwnd); - } + SetWindowMagnificationFilter(hwnd, video.SUPEREAGLE); break; case IDM_RENDER_SCANLINE: - { - Lock lock (win_backbuffer_sync); - video.setfilter(video.SCANLINE); - FilterUpdate(hwnd); - } + SetWindowMagnificationFilter(hwnd, video.SCANLINE); break; case IDM_RENDER_BILINEAR: - { - Lock lock (win_backbuffer_sync); - video.setfilter(video.BILINEAR); - FilterUpdate(hwnd); - } + SetWindowMagnificationFilter(hwnd, video.BILINEAR); break; case IDM_RENDER_NEAREST2X: - { - Lock lock (win_backbuffer_sync); - video.setfilter(video.NEAREST2X); - FilterUpdate(hwnd); - } + SetWindowMagnificationFilter(hwnd, video.NEAREST2X); break; case IDM_RENDER_EPX: - { - Lock lock (win_backbuffer_sync); - video.setfilter(video.EPX); - FilterUpdate(hwnd); - } + SetWindowMagnificationFilter(hwnd, video.EPX); break; case IDM_RENDER_EPXPLUS: - { - Lock lock (win_backbuffer_sync); - video.setfilter(video.EPXPLUS); - FilterUpdate(hwnd); - } + SetWindowMagnificationFilter(hwnd, video.EPXPLUS); break; case IDM_RENDER_EPX1POINT5: - { - Lock lock (win_backbuffer_sync); - video.setfilter(video.EPX1POINT5); - FilterUpdate(hwnd); - } + SetWindowMagnificationFilter(hwnd, video.EPX1POINT5); break; case IDM_RENDER_EPXPLUS1POINT5: - { - Lock lock (win_backbuffer_sync); - video.setfilter(video.EPXPLUS1POINT5); - FilterUpdate(hwnd); - } + SetWindowMagnificationFilter(hwnd, video.EPXPLUS1POINT5); break; case IDM_RENDER_NEAREST1POINT5: - { - Lock lock (win_backbuffer_sync); - video.setfilter(video.NEAREST1POINT5); - FilterUpdate(hwnd); - } + SetWindowMagnificationFilter(hwnd, video.NEAREST1POINT5); break; case IDM_RENDER_NEARESTPLUS1POINT5: - { - Lock lock (win_backbuffer_sync); - video.setfilter(video.NEARESTPLUS1POINT5); - FilterUpdate(hwnd); - } + SetWindowMagnificationFilter(hwnd, video.NEARESTPLUS1POINT5); break; case IDM_RENDER_2XBRZ: - { - Lock lock (win_backbuffer_sync); - video.setfilter(video._2XBRZ); - FilterUpdate(hwnd); - } + SetWindowMagnificationFilter(hwnd, video._2XBRZ); break; case IDM_RENDER_3XBRZ: - { - Lock lock (win_backbuffer_sync); - video.setfilter(video._3XBRZ); - FilterUpdate(hwnd); - } + SetWindowMagnificationFilter(hwnd, video._3XBRZ); break; case IDM_RENDER_4XBRZ: - { - Lock lock (win_backbuffer_sync); - video.setfilter(video._4XBRZ); - FilterUpdate(hwnd); - } + SetWindowMagnificationFilter(hwnd, video._4XBRZ); break; case IDM_RENDER_5XBRZ: - { - Lock lock (win_backbuffer_sync); - video.setfilter(video._5XBRZ); - FilterUpdate(hwnd); - } + SetWindowMagnificationFilter(hwnd, video._5XBRZ); break; case IDM_STATE_LOAD: @@ -5107,54 +4966,102 @@ DOKEYDOWN: return 0; case ID_VIEW_FRAMECOUNTER: + { CommonSettings.hud.FrameCounterDisplay ^= true; WritePrivateProfileBool("Display", "FrameCounter", CommonSettings.hud.FrameCounterDisplay, IniName); osd->clear(); + if (emu_paused || !execute || !romloaded) + { + Display(); + } return 0; + } case ID_VIEW_DISPLAYFPS: + { CommonSettings.hud.FpsDisplay ^= true; WritePrivateProfileBool("Display", "Display Fps", CommonSettings.hud.FpsDisplay, IniName); osd->clear(); + if (emu_paused || !execute || !romloaded) + { + Display(); + } return 0; + } case ID_VIEW_DISPLAYINPUT: + { CommonSettings.hud.ShowInputDisplay ^= true; WritePrivateProfileBool("Display", "Display Input", CommonSettings.hud.ShowInputDisplay, IniName); osd->clear(); + if (emu_paused || !execute || !romloaded) + { + Display(); + } return 0; + } case ID_VIEW_DISPLAYGRAPHICALINPUT: + { CommonSettings.hud.ShowGraphicalInputDisplay ^= true; WritePrivateProfileBool("Display", "Display Graphical Input", CommonSettings.hud.ShowGraphicalInputDisplay, IniName); osd->clear(); + if (emu_paused || !execute || !romloaded) + { + Display(); + } return 0; + } case ID_VIEW_DISPLAYLAG: + { CommonSettings.hud.ShowLagFrameCounter ^= true; WritePrivateProfileBool("Display", "Display Lag Counter", CommonSettings.hud.ShowLagFrameCounter, IniName); osd->clear(); + if (emu_paused || !execute || !romloaded) + { + Display(); + } return 0; + } case ID_VIEW_DISPLAYRTC: + { CommonSettings.hud.ShowRTC ^= true; WritePrivateProfileBool("Display", "Display RTC", CommonSettings.hud.ShowRTC, IniName); osd->clear(); + if (emu_paused || !execute || !romloaded) + { + Display(); + } return 0; + } case ID_VIEW_HUDEDITOR: + { HudEditorMode ^= true; osd->clear(); osd->border(HudEditorMode); - if(!HudEditorMode) + if (!HudEditorMode) osd->SaveHudEditor(); + if (emu_paused || !execute || !romloaded) + { + Display(); + } return 0; + } case ID_VIEW_DISPLAYMICROPHONE: + { CommonSettings.hud.ShowMicrophone ^= true; WritePrivateProfileBool("Display", "Display Microphone", CommonSettings.hud.ShowMicrophone, IniName); osd->clear(); + if (emu_paused || !execute || !romloaded) + { + Display(); + } return 0; + } case ID_RAM_SEARCH: if(!RamSearchHWnd) @@ -5194,40 +5101,35 @@ DOKEYDOWN: break; case ID_DISPLAYMETHOD_DIRECTDRAWHW: - { - Lock lock (win_backbuffer_sync); - displayMethod = DISPMETHOD_DDRAW_HW; - ddraw.systemMemory = false; - WritePrivateProfileInt("Video","Display Method", DISPMETHOD_DDRAW_HW, IniName); - ddraw.createSurfaces(hwnd); - } + displayMethod = DISPMETHOD_DDRAW_HW; + ddraw.systemMemory = false; + WritePrivateProfileInt("Video","Display Method", DISPMETHOD_DDRAW_HW, IniName); + ddraw.createSurfaces(hwnd); + SetDisplayNeedsBufferUpdates(); break; case ID_DISPLAYMETHOD_DIRECTDRAWSW: - { - Lock lock (win_backbuffer_sync); - displayMethod = DISPMETHOD_DDRAW_SW; - ddraw.systemMemory = true; - WritePrivateProfileInt("Video","Display Method", DISPMETHOD_DDRAW_SW, IniName); - ddraw.createSurfaces(hwnd); - } + displayMethod = DISPMETHOD_DDRAW_SW; + ddraw.systemMemory = true; + WritePrivateProfileInt("Video","Display Method", DISPMETHOD_DDRAW_SW, IniName); + ddraw.createSurfaces(hwnd); + SetDisplayNeedsBufferUpdates(); break; case ID_DISPLAYMETHOD_OPENGL: - { - Lock lock (win_backbuffer_sync); - displayMethod = DISPMETHOD_OPENGL; - WritePrivateProfileInt("Video","Display Method", DISPMETHOD_OPENGL, IniName); - } + displayMethod = DISPMETHOD_OPENGL; + WritePrivateProfileInt("Video","Display Method", DISPMETHOD_OPENGL, IniName); + SetDisplayNeedsBufferUpdates(); break; case ID_DISPLAYMETHOD_FILTER: - { - Lock lock (win_backbuffer_sync); - gldisplay.filter = !gldisplay.filter; - WritePrivateProfileInt("Video","Display Method Filter", gldisplay.filter?1:0, IniName); - } + { + bool useOutputFilter = gldisplay.useOutputFilter(); + useOutputFilter = !useOutputFilter; + gldisplay.setUseOutputFilter(useOutputFilter); + WritePrivateProfileInt("Video", "Display Method Filter", gldisplay.useOutputFilter() ? 1 : 0, IniName); break; + } case IDM_RESET: ResetGame(); @@ -5714,39 +5616,15 @@ void Change3DCoreWithFallbackAndSave(int newCore) { printf("Attempting change to 3d core to: %s\n",core3DList[newCore]->name); - if(newCore == GPU3D_OPENGL_OLD) - goto TRY_OGL_OLD; - - if(newCore == GPU3D_SWRAST) - goto TRY_SWRAST; - - if(newCore == RENDERID_NULL) + if (newCore >= 4) { - GPU->Change3DRendererByID(RENDERID_NULL); - goto DONE; + printf("DeSmuME: Invalid 3D renderer chosen; falling back to SoftRasterizer. (core3DList index = %i)\n", newCore); + newCore = GPU3D_SWRAST; } - if(!GPU->Change3DRendererByID(GPU3D_OPENGL_3_2)) - { - printf("falling back to 3d core: %s\n",core3DList[GPU3D_OPENGL_OLD]->name); - goto TRY_OGL_OLD; - } - goto DONE; + GPU->Set3DRendererByID(newCore); -TRY_OGL_OLD: - if(!GPU->Change3DRendererByID(GPU3D_OPENGL_OLD)) - { - printf("falling back to 3d core: %s\n",core3DList[GPU3D_SWRAST]->name); - goto TRY_SWRAST; - } - goto DONE; - -TRY_SWRAST: - GPU->Change3DRendererByID(GPU3D_SWRAST); - -DONE: - int gpu3dSaveValue = ((cur3DCore != RENDERID_NULL) ? cur3DCore : RENDERID_NULL_SAVED); - WritePrivateProfileInt("3D", "Renderer", gpu3dSaveValue, IniName); + WritePrivateProfileInt("3D", "Renderer", newCore, IniName); } LRESULT CALLBACK HUDFontSettingsDlgProc(HWND hw, UINT msg, WPARAM wp, LPARAM lp) @@ -5827,7 +5705,7 @@ LRESULT CALLBACK GFX3DSettingsDlgProc(HWND hw, UINT msg, WPARAM wp, LPARAM lp) CheckDlgButton(hw, IDC_DEPTH_L_EQUAL_PF, CommonSettings.OpenGL_Emulation_DepthLEqualPolygonFacing); SendDlgItemMessage(hw, IDC_NUD_PRESCALEHD, UDM_SETRANGE, 0, MAKELPARAM(16, 1)); - SendDlgItemMessage(hw, IDC_NUD_PRESCALEHD, UDM_SETPOS, 0, video.prescaleHD); + SendDlgItemMessage(hw, IDC_NUD_PRESCALEHD, UDM_SETPOS, 0, (LPARAM)WinGPUEvent->GetFramebufferDimensionsByScaleFactorInteger()); // Generate the Color Depth pop-up menu ComboBox_AddString(GetDlgItem(hw, IDC_GPU_COLOR_DEPTH), "15 bit"); @@ -5900,35 +5778,21 @@ LRESULT CALLBACK GFX3DSettingsDlgProc(HWND hw, UINT msg, WPARAM wp, LPARAM lp) CommonSettings.OpenGL_Emulation_NDSDepthCalculation = IsDlgCheckboxChecked(hw, IDC_NDS_DEPTH_CALC); CommonSettings.OpenGL_Emulation_DepthLEqualPolygonFacing = IsDlgCheckboxChecked(hw, IDC_DEPTH_L_EQUAL_PF); - int newPrescaleHD = video.prescaleHD; + int newPrescaleHD = (int)WinGPUEvent->GetFramebufferDimensionsByScaleFactorInteger(); LRESULT scaleResult = SendDlgItemMessage(hw, IDC_NUD_PRESCALEHD, UDM_GETPOS, 0, 0); if (HIWORD(scaleResult) == 0) { newPrescaleHD = LOWORD(scaleResult); } - { - Lock lock(win_backbuffer_sync); - if(display_mutex) slock_lock(display_mutex); - Change3DCoreWithFallbackAndSave(ComboBox_GetCurSel(GetDlgItem(hw, IDC_3DCORE))); - if (newPrescaleHD != video.prescaleHD) - { - video.SetPrescale(newPrescaleHD, 1); - GPU->SetCustomFramebufferSize(GPU_FRAMEBUFFER_NATIVE_WIDTH*video.prescaleHD, GPU_FRAMEBUFFER_NATIVE_HEIGHT*video.prescaleHD); - } - SyncGpuBpp(); - UpdateScreenRects(); - if(display_mutex) slock_unlock(display_mutex); - // shrink buffer size if necessary - const NDSDisplayInfo &displayInfo = GPU->GetDisplayInfo(); - size_t newBufferSize = displayInfo.customWidth * displayInfo.customHeight * 2 * displayInfo.pixelBytes; - if (newBufferSize < video.srcBufferSize) video.srcBufferSize = newBufferSize; - } + WinGPUEvent->SetFramebufferDimensionsByScaleFactorInteger(newPrescaleHD); + Change3DCoreWithFallbackAndSave(ComboBox_GetCurSel(GetDlgItem(hw, IDC_3DCORE))); + SyncGpuBpp(); WritePrivateProfileBool("3D", "HighResolutionInterpolateColor", CommonSettings.GFX3D_HighResolutionInterpolateColor, IniName); WritePrivateProfileBool("3D", "EnableTXTHack", CommonSettings.GFX3D_TXTHack, IniName); WritePrivateProfileBool("3D", "EnableLineHack", CommonSettings.GFX3D_LineHack, IniName); - WritePrivateProfileInt ("3D", "PrescaleHD", video.prescaleHD, IniName); + WritePrivateProfileInt ("3D", "PrescaleHD", newPrescaleHD, IniName); WritePrivateProfileInt ("3D", "GpuBpp", gpu_bpp, IniName); WritePrivateProfileInt ("3D", "TextureScalingFactor", CommonSettings.GFX3D_Renderer_TextureScalingFactor, IniName); WritePrivateProfileBool("3D", "TextureDeposterize", CommonSettings.GFX3D_Renderer_TextureDeposterize, IniName); @@ -5949,8 +5813,7 @@ LRESULT CALLBACK GFX3DSettingsDlgProc(HWND hw, UINT msg, WPARAM wp, LPARAM lp) return TRUE; case IDC_DEFAULT: { - Change3DCoreWithFallbackAndSave(GPU3D_DEFAULT); - ComboBox_SetCurSel(GetDlgItem(hw, IDC_3DCORE), cur3DCore); + ComboBox_SetCurSel(GetDlgItem(hw, IDC_3DCORE), GPU3D_DEFAULT); //CommonSettings.gfx3d_flushMode = 0; //WritePrivateProfileInt("3D", "AlternateFlush", CommonSettings.gfx3d_flushMode, IniName); } diff --git a/desmume/src/frontend/windows/main.h b/desmume/src/frontend/windows/main.h index 45bacf802..cc9004d7c 100644 --- a/desmume/src/frontend/windows/main.h +++ b/desmume/src/frontend/windows/main.h @@ -1,6 +1,6 @@ /* Copyright (C) 2006 Theo Berkau - Copyright (C) 2006-2016 DeSmuME team + Copyright (C) 2006-2025 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -28,7 +28,6 @@ extern WINCLASS *MainWindow; extern HINSTANCE hAppInst; extern HMENU mainMenu; //Holds handle to the main DeSmuME menu extern CToolBar* MainWindowToolbar; -extern CRITICAL_SECTION win_backbuffer_sync; extern volatile bool execute, paused; extern bool romloaded; diff --git a/desmume/src/frontend/windows/ogl_display.cpp b/desmume/src/frontend/windows/ogl_display.cpp index acba8d611..8b85e36d4 100644 --- a/desmume/src/frontend/windows/ogl_display.cpp +++ b/desmume/src/frontend/windows/ogl_display.cpp @@ -1,5 +1,5 @@ /* -Copyright (C) 2018 DeSmuME team +Copyright (C) 2018-2025 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -16,6 +16,11 @@ along with the this software. If not, see . */ #include "ogl_display.h" +#include "display.h" + + +PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL; +PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT = NULL; bool GLDISPLAY::initialize(HWND hwnd) { @@ -28,14 +33,26 @@ bool GLDISPLAY::initialize(HWND hwnd) this->hwnd = hwnd; privateDC = GetDC(hwnd); wglMakeCurrent(privateDC, privateContext); - - // Certain video drivers may try to set the V-sync setting to whatever they want on - // initialization, and so we can't assume that wantVsync will match whatever the video - // driver is doing. - // - // And so we need to force the V-sync to be whatever default value wantVsync is in - // order to ensure that the actual V-sync setting in OpenGL matches wantVsync. - this->_setvsync(wantVsync); + + // http://stackoverflow.com/questions/589064/how-to-enable-vertical-sync-in-opengl + this->_isVsyncSupported = WGLExtensionSupported("WGL_EXT_swap_control"); + + if (this->_isVsyncSupported) + { + // Extension is supported, init pointers. + wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT"); + + // this is another function from WGL_EXT_swap_control extension + wglGetSwapIntervalEXT = (PFNWGLGETSWAPINTERVALEXTPROC)wglGetProcAddress("wglGetSwapIntervalEXT"); + + // Certain video drivers may try to set the V-sync setting to whatever they want on + // initialization, and so we can't assume that _useVsyncPending will match whatever the video + // driver is doing. + // + // And so we need to force the V-sync to be whatever default value _useVsyncPending is in + // order to ensure that the actual V-sync setting in OpenGL matches _useVsyncPending. + wglSwapIntervalEXT((this->_useVsyncApplied) ? 1 : 0); + } return true; } @@ -60,39 +77,147 @@ bool GLDISPLAY::WGLExtensionSupported(const char *extension_name) // extension is supported return true; } -void GLDISPLAY::_setvsync(bool isVsyncEnabled) -{ - if (!WGLExtensionSupported("WGL_EXT_swap_control")) return; - - //http://stackoverflow.com/questions/589064/how-to-enable-vertical-sync-in-opengl - PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL; - PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT = NULL; - { - // Extension is supported, init pointers. - wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT"); - - // this is another function from WGL_EXT_swap_control extension - wglGetSwapIntervalEXT = (PFNWGLGETSWAPINTERVALEXTPROC)wglGetProcAddress("wglGetSwapIntervalEXT"); - } - - wglSwapIntervalEXT(isVsyncEnabled ? 1 : 0); -} - GLDISPLAY::GLDISPLAY() - : active(false) - , wantVsync(false) - , haveVsync(false) { + _texVideo = (GLuint*)malloc(WIN32_FRAMEBUFFER_COUNT * sizeof(GLuint)); + _texHud = (GLuint*)malloc(WIN32_FRAMEBUFFER_COUNT * sizeof(GLuint)); + + for (size_t i = 0; i < WIN32_FRAMEBUFFER_COUNT; i++) + { + _texVideo[i] = 0; + _texHud[i] = 0; + } + + active = false; + _isVsyncSupported = false; + + _useOutputFilterPending = false; + _useOutputFilterApplied = false; + + _useVsyncPending = false; + _useVsyncApplied = false; +} + +GLDISPLAY::~GLDISPLAY() +{ + free(this->_texVideo); + this->_texVideo = NULL; + + free(this->_texHud); + this->_texHud = NULL; +} + +void GLDISPLAY::initVideoTexture(NDSColorFormat colorFormat, GLsizei videoWidth, GLsizei videoHeight) +{ + const GLint samplerType = (this->_useOutputFilterApplied) ? GL_LINEAR : GL_NEAREST; + const size_t pixBytes = (colorFormat == NDSColorFormat_BGR555_Rev) ? sizeof(u16) : sizeof(u32); + + if (this->_texVideo[0] == 0) + { + //the ds screen fills the texture entirely, so we dont have garbage at edge to worry about, + //but we need to make sure this is clamped for when filtering is selected + glGenTextures(WIN32_FRAMEBUFFER_COUNT, this->_texVideo); + + for (size_t i = 0; i < WIN32_FRAMEBUFFER_COUNT; i++) + { + glBindTexture(GL_TEXTURE_2D, this->_texVideo[i]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, videoWidth, videoHeight, 0, GL_RGBA, (colorFormat == NDSColorFormat_BGR555_Rev) ? GL_UNSIGNED_SHORT_1_5_5_5_REV : GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, samplerType); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, samplerType); + } + } + else + { + for (size_t i = 0; i < WIN32_FRAMEBUFFER_COUNT; i++) + { + glBindTexture(GL_TEXTURE_2D, this->_texVideo[i]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, videoWidth, videoHeight, 0, GL_RGBA, (colorFormat == NDSColorFormat_BGR555_Rev) ? GL_UNSIGNED_SHORT_1_5_5_5_REV : GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + } + } + + if (this->_texHud[0] == 0) + { + glGenTextures(WIN32_FRAMEBUFFER_COUNT, this->_texHud); + + for (size_t i = 0; i < WIN32_FRAMEBUFFER_COUNT; i++) + { + glBindTexture(GL_TEXTURE_2D, this->_texHud[i]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT * 2, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, samplerType); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, samplerType); + } + } +} + +GLuint GLDISPLAY::getTexVideoID(u8 bufferIndex) +{ + return this->_texVideo[bufferIndex]; +} + +GLuint GLDISPLAY::getTexHudID(u8 bufferIndex) +{ + return this->_texHud[bufferIndex]; +} + +void GLDISPLAY::setUseOutputFilter(bool theState) +{ + this->_useOutputFilterPending = theState; +} + +bool GLDISPLAY::useOutputFilter() +{ + return this->_useOutputFilterPending; +} + +void GLDISPLAY::applyOutputFilterOGL() +{ + if (this->_useOutputFilterPending == this->_useOutputFilterApplied) + { + return; + } + + GLint samplerType = (this->_useOutputFilterPending) ? GL_LINEAR : GL_NEAREST; + this->_useOutputFilterApplied = this->_useOutputFilterPending; + + for (size_t i = 0; i < WIN32_FRAMEBUFFER_COUNT; i++) + { + glBindTexture(GL_TEXTURE_2D, this->_texVideo[i]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, samplerType); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, samplerType); + + glBindTexture(GL_TEXTURE_2D, this->_texHud[i]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, samplerType); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, samplerType); + } } void GLDISPLAY::kill() { if (!hwnd) return; + + privateDC = GetDC(hwnd); + wglMakeCurrent(privateDC, privateContext); + + glDeleteTextures(WIN32_FRAMEBUFFER_COUNT, this->_texVideo); + glDeleteTextures(WIN32_FRAMEBUFFER_COUNT, this->_texHud); + + for (size_t i = 0; i < WIN32_FRAMEBUFFER_COUNT; i++) + { + this->_texVideo[i] = 0; + this->_texHud[i] = 0; + } + + wglMakeCurrent(NULL, privateContext); + ReleaseDC(hwnd, privateDC); wglDeleteContext(privateContext); privateContext = NULL; hwnd = NULL; - haveVsync = false; + this->_isVsyncSupported = false; } bool GLDISPLAY::begin(HWND hwnd) @@ -112,24 +237,15 @@ bool GLDISPLAY::begin(HWND hwnd) wglMakeCurrent(privateDC, privateContext); //go ahead and sync the vsync setting while we have the context - if (wantVsync != haveVsync) + if (this->_useVsyncPending != this->_useVsyncApplied) { - _setvsync(wantVsync); - haveVsync = wantVsync; + this->_useVsyncApplied = this->_useVsyncPending; + if (this->_isVsyncSupported) + { + wglSwapIntervalEXT((this->_useVsyncApplied) ? 1 : 0); + } } - if (filter) - { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } - else - { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - } - - return active = true; } @@ -143,7 +259,7 @@ void GLDISPLAY::end() void GLDISPLAY::setvsync(bool vsync) { - wantVsync = vsync; + this->_useVsyncPending = vsync; } void GLDISPLAY::showPage() diff --git a/desmume/src/frontend/windows/ogl_display.h b/desmume/src/frontend/windows/ogl_display.h index 6627db26e..32883312e 100644 --- a/desmume/src/frontend/windows/ogl_display.h +++ b/desmume/src/frontend/windows/ogl_display.h @@ -1,5 +1,5 @@ /* -Copyright (C) 2018 DeSmuME team +Copyright (C) 2018-2025 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,6 +19,7 @@ along with the this software. If not, see . #define _OGL_DISPLAY_H_ #include "types.h" +#include "GPU.h" #include "ogl.h" #include @@ -34,14 +35,31 @@ private: HWND hwnd; bool initialize(HWND hwnd); bool WGLExtensionSupported(const char *extension_name); - void _setvsync(bool isVsyncEnabled); + + bool _isVsyncSupported; + + GLuint *_texVideo; + GLuint *_texHud; + + bool _useOutputFilterPending; + bool _useOutputFilterApplied; + bool _useVsyncPending; + bool _useVsyncApplied; public: - bool active; - bool wantVsync, haveVsync; - bool filter; - GLDISPLAY(); + ~GLDISPLAY(); + + bool active; + + void initVideoTexture(NDSColorFormat colorFormat, GLsizei videoWidth, GLsizei videoHeight); + GLuint getTexVideoID(u8 bufferIndex); + GLuint getTexHudID(u8 bufferIndex); + + void setUseOutputFilter(bool theState); + bool useOutputFilter(); + void applyOutputFilterOGL(); + void kill(); bool begin(HWND hwnd); void end(); diff --git a/desmume/src/frontend/windows/video.h b/desmume/src/frontend/windows/video.h index ce40c9917..d37a80627 100644 --- a/desmume/src/frontend/windows/video.h +++ b/desmume/src/frontend/windows/video.h @@ -1,5 +1,5 @@ /* -Copyright (C) 2009-2015 DeSmuME team +Copyright (C) 2009-2025 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -55,13 +55,13 @@ public: u32 *buffer, *buffer_raw; u32 *filteredbuffer; + SSurface filterSrcSurface; + SSurface filterDstSurface; + void SetPrescale(int prescaleHD, int prescalePost) { if (this->prescaleHD != prescaleHD || this->prescalePost != prescalePost) { - free_aligned(buffer_raw); - free_aligned(filteredbuffer); - this->prescaleHD = prescaleHD; this->prescalePost = prescalePost; prefilterWidth = 256 * prescaleHD; @@ -69,8 +69,6 @@ public: prescaleTotal = prescaleHD; - ResizeBuffers(); - setfilter(currentfilter); } } @@ -81,20 +79,34 @@ public: const int kPadSize = 4; // raw buffer + u32* oldRawBuffer = buffer_raw; size_t rawBufferWidth = prefilterWidth + (kPadSize * 2); size_t rawBufferHeight = prefilterHeight + (kPadSize * 2); rawBufferSize = rawBufferWidth * rawBufferHeight * 4; - buffer_raw = buffer = (u32*)malloc_alignedCacheLine(rawBufferSize); + buffer_raw = buffer = (u32*)malloc_alignedPage(rawBufferSize); + free_aligned(oldRawBuffer); // display buffer + u32* oldFilteredBuffer = filteredbuffer; size_t scratchBufferWidth = width + (kPadSize * 2); size_t scratchBufferHeight = height + (kPadSize * 2); scratchBufferSize = scratchBufferWidth * scratchBufferHeight * 4; - filteredbuffer = (u32*)malloc_alignedCacheLine(scratchBufferSize); + filteredbuffer = (u32*)malloc_alignedPage(scratchBufferSize); + free_aligned(oldFilteredBuffer); //move the buffer pointer inside it's padded area so that earlier reads won't go out of the buffer we allocated buffer += (kPadSize*rawBufferWidth + kPadSize) * 4; + filterSrcSurface.Height = 384 * prescaleHD; + filterSrcSurface.Width = 256 * prescaleHD; + filterSrcSurface.Pitch = filterSrcSurface.Width * 2; + filterSrcSurface.Surface = (u8*)buffer; + + filterDstSurface.Height = height * prescaleHD; + filterDstSurface.Width = width * prescaleHD; + filterDstSurface.Pitch = width * 2; + filterDstSurface.Surface = (u8*)filteredbuffer; + // clean the new buffers clear(); } @@ -137,10 +149,6 @@ public: memset(filteredbuffer, 0, scratchBufferSize); } - void reset() { - SetPrescale(1, 1); //should i do this here? - } - void setfilter(int filter) { if (filter < 0 || filter >= NUM_FILTERS) @@ -184,13 +192,8 @@ public: height = prefilterHeight * 2; break; } - - ResizeBuffers(); } - SSurface src; - SSurface dst; - u16* finalBuffer() const { if (currentfilter == NONE) @@ -199,83 +202,72 @@ public: } void filter() { - - src.Height = 384 * prescaleHD; - src.Width = 256 * prescaleHD; - src.Pitch = src.Width * 2; - src.Surface = (u8*)buffer; - - dst.Height = height * prescaleHD; - dst.Width = width * prescaleHD; - dst.Pitch = width * 2; - dst.Surface = (u8*)filteredbuffer; - switch (currentfilter) { case NONE: break; case LQ2X: - RenderLQ2X(src, dst); + RenderLQ2X(filterSrcSurface, filterDstSurface); break; case LQ2XS: - RenderLQ2XS(src, dst); + RenderLQ2XS(filterSrcSurface, filterDstSurface); break; case HQ2X: - RenderHQ2X(src, dst); + RenderHQ2X(filterSrcSurface, filterDstSurface); break; case HQ4X: - RenderHQ4X(src, dst); + RenderHQ4X(filterSrcSurface, filterDstSurface); break; case HQ2XS: - RenderHQ2XS(src, dst); + RenderHQ2XS(filterSrcSurface, filterDstSurface); break; case _2XSAI: - Render2xSaI(src, dst); + Render2xSaI(filterSrcSurface, filterDstSurface); break; case SUPER2XSAI: - RenderSuper2xSaI(src, dst); + RenderSuper2xSaI(filterSrcSurface, filterDstSurface); break; case SUPEREAGLE: - RenderSuperEagle(src, dst); + RenderSuperEagle(filterSrcSurface, filterDstSurface); break; case SCANLINE: - RenderScanline(src, dst); + RenderScanline(filterSrcSurface, filterDstSurface); break; case BILINEAR: - RenderBilinear(src, dst); + RenderBilinear(filterSrcSurface, filterDstSurface); break; case NEAREST2X: - RenderNearest2X(src, dst); + RenderNearest2X(filterSrcSurface, filterDstSurface); break; case EPX: - RenderEPX(src, dst); + RenderEPX(filterSrcSurface, filterDstSurface); break; case EPXPLUS: - RenderEPXPlus(src, dst); + RenderEPXPlus(filterSrcSurface, filterDstSurface); break; case EPX1POINT5: - RenderEPX_1Point5x(src, dst); + RenderEPX_1Point5x(filterSrcSurface, filterDstSurface); break; case EPXPLUS1POINT5: - RenderEPXPlus_1Point5x(src, dst); + RenderEPXPlus_1Point5x(filterSrcSurface, filterDstSurface); break; case NEAREST1POINT5: - RenderNearest_1Point5x(src, dst); + RenderNearest_1Point5x(filterSrcSurface, filterDstSurface); break; case NEARESTPLUS1POINT5: - RenderNearestPlus_1Point5x(src, dst); + RenderNearestPlus_1Point5x(filterSrcSurface, filterDstSurface); break; case _2XBRZ: - Render2xBRZ(src, dst); + Render2xBRZ(filterSrcSurface, filterDstSurface); break; case _3XBRZ: - Render3xBRZ(src, dst); + Render3xBRZ(filterSrcSurface, filterDstSurface); break; case _4XBRZ: - Render4xBRZ(src, dst); + Render4xBRZ(filterSrcSurface, filterDstSurface); break; case _5XBRZ: - Render5xBRZ(src, dst); + Render5xBRZ(filterSrcSurface, filterDstSurface); break; } }