diff --git a/src/video_core/renderer_metal/maxwell_to_mtl.h b/src/video_core/renderer_metal/maxwell_to_mtl.h index e04ae05f66..eddee8f220 100644 --- a/src/video_core/renderer_metal/maxwell_to_mtl.h +++ b/src/video_core/renderer_metal/maxwell_to_mtl.h @@ -313,4 +313,33 @@ inline MTL::VertexFormat VertexFormat(Maxwell::VertexAttribute::Type type, Maxwe return format; } +inline MTL::IndexType IndexType(Maxwell::IndexFormat format) { + switch (format) { + // TODO: UnsignedByte + case Maxwell::IndexFormat::UnsignedShort: + return MTL::IndexTypeUInt16; + case Maxwell::IndexFormat::UnsignedInt: + return MTL::IndexTypeUInt32; + default: + UNIMPLEMENTED_MSG("Unimplemented index format {}", format); + } + + return MTL::IndexTypeUInt16; +} + +inline size_t IndexSize(Maxwell::IndexFormat format) { + switch (format) { + case Maxwell::IndexFormat::UnsignedByte: + return 1; + case Maxwell::IndexFormat::UnsignedShort: + return 2; + case Maxwell::IndexFormat::UnsignedInt: + return 4; + default: + UNIMPLEMENTED_MSG("Unimplemented index format {}", format); + } + + return 0; +} + } // namespace Metal::MaxwellToMTL diff --git a/src/video_core/renderer_metal/mtl_command_recorder.h b/src/video_core/renderer_metal/mtl_command_recorder.h index 7d7b8efd3b..f2eb4f4383 100644 --- a/src/video_core/renderer_metal/mtl_command_recorder.h +++ b/src/video_core/renderer_metal/mtl_command_recorder.h @@ -7,6 +7,7 @@ #include #include "video_core/engines/maxwell_3d.h" +#include "video_core/renderer_metal/maxwell_to_mtl.h" namespace Metal { @@ -37,10 +38,11 @@ struct BoundSamplerState { struct BoundIndexBuffer { MTL::Buffer* buffer{nullptr}; size_t offset{0}; - MTL::IndexType index_format; - MTL::PrimitiveType primitive_topology; - u32 num_indices; - u32 base_vertex; + MTL::IndexType index_type; + size_t index_size; + //MTL::PrimitiveType primitive_topology; + //u32 num_indices; + //u32 base_vertex; }; struct RenderState { @@ -140,8 +142,13 @@ public: u32 base_vertex) { // TODO: convert parameters to Metal enums render_state.bound_index_buffer = { - buffer, offset, MTL::IndexTypeUInt32, MTL::PrimitiveTypeTriangle, - num_indices, base_vertex}; + buffer, offset, MaxwellToMTL::IndexType(index_format), MaxwellToMTL::IndexSize(index_format)/*, MTL::PrimitiveTypeTriangle, + num_indices, base_vertex*/}; + } + + // Getters + const BoundIndexBuffer& GetBoundIndexBuffer() const { + return render_state.bound_index_buffer; } private: diff --git a/src/video_core/renderer_metal/mtl_graphics_pipeline.cpp b/src/video_core/renderer_metal/mtl_graphics_pipeline.cpp index 9c9d618d1c..d63c11e7e5 100644 --- a/src/video_core/renderer_metal/mtl_graphics_pipeline.cpp +++ b/src/video_core/renderer_metal/mtl_graphics_pipeline.cpp @@ -226,7 +226,7 @@ void GraphicsPipeline::MakePipeline(MTL::RenderPassDescriptor* render_pass) { ASSERT(index < MAX_BUFFERS); // TODO: instancing - auto layout = vertex_descriptor->layouts()->object(index); + auto layout = vertex_descriptor->layouts()->object(MAX_BUFFERS - 1 - index); layout->setStride(array.stride.Value()); } for (size_t index = 0; index < Maxwell::NumVertexAttributes; ++index) { @@ -236,7 +236,7 @@ void GraphicsPipeline::MakePipeline(MTL::RenderPassDescriptor* render_pass) { continue; auto attribute = vertex_descriptor->attributes()->object(index); - attribute->setBufferIndex(input.buffer); + attribute->setBufferIndex(MAX_BUFFERS - 1 - input.buffer); attribute->setOffset(input.offset); attribute->setFormat(MaxwellToMTL::VertexFormat(input.type.Value(), input.size.Value())); } diff --git a/src/video_core/renderer_metal/mtl_pipeline_cache.cpp b/src/video_core/renderer_metal/mtl_pipeline_cache.cpp index 80786e1d1c..cb4be94ba6 100644 --- a/src/video_core/renderer_metal/mtl_pipeline_cache.cpp +++ b/src/video_core/renderer_metal/mtl_pipeline_cache.cpp @@ -332,6 +332,8 @@ GraphicsPipeline* PipelineCache::BuiltPipeline(GraphicsPipeline* pipeline) const if (pipeline->IsBuilt()) { return pipeline; } + + // TODO: what const auto& draw_state = maxwell3d->draw_manager->GetDrawState(); if (draw_state.index_buffer.count <= 6 || draw_state.vertex_buffer.count <= 6) { return pipeline; diff --git a/src/video_core/renderer_metal/mtl_rasterizer.cpp b/src/video_core/renderer_metal/mtl_rasterizer.cpp index 4ef1debd74..f7769f6f55 100644 --- a/src/video_core/renderer_metal/mtl_rasterizer.cpp +++ b/src/video_core/renderer_metal/mtl_rasterizer.cpp @@ -16,6 +16,49 @@ namespace Metal { +using Maxwell = Tegra::Engines::Maxwell3D::Regs; +using MaxwellDrawState = Tegra::Engines::DrawManager::State; +using VideoCommon::ImageViewId; +using VideoCommon::ImageViewType; + +namespace { + +struct DrawParams { + u32 base_instance; + u32 num_instances; + u32 base_vertex; + u32 num_vertices; + u32 first_index; + bool is_indexed; +}; + +DrawParams MakeDrawParams(const MaxwellDrawState& draw_state, u32 num_instances, bool is_indexed) { + DrawParams params{ + .base_instance = draw_state.base_instance, + .num_instances = num_instances, + .base_vertex = is_indexed ? draw_state.base_index : draw_state.vertex_buffer.first, + .num_vertices = is_indexed ? draw_state.index_buffer.count : draw_state.vertex_buffer.count, + .first_index = is_indexed ? draw_state.index_buffer.first : 0, + .is_indexed = is_indexed, + }; + + // 6 triangle vertices per quad, base vertex is part of the index + // See BindQuadIndexBuffer for more details + if (draw_state.topology == Maxwell::PrimitiveTopology::Quads) { + params.num_vertices = (params.num_vertices / 4) * 6; + params.base_vertex = 0; + params.is_indexed = true; + } else if (draw_state.topology == Maxwell::PrimitiveTopology::QuadStrip) { + params.num_vertices = (params.num_vertices - 2) / 2 * 6; + params.base_vertex = 0; + params.is_indexed = true; + } + + return params; +} + +} // Anonymous namespace + AccelerateDMA::AccelerateDMA() = default; bool AccelerateDMA::BufferCopy(GPUVAddr start_address, GPUVAddr end_address, u64 amount) { @@ -41,41 +84,33 @@ RasterizerMetal::RasterizerMetal(Tegra::GPU& gpu_, RasterizerMetal::~RasterizerMetal() = default; void RasterizerMetal::Draw(bool is_indexed, u32 instance_count) { - LOG_DEBUG(Render_Metal, "called"); - // Bind the current graphics pipeline GraphicsPipeline* const pipeline{pipeline_cache.CurrentGraphicsPipeline()}; if (!pipeline) { return; } + // Set the engine pipeline->SetEngine(maxwell3d, gpu_memory); pipeline->Configure(is_indexed); - // HACK: dummy draw call - command_recorder.GetRenderCommandEncoder()->drawPrimitives(MTL::PrimitiveTypeTriangle, - NS::UInteger(0), NS::UInteger(3)); + const auto& draw_state = maxwell3d->draw_manager->GetDrawState(); + const DrawParams draw_params{MakeDrawParams(draw_state, instance_count, is_indexed)}; + + // TODO: get the primitive type + MTL::PrimitiveType primitiveType = MTL::PrimitiveTypeTriangle;//MaxwellToMTL::PrimitiveType(draw_state.topology); - // TODO: uncomment - // command_recorder.CheckIfRenderPassIsActive(); - // const auto& draw_state = maxwell3d->draw_manager->GetDrawState(); if (is_indexed) { - LOG_DEBUG(Render_Metal, "indexed"); - /*[command_buffer drawIndexedPrimitives:MTLPrimitiveTypeTriangle - indexCount:draw_params.num_indices - indexType:MTLIndexTypeUInt32 - indexBuffer:draw_state.index_buffer - indexBufferOffset:draw_params.first_index * sizeof(u32) - instanceCount:draw_params.num_instances - baseVertex:draw_params.base_vertex - baseInstance:draw_params.base_instance];*/ - // cmdbuf.DrawIndexed(draw_params.num_vertices, draw_params.num_instances, - // draw_params.first_index, draw_params.base_vertex, - // draw_params.base_instance); + auto& index_buffer = command_recorder.GetBoundIndexBuffer(); + size_t index_buffer_offset = index_buffer.offset + draw_params.first_index * index_buffer.index_size; + + ASSERT(index_buffer_offset % 4 == 0); + + command_recorder.GetRenderCommandEncoder()->drawIndexedPrimitives(primitiveType, draw_params.num_vertices, index_buffer.index_type, index_buffer.buffer, index_buffer_offset, draw_params.num_instances, + draw_params.base_vertex, draw_params.base_instance); } else { - LOG_DEBUG(Render_Metal, "not indexed"); - // cmdbuf.Draw(draw_params.num_vertices, draw_params.num_instances, - // draw_params.base_vertex, draw_params.base_instance); + command_recorder.GetRenderCommandEncoder()->drawPrimitives(primitiveType, + draw_params.base_vertex, draw_params.num_vertices, draw_params.num_instances, draw_params.base_instance); } } @@ -92,8 +127,6 @@ void RasterizerMetal::Clear(u32 layer_count) { return; } - // TODO: track the textures used by render pass and only begin the render pass if their contents - // are needed Begin render pass command_recorder.BeginOrContinueRenderPass(framebuffer->GetHandle()); }