mirror of
https://github.com/cemu-project/Cemu.git
synced 2024-11-29 12:34:17 +01:00
draw with geometry shaders
This commit is contained in:
parent
2f4ceb33e0
commit
97f441ecf1
@ -2822,7 +2822,7 @@ static void _emitGSReadInputVFetchCode(LatteDecompilerShaderContext* shaderConte
|
||||
|
||||
src->add(" = ");
|
||||
_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, shaderContext->typeTracker.defaultDataType);
|
||||
src->add("(in[");
|
||||
src->add("(objectPayload.vertexOut[");
|
||||
if (texInstruction->textureFetch.srcSel[0] >= 4)
|
||||
cemu_assert_unimplemented();
|
||||
if (texInstruction->textureFetch.srcSel[1] >= 4)
|
||||
@ -3871,7 +3871,7 @@ void LatteDecompiler_emitMSLShader(LatteDecompilerShaderContext* shaderContext,
|
||||
src->addFmt("{} {} main0(", functionType, outputTypeName);
|
||||
LatteDecompiler::emitInputs(shaderContext);
|
||||
src->add(") {" _CRLF);
|
||||
if (shaderContext->options->usesGeometryShader)
|
||||
if (shaderContext->options->usesGeometryShader && (shader->shaderType == LatteConst::ShaderType::Vertex || shader->shaderType == LatteConst::ShaderType::Geometry))
|
||||
{
|
||||
if (shader->shaderType == LatteConst::ShaderType::Vertex)
|
||||
{
|
||||
@ -3884,10 +3884,8 @@ void LatteDecompiler_emitMSLShader(LatteDecompilerShaderContext* shaderContext,
|
||||
// Output is defined as object payload
|
||||
src->add("object_data VertexOut& out = objectPayload.vertexOut[tid];" _CRLF);
|
||||
}
|
||||
else
|
||||
else if (shader->shaderType == LatteConst::ShaderType::Geometry)
|
||||
{
|
||||
// Input is defined as object payload
|
||||
src->add("object_data VertexOut* in = objectPayload.vertexOut;" _CRLF);
|
||||
src->add("GeometryOut out;" _CRLF);
|
||||
// The index of the current vertex that is being emitted
|
||||
src->add("uint vertexIndex = 0;" _CRLF);
|
||||
@ -4093,9 +4091,9 @@ void LatteDecompiler_emitMSLShader(LatteDecompilerShaderContext* shaderContext,
|
||||
{
|
||||
// import from geometry shader
|
||||
if (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)
|
||||
src->addFmt("{} = asy_type<int4>(passParameterSem{});" _CRLF, _getRegisterVarName(shaderContext, gprIndex), psInputSemanticId & 0x7F);
|
||||
src->addFmt("{} = as_type<int4>(in.passParameterSem{});" _CRLF, _getRegisterVarName(shaderContext, gprIndex), psInputSemanticId & 0x7F);
|
||||
else if (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_FLOAT)
|
||||
src->addFmt("{} = passParameterSem{};" _CRLF, _getRegisterVarName(shaderContext, gprIndex), psInputSemanticId & 0x7F);
|
||||
src->addFmt("{} = in.passParameterSem{};" _CRLF, _getRegisterVarName(shaderContext, gprIndex), psInputSemanticId & 0x7F);
|
||||
else
|
||||
cemu_assert_unimplemented();
|
||||
}
|
||||
@ -4137,7 +4135,7 @@ void LatteDecompiler_emitMSLShader(LatteDecompilerShaderContext* shaderContext,
|
||||
src->add("out.pointSize = supportBuffer.pointSize;" _CRLF);
|
||||
}
|
||||
|
||||
if (shaderContext->options->usesGeometryShader)
|
||||
if (shaderContext->options->usesGeometryShader && (shader->shaderType == LatteConst::ShaderType::Vertex || shader->shaderType == LatteConst::ShaderType::Geometry))
|
||||
{
|
||||
if (shader->shaderType == LatteConst::ShaderType::Vertex)
|
||||
{
|
||||
|
@ -325,7 +325,7 @@ namespace LatteDecompiler
|
||||
{
|
||||
if (decompilerContext->parsedGSCopyShader->paramMapping[p].exportType != 2)
|
||||
continue;
|
||||
src->addFmt("float4 passParameterSem{} [[user(locn)]];" _CRLF, (sint32)decompilerContext->parsedGSCopyShader->paramMapping[p].exportParam, decompilerContext->parsedGSCopyShader->paramMapping[p].exportParam & 0x7F);
|
||||
src->addFmt("float4 passParameterSem{} [[user(locn{})]];" _CRLF, (sint32)decompilerContext->parsedGSCopyShader->paramMapping[p].exportParam, decompilerContext->parsedGSCopyShader->paramMapping[p].exportParam & 0x7F);
|
||||
}
|
||||
src->add("};" _CRLF _CRLF);
|
||||
|
||||
@ -345,9 +345,9 @@ namespace LatteDecompiler
|
||||
{
|
||||
src->add("#if PRIMITIVE_TYPE == point" _CRLF);
|
||||
src->add("#define VERTICES_PER_PRIMITIVE 1" _CRLF);
|
||||
src->add("#if PRIMITIVE_TYPE == line" _CRLF);
|
||||
src->add("#elif PRIMITIVE_TYPE == line" _CRLF);
|
||||
src->add("#define VERTICES_PER_PRIMITIVE 2" _CRLF);
|
||||
src->add("#if PRIMITIVE_TYPE == triangle" _CRLF);
|
||||
src->add("#elif PRIMITIVE_TYPE == triangle" _CRLF);
|
||||
src->add("#define VERTICES_PER_PRIMITIVE 3" _CRLF);
|
||||
src->add("#else" _CRLF);
|
||||
src->add("#error unsupported primitive type" _CRLF);
|
||||
@ -462,7 +462,7 @@ namespace LatteDecompiler
|
||||
src->add(", mesh_grid_properties meshGridProperties");
|
||||
src->add(", uint tig [[threadgroup_position_in_grid]]");
|
||||
src->add(", uint tid [[thread_index_in_threadgroup]]");
|
||||
src->add(", VERTEX_BUFFER_DEFINITIONS");
|
||||
src->add(" VERTEX_BUFFER_DEFINITIONS");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -9,6 +9,8 @@
|
||||
|
||||
#include "HW/Latte/Core/FetchShader.h"
|
||||
#include "HW/Latte/ISA/RegDefines.h"
|
||||
#include "Metal/MTLDevice.hpp"
|
||||
#include "Metal/MTLRenderPipeline.hpp"
|
||||
#include "config/ActiveSettings.h"
|
||||
|
||||
#define INVALID_TITLE_ID 0xFFFFFFFFFFFFFFFF
|
||||
@ -18,6 +20,68 @@ uint64 s_cacheTitleId = INVALID_TITLE_ID;
|
||||
extern std::atomic_int g_compiled_shaders_total;
|
||||
extern std::atomic_int g_compiled_shaders_async;
|
||||
|
||||
template<typename T>
|
||||
void SetFragmentState(T* desc, class CachedFBOMtl* activeFBO, const LatteContextRegister& lcr)
|
||||
{
|
||||
// Color attachments
|
||||
const Latte::LATTE_CB_COLOR_CONTROL& colorControlReg = lcr.CB_COLOR_CONTROL;
|
||||
uint32 blendEnableMask = colorControlReg.get_BLEND_MASK();
|
||||
uint32 renderTargetMask = lcr.CB_TARGET_MASK.get_MASK();
|
||||
for (uint8 i = 0; i < 8; i++)
|
||||
{
|
||||
const auto& colorBuffer = activeFBO->colorBuffer[i];
|
||||
auto texture = static_cast<LatteTextureViewMtl*>(colorBuffer.texture);
|
||||
if (!texture)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
auto colorAttachment = desc->colorAttachments()->object(i);
|
||||
colorAttachment->setPixelFormat(texture->GetRGBAView()->pixelFormat());
|
||||
colorAttachment->setWriteMask(GetMtlColorWriteMask((renderTargetMask >> (i * 4)) & 0xF));
|
||||
|
||||
// Blending
|
||||
bool blendEnabled = ((blendEnableMask & (1 << i))) != 0;
|
||||
// Only float data type is blendable
|
||||
if (blendEnabled && GetMtlPixelFormatInfo(texture->format, false).dataType == MetalDataType::FLOAT)
|
||||
{
|
||||
colorAttachment->setBlendingEnabled(true);
|
||||
|
||||
const auto& blendControlReg = lcr.CB_BLENDN_CONTROL[i];
|
||||
|
||||
auto rgbBlendOp = GetMtlBlendOp(blendControlReg.get_COLOR_COMB_FCN());
|
||||
auto srcRgbBlendFactor = GetMtlBlendFactor(blendControlReg.get_COLOR_SRCBLEND());
|
||||
auto dstRgbBlendFactor = GetMtlBlendFactor(blendControlReg.get_COLOR_DSTBLEND());
|
||||
|
||||
colorAttachment->setRgbBlendOperation(rgbBlendOp);
|
||||
colorAttachment->setSourceRGBBlendFactor(srcRgbBlendFactor);
|
||||
colorAttachment->setDestinationRGBBlendFactor(dstRgbBlendFactor);
|
||||
if (blendControlReg.get_SEPARATE_ALPHA_BLEND())
|
||||
{
|
||||
colorAttachment->setAlphaBlendOperation(GetMtlBlendOp(blendControlReg.get_ALPHA_COMB_FCN()));
|
||||
colorAttachment->setSourceAlphaBlendFactor(GetMtlBlendFactor(blendControlReg.get_ALPHA_SRCBLEND()));
|
||||
colorAttachment->setDestinationAlphaBlendFactor(GetMtlBlendFactor(blendControlReg.get_ALPHA_DSTBLEND()));
|
||||
}
|
||||
else
|
||||
{
|
||||
colorAttachment->setAlphaBlendOperation(rgbBlendOp);
|
||||
colorAttachment->setSourceAlphaBlendFactor(srcRgbBlendFactor);
|
||||
colorAttachment->setDestinationAlphaBlendFactor(dstRgbBlendFactor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Depth stencil attachment
|
||||
if (activeFBO->depthBuffer.texture)
|
||||
{
|
||||
auto texture = static_cast<LatteTextureViewMtl*>(activeFBO->depthBuffer.texture);
|
||||
desc->setDepthAttachmentPixelFormat(texture->GetRGBAView()->pixelFormat());
|
||||
if (activeFBO->depthBuffer.hasStencil)
|
||||
{
|
||||
desc->setStencilAttachmentPixelFormat(texture->GetRGBAView()->pixelFormat());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MetalPipelineCache::ShaderCacheLoading_begin(uint64 cacheTitleId)
|
||||
{
|
||||
s_cacheTitleId = cacheTitleId;
|
||||
@ -53,9 +117,9 @@ MetalPipelineCache::~MetalPipelineCache()
|
||||
m_binaryArchiveURL->release();
|
||||
}
|
||||
|
||||
MTL::RenderPipelineState* MetalPipelineCache::GetPipelineState(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* pixelShader, CachedFBOMtl* activeFBO, const LatteContextRegister& lcr)
|
||||
MTL::RenderPipelineState* MetalPipelineCache::GetRenderPipelineState(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* pixelShader, CachedFBOMtl* activeFBO, const LatteContextRegister& lcr)
|
||||
{
|
||||
uint64 stateHash = CalculatePipelineHash(fetchShader, vertexShader, pixelShader, activeFBO, lcr);
|
||||
uint64 stateHash = CalculateRenderPipelineHash(fetchShader, vertexShader, pixelShader, activeFBO, lcr);
|
||||
auto& pipeline = m_pipelineCache[stateHash];
|
||||
if (pipeline)
|
||||
return pipeline;
|
||||
@ -127,65 +191,18 @@ MTL::RenderPipelineState* MetalPipelineCache::GetPipelineState(const LatteFetchS
|
||||
// TODO: don't always set the vertex descriptor?
|
||||
desc->setVertexDescriptor(vertexDescriptor);
|
||||
|
||||
// Color attachments
|
||||
const Latte::LATTE_CB_COLOR_CONTROL& colorControlReg = lcr.CB_COLOR_CONTROL;
|
||||
uint32 blendEnableMask = colorControlReg.get_BLEND_MASK();
|
||||
uint32 renderTargetMask = lcr.CB_TARGET_MASK.get_MASK();
|
||||
for (uint8 i = 0; i < 8; i++)
|
||||
{
|
||||
const auto& colorBuffer = activeFBO->colorBuffer[i];
|
||||
auto texture = static_cast<LatteTextureViewMtl*>(colorBuffer.texture);
|
||||
if (!texture)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
auto colorAttachment = desc->colorAttachments()->object(i);
|
||||
colorAttachment->setPixelFormat(texture->GetRGBAView()->pixelFormat());
|
||||
colorAttachment->setWriteMask(GetMtlColorWriteMask((renderTargetMask >> (i * 4)) & 0xF));
|
||||
SetFragmentState(desc, activeFBO, lcr);
|
||||
|
||||
// Blending
|
||||
bool blendEnabled = ((blendEnableMask & (1 << i))) != 0;
|
||||
// Only float data type is blendable
|
||||
if (blendEnabled && GetMtlPixelFormatInfo(texture->format, false).dataType == MetalDataType::FLOAT)
|
||||
{
|
||||
colorAttachment->setBlendingEnabled(true);
|
||||
TryLoadBinaryArchive();
|
||||
|
||||
const auto& blendControlReg = lcr.CB_BLENDN_CONTROL[i];
|
||||
|
||||
auto rgbBlendOp = GetMtlBlendOp(blendControlReg.get_COLOR_COMB_FCN());
|
||||
auto srcRgbBlendFactor = GetMtlBlendFactor(blendControlReg.get_COLOR_SRCBLEND());
|
||||
auto dstRgbBlendFactor = GetMtlBlendFactor(blendControlReg.get_COLOR_DSTBLEND());
|
||||
|
||||
colorAttachment->setRgbBlendOperation(rgbBlendOp);
|
||||
colorAttachment->setSourceRGBBlendFactor(srcRgbBlendFactor);
|
||||
colorAttachment->setDestinationRGBBlendFactor(dstRgbBlendFactor);
|
||||
if (blendControlReg.get_SEPARATE_ALPHA_BLEND())
|
||||
{
|
||||
colorAttachment->setAlphaBlendOperation(GetMtlBlendOp(blendControlReg.get_ALPHA_COMB_FCN()));
|
||||
colorAttachment->setSourceAlphaBlendFactor(GetMtlBlendFactor(blendControlReg.get_ALPHA_SRCBLEND()));
|
||||
colorAttachment->setDestinationAlphaBlendFactor(GetMtlBlendFactor(blendControlReg.get_ALPHA_DSTBLEND()));
|
||||
}
|
||||
else
|
||||
{
|
||||
colorAttachment->setAlphaBlendOperation(rgbBlendOp);
|
||||
colorAttachment->setSourceAlphaBlendFactor(srcRgbBlendFactor);
|
||||
colorAttachment->setDestinationAlphaBlendFactor(dstRgbBlendFactor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Depth stencil attachment
|
||||
if (activeFBO->depthBuffer.texture)
|
||||
{
|
||||
auto texture = static_cast<LatteTextureViewMtl*>(activeFBO->depthBuffer.texture);
|
||||
desc->setDepthAttachmentPixelFormat(texture->GetRGBAView()->pixelFormat());
|
||||
if (activeFBO->depthBuffer.hasStencil)
|
||||
{
|
||||
desc->setStencilAttachmentPixelFormat(texture->GetRGBAView()->pixelFormat());
|
||||
}
|
||||
}
|
||||
|
||||
LoadBinary(desc);
|
||||
// Load binary
|
||||
if (m_binaryArchive)
|
||||
{
|
||||
NS::Object* binArchives[] = {m_binaryArchive};
|
||||
auto binaryArchives = NS::Array::alloc()->init(binArchives, 1);
|
||||
desc->setBinaryArchives(binaryArchives);
|
||||
binaryArchives->release();
|
||||
}
|
||||
|
||||
NS::Error* error = nullptr;
|
||||
#ifdef CEMU_DEBUG_ASSERT
|
||||
@ -211,10 +228,21 @@ MTL::RenderPipelineState* MetalPipelineCache::GetPipelineState(const LatteFetchS
|
||||
{
|
||||
debug_printf("error creating render pipeline state: %s\n", error->localizedDescription()->utf8String());
|
||||
error->release();
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
SaveBinary(desc);
|
||||
// Save binary
|
||||
if (m_binaryArchive)
|
||||
{
|
||||
NS::Error* error = nullptr;
|
||||
m_binaryArchive->addRenderPipelineFunctions(desc, &error);
|
||||
if (error)
|
||||
{
|
||||
debug_printf("error saving render pipeline functions: %s\n", error->localizedDescription()->utf8String());
|
||||
error->release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//newPipelineCount++;
|
||||
@ -230,7 +258,57 @@ MTL::RenderPipelineState* MetalPipelineCache::GetPipelineState(const LatteFetchS
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
uint64 MetalPipelineCache::CalculatePipelineHash(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* pixelShader, class CachedFBOMtl* activeFBO, const LatteContextRegister& lcr)
|
||||
MTL::RenderPipelineState* MetalPipelineCache::GetMeshPipelineState(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* geometryShader, const LatteDecompilerShader* pixelShader, CachedFBOMtl* activeFBO, const LatteContextRegister& lcr, Renderer::INDEX_TYPE hostIndexType)
|
||||
{
|
||||
uint64 stateHash = CalculateRenderPipelineHash(fetchShader, vertexShader, pixelShader, activeFBO, lcr);
|
||||
|
||||
stateHash += lcr.GetRawView()[mmVGT_PRIMITIVE_TYPE];
|
||||
stateHash = std::rotl<uint64>(stateHash, 7);
|
||||
|
||||
stateHash += (uint8)hostIndexType;
|
||||
stateHash = std::rotl<uint64>(stateHash, 7); // TODO: 7?s
|
||||
|
||||
auto& pipeline = m_pipelineCache[stateHash];
|
||||
if (pipeline)
|
||||
return pipeline;
|
||||
|
||||
auto mtlObjectShader = static_cast<RendererShaderMtl*>(vertexShader->shader);
|
||||
auto mtlMeshShader = static_cast<RendererShaderMtl*>(geometryShader->shader);
|
||||
auto mtlPixelShader = static_cast<RendererShaderMtl*>(pixelShader->shader);
|
||||
mtlObjectShader->CompileObjectFunction(lcr, fetchShader, vertexShader, hostIndexType);
|
||||
mtlMeshShader->CompileMeshFunction(lcr, fetchShader);
|
||||
mtlPixelShader->CompileFragmentFunction(activeFBO);
|
||||
|
||||
// Render pipeline state
|
||||
MTL::MeshRenderPipelineDescriptor* desc = MTL::MeshRenderPipelineDescriptor::alloc()->init();
|
||||
desc->setObjectFunction(mtlObjectShader->GetFunction());
|
||||
desc->setMeshFunction(mtlMeshShader->GetFunction());
|
||||
desc->setFragmentFunction(mtlPixelShader->GetFunction());
|
||||
|
||||
SetFragmentState(desc, activeFBO, lcr);
|
||||
|
||||
TryLoadBinaryArchive();
|
||||
|
||||
// Load binary
|
||||
// TODO: no binary archives? :(
|
||||
|
||||
NS::Error* error = nullptr;
|
||||
#ifdef CEMU_DEBUG_ASSERT
|
||||
desc->setLabel(GetLabel("Mesh pipeline state", desc));
|
||||
#endif
|
||||
pipeline = m_mtlr->GetDevice()->newRenderPipelineState(desc, MTL::PipelineOptionNone, nullptr, &error);
|
||||
if (error)
|
||||
{
|
||||
debug_printf("error creating render pipeline state: %s\n", error->localizedDescription()->utf8String());
|
||||
error->release();
|
||||
return nullptr;
|
||||
}
|
||||
desc->release();
|
||||
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
uint64 MetalPipelineCache::CalculateRenderPipelineHash(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* pixelShader, class CachedFBOMtl* activeFBO, const LatteContextRegister& lcr)
|
||||
{
|
||||
// Hash
|
||||
uint64 stateHash = 0;
|
||||
@ -261,9 +339,6 @@ uint64 MetalPipelineCache::CalculatePipelineHash(const LatteFetchShader* fetchSh
|
||||
stateHash += fetchShader->getVkPipelineHashFragment();
|
||||
stateHash = std::rotl<uint64>(stateHash, 7);
|
||||
|
||||
stateHash += lcr.GetRawView()[mmVGT_PRIMITIVE_TYPE];
|
||||
stateHash = std::rotl<uint64>(stateHash, 7);
|
||||
|
||||
stateHash += lcr.GetRawView()[mmVGT_STRMOUT_EN];
|
||||
stateHash = std::rotl<uint64>(stateHash, 7);
|
||||
|
||||
@ -340,30 +415,3 @@ void MetalPipelineCache::TryLoadBinaryArchive()
|
||||
}
|
||||
desc->release();
|
||||
}
|
||||
|
||||
void MetalPipelineCache::LoadBinary(MTL::RenderPipelineDescriptor* desc)
|
||||
{
|
||||
TryLoadBinaryArchive();
|
||||
|
||||
if (!m_binaryArchive)
|
||||
return;
|
||||
|
||||
NS::Object* binArchives[] = {m_binaryArchive};
|
||||
auto binaryArchives = NS::Array::alloc()->init(binArchives, 1);
|
||||
desc->setBinaryArchives(binaryArchives);
|
||||
binaryArchives->release();
|
||||
}
|
||||
|
||||
void MetalPipelineCache::SaveBinary(MTL::RenderPipelineDescriptor* desc)
|
||||
{
|
||||
if (!m_binaryArchive)
|
||||
return;
|
||||
|
||||
NS::Error* error = nullptr;
|
||||
m_binaryArchive->addRenderPipelineFunctions(desc, &error);
|
||||
if (error)
|
||||
{
|
||||
debug_printf("error saving render pipeline functions: %s\n", error->localizedDescription()->utf8String());
|
||||
error->release();
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "HW/Latte/ISA/LatteReg.h"
|
||||
#include "HW/Latte/LegacyShaderDecompiler/LatteDecompiler.h"
|
||||
#include "Cafe/HW/Latte/Renderer/Renderer.h"
|
||||
|
||||
class MetalPipelineCache
|
||||
{
|
||||
@ -15,7 +16,9 @@ public:
|
||||
MetalPipelineCache(class MetalRenderer* metalRenderer) : m_mtlr{metalRenderer} {}
|
||||
~MetalPipelineCache();
|
||||
|
||||
MTL::RenderPipelineState* GetPipelineState(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* pixelShader, class CachedFBOMtl* activeFBO, const LatteContextRegister& lcr);
|
||||
MTL::RenderPipelineState* GetRenderPipelineState(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* pixelShader, class CachedFBOMtl* activeFBO, const LatteContextRegister& lcr);
|
||||
|
||||
MTL::RenderPipelineState* GetMeshPipelineState(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* geometryShader, const LatteDecompilerShader* pixelShader, class CachedFBOMtl* activeFBO, const LatteContextRegister& lcr, Renderer::INDEX_TYPE hostIndexType);
|
||||
|
||||
private:
|
||||
class MetalRenderer* m_mtlr;
|
||||
@ -25,11 +28,7 @@ private:
|
||||
NS::URL* m_binaryArchiveURL;
|
||||
MTL::BinaryArchive* m_binaryArchive;
|
||||
|
||||
uint64 CalculatePipelineHash(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* pixelShader, class CachedFBOMtl* activeFBO, const LatteContextRegister& lcr);
|
||||
uint64 CalculateRenderPipelineHash(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* pixelShader, class CachedFBOMtl* activeFBO, const LatteContextRegister& lcr);
|
||||
|
||||
void TryLoadBinaryArchive();
|
||||
|
||||
void LoadBinary(MTL::RenderPipelineDescriptor* desc);
|
||||
|
||||
void SaveBinary(MTL::RenderPipelineDescriptor* desc);
|
||||
};
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "Common/precompiled.h"
|
||||
#include "HW/Latte/Renderer/Metal/MetalCommon.h"
|
||||
#include "Metal/MTLDevice.hpp"
|
||||
#include "Metal/MTLRenderCommandEncoder.hpp"
|
||||
#include "gui/guiWrapper.h"
|
||||
|
||||
#define COMMIT_TRESHOLD 256
|
||||
@ -28,6 +29,63 @@ extern bool hasValidFramebufferAttached;
|
||||
|
||||
float supportBufferData[512 * 4];
|
||||
|
||||
void SetBuffer(MTL::RenderCommandEncoder* renderCommandEncoder, MetalShaderType shaderType, MTL::Buffer* buffer, size_t offset, uint32 index)
|
||||
{
|
||||
switch (shaderType)
|
||||
{
|
||||
case METAL_SHADER_TYPE_VERTEX:
|
||||
renderCommandEncoder->setVertexBuffer(buffer, offset, index);
|
||||
break;
|
||||
case METAL_SHADER_TYPE_OBJECT:
|
||||
renderCommandEncoder->setObjectBuffer(buffer, offset, index);
|
||||
break;
|
||||
case METAL_SHADER_TYPE_MESH:
|
||||
renderCommandEncoder->setMeshBuffer(buffer, offset, index);
|
||||
break;
|
||||
case METAL_SHADER_TYPE_FRAGMENT:
|
||||
renderCommandEncoder->setFragmentBuffer(buffer, offset, index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SetTexture(MTL::RenderCommandEncoder* renderCommandEncoder, MetalShaderType shaderType, MTL::Texture* texture, uint32 index)
|
||||
{
|
||||
switch (shaderType)
|
||||
{
|
||||
case METAL_SHADER_TYPE_VERTEX:
|
||||
renderCommandEncoder->setVertexTexture(texture, index);
|
||||
break;
|
||||
case METAL_SHADER_TYPE_OBJECT:
|
||||
renderCommandEncoder->setObjectTexture(texture, index);
|
||||
break;
|
||||
case METAL_SHADER_TYPE_MESH:
|
||||
renderCommandEncoder->setMeshTexture(texture, index);
|
||||
break;
|
||||
case METAL_SHADER_TYPE_FRAGMENT:
|
||||
renderCommandEncoder->setFragmentTexture(texture, index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SetSamplerState(MTL::RenderCommandEncoder* renderCommandEncoder, MetalShaderType shaderType, MTL::SamplerState* samplerState, uint32 index)
|
||||
{
|
||||
switch (shaderType)
|
||||
{
|
||||
case METAL_SHADER_TYPE_VERTEX:
|
||||
renderCommandEncoder->setVertexSamplerState(samplerState, index);
|
||||
break;
|
||||
case METAL_SHADER_TYPE_OBJECT:
|
||||
renderCommandEncoder->setObjectSamplerState(samplerState, index);
|
||||
break;
|
||||
case METAL_SHADER_TYPE_MESH:
|
||||
renderCommandEncoder->setMeshSamplerState(samplerState, index);
|
||||
break;
|
||||
case METAL_SHADER_TYPE_FRAGMENT:
|
||||
renderCommandEncoder->setFragmentSamplerState(samplerState, index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
MetalRenderer::MetalRenderer()
|
||||
{
|
||||
m_device = MTL::CreateSystemDefaultDevice();
|
||||
@ -654,7 +712,6 @@ void MetalRenderer::buffer_bindVertexBuffer(uint32 bufferIndex, uint32 offset, u
|
||||
m_memoryManager->UntrackVertexBuffer(bufferIndex);
|
||||
}
|
||||
|
||||
buffer.needsRebind = true;
|
||||
buffer.offset = offset;
|
||||
buffer.size = size;
|
||||
buffer.restrideInfo = {};
|
||||
@ -664,7 +721,7 @@ void MetalRenderer::buffer_bindVertexBuffer(uint32 bufferIndex, uint32 offset, u
|
||||
|
||||
void MetalRenderer::buffer_bindUniformBuffer(LatteConst::ShaderType shaderType, uint32 bufferIndex, uint32 offset, uint32 size)
|
||||
{
|
||||
m_state.m_uniformBufferOffsets[GetMtlShaderType(shaderType)][bufferIndex] = offset;
|
||||
m_state.m_uniformBufferOffsets[GetMtlGeneralShaderType(shaderType)][bufferIndex] = offset;
|
||||
}
|
||||
|
||||
RendererShader* MetalRenderer::shader_create(RendererShader::ShaderType type, uint64 baseHash, uint64 auxHash, const std::string& source, bool isGameShader, bool isGfxPackShader)
|
||||
@ -957,16 +1014,19 @@ void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32
|
||||
auto restridedBuffer = m_memoryManager->RestrideBufferIfNeeded(i, bufferStride);
|
||||
|
||||
// Bind
|
||||
if (vertexBufferRange.needsRebind)
|
||||
if (true)
|
||||
{
|
||||
renderCommandEncoder->setVertexBuffer(restridedBuffer.buffer, restridedBuffer.offset, GET_MTL_VERTEX_BUFFER_INDEX(i));
|
||||
vertexBufferRange.needsRebind = false;
|
||||
SetBuffer(renderCommandEncoder, GetMtlShaderType(vertexShader->shaderType, (geometryShader != nullptr)),restridedBuffer.buffer, restridedBuffer.offset, GET_MTL_VERTEX_BUFFER_INDEX(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Render pipeline state
|
||||
MTL::RenderPipelineState* renderPipelineState = m_pipelineCache->GetPipelineState(fetchShader, vertexShader, pixelShader, m_state.m_lastUsedFBO, LatteGPUState.contextNew);
|
||||
MTL::RenderPipelineState* renderPipelineState;
|
||||
if (geometryShader)
|
||||
renderPipelineState = m_pipelineCache->GetMeshPipelineState(fetchShader, vertexShader, geometryShader, pixelShader, m_state.m_lastUsedFBO, LatteGPUState.contextNew, hostIndexType);
|
||||
else
|
||||
renderPipelineState = m_pipelineCache->GetRenderPipelineState(fetchShader, vertexShader, pixelShader, m_state.m_lastUsedFBO, LatteGPUState.contextNew);
|
||||
if (renderPipelineState != encoderState.m_renderPipelineState)
|
||||
{
|
||||
renderCommandEncoder->setRenderPipelineState(renderPipelineState);
|
||||
@ -978,18 +1038,51 @@ void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32
|
||||
LatteStreamout_PrepareDrawcall(count, instanceCount);
|
||||
|
||||
// Uniform buffers, textures and samplers
|
||||
BindStageResources(renderCommandEncoder, vertexShader);
|
||||
BindStageResources(renderCommandEncoder, pixelShader);
|
||||
BindStageResources(renderCommandEncoder, vertexShader, (geometryShader != nullptr));
|
||||
if (geometryShader)
|
||||
BindStageResources(renderCommandEncoder, geometryShader, (geometryShader != nullptr));
|
||||
BindStageResources(renderCommandEncoder, pixelShader, (geometryShader != nullptr));
|
||||
|
||||
// Draw
|
||||
MTL::Buffer* indexBuffer = nullptr;
|
||||
if (hostIndexType != INDEX_TYPE::NONE)
|
||||
indexBuffer = m_memoryManager->GetTemporaryBufferAllocator().GetBuffer(indexBufferIndex);
|
||||
if (geometryShader)
|
||||
{
|
||||
auto mtlIndexType = GetMtlIndexType(hostIndexType);
|
||||
MTL::Buffer* indexBuffer = m_memoryManager->GetTemporaryBufferAllocator().GetBuffer(indexBufferIndex);
|
||||
renderCommandEncoder->drawIndexedPrimitives(mtlPrimitiveType, hostIndexCount, mtlIndexType, indexBuffer, indexBufferOffset, instanceCount, baseVertex, baseInstance);
|
||||
} else
|
||||
// TODO: don't hardcode the index
|
||||
if (indexBuffer)
|
||||
renderCommandEncoder->setObjectBuffer(indexBuffer, indexBufferOffset, 20);
|
||||
|
||||
uint32 verticesPerPrimitive = 0;
|
||||
switch (primitiveMode)
|
||||
{
|
||||
case LattePrimitiveMode::POINTS:
|
||||
verticesPerPrimitive = 1;
|
||||
break;
|
||||
case LattePrimitiveMode::LINES:
|
||||
verticesPerPrimitive = 2;
|
||||
break;
|
||||
case LattePrimitiveMode::TRIANGLES:
|
||||
verticesPerPrimitive = 3;
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Invalid primitive mode");
|
||||
break;
|
||||
}
|
||||
|
||||
renderCommandEncoder->drawMeshThreadgroups(MTL::Size(count / verticesPerPrimitive, 1, 1), MTL::Size(verticesPerPrimitive, 1, 1), MTL::Size(1, 1, 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
renderCommandEncoder->drawPrimitives(mtlPrimitiveType, baseVertex, count, instanceCount, baseInstance);
|
||||
if (indexBuffer)
|
||||
{
|
||||
auto mtlIndexType = GetMtlIndexType(hostIndexType);
|
||||
renderCommandEncoder->drawIndexedPrimitives(mtlPrimitiveType, hostIndexCount, mtlIndexType, indexBuffer, indexBufferOffset, instanceCount, baseVertex, baseInstance);
|
||||
}
|
||||
else
|
||||
{
|
||||
renderCommandEncoder->drawPrimitives(mtlPrimitiveType, baseVertex, count, instanceCount, baseInstance);
|
||||
}
|
||||
}
|
||||
|
||||
LatteStreamout_FinishDrawcall(false);
|
||||
@ -1080,7 +1173,7 @@ MTL::RenderCommandEncoder* MetalRenderer::GetTemporaryRenderCommandEncoder(MTL::
|
||||
}
|
||||
|
||||
// Some render passes clear the attachments, forceRecreate is supposed to be used in those cases
|
||||
MTL::RenderCommandEncoder* MetalRenderer::GetRenderCommandEncoder(bool forceRecreate, bool rebindStateIfNewEncoder)
|
||||
MTL::RenderCommandEncoder* MetalRenderer::GetRenderCommandEncoder(bool forceRecreate)
|
||||
{
|
||||
// Check if we need to begin a new render pass
|
||||
if (m_commandEncoder)
|
||||
@ -1134,12 +1227,6 @@ MTL::RenderCommandEncoder* MetalRenderer::GetRenderCommandEncoder(bool forceRecr
|
||||
|
||||
ResetEncoderState();
|
||||
|
||||
if (rebindStateIfNewEncoder)
|
||||
{
|
||||
// Rebind all the render state
|
||||
RebindRenderState(renderCommandEncoder);
|
||||
}
|
||||
|
||||
return renderCommandEncoder;
|
||||
}
|
||||
|
||||
@ -1253,9 +1340,9 @@ bool MetalRenderer::AcquireNextDrawable(bool mainWindow)
|
||||
return true;
|
||||
}
|
||||
|
||||
void MetalRenderer::BindStageResources(MTL::RenderCommandEncoder* renderCommandEncoder, LatteDecompilerShader* shader)
|
||||
void MetalRenderer::BindStageResources(MTL::RenderCommandEncoder* renderCommandEncoder, LatteDecompilerShader* shader, bool usesGeometryShader)
|
||||
{
|
||||
auto mtlShaderType = GetMtlShaderType(shader->shaderType);
|
||||
auto mtlShaderType = GetMtlShaderType(shader->shaderType, usesGeometryShader);
|
||||
|
||||
sint32 textureCount = shader->resourceMapping.getTextureCount();
|
||||
for (int i = 0; i < textureCount; ++i)
|
||||
@ -1295,88 +1382,21 @@ void MetalRenderer::BindStageResources(MTL::RenderCommandEncoder* renderCommandE
|
||||
{
|
||||
// TODO: don't bind if already bound
|
||||
if (textureDim == Latte::E_DIM::DIM_1D)
|
||||
{
|
||||
switch (shader->shaderType)
|
||||
{
|
||||
case LatteConst::ShaderType::Vertex:
|
||||
{
|
||||
renderCommandEncoder->setVertexTexture(m_nullTexture1D, binding);
|
||||
renderCommandEncoder->setVertexSamplerState(m_nearestSampler, binding);
|
||||
break;
|
||||
}
|
||||
case LatteConst::ShaderType::Pixel:
|
||||
{
|
||||
renderCommandEncoder->setFragmentTexture(m_nullTexture1D, binding);
|
||||
renderCommandEncoder->setVertexSamplerState(m_nearestSampler, binding);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
}
|
||||
SetTexture(renderCommandEncoder, mtlShaderType, m_nullTexture1D, binding);
|
||||
else
|
||||
{
|
||||
switch (shader->shaderType)
|
||||
{
|
||||
case LatteConst::ShaderType::Vertex:
|
||||
{
|
||||
renderCommandEncoder->setVertexTexture(m_nullTexture2D, binding);
|
||||
renderCommandEncoder->setVertexSamplerState(m_nearestSampler, binding);
|
||||
break;
|
||||
}
|
||||
case LatteConst::ShaderType::Pixel:
|
||||
{
|
||||
renderCommandEncoder->setFragmentTexture(m_nullTexture2D, binding);
|
||||
renderCommandEncoder->setVertexSamplerState(m_nearestSampler, binding);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
}
|
||||
SetTexture(renderCommandEncoder, mtlShaderType, m_nullTexture2D, binding);
|
||||
SetSamplerState(renderCommandEncoder, mtlShaderType, m_nearestSampler, binding);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (textureDim == Latte::E_DIM::DIM_1D && (textureView->dim != Latte::E_DIM::DIM_1D))
|
||||
{
|
||||
switch (shader->shaderType)
|
||||
{
|
||||
case LatteConst::ShaderType::Vertex:
|
||||
{
|
||||
renderCommandEncoder->setVertexTexture(m_nullTexture1D, binding);
|
||||
renderCommandEncoder->setVertexSamplerState(m_nearestSampler, binding);
|
||||
break;
|
||||
}
|
||||
case LatteConst::ShaderType::Pixel:
|
||||
{
|
||||
renderCommandEncoder->setFragmentTexture(m_nullTexture1D, binding);
|
||||
renderCommandEncoder->setVertexSamplerState(m_nearestSampler, binding);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
SetTexture(renderCommandEncoder, mtlShaderType, m_nullTexture1D, binding);
|
||||
continue;
|
||||
}
|
||||
else if (textureDim == Latte::E_DIM::DIM_2D && (textureView->dim != Latte::E_DIM::DIM_2D && textureView->dim != Latte::E_DIM::DIM_2D_MSAA))
|
||||
{
|
||||
switch (shader->shaderType)
|
||||
{
|
||||
case LatteConst::ShaderType::Vertex:
|
||||
{
|
||||
renderCommandEncoder->setVertexTexture(m_nullTexture2D, binding);
|
||||
renderCommandEncoder->setVertexSamplerState(m_nearestSampler, binding);
|
||||
break;
|
||||
}
|
||||
case LatteConst::ShaderType::Pixel:
|
||||
{
|
||||
renderCommandEncoder->setFragmentTexture(m_nullTexture2D, binding);
|
||||
renderCommandEncoder->setVertexSamplerState(m_nearestSampler, binding);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
SetTexture(renderCommandEncoder, mtlShaderType, m_nullTexture2D, binding);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1399,21 +1419,7 @@ void MetalRenderer::BindStageResources(MTL::RenderCommandEncoder* renderCommandE
|
||||
{
|
||||
boundSampler = sampler;
|
||||
|
||||
switch (shader->shaderType)
|
||||
{
|
||||
case LatteConst::ShaderType::Vertex:
|
||||
{
|
||||
renderCommandEncoder->setVertexSamplerState(sampler, binding);
|
||||
break;
|
||||
}
|
||||
case LatteConst::ShaderType::Pixel:
|
||||
{
|
||||
renderCommandEncoder->setFragmentSamplerState(sampler, binding);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
SetSamplerState(renderCommandEncoder, mtlShaderType, sampler, binding);
|
||||
}
|
||||
|
||||
// get texture register word 0
|
||||
@ -1425,21 +1431,7 @@ void MetalRenderer::BindStageResources(MTL::RenderCommandEncoder* renderCommandE
|
||||
boundTexture = {textureView, word4};
|
||||
|
||||
MTL::Texture* mtlTexture = textureView->GetSwizzledView(word4);
|
||||
switch (shader->shaderType)
|
||||
{
|
||||
case LatteConst::ShaderType::Vertex:
|
||||
{
|
||||
renderCommandEncoder->setVertexTexture(mtlTexture, binding);
|
||||
break;
|
||||
}
|
||||
case LatteConst::ShaderType::Pixel:
|
||||
{
|
||||
renderCommandEncoder->setFragmentTexture(mtlTexture, binding);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
SetTexture(renderCommandEncoder, mtlShaderType, mtlTexture, binding);
|
||||
}
|
||||
|
||||
// Support buffer
|
||||
@ -1531,23 +1523,7 @@ void MetalRenderer::BindStageResources(MTL::RenderCommandEncoder* renderCommandE
|
||||
if (!HasUnifiedMemory())
|
||||
buffer->didModifyRange(NS::Range(supportBuffer.offset, size));
|
||||
|
||||
switch (shader->shaderType)
|
||||
{
|
||||
case LatteConst::ShaderType::Vertex:
|
||||
{
|
||||
renderCommandEncoder->setVertexBuffer(buffer, supportBuffer.offset, MTL_SUPPORT_BUFFER_BINDING);
|
||||
//renderCommandEncoder->setVertexBytes(supportBufferData, sizeof(supportBufferData), MTL_SUPPORT_BUFFER_BINDING);
|
||||
break;
|
||||
}
|
||||
case LatteConst::ShaderType::Pixel:
|
||||
{
|
||||
renderCommandEncoder->setFragmentBuffer(buffer, supportBuffer.offset, MTL_SUPPORT_BUFFER_BINDING);
|
||||
//renderCommandEncoder->setFragmentBytes(supportBufferData, sizeof(supportBufferData), MTL_SUPPORT_BUFFER_BINDING);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
SetBuffer(renderCommandEncoder, mtlShaderType, buffer, supportBuffer.offset, MTL_SUPPORT_BUFFER_BINDING);
|
||||
}
|
||||
|
||||
// Uniform buffers
|
||||
@ -1562,7 +1538,7 @@ void MetalRenderer::BindStageResources(MTL::RenderCommandEncoder* renderCommandE
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t offset = m_state.m_uniformBufferOffsets[mtlShaderType][i];
|
||||
size_t offset = m_state.m_uniformBufferOffsets[GetMtlGeneralShaderType(shader->shaderType)][i];
|
||||
if (offset == INVALID_OFFSET)
|
||||
continue;
|
||||
|
||||
@ -1573,57 +1549,18 @@ void MetalRenderer::BindStageResources(MTL::RenderCommandEncoder* renderCommandE
|
||||
boundOffset = offset;
|
||||
|
||||
// TODO: only set the offset if already bound
|
||||
switch (shader->shaderType)
|
||||
{
|
||||
case LatteConst::ShaderType::Vertex:
|
||||
{
|
||||
renderCommandEncoder->setVertexBuffer(m_memoryManager->GetBufferCache(), offset, binding);
|
||||
break;
|
||||
}
|
||||
case LatteConst::ShaderType::Pixel:
|
||||
{
|
||||
renderCommandEncoder->setFragmentBuffer(m_memoryManager->GetBufferCache(), offset, binding);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
SetBuffer(renderCommandEncoder, mtlShaderType, m_memoryManager->GetBufferCache(), offset, binding);
|
||||
}
|
||||
}
|
||||
|
||||
// Storage buffer
|
||||
if (shader->resourceMapping.tfStorageBindingPoint >= 0)
|
||||
{
|
||||
switch (shader->shaderType)
|
||||
{
|
||||
case LatteConst::ShaderType::Vertex:
|
||||
{
|
||||
renderCommandEncoder->setVertexBuffer(m_xfbRingBuffer, 0, shader->resourceMapping.tfStorageBindingPoint);
|
||||
break;
|
||||
}
|
||||
case LatteConst::ShaderType::Pixel:
|
||||
{
|
||||
renderCommandEncoder->setFragmentBuffer(m_xfbRingBuffer, 0, shader->resourceMapping.tfStorageBindingPoint);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
SetBuffer(renderCommandEncoder, mtlShaderType, m_xfbRingBuffer, 0, shader->resourceMapping.tfStorageBindingPoint);
|
||||
m_state.m_encoderState.m_uniformBufferOffsets[mtlShaderType][shader->resourceMapping.tfStorageBindingPoint] = INVALID_OFFSET;
|
||||
}
|
||||
}
|
||||
|
||||
void MetalRenderer::RebindRenderState(MTL::RenderCommandEncoder* renderCommandEncoder)
|
||||
{
|
||||
// Vertex buffers
|
||||
for (uint8 i = 0; i < MAX_MTL_BUFFERS; i++)
|
||||
{
|
||||
auto& vertexBufferRange = m_state.m_vertexBuffers[i];
|
||||
if (vertexBufferRange.offset != INVALID_OFFSET)
|
||||
vertexBufferRange.needsRebind = true;
|
||||
}
|
||||
}
|
||||
|
||||
void MetalRenderer::ClearColorTextureInternal(MTL::Texture* mtlTexture, sint32 sliceIndex, sint32 mipIndex, float r, float g, float b, float a)
|
||||
{
|
||||
MTL::RenderPassDescriptor* renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init();
|
||||
|
@ -31,27 +31,57 @@ struct MetalRestrideInfo
|
||||
|
||||
struct MetalBoundBuffer
|
||||
{
|
||||
bool needsRebind = false;
|
||||
size_t offset = INVALID_OFFSET;
|
||||
size_t size = 0;
|
||||
// Memory manager will write restride info to this variable
|
||||
MetalRestrideInfo restrideInfo;
|
||||
};
|
||||
|
||||
enum MetalGeneralShaderType
|
||||
{
|
||||
METAL_GENERAL_SHADER_TYPE_VERTEX,
|
||||
METAL_GENERAL_SHADER_TYPE_GEOMETRY,
|
||||
METAL_GENERAL_SHADER_TYPE_FRAGMENT,
|
||||
|
||||
METAL_GENERAL_SHADER_TYPE_TOTAL
|
||||
};
|
||||
|
||||
inline MetalGeneralShaderType GetMtlGeneralShaderType(LatteConst::ShaderType shaderType)
|
||||
{
|
||||
switch (shaderType)
|
||||
{
|
||||
case LatteConst::ShaderType::Vertex:
|
||||
return METAL_GENERAL_SHADER_TYPE_VERTEX;
|
||||
case LatteConst::ShaderType::Geometry:
|
||||
return METAL_GENERAL_SHADER_TYPE_GEOMETRY;
|
||||
case LatteConst::ShaderType::Pixel:
|
||||
return METAL_GENERAL_SHADER_TYPE_FRAGMENT;
|
||||
default:
|
||||
return METAL_GENERAL_SHADER_TYPE_TOTAL;
|
||||
}
|
||||
}
|
||||
|
||||
enum MetalShaderType
|
||||
{
|
||||
METAL_SHADER_TYPE_VERTEX,
|
||||
METAL_SHADER_TYPE_OBJECT,
|
||||
METAL_SHADER_TYPE_MESH,
|
||||
METAL_SHADER_TYPE_FRAGMENT,
|
||||
|
||||
METAL_SHADER_TYPE_TOTAL
|
||||
};
|
||||
|
||||
inline MetalShaderType GetMtlShaderType(LatteConst::ShaderType shaderType)
|
||||
inline MetalShaderType GetMtlShaderType(LatteConst::ShaderType shaderType, bool usesGeometryShader)
|
||||
{
|
||||
switch (shaderType)
|
||||
{
|
||||
case LatteConst::ShaderType::Vertex:
|
||||
return METAL_SHADER_TYPE_VERTEX;
|
||||
if (usesGeometryShader)
|
||||
return METAL_SHADER_TYPE_OBJECT;
|
||||
else
|
||||
return METAL_SHADER_TYPE_VERTEX;
|
||||
case LatteConst::ShaderType::Geometry:
|
||||
return METAL_SHADER_TYPE_MESH;
|
||||
case LatteConst::ShaderType::Pixel:
|
||||
return METAL_SHADER_TYPE_FRAGMENT;
|
||||
default:
|
||||
@ -105,7 +135,7 @@ struct MetalState
|
||||
MetalBoundBuffer m_vertexBuffers[MAX_MTL_BUFFERS] = {{}};
|
||||
// TODO: find out what is the max number of bound textures on the Wii U
|
||||
class LatteTextureViewMtl* m_textures[64] = {nullptr};
|
||||
size_t m_uniformBufferOffsets[METAL_SHADER_TYPE_TOTAL][MAX_MTL_BUFFERS];
|
||||
size_t m_uniformBufferOffsets[METAL_GENERAL_SHADER_TYPE_TOTAL][MAX_MTL_BUFFERS];
|
||||
|
||||
MTL::Viewport m_viewport;
|
||||
MTL::ScissorRect m_scissor;
|
||||
@ -347,7 +377,7 @@ public:
|
||||
bool CommandBufferCompleted(MTL::CommandBuffer* commandBuffer);
|
||||
void WaitForCommandBufferCompletion(MTL::CommandBuffer* commandBuffer);
|
||||
MTL::RenderCommandEncoder* GetTemporaryRenderCommandEncoder(MTL::RenderPassDescriptor* renderPassDescriptor);
|
||||
MTL::RenderCommandEncoder* GetRenderCommandEncoder(bool forceRecreate = false, bool rebindStateIfNewEncoder = true);
|
||||
MTL::RenderCommandEncoder* GetRenderCommandEncoder(bool forceRecreate = false);
|
||||
MTL::ComputeCommandEncoder* GetComputeCommandEncoder();
|
||||
MTL::BlitCommandEncoder* GetBlitCommandEncoder();
|
||||
void EndEncoding();
|
||||
@ -355,8 +385,7 @@ public:
|
||||
|
||||
bool AcquireNextDrawable(bool mainWindow);
|
||||
|
||||
void BindStageResources(MTL::RenderCommandEncoder* renderCommandEncoder, LatteDecompilerShader* shader);
|
||||
void RebindRenderState(MTL::RenderCommandEncoder* renderCommandEncoder);
|
||||
void BindStageResources(MTL::RenderCommandEncoder* renderCommandEncoder, LatteDecompilerShader* shader, bool usesGeometryShader);
|
||||
|
||||
void ClearColorTextureInternal(MTL::Texture* mtlTexture, sint32 sliceIndex, sint32 mipIndex, float r, float g, float b, float a);
|
||||
|
||||
|
@ -58,7 +58,6 @@ void RendererShaderMtl::CompileObjectFunction(const LatteContextRegister& lcr, c
|
||||
std::string vertexBufferDefinitions = "#define VERTEX_BUFFER_DEFINITIONS ";
|
||||
std::string vertexBuffers = "#define VERTEX_BUFFERS ";
|
||||
std::string inputFetchDefinition = "VertexIn fetchInput(thread uint& vid VERTEX_BUFFER_DEFINITIONS) {\n";
|
||||
inputFetchDefinition += "VertexIn in;\n";
|
||||
if (hostIndexType != Renderer::INDEX_TYPE::NONE)
|
||||
{
|
||||
vertexBufferDefinitions += ", device ";
|
||||
@ -77,8 +76,9 @@ void RendererShaderMtl::CompileObjectFunction(const LatteContextRegister& lcr, c
|
||||
// TODO: don't hardcode the index
|
||||
vertexBufferDefinitions += "* indexBuffer [[buffer(20)]]";
|
||||
vertexBuffers += ", indexBuffer";
|
||||
inputFetchDefinition += "vid = indexBuffer[vid]\n";
|
||||
inputFetchDefinition += "vid = indexBuffer[vid];\n";
|
||||
}
|
||||
inputFetchDefinition += "VertexIn in;\n";
|
||||
for (auto& bufferGroup : fetchShader->bufferGroups)
|
||||
{
|
||||
std::optional<LatteConst::VertexFetchType2> fetchType;
|
||||
@ -92,51 +92,67 @@ void RendererShaderMtl::CompileObjectFunction(const LatteContextRegister& lcr, c
|
||||
continue; // attribute not used?
|
||||
|
||||
std::string formatName;
|
||||
uint8 componentCount = 0;
|
||||
switch (GetMtlVertexFormat(attr.format))
|
||||
{
|
||||
case MTL::VertexFormatUChar:
|
||||
formatName = "uchar";
|
||||
componentCount = 1;
|
||||
break;
|
||||
case MTL::VertexFormatUChar2:
|
||||
formatName = "uchar2";
|
||||
componentCount = 2;
|
||||
break;
|
||||
case MTL::VertexFormatUChar3:
|
||||
formatName = "uchar3";
|
||||
componentCount = 3;
|
||||
break;
|
||||
case MTL::VertexFormatUChar4:
|
||||
formatName = "uchar4";
|
||||
componentCount = 4;
|
||||
break;
|
||||
case MTL::VertexFormatUShort:
|
||||
formatName = "ushort";
|
||||
componentCount = 1;
|
||||
break;
|
||||
case MTL::VertexFormatUShort2:
|
||||
formatName = "ushort2";
|
||||
componentCount = 2;
|
||||
break;
|
||||
case MTL::VertexFormatUShort3:
|
||||
formatName = "ushort3";
|
||||
componentCount = 3;
|
||||
break;
|
||||
case MTL::VertexFormatUShort4:
|
||||
formatName = "ushort4";
|
||||
componentCount = 4;
|
||||
break;
|
||||
case MTL::VertexFormatUInt:
|
||||
formatName = "uint";
|
||||
componentCount = 1;
|
||||
break;
|
||||
case MTL::VertexFormatUInt2:
|
||||
formatName = "uint2";
|
||||
componentCount = 2;
|
||||
break;
|
||||
case MTL::VertexFormatUInt3:
|
||||
formatName = "uint3";
|
||||
componentCount = 3;
|
||||
break;
|
||||
case MTL::VertexFormatUInt4:
|
||||
formatName = "uint4";
|
||||
componentCount = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
// Fetch the attribute
|
||||
inputFetchDefinition += "in.ATTRIBUTE_NAME" + std::to_string(semanticId) + " = ";
|
||||
inputFetchDefinition += "*(device " + formatName + "*)";
|
||||
inputFetchDefinition += "uint4(*(device " + formatName + "*)";
|
||||
inputFetchDefinition += "(vertexBuffer" + std::to_string(attr.attributeBufferIndex);
|
||||
inputFetchDefinition += " + vid + " + std::to_string(attr.offset) + ");\n";
|
||||
inputFetchDefinition += " + vid + " + std::to_string(attr.offset) + ")";
|
||||
for (uint8 i = 0; i < (4 - componentCount); i++)
|
||||
inputFetchDefinition += ", 0";
|
||||
inputFetchDefinition += ");\n";
|
||||
|
||||
if (fetchType.has_value())
|
||||
cemu_assert_debug(fetchType == attr.fetchType);
|
||||
@ -153,7 +169,8 @@ void RendererShaderMtl::CompileObjectFunction(const LatteContextRegister& lcr, c
|
||||
uint32 bufferBaseRegisterIndex = mmSQ_VTX_ATTRIBUTE_BLOCK_START + bufferIndex * 7;
|
||||
uint32 bufferStride = (lcr.GetRawView()[bufferBaseRegisterIndex + 2] >> 11) & 0xFFFF;
|
||||
|
||||
fullCode += ", device uchar* vertexBuffer" + std::to_string(bufferIndex) + " [[buffer(" + std::to_string(GET_MTL_VERTEX_BUFFER_INDEX(bufferIndex)) + ")]]";
|
||||
vertexBufferDefinitions += ", device uchar* vertexBuffer" + std::to_string(bufferIndex) + " [[buffer(" + std::to_string(GET_MTL_VERTEX_BUFFER_INDEX(bufferIndex)) + ")]]";
|
||||
vertexBuffers += ", vertexBuffer" + std::to_string(bufferIndex);
|
||||
}
|
||||
inputFetchDefinition += "return in;\n";
|
||||
inputFetchDefinition += "}\n";
|
||||
|
Loading…
Reference in New Issue
Block a user