diff --git a/src/Cafe/CafeSystem.cpp b/src/Cafe/CafeSystem.cpp index 09020130..66b0969f 100644 --- a/src/Cafe/CafeSystem.cpp +++ b/src/Cafe/CafeSystem.cpp @@ -258,6 +258,7 @@ void InfoLog_PrintActiveSettings() else if (ActiveSettings::GetGraphicsAPI() == GraphicAPI::kMetal) { cemuLog_log(LogType::Force, "Async compile: {}", GetConfig().async_compile.GetValue() ? "true" : "false"); + cemuLog_log(LogType::Force, "Force mesh shaders: {}", GetConfig().force_mesh_shaders.GetValue() ? "true" : "false"); cemuLog_log(LogType::Force, "Fast math: {}", g_current_game_profile->GetFastMath() ? "true" : "false"); cemuLog_log(LogType::Force, "Buffer cache type: {}", g_current_game_profile->GetBufferCacheMode()); cemuLog_log(LogType::Force, "Position invariance: {}", g_current_game_profile->GetPositionInvariance()); diff --git a/src/Cafe/HW/Latte/Core/LatteShader.cpp b/src/Cafe/HW/Latte/Core/LatteShader.cpp index 3091e079..77ea3819 100644 --- a/src/Cafe/HW/Latte/Core/LatteShader.cpp +++ b/src/Cafe/HW/Latte/Core/LatteShader.cpp @@ -510,7 +510,7 @@ void LatteSHRC_UpdateVSBaseHash(uint8* vertexShaderPtr, uint32 vertexShaderSize, vsHash += tmp; auto primitiveType = LatteGPUState.contextNew.VGT_PRIMITIVE_TYPE.get_PRIMITIVE_MODE(); - // TODO: include always in the hash in case of geometry shader or rect shader + // TODO: include always in the hash in case of geometry shader or rect shader on Metal if (primitiveType == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::RECTS) { vsHash += 13ULL; @@ -528,7 +528,9 @@ void LatteSHRC_UpdateVSBaseHash(uint8* vertexShaderPtr, uint32 vertexShaderSize, #if ENABLE_METAL if (g_renderer->GetType() == RendererAPI::Metal) { - if (usesGeometryShader || _activeFetchShader->mtlFetchVertexManually) + bool isRectVertexShader = (primitiveType == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::RECTS); + + if ((usesGeometryShader || isRectVertexShader) || _activeFetchShader->mtlFetchVertexManually) { for (sint32 g = 0; g < _activeFetchShader->bufferGroups.size(); g++) { @@ -542,7 +544,7 @@ void LatteSHRC_UpdateVSBaseHash(uint8* vertexShaderPtr, uint32 vertexShaderSize, } } - if (!usesGeometryShader) + if (!(usesGeometryShader || isRectVertexShader)) { if (LatteGPUState.contextNew.IsRasterizationEnabled()) vsHash += 51ULL; diff --git a/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerAnalyzer.cpp b/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerAnalyzer.cpp index ce320316..fe0caed8 100644 --- a/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerAnalyzer.cpp +++ b/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerAnalyzer.cpp @@ -10,6 +10,9 @@ #include "Cafe/HW/Latte/Renderer/Renderer.h" #include "Common/MemPtr.h" #include "HW/Latte/ISA/LatteReg.h" +#if ENABLE_METAL +#include "HW/Latte/Renderer/Metal/MetalCommon.h" +#endif // Defined in LatteTextureLegacy.cpp Latte::E_GX2SURFFMT LatteTexture_ReconstructGX2Format(const Latte::LATTE_SQ_TEX_RESOURCE_WORD1_N& texUnitWord1, const Latte::LATTE_SQ_TEX_RESOURCE_WORD4_N& texUnitWord4); @@ -557,9 +560,9 @@ namespace LatteDecompiler } if (g_renderer->GetType() == RendererAPI::Metal) { - bool isRectVertexShader = (static_cast(decompilerContext->contextRegisters[mmVGT_PRIMITIVE_TYPE]) == LattePrimitiveMode::RECTS); + bool usesGeometryShader = UseGeometryShader(*decompilerContext->contextRegistersNew, decompilerContext->options->usesGeometryShader); - if (decompilerContext->shaderType == LatteConst::ShaderType::Vertex && (decompilerContext->options->usesGeometryShader || isRectVertexShader)) + if (decompilerContext->shaderType == LatteConst::ShaderType::Vertex && usesGeometryShader) decompilerContext->hasUniformVarBlock = true; // uf_verticesPerInstance } } diff --git a/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitMSL.cpp b/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitMSL.cpp index a2b0bc2d..a9f682a6 100644 --- a/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitMSL.cpp +++ b/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitMSL.cpp @@ -3933,8 +3933,8 @@ static void LatteDecompiler_emitAttributeImport(LatteDecompilerShaderContext* sh void LatteDecompiler_emitMSLShader(LatteDecompilerShaderContext* shaderContext, LatteDecompilerShader* shader) { - bool isRectVertexShader = (static_cast(shaderContext->contextRegisters[mmVGT_PRIMITIVE_TYPE]) == LattePrimitiveMode::RECTS); - bool usesGeometryShader = (shaderContext->options->usesGeometryShader || isRectVertexShader); + bool isRectVertexShader = UseRectEmulation(*shaderContext->contextRegistersNew); + bool usesGeometryShader = UseGeometryShader(*shaderContext->contextRegistersNew, shaderContext->options->usesGeometryShader); bool fetchVertexManually = (usesGeometryShader || (shaderContext->fetchShader && shaderContext->fetchShader->mtlFetchVertexManually)); // Rasterization @@ -3953,7 +3953,7 @@ void LatteDecompiler_emitMSLShader(LatteDecompilerShaderContext* shaderContext, src->add("#include " _CRLF); src->add("using namespace metal;" _CRLF); // header part (definitions for inputs and outputs) - LatteDecompiler::emitHeader(shaderContext, isRectVertexShader, fetchVertexManually, rasterizationEnabled); + LatteDecompiler::emitHeader(shaderContext, isRectVertexShader, usesGeometryShader, fetchVertexManually, rasterizationEnabled); // helper functions LatteDecompiler_emitHelperFunctions(shaderContext, src); const char* functionType = ""; @@ -4131,7 +4131,7 @@ void LatteDecompiler_emitMSLShader(LatteDecompilerShaderContext* shaderContext, } // start of main src->addFmt("{} {} main0(", functionType, outputTypeName); - LatteDecompiler::emitInputs(shaderContext, isRectVertexShader, fetchVertexManually); + LatteDecompiler::emitInputs(shaderContext, isRectVertexShader, usesGeometryShader, fetchVertexManually); src->add(") {" _CRLF); if (fetchVertexManually && (shader->shaderType == LatteConst::ShaderType::Vertex || shader->shaderType == LatteConst::ShaderType::Geometry)) { diff --git a/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitMSLHeader.hpp b/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitMSLHeader.hpp index 96797699..475ec0da 100644 --- a/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitMSLHeader.hpp +++ b/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitMSLHeader.hpp @@ -6,7 +6,7 @@ namespace LatteDecompiler { - static void _emitUniformVariables(LatteDecompilerShaderContext* decompilerContext, bool isRectVertexShader) + static void _emitUniformVariables(LatteDecompilerShaderContext* decompilerContext, bool usesGeometryShader) { auto src = decompilerContext->shaderSource; @@ -87,7 +87,7 @@ namespace LatteDecompiler } // define verticesPerInstance + streamoutBufferBaseX if ((shader->shaderType == LatteConst::ShaderType::Vertex && - (decompilerContext->options->usesGeometryShader || isRectVertexShader)) || + usesGeometryShader) || (decompilerContext->analyzer.useSSBOForStreamout && (shader->shaderType == LatteConst::ShaderType::Vertex && !decompilerContext->options->usesGeometryShader) || (shader->shaderType == LatteConst::ShaderType::Geometry))) @@ -270,7 +270,7 @@ namespace LatteDecompiler src->add("};" _CRLF _CRLF); } - static void _emitInputsAndOutputs(LatteDecompilerShaderContext* decompilerContext, bool isRectVertexShader, bool fetchVertexManually, bool rasterizationEnabled) + static void _emitInputsAndOutputs(LatteDecompilerShaderContext* decompilerContext, bool isRectVertexShader, bool usesGeometryShader, bool fetchVertexManually, bool rasterizationEnabled) { auto src = decompilerContext->shaderSource; @@ -304,7 +304,7 @@ namespace LatteDecompiler src->add("};" _CRLF _CRLF); } - if (!decompilerContext->options->usesGeometryShader) + if (!usesGeometryShader || isRectVertexShader) { if (decompilerContext->shaderType == LatteConst::ShaderType::Vertex && rasterizationEnabled) _emitVSOutputs(decompilerContext, isRectVertexShader); @@ -357,11 +357,11 @@ namespace LatteDecompiler } } - static void emitHeader(LatteDecompilerShaderContext* decompilerContext, bool isRectVertexShader, bool fetchVertexManually, bool rasterizationEnabled) + static void emitHeader(LatteDecompilerShaderContext* decompilerContext, bool isRectVertexShader, bool usesGeometryShader, bool fetchVertexManually, bool rasterizationEnabled) { auto src = decompilerContext->shaderSource; - if ((decompilerContext->options->usesGeometryShader || isRectVertexShader) && (decompilerContext->shaderType == LatteConst::ShaderType::Vertex || decompilerContext->shaderType == LatteConst::ShaderType::Geometry)) + if (usesGeometryShader && (decompilerContext->shaderType == LatteConst::ShaderType::Vertex || decompilerContext->shaderType == LatteConst::ShaderType::Geometry)) { LattePrimitiveMode vsOutPrimType = decompilerContext->contextRegistersNew->VGT_PRIMITIVE_TYPE.get_PRIMITIVE_MODE(); src->addFmt("#define VERTICES_PER_VERTEX_PRIMITIVE {}" _CRLF, GetVerticesPerPrimitive(vsOutPrimType)); @@ -399,11 +399,11 @@ namespace LatteDecompiler if(dump_shaders_enabled) decompilerContext->shaderSource->add("// start of shader inputs/outputs, predetermined by Cemu. Do not touch" _CRLF); // uniform variables - _emitUniformVariables(decompilerContext, isRectVertexShader); + _emitUniformVariables(decompilerContext, usesGeometryShader); // uniform buffers _emitUniformBuffers(decompilerContext); // inputs and outputs - _emitInputsAndOutputs(decompilerContext, isRectVertexShader, fetchVertexManually, rasterizationEnabled); + _emitInputsAndOutputs(decompilerContext, isRectVertexShader, usesGeometryShader, fetchVertexManually, rasterizationEnabled); if (dump_shaders_enabled) decompilerContext->shaderSource->add("// end of shader inputs/outputs" _CRLF); @@ -491,14 +491,14 @@ namespace LatteDecompiler } } - static void emitInputs(LatteDecompilerShaderContext* decompilerContext, bool isRectVertexShader, bool fetchVertexManually) + static void emitInputs(LatteDecompilerShaderContext* decompilerContext, bool isRectVertexShader, bool usesGeometryShader, bool fetchVertexManually) { auto src = decompilerContext->shaderSource; switch (decompilerContext->shaderType) { case LatteConst::ShaderType::Vertex: - if (decompilerContext->options->usesGeometryShader || isRectVertexShader) + if (usesGeometryShader) { src->add("object_data ObjectPayload& objectPayload [[payload]]"); src->add(", mesh_grid_properties meshGridProperties"); diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalCommon.h b/src/Cafe/HW/Latte/Renderer/Metal/MetalCommon.h index b46978ec..d16c5597 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalCommon.h +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalCommon.h @@ -210,3 +210,12 @@ inline bool PrimitiveRequiresConnection(LattePrimitiveMode primitiveMode) else return false; } + +inline bool UseRectEmulation(const LatteContextRegister& lcr) { + const LattePrimitiveMode primitiveMode = lcr.VGT_PRIMITIVE_TYPE.get_PRIMITIVE_MODE(); + return (primitiveMode == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::RECTS); +} + +inline bool UseGeometryShader(const LatteContextRegister& lcr, bool hasGeometryShader) { + return hasGeometryShader || UseRectEmulation(lcr); +} diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCompiler.cpp b/src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCompiler.cpp index 1892c257..6193ab10 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCompiler.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCompiler.cpp @@ -283,16 +283,15 @@ MetalPipelineCompiler::~MetalPipelineCompiler() m_binaryArchiveURL->release(); */ - m_pipelineDescriptor->release(); + if (m_pipelineDescriptor) + m_pipelineDescriptor->release(); } void MetalPipelineCompiler::InitFromState(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* geometryShader, const LatteDecompilerShader* pixelShader, const MetalAttachmentsInfo& lastUsedAttachmentsInfo, const MetalAttachmentsInfo& activeAttachmentsInfo, const LatteContextRegister& lcr) { - // Check if the pipeline uses a geometry shader - const LattePrimitiveMode primitiveMode = static_cast(lcr.VGT_PRIMITIVE_TYPE.get_PRIMITIVE_MODE()); - bool isPrimitiveRect = (primitiveMode == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::RECTS); - - m_usesGeometryShader = (geometryShader != nullptr || isPrimitiveRect); + m_usesGeometryShader = UseGeometryShader(lcr, geometryShader != nullptr); + if (m_usesGeometryShader && !m_mtlr->SupportsMeshShaders()) + return; // Rasterization m_rasterizationEnabled = lcr.IsRasterizationEnabled(); @@ -301,7 +300,7 @@ void MetalPipelineCompiler::InitFromState(const LatteFetchShader* fetchShader, c m_vertexShaderMtl = static_cast(vertexShader->shader); if (geometryShader) m_geometryShaderMtl = static_cast(geometryShader->shader); - else if (isPrimitiveRect) + else if (UseRectEmulation(lcr)) m_geometryShaderMtl = rectsEmulationGS_generate(m_mtlr, vertexShader, lcr); else m_geometryShaderMtl = nullptr; @@ -315,6 +314,9 @@ void MetalPipelineCompiler::InitFromState(const LatteFetchShader* fetchShader, c bool MetalPipelineCompiler::Compile(bool forceCompile, bool isRenderThread, bool showInOverlay) { + if (m_usesGeometryShader && !m_mtlr->SupportsMeshShaders()) + return false; + if (forceCompile) { // if some shader stages are not compiled yet, compile them now diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCompiler.h b/src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCompiler.h index 5006ed59..4d21e53d 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCompiler.h +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCompiler.h @@ -30,7 +30,7 @@ private: bool m_usesGeometryShader; bool m_rasterizationEnabled; - NS::Object* m_pipelineDescriptor; + NS::Object* m_pipelineDescriptor = nullptr; void InitFromStateRender(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const class MetalAttachmentsInfo& lastUsedAttachmentsInfo, const class MetalAttachmentsInfo& activeAttachmentsInfo, const LatteContextRegister& lcr); diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp index 02bf91f8..90b852d7 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp @@ -21,7 +21,6 @@ #include "Cemu/Logging/CemuLogging.h" #include "Cafe/HW/Latte/Core/FetchShader.h" #include "Cafe/HW/Latte/Core/LatteConst.h" -#include "HW/Latte/Renderer/Metal/MetalCommon.h" #include "config/CemuConfig.h" #include "gui/guiWrapper.h" @@ -171,6 +170,7 @@ MetalRenderer::MetalRenderer() m_supportsFramebufferFetch = GetConfig().framebuffer_fetch.GetValue() ? m_device->supportsFamily(MTL::GPUFamilyApple2) : false; m_hasUnifiedMemory = m_device->hasUnifiedMemory(); m_supportsMetal3 = m_device->supportsFamily(MTL::GPUFamilyMetal3); + m_supportsMeshShaders = (m_supportsMetal3 && (m_vendor != GfxVendor::Intel || GetConfig().force_mesh_shaders.GetValue())); // Intel GPUs have issues with mesh shaders m_recommendedMaxVRAMUsage = m_device->recommendedMaxWorkingSetSize(); m_pixelFormatSupport = MetalPixelFormatSupport(m_device); @@ -1134,9 +1134,11 @@ void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 // Primitive type const LattePrimitiveMode primitiveMode = LatteGPUState.contextNew.VGT_PRIMITIVE_TYPE.get_PRIMITIVE_MODE(); auto mtlPrimitiveType = GetMtlPrimitiveType(primitiveMode); - bool isPrimitiveRect = (primitiveMode == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::RECTS); - bool usesGeometryShader = (geometryShader != nullptr || isPrimitiveRect); + bool usesGeometryShader = UseGeometryShader(LatteGPUState.contextNew, geometryShader != nullptr); + if (usesGeometryShader && !m_supportsMeshShaders) + return; + bool fetchVertexManually = (usesGeometryShader || fetchShader->mtlFetchVertexManually); // Index buffer @@ -1293,7 +1295,7 @@ void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 // todo - how does culling behave with rects? // right now we just assume that their winding is always CW - if (isPrimitiveRect) + if (primitiveMode == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::RECTS) { if (frontFace == Latte::LATTE_PA_SU_SC_MODE_CNTL::E_FRONTFACE::CW) cullFront = cullBack; @@ -1380,7 +1382,7 @@ void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 // Uniform buffers, textures and samplers BindStageResources(renderCommandEncoder, vertexShader, usesGeometryShader); - if (geometryShader) + if (usesGeometryShader && geometryShader) BindStageResources(renderCommandEncoder, geometryShader, usesGeometryShader); BindStageResources(renderCommandEncoder, pixelShader, usesGeometryShader); diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h index 6dc780d8..428284f2 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h @@ -6,7 +6,6 @@ #include "Cafe/HW/Latte/Renderer/Metal/MetalPerformanceMonitor.h" #include "Cafe/HW/Latte/Renderer/Metal/MetalOutputShaderCache.h" #include "Cafe/HW/Latte/Renderer/Metal/MetalAttachmentsInfo.h" -#include "Foundation/NSAutoreleasePool.hpp" enum MetalGeneralShaderType { @@ -385,6 +384,11 @@ public: return m_supportsMetal3; } + bool SupportsMeshShaders() const + { + return m_supportsMeshShaders; + } + //MTL::StorageMode GetOptimalTextureStorageMode() const //{ // return (m_isAppleGPU ? MTL::StorageModeShared : MTL::StorageModePrivate); @@ -483,6 +487,7 @@ private: bool m_supportsFramebufferFetch; bool m_hasUnifiedMemory; bool m_supportsMetal3; + bool m_supportsMeshShaders; uint32 m_recommendedMaxVRAMUsage; MetalPixelFormatSupport m_pixelFormatSupport; diff --git a/src/config/CemuConfig.cpp b/src/config/CemuConfig.cpp index 7542dc31..3878cb80 100644 --- a/src/config/CemuConfig.cpp +++ b/src/config/CemuConfig.cpp @@ -222,6 +222,7 @@ void CemuConfig::Load(XMLConfigParser& parser) fullscreen_scaling = graphic.get("FullscreenScaling", kKeepAspectRatio); async_compile = graphic.get("AsyncCompile", async_compile); vk_accurate_barriers = graphic.get("vkAccurateBarriers", true); // this used to be "VulkanAccurateBarriers" but because we changed the default to true in 1.27.1 the option name had to be changed + force_mesh_shaders = graphic.get("ForceMeshShaders", false); auto overlay_node = graphic.get("Overlay"); if(overlay_node.valid()) @@ -477,6 +478,7 @@ void CemuConfig::Save(XMLConfigParser& parser) graphic.set("mtlDevice", mtl_graphic_device_uuid); graphic.set("VSync", vsync); graphic.set("GX2DrawdoneSync", gx2drawdone_sync); + graphic.set("ForceMeshShaders", force_mesh_shaders); //graphic.set("PrecompiledShaders", precompiled_shaders.GetValue()); graphic.set("UpscaleFilter", upscale_filter); graphic.set("DownscaleFilter", downscale_filter); diff --git a/src/config/CemuConfig.h b/src/config/CemuConfig.h index e9fb225c..a931403d 100644 --- a/src/config/CemuConfig.h +++ b/src/config/CemuConfig.h @@ -494,6 +494,7 @@ struct CemuConfig ConfigValue gx2drawdone_sync { true }; ConfigValue render_upside_down{ false }; ConfigValue async_compile{ true }; + ConfigValue force_mesh_shaders{ false }; ConfigValue vk_accurate_barriers{ true }; diff --git a/src/gui/GeneralSettings2.cpp b/src/gui/GeneralSettings2.cpp index 31d16481..3d8e4c6a 100644 --- a/src/gui/GeneralSettings2.cpp +++ b/src/gui/GeneralSettings2.cpp @@ -367,6 +367,10 @@ wxPanel* GeneralSettings2::AddGraphicsPage(wxNotebook* notebook) m_gx2drawdone_sync->SetToolTip(_("If synchronization is requested by the game, the emulated CPU will wait for the GPU to finish all operations.\nThis is more accurate behavior, but may cause lower performance")); graphic_misc_row->Add(m_gx2drawdone_sync, 0, wxALL, 5); + m_force_mesh_shaders = new wxCheckBox(box, wxID_ANY, _("Force mesh shaders")); + m_force_mesh_shaders->SetToolTip(_("Force mesh shaders on all GPUs that support them. Mesh shaders are disabled by default on Intel GPUs due to potential stability issues")); + graphic_misc_row->Add(m_force_mesh_shaders, 0, wxALL, 5); + box_sizer->Add(graphic_misc_row, 1, wxEXPAND, 5); graphics_panel_sizer->Add(box_sizer, 0, wxEXPAND | wxALL, 5); } @@ -1100,6 +1104,7 @@ void GeneralSettings2::StoreConfig() config.vsync = m_vsync->GetSelection(); config.gx2drawdone_sync = m_gx2drawdone_sync->IsChecked(); + config.force_mesh_shaders = m_force_mesh_shaders->IsChecked(); config.async_compile = m_async_compile->IsChecked(); config.upscale_filter = m_upscale_filter->GetSelection(); @@ -1580,12 +1585,14 @@ void GeneralSettings2::HandleGraphicsApiSelection() m_gx2drawdone_sync->Enable(); m_async_compile->Disable(); + m_force_mesh_shaders->Disable(); } else if (m_graphic_api->GetSelection() == 1) { // Vulkan m_gx2drawdone_sync->Disable(); m_async_compile->Enable(); + m_force_mesh_shaders->Disable(); m_vsync->AppendString(_("Off")); m_vsync->AppendString(_("Double buffering")); @@ -1623,11 +1630,10 @@ void GeneralSettings2::HandleGraphicsApiSelection() // Metal m_gx2drawdone_sync->Disable(); m_async_compile->Enable(); + m_force_mesh_shaders->Enable(); - // TODO: vsync options m_vsync->AppendString(_("Off")); - m_vsync->AppendString(_("Double buffering")); - m_vsync->AppendString(_("Triple buffering")); + m_vsync->AppendString(_("On")); m_vsync->Select(selection); @@ -1708,6 +1714,7 @@ void GeneralSettings2::ApplyConfig() m_vsync->SetSelection(config.vsync); m_async_compile->SetValue(config.async_compile); m_gx2drawdone_sync->SetValue(config.gx2drawdone_sync); + m_force_mesh_shaders->SetValue(config.force_mesh_shaders); m_upscale_filter->SetSelection(config.upscale_filter); m_downscale_filter->SetSelection(config.downscale_filter); m_fullscreen_scaling->SetSelection(config.fullscreen_scaling); diff --git a/src/gui/GeneralSettings2.h b/src/gui/GeneralSettings2.h index 58459e95..0118359a 100644 --- a/src/gui/GeneralSettings2.h +++ b/src/gui/GeneralSettings2.h @@ -53,7 +53,7 @@ private: // Graphics wxChoice* m_graphic_api, * m_graphic_device; wxChoice* m_vsync; - wxCheckBox *m_async_compile, *m_gx2drawdone_sync; + wxCheckBox *m_async_compile, *m_gx2drawdone_sync, *m_force_mesh_shaders; wxRadioBox* m_upscale_filter, *m_downscale_filter, *m_fullscreen_scaling; wxChoice* m_overlay_position, *m_notification_position, *m_overlay_scale, *m_notification_scale; wxCheckBox* m_controller_profile_name, *m_controller_low_battery, *m_shader_compiling, *m_friends_data;