Skip to content

Commit

Permalink
support line strip as vertex output with geometry shaders
Browse files Browse the repository at this point in the history
  • Loading branch information
SamoZ256 committed Jan 28, 2025
1 parent 1fb9cfd commit 3fececc
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -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)
Expand Down
31 changes: 31 additions & 0 deletions src/Cafe/HW/Latte/Renderer/Metal/MetalCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ inline bool executeCommand(fmt::format_string<T...> fmt, T&&... args) {
return true;
}

/*
class MemoryMappedFile
{
public:
Expand Down Expand Up @@ -179,3 +180,33 @@ class MemoryMappedFile
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;
}
27 changes: 8 additions & 19 deletions src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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
{
Expand Down

0 comments on commit 3fececc

Please sign in to comment.