mirror of
https://github.com/cemu-project/Cemu.git
synced 2025-04-29 14:59:26 -04:00
Merge pull request #21 from SamoZ256/metal-mesh-shaders-check
Check for mesh shaders support
This commit is contained in:
commit
1367e11d26
14 changed files with 71 additions and 37 deletions
|
@ -258,6 +258,7 @@ void InfoLog_PrintActiveSettings()
|
||||||
else if (ActiveSettings::GetGraphicsAPI() == GraphicAPI::kMetal)
|
else if (ActiveSettings::GetGraphicsAPI() == GraphicAPI::kMetal)
|
||||||
{
|
{
|
||||||
cemuLog_log(LogType::Force, "Async compile: {}", GetConfig().async_compile.GetValue() ? "true" : "false");
|
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, "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, "Buffer cache type: {}", g_current_game_profile->GetBufferCacheMode());
|
||||||
cemuLog_log(LogType::Force, "Position invariance: {}", g_current_game_profile->GetPositionInvariance());
|
cemuLog_log(LogType::Force, "Position invariance: {}", g_current_game_profile->GetPositionInvariance());
|
||||||
|
|
|
@ -510,7 +510,7 @@ void LatteSHRC_UpdateVSBaseHash(uint8* vertexShaderPtr, uint32 vertexShaderSize,
|
||||||
vsHash += tmp;
|
vsHash += tmp;
|
||||||
|
|
||||||
auto primitiveType = LatteGPUState.contextNew.VGT_PRIMITIVE_TYPE.get_PRIMITIVE_MODE();
|
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)
|
if (primitiveType == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::RECTS)
|
||||||
{
|
{
|
||||||
vsHash += 13ULL;
|
vsHash += 13ULL;
|
||||||
|
@ -528,7 +528,9 @@ void LatteSHRC_UpdateVSBaseHash(uint8* vertexShaderPtr, uint32 vertexShaderSize,
|
||||||
#if ENABLE_METAL
|
#if ENABLE_METAL
|
||||||
if (g_renderer->GetType() == RendererAPI::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++)
|
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())
|
if (LatteGPUState.contextNew.IsRasterizationEnabled())
|
||||||
vsHash += 51ULL;
|
vsHash += 51ULL;
|
||||||
|
|
|
@ -10,6 +10,9 @@
|
||||||
#include "Cafe/HW/Latte/Renderer/Renderer.h"
|
#include "Cafe/HW/Latte/Renderer/Renderer.h"
|
||||||
#include "Common/MemPtr.h"
|
#include "Common/MemPtr.h"
|
||||||
#include "HW/Latte/ISA/LatteReg.h"
|
#include "HW/Latte/ISA/LatteReg.h"
|
||||||
|
#if ENABLE_METAL
|
||||||
|
#include "HW/Latte/Renderer/Metal/MetalCommon.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
// Defined in LatteTextureLegacy.cpp
|
// 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);
|
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)
|
if (g_renderer->GetType() == RendererAPI::Metal)
|
||||||
{
|
{
|
||||||
bool isRectVertexShader = (static_cast<LattePrimitiveMode>(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
|
decompilerContext->hasUniformVarBlock = true; // uf_verticesPerInstance
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3933,8 +3933,8 @@ static void LatteDecompiler_emitAttributeImport(LatteDecompilerShaderContext* sh
|
||||||
|
|
||||||
void LatteDecompiler_emitMSLShader(LatteDecompilerShaderContext* shaderContext, LatteDecompilerShader* shader)
|
void LatteDecompiler_emitMSLShader(LatteDecompilerShaderContext* shaderContext, LatteDecompilerShader* shader)
|
||||||
{
|
{
|
||||||
bool isRectVertexShader = (static_cast<LattePrimitiveMode>(shaderContext->contextRegisters[mmVGT_PRIMITIVE_TYPE]) == LattePrimitiveMode::RECTS);
|
bool isRectVertexShader = UseRectEmulation(*shaderContext->contextRegistersNew);
|
||||||
bool usesGeometryShader = (shaderContext->options->usesGeometryShader || isRectVertexShader);
|
bool usesGeometryShader = UseGeometryShader(*shaderContext->contextRegistersNew, shaderContext->options->usesGeometryShader);
|
||||||
bool fetchVertexManually = (usesGeometryShader || (shaderContext->fetchShader && shaderContext->fetchShader->mtlFetchVertexManually));
|
bool fetchVertexManually = (usesGeometryShader || (shaderContext->fetchShader && shaderContext->fetchShader->mtlFetchVertexManually));
|
||||||
|
|
||||||
// Rasterization
|
// Rasterization
|
||||||
|
@ -3953,7 +3953,7 @@ void LatteDecompiler_emitMSLShader(LatteDecompilerShaderContext* shaderContext,
|
||||||
src->add("#include <metal_stdlib>" _CRLF);
|
src->add("#include <metal_stdlib>" _CRLF);
|
||||||
src->add("using namespace metal;" _CRLF);
|
src->add("using namespace metal;" _CRLF);
|
||||||
// header part (definitions for inputs and outputs)
|
// header part (definitions for inputs and outputs)
|
||||||
LatteDecompiler::emitHeader(shaderContext, isRectVertexShader, fetchVertexManually, rasterizationEnabled);
|
LatteDecompiler::emitHeader(shaderContext, isRectVertexShader, usesGeometryShader, fetchVertexManually, rasterizationEnabled);
|
||||||
// helper functions
|
// helper functions
|
||||||
LatteDecompiler_emitHelperFunctions(shaderContext, src);
|
LatteDecompiler_emitHelperFunctions(shaderContext, src);
|
||||||
const char* functionType = "";
|
const char* functionType = "";
|
||||||
|
@ -4131,7 +4131,7 @@ void LatteDecompiler_emitMSLShader(LatteDecompilerShaderContext* shaderContext,
|
||||||
}
|
}
|
||||||
// start of main
|
// start of main
|
||||||
src->addFmt("{} {} main0(", functionType, outputTypeName);
|
src->addFmt("{} {} main0(", functionType, outputTypeName);
|
||||||
LatteDecompiler::emitInputs(shaderContext, isRectVertexShader, fetchVertexManually);
|
LatteDecompiler::emitInputs(shaderContext, isRectVertexShader, usesGeometryShader, fetchVertexManually);
|
||||||
src->add(") {" _CRLF);
|
src->add(") {" _CRLF);
|
||||||
if (fetchVertexManually && (shader->shaderType == LatteConst::ShaderType::Vertex || shader->shaderType == LatteConst::ShaderType::Geometry))
|
if (fetchVertexManually && (shader->shaderType == LatteConst::ShaderType::Vertex || shader->shaderType == LatteConst::ShaderType::Geometry))
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
namespace LatteDecompiler
|
namespace LatteDecompiler
|
||||||
{
|
{
|
||||||
static void _emitUniformVariables(LatteDecompilerShaderContext* decompilerContext, bool isRectVertexShader)
|
static void _emitUniformVariables(LatteDecompilerShaderContext* decompilerContext, bool usesGeometryShader)
|
||||||
{
|
{
|
||||||
auto src = decompilerContext->shaderSource;
|
auto src = decompilerContext->shaderSource;
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ namespace LatteDecompiler
|
||||||
}
|
}
|
||||||
// define verticesPerInstance + streamoutBufferBaseX
|
// define verticesPerInstance + streamoutBufferBaseX
|
||||||
if ((shader->shaderType == LatteConst::ShaderType::Vertex &&
|
if ((shader->shaderType == LatteConst::ShaderType::Vertex &&
|
||||||
(decompilerContext->options->usesGeometryShader || isRectVertexShader)) ||
|
usesGeometryShader) ||
|
||||||
(decompilerContext->analyzer.useSSBOForStreamout &&
|
(decompilerContext->analyzer.useSSBOForStreamout &&
|
||||||
(shader->shaderType == LatteConst::ShaderType::Vertex && !decompilerContext->options->usesGeometryShader) ||
|
(shader->shaderType == LatteConst::ShaderType::Vertex && !decompilerContext->options->usesGeometryShader) ||
|
||||||
(shader->shaderType == LatteConst::ShaderType::Geometry)))
|
(shader->shaderType == LatteConst::ShaderType::Geometry)))
|
||||||
|
@ -270,7 +270,7 @@ namespace LatteDecompiler
|
||||||
src->add("};" _CRLF _CRLF);
|
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;
|
auto src = decompilerContext->shaderSource;
|
||||||
|
|
||||||
|
@ -304,7 +304,7 @@ namespace LatteDecompiler
|
||||||
src->add("};" _CRLF _CRLF);
|
src->add("};" _CRLF _CRLF);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!decompilerContext->options->usesGeometryShader)
|
if (!usesGeometryShader || isRectVertexShader)
|
||||||
{
|
{
|
||||||
if (decompilerContext->shaderType == LatteConst::ShaderType::Vertex && rasterizationEnabled)
|
if (decompilerContext->shaderType == LatteConst::ShaderType::Vertex && rasterizationEnabled)
|
||||||
_emitVSOutputs(decompilerContext, isRectVertexShader);
|
_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;
|
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();
|
LattePrimitiveMode vsOutPrimType = decompilerContext->contextRegistersNew->VGT_PRIMITIVE_TYPE.get_PRIMITIVE_MODE();
|
||||||
src->addFmt("#define VERTICES_PER_VERTEX_PRIMITIVE {}" _CRLF, GetVerticesPerPrimitive(vsOutPrimType));
|
src->addFmt("#define VERTICES_PER_VERTEX_PRIMITIVE {}" _CRLF, GetVerticesPerPrimitive(vsOutPrimType));
|
||||||
|
@ -399,11 +399,11 @@ namespace LatteDecompiler
|
||||||
if(dump_shaders_enabled)
|
if(dump_shaders_enabled)
|
||||||
decompilerContext->shaderSource->add("// start of shader inputs/outputs, predetermined by Cemu. Do not touch" _CRLF);
|
decompilerContext->shaderSource->add("// start of shader inputs/outputs, predetermined by Cemu. Do not touch" _CRLF);
|
||||||
// uniform variables
|
// uniform variables
|
||||||
_emitUniformVariables(decompilerContext, isRectVertexShader);
|
_emitUniformVariables(decompilerContext, usesGeometryShader);
|
||||||
// uniform buffers
|
// uniform buffers
|
||||||
_emitUniformBuffers(decompilerContext);
|
_emitUniformBuffers(decompilerContext);
|
||||||
// inputs and outputs
|
// inputs and outputs
|
||||||
_emitInputsAndOutputs(decompilerContext, isRectVertexShader, fetchVertexManually, rasterizationEnabled);
|
_emitInputsAndOutputs(decompilerContext, isRectVertexShader, usesGeometryShader, fetchVertexManually, rasterizationEnabled);
|
||||||
|
|
||||||
if (dump_shaders_enabled)
|
if (dump_shaders_enabled)
|
||||||
decompilerContext->shaderSource->add("// end of shader inputs/outputs" _CRLF);
|
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;
|
auto src = decompilerContext->shaderSource;
|
||||||
|
|
||||||
switch (decompilerContext->shaderType)
|
switch (decompilerContext->shaderType)
|
||||||
{
|
{
|
||||||
case LatteConst::ShaderType::Vertex:
|
case LatteConst::ShaderType::Vertex:
|
||||||
if (decompilerContext->options->usesGeometryShader || isRectVertexShader)
|
if (usesGeometryShader)
|
||||||
{
|
{
|
||||||
src->add("object_data ObjectPayload& objectPayload [[payload]]");
|
src->add("object_data ObjectPayload& objectPayload [[payload]]");
|
||||||
src->add(", mesh_grid_properties meshGridProperties");
|
src->add(", mesh_grid_properties meshGridProperties");
|
||||||
|
|
|
@ -210,3 +210,12 @@ inline bool PrimitiveRequiresConnection(LattePrimitiveMode primitiveMode)
|
||||||
else
|
else
|
||||||
return false;
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -283,16 +283,15 @@ MetalPipelineCompiler::~MetalPipelineCompiler()
|
||||||
|
|
||||||
m_binaryArchiveURL->release();
|
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)
|
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
|
m_usesGeometryShader = UseGeometryShader(lcr, geometryShader != nullptr);
|
||||||
const LattePrimitiveMode primitiveMode = static_cast<LattePrimitiveMode>(lcr.VGT_PRIMITIVE_TYPE.get_PRIMITIVE_MODE());
|
if (m_usesGeometryShader && !m_mtlr->SupportsMeshShaders())
|
||||||
bool isPrimitiveRect = (primitiveMode == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::RECTS);
|
return;
|
||||||
|
|
||||||
m_usesGeometryShader = (geometryShader != nullptr || isPrimitiveRect);
|
|
||||||
|
|
||||||
// Rasterization
|
// Rasterization
|
||||||
m_rasterizationEnabled = lcr.IsRasterizationEnabled();
|
m_rasterizationEnabled = lcr.IsRasterizationEnabled();
|
||||||
|
@ -301,7 +300,7 @@ void MetalPipelineCompiler::InitFromState(const LatteFetchShader* fetchShader, c
|
||||||
m_vertexShaderMtl = static_cast<RendererShaderMtl*>(vertexShader->shader);
|
m_vertexShaderMtl = static_cast<RendererShaderMtl*>(vertexShader->shader);
|
||||||
if (geometryShader)
|
if (geometryShader)
|
||||||
m_geometryShaderMtl = static_cast<RendererShaderMtl*>(geometryShader->shader);
|
m_geometryShaderMtl = static_cast<RendererShaderMtl*>(geometryShader->shader);
|
||||||
else if (isPrimitiveRect)
|
else if (UseRectEmulation(lcr))
|
||||||
m_geometryShaderMtl = rectsEmulationGS_generate(m_mtlr, vertexShader, lcr);
|
m_geometryShaderMtl = rectsEmulationGS_generate(m_mtlr, vertexShader, lcr);
|
||||||
else
|
else
|
||||||
m_geometryShaderMtl = nullptr;
|
m_geometryShaderMtl = nullptr;
|
||||||
|
@ -315,6 +314,9 @@ void MetalPipelineCompiler::InitFromState(const LatteFetchShader* fetchShader, c
|
||||||
|
|
||||||
bool MetalPipelineCompiler::Compile(bool forceCompile, bool isRenderThread, bool showInOverlay)
|
bool MetalPipelineCompiler::Compile(bool forceCompile, bool isRenderThread, bool showInOverlay)
|
||||||
{
|
{
|
||||||
|
if (m_usesGeometryShader && !m_mtlr->SupportsMeshShaders())
|
||||||
|
return false;
|
||||||
|
|
||||||
if (forceCompile)
|
if (forceCompile)
|
||||||
{
|
{
|
||||||
// if some shader stages are not compiled yet, compile them now
|
// if some shader stages are not compiled yet, compile them now
|
||||||
|
|
|
@ -30,7 +30,7 @@ private:
|
||||||
bool m_usesGeometryShader;
|
bool m_usesGeometryShader;
|
||||||
bool m_rasterizationEnabled;
|
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);
|
void InitFromStateRender(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const class MetalAttachmentsInfo& lastUsedAttachmentsInfo, const class MetalAttachmentsInfo& activeAttachmentsInfo, const LatteContextRegister& lcr);
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
#include "Cemu/Logging/CemuLogging.h"
|
#include "Cemu/Logging/CemuLogging.h"
|
||||||
#include "Cafe/HW/Latte/Core/FetchShader.h"
|
#include "Cafe/HW/Latte/Core/FetchShader.h"
|
||||||
#include "Cafe/HW/Latte/Core/LatteConst.h"
|
#include "Cafe/HW/Latte/Core/LatteConst.h"
|
||||||
#include "HW/Latte/Renderer/Metal/MetalCommon.h"
|
|
||||||
#include "config/CemuConfig.h"
|
#include "config/CemuConfig.h"
|
||||||
#include "gui/guiWrapper.h"
|
#include "gui/guiWrapper.h"
|
||||||
|
|
||||||
|
@ -171,6 +170,7 @@ MetalRenderer::MetalRenderer()
|
||||||
m_supportsFramebufferFetch = GetConfig().framebuffer_fetch.GetValue() ? m_device->supportsFamily(MTL::GPUFamilyApple2) : false;
|
m_supportsFramebufferFetch = GetConfig().framebuffer_fetch.GetValue() ? m_device->supportsFamily(MTL::GPUFamilyApple2) : false;
|
||||||
m_hasUnifiedMemory = m_device->hasUnifiedMemory();
|
m_hasUnifiedMemory = m_device->hasUnifiedMemory();
|
||||||
m_supportsMetal3 = m_device->supportsFamily(MTL::GPUFamilyMetal3);
|
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_recommendedMaxVRAMUsage = m_device->recommendedMaxWorkingSetSize();
|
||||||
m_pixelFormatSupport = MetalPixelFormatSupport(m_device);
|
m_pixelFormatSupport = MetalPixelFormatSupport(m_device);
|
||||||
|
|
||||||
|
@ -1134,9 +1134,11 @@ void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32
|
||||||
// Primitive type
|
// Primitive type
|
||||||
const LattePrimitiveMode primitiveMode = LatteGPUState.contextNew.VGT_PRIMITIVE_TYPE.get_PRIMITIVE_MODE();
|
const LattePrimitiveMode primitiveMode = LatteGPUState.contextNew.VGT_PRIMITIVE_TYPE.get_PRIMITIVE_MODE();
|
||||||
auto mtlPrimitiveType = GetMtlPrimitiveType(primitiveMode);
|
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);
|
bool fetchVertexManually = (usesGeometryShader || fetchShader->mtlFetchVertexManually);
|
||||||
|
|
||||||
// Index buffer
|
// Index buffer
|
||||||
|
@ -1293,7 +1295,7 @@ void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32
|
||||||
|
|
||||||
// todo - how does culling behave with rects?
|
// todo - how does culling behave with rects?
|
||||||
// right now we just assume that their winding is always CW
|
// 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)
|
if (frontFace == Latte::LATTE_PA_SU_SC_MODE_CNTL::E_FRONTFACE::CW)
|
||||||
cullFront = cullBack;
|
cullFront = cullBack;
|
||||||
|
@ -1380,7 +1382,7 @@ void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32
|
||||||
|
|
||||||
// Uniform buffers, textures and samplers
|
// Uniform buffers, textures and samplers
|
||||||
BindStageResources(renderCommandEncoder, vertexShader, usesGeometryShader);
|
BindStageResources(renderCommandEncoder, vertexShader, usesGeometryShader);
|
||||||
if (geometryShader)
|
if (usesGeometryShader && geometryShader)
|
||||||
BindStageResources(renderCommandEncoder, geometryShader, usesGeometryShader);
|
BindStageResources(renderCommandEncoder, geometryShader, usesGeometryShader);
|
||||||
BindStageResources(renderCommandEncoder, pixelShader, usesGeometryShader);
|
BindStageResources(renderCommandEncoder, pixelShader, usesGeometryShader);
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
#include "Cafe/HW/Latte/Renderer/Metal/MetalPerformanceMonitor.h"
|
#include "Cafe/HW/Latte/Renderer/Metal/MetalPerformanceMonitor.h"
|
||||||
#include "Cafe/HW/Latte/Renderer/Metal/MetalOutputShaderCache.h"
|
#include "Cafe/HW/Latte/Renderer/Metal/MetalOutputShaderCache.h"
|
||||||
#include "Cafe/HW/Latte/Renderer/Metal/MetalAttachmentsInfo.h"
|
#include "Cafe/HW/Latte/Renderer/Metal/MetalAttachmentsInfo.h"
|
||||||
#include "Foundation/NSAutoreleasePool.hpp"
|
|
||||||
|
|
||||||
enum MetalGeneralShaderType
|
enum MetalGeneralShaderType
|
||||||
{
|
{
|
||||||
|
@ -385,6 +384,11 @@ public:
|
||||||
return m_supportsMetal3;
|
return m_supportsMetal3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SupportsMeshShaders() const
|
||||||
|
{
|
||||||
|
return m_supportsMeshShaders;
|
||||||
|
}
|
||||||
|
|
||||||
//MTL::StorageMode GetOptimalTextureStorageMode() const
|
//MTL::StorageMode GetOptimalTextureStorageMode() const
|
||||||
//{
|
//{
|
||||||
// return (m_isAppleGPU ? MTL::StorageModeShared : MTL::StorageModePrivate);
|
// return (m_isAppleGPU ? MTL::StorageModeShared : MTL::StorageModePrivate);
|
||||||
|
@ -483,6 +487,7 @@ private:
|
||||||
bool m_supportsFramebufferFetch;
|
bool m_supportsFramebufferFetch;
|
||||||
bool m_hasUnifiedMemory;
|
bool m_hasUnifiedMemory;
|
||||||
bool m_supportsMetal3;
|
bool m_supportsMetal3;
|
||||||
|
bool m_supportsMeshShaders;
|
||||||
uint32 m_recommendedMaxVRAMUsage;
|
uint32 m_recommendedMaxVRAMUsage;
|
||||||
MetalPixelFormatSupport m_pixelFormatSupport;
|
MetalPixelFormatSupport m_pixelFormatSupport;
|
||||||
|
|
||||||
|
|
|
@ -222,6 +222,7 @@ void CemuConfig::Load(XMLConfigParser& parser)
|
||||||
fullscreen_scaling = graphic.get("FullscreenScaling", kKeepAspectRatio);
|
fullscreen_scaling = graphic.get("FullscreenScaling", kKeepAspectRatio);
|
||||||
async_compile = graphic.get("AsyncCompile", async_compile);
|
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
|
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");
|
auto overlay_node = graphic.get("Overlay");
|
||||||
if(overlay_node.valid())
|
if(overlay_node.valid())
|
||||||
|
@ -477,6 +478,7 @@ void CemuConfig::Save(XMLConfigParser& parser)
|
||||||
graphic.set("mtlDevice", mtl_graphic_device_uuid);
|
graphic.set("mtlDevice", mtl_graphic_device_uuid);
|
||||||
graphic.set("VSync", vsync);
|
graphic.set("VSync", vsync);
|
||||||
graphic.set("GX2DrawdoneSync", gx2drawdone_sync);
|
graphic.set("GX2DrawdoneSync", gx2drawdone_sync);
|
||||||
|
graphic.set("ForceMeshShaders", force_mesh_shaders);
|
||||||
//graphic.set("PrecompiledShaders", precompiled_shaders.GetValue());
|
//graphic.set("PrecompiledShaders", precompiled_shaders.GetValue());
|
||||||
graphic.set("UpscaleFilter", upscale_filter);
|
graphic.set("UpscaleFilter", upscale_filter);
|
||||||
graphic.set("DownscaleFilter", downscale_filter);
|
graphic.set("DownscaleFilter", downscale_filter);
|
||||||
|
|
|
@ -494,6 +494,7 @@ struct CemuConfig
|
||||||
ConfigValue<bool> gx2drawdone_sync { true };
|
ConfigValue<bool> gx2drawdone_sync { true };
|
||||||
ConfigValue<bool> render_upside_down{ false };
|
ConfigValue<bool> render_upside_down{ false };
|
||||||
ConfigValue<bool> async_compile{ true };
|
ConfigValue<bool> async_compile{ true };
|
||||||
|
ConfigValue<bool> force_mesh_shaders{ false };
|
||||||
|
|
||||||
ConfigValue<bool> vk_accurate_barriers{ true };
|
ConfigValue<bool> vk_accurate_barriers{ true };
|
||||||
|
|
||||||
|
|
|
@ -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"));
|
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);
|
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);
|
box_sizer->Add(graphic_misc_row, 1, wxEXPAND, 5);
|
||||||
graphics_panel_sizer->Add(box_sizer, 0, wxEXPAND | wxALL, 5);
|
graphics_panel_sizer->Add(box_sizer, 0, wxEXPAND | wxALL, 5);
|
||||||
}
|
}
|
||||||
|
@ -1100,6 +1104,7 @@ void GeneralSettings2::StoreConfig()
|
||||||
|
|
||||||
config.vsync = m_vsync->GetSelection();
|
config.vsync = m_vsync->GetSelection();
|
||||||
config.gx2drawdone_sync = m_gx2drawdone_sync->IsChecked();
|
config.gx2drawdone_sync = m_gx2drawdone_sync->IsChecked();
|
||||||
|
config.force_mesh_shaders = m_force_mesh_shaders->IsChecked();
|
||||||
config.async_compile = m_async_compile->IsChecked();
|
config.async_compile = m_async_compile->IsChecked();
|
||||||
|
|
||||||
config.upscale_filter = m_upscale_filter->GetSelection();
|
config.upscale_filter = m_upscale_filter->GetSelection();
|
||||||
|
@ -1580,12 +1585,14 @@ void GeneralSettings2::HandleGraphicsApiSelection()
|
||||||
|
|
||||||
m_gx2drawdone_sync->Enable();
|
m_gx2drawdone_sync->Enable();
|
||||||
m_async_compile->Disable();
|
m_async_compile->Disable();
|
||||||
|
m_force_mesh_shaders->Disable();
|
||||||
}
|
}
|
||||||
else if (m_graphic_api->GetSelection() == 1)
|
else if (m_graphic_api->GetSelection() == 1)
|
||||||
{
|
{
|
||||||
// Vulkan
|
// Vulkan
|
||||||
m_gx2drawdone_sync->Disable();
|
m_gx2drawdone_sync->Disable();
|
||||||
m_async_compile->Enable();
|
m_async_compile->Enable();
|
||||||
|
m_force_mesh_shaders->Disable();
|
||||||
|
|
||||||
m_vsync->AppendString(_("Off"));
|
m_vsync->AppendString(_("Off"));
|
||||||
m_vsync->AppendString(_("Double buffering"));
|
m_vsync->AppendString(_("Double buffering"));
|
||||||
|
@ -1623,11 +1630,10 @@ void GeneralSettings2::HandleGraphicsApiSelection()
|
||||||
// Metal
|
// Metal
|
||||||
m_gx2drawdone_sync->Disable();
|
m_gx2drawdone_sync->Disable();
|
||||||
m_async_compile->Enable();
|
m_async_compile->Enable();
|
||||||
|
m_force_mesh_shaders->Enable();
|
||||||
|
|
||||||
// TODO: vsync options
|
|
||||||
m_vsync->AppendString(_("Off"));
|
m_vsync->AppendString(_("Off"));
|
||||||
m_vsync->AppendString(_("Double buffering"));
|
m_vsync->AppendString(_("On"));
|
||||||
m_vsync->AppendString(_("Triple buffering"));
|
|
||||||
|
|
||||||
m_vsync->Select(selection);
|
m_vsync->Select(selection);
|
||||||
|
|
||||||
|
@ -1708,6 +1714,7 @@ void GeneralSettings2::ApplyConfig()
|
||||||
m_vsync->SetSelection(config.vsync);
|
m_vsync->SetSelection(config.vsync);
|
||||||
m_async_compile->SetValue(config.async_compile);
|
m_async_compile->SetValue(config.async_compile);
|
||||||
m_gx2drawdone_sync->SetValue(config.gx2drawdone_sync);
|
m_gx2drawdone_sync->SetValue(config.gx2drawdone_sync);
|
||||||
|
m_force_mesh_shaders->SetValue(config.force_mesh_shaders);
|
||||||
m_upscale_filter->SetSelection(config.upscale_filter);
|
m_upscale_filter->SetSelection(config.upscale_filter);
|
||||||
m_downscale_filter->SetSelection(config.downscale_filter);
|
m_downscale_filter->SetSelection(config.downscale_filter);
|
||||||
m_fullscreen_scaling->SetSelection(config.fullscreen_scaling);
|
m_fullscreen_scaling->SetSelection(config.fullscreen_scaling);
|
||||||
|
|
|
@ -53,7 +53,7 @@ private:
|
||||||
// Graphics
|
// Graphics
|
||||||
wxChoice* m_graphic_api, * m_graphic_device;
|
wxChoice* m_graphic_api, * m_graphic_device;
|
||||||
wxChoice* m_vsync;
|
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;
|
wxRadioBox* m_upscale_filter, *m_downscale_filter, *m_fullscreen_scaling;
|
||||||
wxChoice* m_overlay_position, *m_notification_position, *m_overlay_scale, *m_notification_scale;
|
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;
|
wxCheckBox* m_controller_profile_name, *m_controller_low_battery, *m_shader_compiling, *m_friends_data;
|
||||||
|
|
Loading…
Add table
Reference in a new issue