Compare commits

...

3 Commits

Author SHA1 Message Date
rogerman
588b1ad15f OpenGL Renderer: Remove extraneous glFinish() calls that cause a minor performance loss on older GPUs. (Regression from commit 8238c35.) 2025-10-02 00:17:35 -07:00
rogerman
2f4fab6200 Fix compiling for GTK3 port. (Regression from commit d5e4ed5.) 2025-10-01 23:58:28 -07:00
rogerman
d5e4ed57d7 GPU: Major refactor that simplifies the code and moves all GPU settings changes (except for 3D-related settings) to occur right before the beginning of line zero. All ports have been significantly affected by this change.
- GPU core: GPU engine class instantiations are now allocated with new and delete operators, rather than using static Allocate() and FinalizeAndDeallocate() methods.
- GPU core: GPU engines now reference an assigned GPUSubsystem object, rather than referencing the GPU global variable.
- Cocoa Port: Move all CGL context creation code to its own appropriate file. This now follows the same code pattern as WGL, GLX, EGL, and SDL.
- Windows Port: Reduce host memory usage for video framebuffers by using the framebuffer page system in GPUSubsystem directly instead of copying to separate DisplayBuffer structs.
- WIndows Port: Slightly improve overall video performance for both DirectDraw and OpenGL by eliminating one framebuffer copy.
- Windows Port: Significantly improve OpenGL video performance further (when running without video magnification filters) through better texture management, and also by eliminating one additional framebuffer copy.
- Windows Port: Virtually eliminate all CPU usage when the emulation is idle by eliminating periodic video redrawing.
- Windows Port: Greatly improve HUD redrawing when the emulation is idle. Window redrawing can now be up to the refresh rate of the host monitor.
- Windows Port: Fix a bug where changing the video magnification filter would cause a memory leak.
- GTK2 Port Only: Now supports vector fonts for HUD drawing via AGG2D_USE_VECTORFONTS, just like how the GTK3 port does it.
- GTK2 / GTK3 Ports: The Code::Blocks project file now defines AGG2D_USE_VECTORFONTS for both ports.
- GTK2 / GTK3 Ports: Maximum GPU Scaling Factor increased from 10.0 to 16.0. This now matches the maximum GPU Scaling Factor for the Cocoa and Windows ports.
- GTK2 / GTK3 Ports: The default color format is now 18-bit RGB666 instead of 15-bit RGB555. This is the actual color format for the NDS, and now matches the default color format for the Cocoa and Windows ports.
- GTK2 / GTK3 Ports: For anyone who cares to implement this -- it is now possible to set the video output color format, as the code is now ready for it. (Just set up some UI to call gtk*Event->SetColorFormat(), passing in an NDSColorFormat enum value to set the color format.)
- GTK2 / GTK3 Ports: Fix a bug where taking screenshots would fail.
2025-10-01 23:17:56 -07:00
34 changed files with 3040 additions and 1897 deletions

View File

