support line strip as vertex output with geometry shaders

This commit is contained in:
Samuliak 2025-01-28 19:23:47 +01:00
parent 1fb9cfd783
commit 3fececc3ba
No known key found for this signature in database
4 changed files with 48 additions and 41 deletions

View file

@ -4140,7 +4140,11 @@ void LatteDecompiler_emitMSLShader(LatteDecompilerShaderContext* shaderContext,
if (usesGeometryShader)
{
// Calculate the imaginary vertex id
src->add("uint vid = tig * VERTICES_PER_VERTEX_PRIMITIVE + tid;" _CRLF);
LattePrimitiveMode vsOutPrimType = shaderContext->contextRegistersNew->VGT_PRIMITIVE_TYPE.get_PRIMITIVE_MODE();
if (PrimitiveRequiresConnection(vsOutPrimType))
src->add("uint vid = tig + tid;" _CRLF);
else
src->add("uint vid = tig * VERTICES_PER_VERTEX_PRIMITIVE + tid;" _CRLF);
src->add("uint iid = vid / supportBuffer.verticesPerInstance;" _CRLF);
src->add("vid %= supportBuffer.verticesPerInstance;" _CRLF);

View file

@ -2,7 +2,7 @@
#include "Common/precompiled.h"
#include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h"
#include "HW/Latte/Core/LatteShader.h"
#include "Cafe/HW/Latte/Core/LatteShader.h"
namespace LatteDecompiler
{
@ -363,27 +363,10 @@ namespace LatteDecompiler
if ((decompilerContext->options->usesGeometryShader || isRectVertexShader) && (decompilerContext->shaderType == LatteConst::ShaderType::Vertex || decompilerContext->shaderType == LatteConst::ShaderType::Geometry))
{
LattePrimitiveMode vsOutPrimType = static_cast<LattePrimitiveMode>(decompilerContext->contextRegisters[mmVGT_PRIMITIVE_TYPE]);
uint32 gsOutPrimType = decompilerContext->contextRegisters[mmVGT_GS_OUT_PRIM_TYPE];
LattePrimitiveMode vsOutPrimType = decompilerContext->contextRegistersNew->VGT_PRIMITIVE_TYPE.get_PRIMITIVE_MODE();
src->addFmt("#define VERTICES_PER_VERTEX_PRIMITIVE {}" _CRLF, GetVerticesPerPrimitive(vsOutPrimType));
switch (vsOutPrimType)
{
case LattePrimitiveMode::POINTS:
src->add("#define VERTICES_PER_VERTEX_PRIMITIVE 1" _CRLF);
break;
case LattePrimitiveMode::LINES:
src->add("#define VERTICES_PER_VERTEX_PRIMITIVE 2" _CRLF);
break;
case LattePrimitiveMode::TRIANGLES:
src->add("#define VERTICES_PER_VERTEX_PRIMITIVE 3" _CRLF);
break;
case LattePrimitiveMode::RECTS:
src->add("#define VERTICES_PER_VERTEX_PRIMITIVE 3" _CRLF);
break;
default:
cemuLog_log(LogType::Force, "Unknown vertex out primitive type {}", vsOutPrimType);
break;
}
uint32 gsOutPrimType = decompilerContext->contextRegisters[mmVGT_GS_OUT_PRIM_TYPE];
if (decompilerContext->shaderType == LatteConst::ShaderType::Geometry)
{
switch (gsOutPrimType)

View file

@ -117,6 +117,7 @@ inline bool executeCommand(fmt::format_string<T...> fmt, T&&... args) {
return true;
}
/*
class MemoryMappedFile
{
public:
@ -179,3 +180,33 @@ private:
void* m_data = nullptr;
size_t m_fileSize = 0;
};
*/
inline uint32 GetVerticesPerPrimitive(LattePrimitiveMode primitiveMode)
{
switch (primitiveMode)
{
case LattePrimitiveMode::POINTS:
return 1;
case LattePrimitiveMode::LINES:
return 2;
case LattePrimitiveMode::LINE_STRIP:
// Same as line, but requires connection
return 2;
case LattePrimitiveMode::TRIANGLES:
return 3;
case LattePrimitiveMode::RECTS:
return 3;
default:
cemuLog_log(LogType::Force, "Unimplemented primitive type {}", primitiveMode);
return 0;
}
}
inline bool PrimitiveRequiresConnection(LattePrimitiveMode primitiveMode)
{
if (primitiveMode == LattePrimitiveMode::LINE_STRIP)
return true;
else
return false;
}

View file

@ -1132,7 +1132,7 @@ void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32
*/
// Primitive type
const LattePrimitiveMode primitiveMode = static_cast<LattePrimitiveMode>(LatteGPUState.contextRegister[mmVGT_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);
@ -1394,25 +1394,14 @@ void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32
renderCommandEncoder->setObjectBytes(&hostIndexTypeU8, sizeof(hostIndexTypeU8), vertexShader->resourceMapping.indexTypeBinding);
encoderState.m_buffers[METAL_SHADER_TYPE_OBJECT][vertexShader->resourceMapping.indexTypeBinding] = {nullptr};
uint32 verticesPerPrimitive = 0;
switch (primitiveMode)
{
case LattePrimitiveMode::POINTS:
verticesPerPrimitive = 1;
break;
case LattePrimitiveMode::LINES:
verticesPerPrimitive = 2;
break;
case LattePrimitiveMode::TRIANGLES:
case LattePrimitiveMode::RECTS:
verticesPerPrimitive = 3;
break;
default:
cemuLog_log(LogType::Force, "unimplemented geometry shader primitive mode {}", (uint32)primitiveMode);
break;
}
uint32 verticesPerPrimitive = GetVerticesPerPrimitive(primitiveMode);
uint32 threadgroupCount = count * instanceCount;
if (PrimitiveRequiresConnection(primitiveMode))
threadgroupCount -= verticesPerPrimitive - 1;
else
threadgroupCount /= verticesPerPrimitive;
renderCommandEncoder->drawMeshThreadgroups(MTL::Size(count * instanceCount / verticesPerPrimitive, 1, 1), MTL::Size(verticesPerPrimitive, 1, 1), MTL::Size(1, 1, 1));
renderCommandEncoder->drawMeshThreadgroups(MTL::Size(threadgroupCount, 1, 1), MTL::Size(verticesPerPrimitive, 1, 1), MTL::Size(1, 1, 1));
}
else
{