@@ -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<OUTPUTFORMAT>(this->_vramBlockOBJAddress, 0);
const void *__restrict vramColorPtr = this->_gpuSystem->GetCustomVRAMAddressUsingMappedAddress<OUTPUTFORMAT>(this->_vramBlockOBJAddress, 0);
this->_CompositeVRAMLineDeferred<COMPOSITORMODE, OUTPUTFORMAT, GPULayerType_OBJ, WILLPERFORMWINDOWTEST>(compInfo, vramColorPtr);
}
else
@@ -2527,7 +2539,7 @@ void GPUEngineBase::_RenderLine_LayerOBJ(GPUEngineCompositorInfo &compInfo, item
if (useCustomVRAM)
{
const void *__restrict vramColorPtr = GPU->GetCustomVRAMAddressUsingMappedAddress<OUTPUTFORMAT>(this->_vramBlockOBJAddress, 0);
const void *__restrict vramColorPtr = this->_gpuSystem->GetCustomVRAMAddressUsingMappedAddress<OUTPUTFORMAT>(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 <size_t WIN_NUM>
@@ -2862,7 +2875,7 @@ FORCEINLINE void GPUEngineBase::_RenderLine_LayerBG_Final(GPUEngineCompositorInf
{
if (useCustomVRAM)
{
const void *__restrict vramColorPtr = GPU->GetCustomVRAMAddressUsingMappedAddress<OUTPUTFORMAT>(compInfo.renderState.selectedBGLayer->BMPAddress, compInfo.line.blockOffsetCustom);
const void *__restrict vramColorPtr = this->_gpuSystem->GetCustomVRAMAddressUsingMappedAddress<OUTPUTFORMAT>(compInfo.renderState.selectedBGLayer->BMPAddress, compInfo.line.blockOffsetCustom);
this->_CompositeVRAMLineDeferred<COMPOSITORMODE, OUTPUTFORMAT, GPULayerType_BG, WILLPERFORMWINDOWTEST>(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;

View File

@@ -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);

View File

@@ -3135,8 +3135,6 @@ Render3DError OpenGLRenderer::ApplyRenderingSettings(const GFX3D_State &renderSt
return OGLERROR_BEGINGL_FAILED;
}
glFinish();
const bool didSelectedMultisampleSizeChange = (this->_selectedMultisampleSize != CommonSettings.GFX3D_Renderer_MultisampleSize);
const bool didEmulateNDSDepthCalculationChange = (this->_emulateNDSDepthCalculation != CommonSettings.OpenGL_Emulation_NDSDepthCalculation);
const bool didEnableTextureSmoothingChange = (this->_enableTextureSmoothing != CommonSettings.GFX3D_Renderer_TextureSmoothing);
@@ -3200,7 +3198,6 @@ Render3DError OpenGLRenderer::ApplyRenderingSettings(const GFX3D_State &renderSt
}
}
glFinish();
ENDGL();
return error;
}

View File

@@ -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;

View File

@@ -913,6 +913,28 @@ void ClientDisplayViewOutputManager::SetNDSFrameInfoToAll(const NDSFrameInfo &fr
pthread_mutex_unlock(&this->_pendingUnregisterListMutex);
}
void ClientDisplayViewOutputManager::GenerateViewListAll(std::vector<ClientDisplayViewInterface *> &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<ClientDisplayViewInterface *> &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<ClientDisplayViewInterface *> 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);
}
}

View File

@@ -224,6 +224,7 @@ public:
void TakeFrameCountAll();
void SetNDSFrameInfoToAll(const NDSFrameInfo &frameInfo);
void GenerateViewListAll(std::vector<ClientDisplayViewInterface *> &outFinalizeList);
void GenerateFlushListForDisplay(int32_t displayID, std::vector<ClientDisplayViewInterface *> &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<ClientDisplayViewInterface *> &cdvFlushList, uint64_t timeStampNow, uint64_t timeStampOutput);
virtual void FinalizeAllViews();
};
#endif // _CLIENT_OUTPUT_DISPLAY_H_

View File

@@ -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 = "<group>"; };
AB5B1D4921D1F31E00BF0E0F /* MetalRendererCommonShaders.metal */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.metal; path = MetalRendererCommonShaders.metal; sourceTree = "<group>"; };
AB64987B13ECC73800EE7DD2 /* FileTypeInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = FileTypeInfo.plist; sourceTree = "<group>"; };
AB64DC442E78E3710092D8FC /* cgl_3Demu.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cgl_3Demu.h; sourceTree = "<group>"; };
AB64DC452E78E3710092D8FC /* cgl_3Demu.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = cgl_3Demu.cpp; sourceTree = "<group>"; };
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 = "<group>"; };
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 = "<group>"; };
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 = "<group>"; };
@@ -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 */,

View File

@@ -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 = "<group>"; };
AB1E5A342E73F0AC008AFF9F /* ClientFirmwareControl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ClientFirmwareControl.cpp; sourceTree = "<group>"; };
AB1E5A352E73F0AC008AFF9F /* ClientFirmwareControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ClientFirmwareControl.h; sourceTree = "<group>"; };
AB1E6DA42E7C63420057B8C9 /* cgl_3Demu.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cgl_3Demu.cpp; sourceTree = "<group>"; };
AB1E6DA52E7C63420057B8C9 /* cgl_3Demu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cgl_3Demu.h; sourceTree = "<group>"; };
AB213D43170CB141006DDB0F /* InputProfileController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InputProfileController.h; sourceTree = "<group>"; };
AB213D44170CB141006DDB0F /* InputProfileController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = InputProfileController.mm; sourceTree = "<group>"; };
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;

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
#include "cgl_3Demu.h"
#include <sys/types.h>
#include <sys/sysctl.h>
#include <CoreVideo/CoreVideo.h>
#include <OpenGL/OpenGL.h>
#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;
}

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef _CGL_3DEMU_H_
#define _CGL_3DEMU_H_
#include <stddef.h>
#include <stdint.h>
// 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_

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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(&param->condThreadExecute, &param->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;

View File

@@ -23402,7 +23402,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<bool key="NSWindowIsRestorable">YES</bool>
</object>
<object class="NSCustomView" id="1047589062">
<reference key="NSNextResponder"/>
<nil key="NSNextResponder"/>
<int key="NSvFlags">256</int>
<array class="NSMutableArray" key="NSSubviews">
<object class="NSTabView" id="765488716">
@@ -23410,7 +23410,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">12</int>
<string key="NSFrame">{{13, 131}, {240, 173}}</string>
<reference key="NSSuperview" ref="1047589062"/>
<reference key="NSWindow"/>
<array class="NSMutableArray" key="NSTabViewItems">
<object class="NSTabViewItem" id="677111712">
<string key="NSIdentifier">APProfile1</string>
@@ -23423,7 +23422,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{-1, 113}, {78, 14}}</string>
<reference key="NSSuperview" ref="218651205"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="248134801">
<int key="NSCellFlags">68157504</int>
@@ -23442,7 +23440,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{105, 113}, {12, 17}}</string>
<reference key="NSSuperview" ref="218651205"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="215725751">
<int key="NSCellFlags">68157504</int>
@@ -23461,7 +23458,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{141, 113}, {12, 17}}</string>
<reference key="NSSuperview" ref="218651205"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="693495382">
<int key="NSCellFlags">68157504</int>
@@ -23480,7 +23476,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{177, 113}, {12, 17}}</string>
<reference key="NSSuperview" ref="218651205"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="712625450">
<int key="NSCellFlags">68157504</int>
@@ -23499,7 +23494,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{78, 111}, {30, 19}}</string>
<reference key="NSSuperview" ref="218651205"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="813689229">
<int key="NSCellFlags">-1804599231</int>
@@ -23560,7 +23554,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{114, 111}, {30, 19}}</string>
<reference key="NSSuperview" ref="218651205"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="523568071">
<int key="NSCellFlags">-1804599231</int>
@@ -23621,7 +23614,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{150, 111}, {30, 19}}</string>
<reference key="NSSuperview" ref="218651205"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="759244391">
<int key="NSCellFlags">-1804599231</int>
@@ -23682,7 +23674,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{186, 111}, {30, 19}}</string>
<reference key="NSSuperview" ref="218651205"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="802945601">
<int key="NSCellFlags">-1804599231</int>
@@ -23743,7 +23734,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{-1, 61}, {78, 14}}</string>
<reference key="NSSuperview" ref="218651205"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="335414139">
<int key="NSCellFlags">68157504</int>
@@ -23762,7 +23752,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{105, 61}, {12, 17}}</string>
<reference key="NSSuperview" ref="218651205"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="599056379">
<int key="NSCellFlags">68157504</int>
@@ -23781,7 +23770,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{141, 61}, {12, 17}}</string>
<reference key="NSSuperview" ref="218651205"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="508993908">
<int key="NSCellFlags">68157504</int>
@@ -23800,7 +23788,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{177, 61}, {12, 17}}</string>
<reference key="NSSuperview" ref="218651205"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="729663006">
<int key="NSCellFlags">68157504</int>
@@ -23819,7 +23806,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{78, 59}, {30, 19}}</string>
<reference key="NSSuperview" ref="218651205"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="39780428">
<int key="NSCellFlags">-1804599231</int>
@@ -23880,7 +23866,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{114, 59}, {30, 19}}</string>
<reference key="NSSuperview" ref="218651205"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="337353623">
<int key="NSCellFlags">-1804599231</int>
@@ -23941,7 +23926,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{150, 59}, {30, 19}}</string>
<reference key="NSSuperview" ref="218651205"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="188117828">
<int key="NSCellFlags">-1804599231</int>
@@ -24002,7 +23986,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{186, 59}, {30, 19}}</string>
<reference key="NSSuperview" ref="218651205"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="1002936840">
<int key="NSCellFlags">-1804599231</int>
@@ -24063,7 +24046,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{-1, 34}, {78, 14}}</string>
<reference key="NSSuperview" ref="218651205"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="466379411">
<int key="NSCellFlags">68157504</int>
@@ -24082,7 +24064,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{105, 34}, {12, 17}}</string>
<reference key="NSSuperview" ref="218651205"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="1017974847">
<int key="NSCellFlags">68157504</int>
@@ -24101,7 +24082,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{141, 34}, {12, 17}}</string>
<reference key="NSSuperview" ref="218651205"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="118350312">
<int key="NSCellFlags">68157504</int>
@@ -24120,7 +24100,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{177, 34}, {12, 17}}</string>
<reference key="NSSuperview" ref="218651205"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="317987369">
<int key="NSCellFlags">68157504</int>
@@ -24139,7 +24118,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{78, 32}, {30, 19}}</string>
<reference key="NSSuperview" ref="218651205"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="696342921">
<int key="NSCellFlags">-1804599231</int>
@@ -24200,7 +24178,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{114, 32}, {30, 19}}</string>
<reference key="NSSuperview" ref="218651205"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="774996430">
<int key="NSCellFlags">-1804599231</int>
@@ -24261,7 +24238,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{150, 32}, {30, 19}}</string>
<reference key="NSSuperview" ref="218651205"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="334371039">
<int key="NSCellFlags">-1804599231</int>
@@ -24322,7 +24298,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{186, 32}, {30, 19}}</string>
<reference key="NSSuperview" ref="218651205"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="944476722">
<int key="NSCellFlags">-1804599231</int>
@@ -24383,7 +24358,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{-1, 8}, {78, 14}}</string>
<reference key="NSSuperview" ref="218651205"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="217667141">
<int key="NSCellFlags">68157504</int>
@@ -24402,7 +24376,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{105, 8}, {12, 17}}</string>
<reference key="NSSuperview" ref="218651205"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="33184596">
<int key="NSCellFlags">68157504</int>
@@ -24421,7 +24394,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{141, 8}, {12, 17}}</string>
<reference key="NSSuperview" ref="218651205"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="860400728">
<int key="NSCellFlags">68157504</int>
@@ -24440,7 +24412,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{177, 8}, {12, 17}}</string>
<reference key="NSSuperview" ref="218651205"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="976910532">
<int key="NSCellFlags">68157504</int>
@@ -24459,7 +24430,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{78, 6}, {30, 19}}</string>
<reference key="NSSuperview" ref="218651205"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="83858405">
<int key="NSCellFlags">-1804599231</int>
@@ -24520,7 +24490,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{114, 6}, {30, 19}}</string>
<reference key="NSSuperview" ref="218651205"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="589602506">
<int key="NSCellFlags">-1804599231</int>
@@ -24581,7 +24550,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{150, 6}, {30, 19}}</string>
<reference key="NSSuperview" ref="218651205"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="789924947">
<int key="NSCellFlags">-1804599231</int>
@@ -24642,7 +24610,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{186, 6}, {30, 19}}</string>
<reference key="NSSuperview" ref="218651205"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="419271545">
<int key="NSCellFlags">-1804599231</int>
@@ -24703,7 +24670,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{1, 86}, {76, 14}}</string>
<reference key="NSSuperview" ref="218651205"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="562527656">
<int key="NSCellFlags">68157504</int>
@@ -24722,7 +24688,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{93, 86}, {126, 14}}</string>
<reference key="NSSuperview" ref="218651205"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="263307556">
<int key="NSCellFlags">68157504</int>
@@ -24742,7 +24707,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{75, 81}, {19, 27}}</string>
<reference key="NSSuperview" ref="218651205"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSStepperCell" key="NSCell" id="83887509">
<int key="NSCellFlags">67895328</int>
@@ -24759,7 +24723,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
</array>
<string key="NSFrame">{{10, 25}, {220, 135}}</string>
<reference key="NSSuperview" ref="765488716"/>
<reference key="NSWindow"/>
</object>
<string key="NSLabel">Profile 1</string>
<reference key="NSColor" ref="266180242"/>
@@ -27410,7 +27373,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{105, 305}, {140, 28}}</string>
<reference key="NSSuperview" ref="1047589062"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSButtonCell" key="NSCell" id="752111897">
<int key="NSCellFlags">67108864</int>
@@ -27432,7 +27394,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{109, 331}, {134, 14}}</string>
<reference key="NSSuperview" ref="1047589062"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="925349783">
<int key="NSCellFlags">70254657</int>
@@ -27452,7 +27413,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{17, 331}, {88, 14}}</string>
<reference key="NSSuperview" ref="1047589062"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="548329957">
<int key="NSCellFlags">68157504</int>
@@ -27471,7 +27431,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{53, 9}, {154, 19}}</string>
<reference key="NSSuperview" ref="1047589062"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSButtonCell" key="NSCell" id="31187818">
<int key="NSCellFlags">-2080374784</int>
@@ -27493,7 +27452,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{107, 406}, {136, 22}}</string>
<reference key="NSSuperview" ref="1047589062"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSPopUpButtonCell" key="NSCell" id="123761775">
<int key="NSCellFlags">-2076180416</int>
@@ -27718,7 +27676,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{107, 353}, {136, 22}}</string>
<reference key="NSSuperview" ref="1047589062"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSPopUpButtonCell" key="NSCell" id="1065443010">
<int key="NSCellFlags">-2076180416</int>
@@ -27818,7 +27775,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{17, 36}, {226, 98}}</string>
<reference key="NSSuperview" ref="1047589062"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="848793508">
<int key="NSCellFlags">67108864</int>
@@ -27837,7 +27793,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{110, 381}, {133, 27}}</string>
<reference key="NSSuperview" ref="1047589062"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSDatePickerCell" key="NSCell" id="239726529">
<int key="NSCellFlags">71303168</int>
@@ -27857,7 +27812,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{17, 358}, {88, 14}}</string>
<reference key="NSSuperview" ref="1047589062"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="498265556">
<int key="NSCellFlags">68157504</int>
@@ -27876,7 +27830,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{17, 385}, {88, 14}}</string>
<reference key="NSSuperview" ref="1047589062"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="316957117">
<int key="NSCellFlags">68157504</int>
@@ -27895,7 +27848,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{17, 411}, {88, 14}}</string>
<reference key="NSSuperview" ref="1047589062"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="752577603">
<int key="NSCellFlags">68157504</int>
@@ -27914,7 +27866,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{17, 457}, {88, 14}}</string>
<reference key="NSSuperview" ref="1047589062"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="540778151">
<int key="NSCellFlags">68157504</int>
@@ -27933,7 +27884,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{17, 483}, {88, 14}}</string>
<reference key="NSSuperview" ref="1047589062"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="299410061">
<int key="NSCellFlags">68157504</int>
@@ -27952,7 +27902,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{110, 434}, {130, 40}}</string>
<reference key="NSSuperview" ref="1047589062"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="307489802">
<int key="NSCellFlags">-1805647871</int>
@@ -27973,7 +27922,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{110, 481}, {130, 19}}</string>
<reference key="NSSuperview" ref="1047589062"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="962862279">
<int key="NSCellFlags">-1804599231</int>
@@ -27991,8 +27939,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
</object>
</array>
<string key="NSFrameSize">{260, 513}</string>
<reference key="NSSuperview"/>
<reference key="NSWindow"/>
<string key="NSClassName">NSView</string>
</object>
<object class="NSDrawer" id="401056227">
@@ -32969,7 +32915,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<nil key="NSUserInterfaceItemIdentifier"/>
<string key="NSWindowContentMaxSize">{1.7976931348623157e+308, 1.7976931348623157e+308}</string>
<object class="NSView" key="NSWindowView" id="924299424">
<reference key="NSNextResponder"/>
<nil key="NSNextResponder"/>
<int key="NSvFlags">256</int>
<array class="NSMutableArray" key="NSSubviews">
<object class="NSBox" id="1036485405">
@@ -32985,7 +32931,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{18, 13}, {110, 78}}</string>
<reference key="NSSuperview" ref="946617804"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<bool key="NSAllowsLogicalLayoutDirection">NO</bool>
<int key="NSNumRows">4</int>
@@ -33252,12 +33197,10 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
</array>
<string key="NSFrame">{{1, 1}, {213, 100}}</string>
<reference key="NSSuperview" ref="1036485405"/>
<reference key="NSWindow"/>
</object>
</array>
<string key="NSFrame">{{16, 179}, {215, 116}}</string>
<reference key="NSSuperview" ref="924299424"/>
<reference key="NSWindow"/>
<string key="NSOffsets">{0, 0}</string>
<object class="NSTextFieldCell" key="NSTitleCell">
<int key="NSCellFlags">67108864</int>
@@ -33286,7 +33229,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{18, 80}, {154, 38}}</string>
<reference key="NSSuperview" ref="651086227"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<bool key="NSAllowsLogicalLayoutDirection">NO</bool>
<int key="NSNumRows">2</int>
@@ -33529,7 +33471,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{53, 14}, {100, 58}}</string>
<reference key="NSSuperview" ref="651086227"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<bool key="NSAllowsLogicalLayoutDirection">NO</bool>
<int key="NSNumRows">3</int>
@@ -33782,12 +33723,10 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
</array>
<string key="NSFrame">{{1, 1}, {213, 128}}</string>
<reference key="NSSuperview" ref="982308127"/>
<reference key="NSWindow"/>
</object>
</array>
<string key="NSFrame">{{16, 31}, {215, 144}}</string>
<reference key="NSSuperview" ref="924299424"/>
<reference key="NSWindow"/>
<string key="NSOffsets">{0, 0}</string>
<object class="NSTextFieldCell" key="NSTitleCell">
<int key="NSCellFlags">67108864</int>
@@ -33816,7 +33755,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{15, 12}, {135, 18}}</string>
<reference key="NSSuperview" ref="216894813"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSButtonCell" key="NSCell" id="291427635">
<int key="NSCellFlags">-2080374784</int>
@@ -33838,12 +33776,10 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
</array>
<string key="NSFrame">{{1, 1}, {213, 38}}</string>
<reference key="NSSuperview" ref="658920776"/>
<reference key="NSWindow"/>
</object>
</array>
<string key="NSFrame">{{16, 299}, {215, 54}}</string>
<reference key="NSSuperview" ref="924299424"/>
<reference key="NSWindow"/>
<string key="NSOffsets">{0, 0}</string>
<object class="NSTextFieldCell" key="NSTitleCell">
<int key="NSCellFlags">67108864</int>
@@ -33872,7 +33808,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{40, 13}, {115, 21}}</string>
<reference key="NSSuperview" ref="112653742"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSSliderCell" key="NSCell" id="811159600">
<int key="NSCellFlags">67371264</int>
@@ -33895,7 +33830,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{147, 17}, {52, 14}}</string>
<reference key="NSSuperview" ref="112653742"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="365973783">
<int key="NSCellFlags">68157504</int>
@@ -33967,7 +33901,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
</set>
<string key="NSFrame">{{18, 16}, {16, 16}}</string>
<reference key="NSSuperview" ref="112653742"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSImageCell" key="NSCell" id="32483980">
<int key="NSCellFlags">134217728</int>
@@ -33984,12 +33917,10 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
</array>
<string key="NSFrame">{{1, 1}, {213, 46}}</string>
<reference key="NSSuperview" ref="755029719"/>
<reference key="NSWindow"/>
</object>
</array>
<string key="NSFrame">{{16, 357}, {215, 62}}</string>
<reference key="NSSuperview" ref="924299424"/>
<reference key="NSWindow"/>
<string key="NSOffsets">{0, 0}</string>
<object class="NSTextFieldCell" key="NSTitleCell">
<int key="NSCellFlags">67108864</int>
@@ -34010,7 +33941,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{43, 8}, {162, 19}}</string>
<reference key="NSSuperview" ref="924299424"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<object class="NSButtonCell" key="NSCell" id="1024891561">
<int key="NSCellFlags">-2080374784</int>
@@ -34040,7 +33970,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="NSvFlags">268</int>
<string key="NSFrame">{{18, 14}, {128, 38}}</string>
<reference key="NSSuperview" ref="300862151"/>
<reference key="NSWindow"/>
<bool key="NSEnabled">YES</bool>
<bool key="NSAllowsLogicalLayoutDirection">NO</bool>
<int key="NSNumRows">2</int>
@@ -34281,12 +34210,10 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
</array>
<string key="NSFrame">{{1, 1}, {213, 62}}</string>
<reference key="NSSuperview" ref="67832852"/>
<reference key="NSWindow"/>
</object>
</array>
<string key="NSFrame">{{16, 423}, {215, 78}}</string>
<reference key="NSSuperview" ref="924299424"/>
<reference key="NSWindow"/>
<string key="NSOffsets">{0, 0}</string>
<object class="NSTextFieldCell" key="NSTitleCell">
<int key="NSCellFlags">67108864</int>
@@ -34304,8 +34231,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
</object>
</array>
<string key="NSFrameSize">{248, 519}</string>
<reference key="NSSuperview"/>
<reference key="NSWindow"/>
</object>
<string key="NSScreenRect">{{0, 0}, {1920, 1177}}</string>
<string key="NSMaxSize">{1.7976931348623157e+308, 1.7976931348623157e+308}</string>
@@ -42171,6 +42096,11 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<bool key="NSEditable">YES</bool>
<object class="_NSManagedProxy" key="_NSManagedProxy"/>
</object>
<object class="NSObjectController" id="884957499">
<string key="NSObjectClassName">CocoaGraphicsController</string>
<bool key="NSEditable">YES</bool>
<object class="_NSManagedProxy" key="_NSManagedProxy"/>
</object>
<object class="NSObjectController" id="258098641">
<array class="NSMutableArray" key="NSDeclaredKeys">
<string>isWorking</string>
@@ -61123,7 +61053,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<int key="objectID">3959</int>
<reference key="object" ref="335932557"/>
<reference key="parent" ref="0"/>
<string key="objectName">CocoaDS Sound Controller</string>
<string key="objectName">Audio Controller</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">3965</int>
@@ -80217,6 +80147,12 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<reference key="object" ref="89523477"/>
<reference key="parent" ref="979196776"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">12480</int>
<reference key="object" ref="884957499"/>
<reference key="parent" ref="0"/>
<string key="objectName">Graphics Controller</string>
</object>
</array>
</object>
<dictionary class="NSMutableDictionary" key="flattenedProperties">
@@ -83041,6 +82977,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<string key="12461.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="12462.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="12463.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="12480.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="125.IBEditorWindowLastContentRect">{{903, 773}, {143, 23}}</string>
<string key="125.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="126.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
@@ -86362,7 +86299,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2
<nil key="activeLocalization"/>
<dictionary class="NSMutableDictionary" key="localizations"/>
<nil key="sourceID"/>
<int key="maxID">12479</int>
<int key="maxID">12480</int>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes">
<array class="NSMutableArray" key="referencedPartialClassDescriptionsV3.1+">

View File

@@ -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 &currentDisplayInfo);

View File

@@ -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;

View File

@@ -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

View File

@@ -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);

View File

@@ -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");

View File

@@ -164,6 +164,9 @@
<Add library="/usr/lib/aarch64-linux-gnu/libopenal.so" />
<Add library="/usr/lib/aarch64-linux-gnu/libGLESv2.so" />
<Add library="/usr/lib/aarch64-linux-gnu/libEGL.so" />
<Add library="/usr/lib/aarch64-linux-gnu/libfontconfig.so" />
<Add library="/usr/lib/aarch64-linux-gnu/libaggfontfreetype.a" />
<Add library="/usr/lib/aarch64-linux-gnu/libfreetype.so" />
</Linker>
</Target>
<Target title="GTK2_AArch64_Release">
@@ -195,6 +198,9 @@
<Add library="/usr/lib/aarch64-linux-gnu/libopenal.so" />
<Add library="/usr/lib/aarch64-linux-gnu/libGLESv2.so" />
<Add library="/usr/lib/aarch64-linux-gnu/libEGL.so" />
<Add library="/usr/lib/aarch64-linux-gnu/libfontconfig.so" />
<Add library="/usr/lib/aarch64-linux-gnu/libaggfontfreetype.a" />
<Add library="/usr/lib/aarch64-linux-gnu/libfreetype.so" />
</Linker>
</Target>
<Target title="GTK3_AArch64_Debug">
@@ -222,6 +228,9 @@
<Add library="/usr/lib/aarch64-linux-gnu/libopenal.so" />
<Add library="/usr/lib/aarch64-linux-gnu/libGLESv2.so" />
<Add library="/usr/lib/aarch64-linux-gnu/libEGL.so" />
<Add library="/usr/lib/aarch64-linux-gnu/libfontconfig.so" />
<Add library="/usr/lib/aarch64-linux-gnu/libaggfontfreetype.a" />
<Add library="/usr/lib/aarch64-linux-gnu/libfreetype.so" />
</Linker>
<ExtraCommands>
<Add before='rm -f &quot;../gtk/gresource.c&quot;' />
@@ -262,6 +271,9 @@
<Add library="/usr/lib/aarch64-linux-gnu/libopenal.so" />
<Add library="/usr/lib/aarch64-linux-gnu/libGLESv2.so" />
<Add library="/usr/lib/aarch64-linux-gnu/libEGL.so" />
<Add library="/usr/lib/aarch64-linux-gnu/libfontconfig.so" />
<Add library="/usr/lib/aarch64-linux-gnu/libaggfontfreetype.a" />
<Add library="/usr/lib/aarch64-linux-gnu/libfreetype.so" />
</Linker>
<ExtraCommands>
<Add before='rm -f &quot;../gtk/gresource.c&quot;' />
@@ -299,6 +311,9 @@
<Add library="/usr/lib/aarch64-linux-gnu/libagg.a" />
<Add library="/usr/lib/aarch64-linux-gnu/libSDL2.so" />
<Add library="/usr/lib/aarch64-linux-gnu/libopenal.so" />
<Add library="/usr/lib/aarch64-linux-gnu/libfontconfig.so" />
<Add library="/usr/lib/aarch64-linux-gnu/libaggfontfreetype.a" />
<Add library="/usr/lib/aarch64-linux-gnu/libfreetype.so" />
</Linker>
</Target>
</Build>
@@ -310,6 +325,7 @@
<Add option="-DHAVE_LIBAGG" />
<Add option="-DHAVE_LIBSOUNDTOUCH" />
<Add option="-DHAVE_OPENAL" />
<Add option="-DAGG2D_USE_VECTORFONTS" />
<Add directory="/usr/include" />
<Add directory="/usr/include/agg2" />
<Add directory="/usr/include/SDL2" />
@@ -326,6 +342,9 @@
<Add library="/usr/lib/x86_64-linux-gnu/libagg.a" />
<Add library="/usr/lib/x86_64-linux-gnu/libSDL2.so" />
<Add library="/usr/lib/x86_64-linux-gnu/libopenal.so" />
<Add library="/usr/lib/x86_64-linux-gnu/libfontconfig.so" />
<Add library="/usr/lib/x86_64-linux-gnu/libaggfontfreetype.a" />
<Add library="/usr/lib/x86_64-linux-gnu/libfreetype.so" />
</Linker>
<Unit filename="../../../Database.cpp" />
<Unit filename="../../../Database.h" />

View File

@@ -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 <SDL.h>
#include <X11/Xlib.h>
#include <vector>
#ifdef AGG2D_USE_VECTORFONTS
#include <fontconfig/fontconfig.h>
#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;
@@ -134,6 +135,19 @@ enum {
SUB_OBJ
};
#ifdef HAVE_LIBAGG
enum hud_display_enum {
HUD_DISPLAY_FPS,
HUD_DISPLAY_INPUT,
HUD_DISPLAY_GINPUT,
HUD_DISPLAY_FCOUNTER,
HUD_DISPLAY_LCOUNTER,
HUD_DISPLAY_RTC,
HUD_DISPLAY_MIC,
HUD_DISPLAY_EDITOR,
};
#endif
#ifdef AGG2D_USE_VECTORFONTS
#define VECTOR_FONT_BASE_SIZE 16
@@ -198,6 +212,7 @@ static void Modify_Interpolation(GSimpleAction *action, GVariant *parameter, gpo
static void SetOrientation(GSimpleAction *action, GVariant *parameter, gpointer user_data);
static void ToggleLayerVisibility(GSimpleAction *action, GVariant *parameter, gpointer user_data);
#ifdef HAVE_LIBAGG
static void ToggleHudDisplay(hud_display_enum hudId, gboolean active);
static void HudFps(GSimpleAction *action, GVariant *parameter, gpointer user_data);
static void HudInput(GSimpleAction *action, GVariant *parameter, gpointer user_data);
static void HudGraphicalInput(GSimpleAction *action, GVariant *parameter, gpointer user_data);
@@ -1394,14 +1409,8 @@ static int ConfigureDrawingArea(GtkWidget *widget, GdkEventConfigure *event, gpo
return TRUE;
}
static inline void gpu_screen_to_rgb(u32* dst)
{
ColorspaceConvertBuffer555xTo8888Opaque<false, false, BESwapDst>(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 +1615,59 @@ static gboolean ExposeDrawingArea (GtkWidget *widget, GdkEventExpose *event, gpo
return TRUE;
}
static void RedrawScreen() {
ColorspaceConvertBuffer555xTo8888Opaque<true, false, BESwapDst>(
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 +1679,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 +1692,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 +1708,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 +2468,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 +2476,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 +2535,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<true, false>(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 +2591,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 +2949,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) {
@@ -3072,16 +3110,6 @@ static void desmume_gtk_menu_tool_layers(GtkApplication *app)
}
#ifdef HAVE_LIBAGG
enum hud_display_enum {
HUD_DISPLAY_FPS,
HUD_DISPLAY_INPUT,
HUD_DISPLAY_GINPUT,
HUD_DISPLAY_FCOUNTER,
HUD_DISPLAY_LCOUNTER,
HUD_DISPLAY_RTC,
HUD_DISPLAY_MIC,
HUD_DISPLAY_EDITOR,
};
static void ToggleHudDisplay(hud_display_enum hudId, gboolean active)
{
@@ -3400,7 +3428,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 +3455,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 +3525,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 +4144,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 +4276,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<true, false, BESwapNone>( (u16 *)latestDisplayInfo.masterCustomBuffer, (u32 *)video->GetSrcBufferPtr(), latestDisplayInfo.customWidth * latestDisplayInfo.customHeight * 2);
}
else
{
ColorspaceConvertBuffer888xTo8888Opaque<true, false>( (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);
}

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
#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

View File

@@ -21,9 +21,6 @@
#include "config.h"
using std::string;
using std::vector;
namespace desmume {
namespace config {
@@ -81,10 +78,10 @@ void value<float>::save() {
g_key_file_set_double(this->mKeyFile, this->mSection.c_str(), this->mKey.c_str(), this->mData);
}
/* class value<string> */
/* class value<std::string> */
template<>
void value<string>::load() {
void value<std::string>::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<string>::load() {
}
template<>
void value<string>::save() {
void value<std::string>::save() {
g_key_file_set_string(this->mKeyFile, this->mSection.c_str(), this->mKey.c_str(), this->mData.c_str());
}
/* class value<std::vector<int>> */
template<>
void value<std::vector<int>>::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<std::vector<int>>::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()

View File

@@ -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<int>, std::vector<int>(), HudDisplay, Layout)
/* Config */
OPT(fpslimiter, bool, true, Config, FpsLimiter)

View File

@@ -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 <X11/Xlib.h>
#include <sys/stat.h>
#ifdef AGG2D_USE_VECTORFONTS
#include <fontconfig/fontconfig.h>
#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<false, false, BESwapDst>(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<true, false, BESwapDst>(
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<true, false>(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<int> 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<int> 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<true, false, BESwapNone>( (u16 *)latestDisplayInfo.masterCustomBuffer, (u32 *)video->GetSrcBufferPtr(), latestDisplayInfo.customWidth * latestDisplayInfo.customHeight * 2);
}
else
{
ColorspaceConvertBuffer888xTo8888Opaque<true, false>( (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);
}

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
#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

View File

@@ -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 <http://www.gnu.org/licenses/>.
#include <windowsx.h>
#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<typename T> static void doRotate(void* dst)
template<typename T> 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<u32>(ddraw.surfDescBack.lpSurface);
doRotate<u32>(srcFramebuffer, (u8*)ddraw.surfDescBack.lpSurface);
break;
case 24:
doRotate<pix24>(ddraw.surfDescBack.lpSurface);
doRotate<pix24>(srcFramebuffer, (u8*)ddraw.surfDescBack.lpSurface);
break;
case 16:
if (ddraw.surfDescBack.ddpfPixelFormat.dwGBitMask != 0x3E0)
doRotate<pix16>(ddraw.surfDescBack.lpSurface);
doRotate<pix16>(srcFramebuffer, (u8*)ddraw.surfDescBack.lpSurface);
else
doRotate<pix15>(ddraw.surfDescBack.lpSurface);
doRotate<pix15>(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<true, false, BESwapNone>((u16 *)video.srcBuffer, video.buffer, video.srcBufferSize / 2);
else
ColorspaceConvertBuffer888xTo8888Opaque<true, false>((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<false, false>(video.buffer, pixCount, displayInfo.backlightIntensity[NDSDisplayID_Main]);
ColorspaceApplyIntensityToBuffer32<false, false>(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<true, false, BESwapNone>((u16*)video.srcBuffer, video.buffer, video.srcBufferSize / sizeof(u16));
else
ColorspaceConvertBuffer888xTo8888Opaque<true, false>((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<false, false>(video.buffer, pixCount, dispInfo.backlightIntensity[NDSDisplayID_Main]);
ColorspaceApplyIntensityToBuffer32<false, false>(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<T_AGG_PF_RGBA>(), 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<T_AGG_PF_RGBA>(), 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);
}

View File

@@ -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 <http://www.gnu.org/licenses/>.
#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);

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
#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()

View File

@@ -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 <http://www.gnu.org/licenses/>.
#define _OGL_DISPLAY_H_
#include "types.h"
#include "GPU.h"
#include "ogl.h"
#include <GL/gl.h>
@@ -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();

View File

@@ -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;
}
}