diff --git a/src/video_core/renderer_metal/maxwell_to_mtl.h b/src/video_core/renderer_metal/maxwell_to_mtl.h index d4bbfc5c25..e04ae05f66 100644 --- a/src/video_core/renderer_metal/maxwell_to_mtl.h +++ b/src/video_core/renderer_metal/maxwell_to_mtl.h @@ -145,4 +145,172 @@ inline size_t GetTextureBytesPerRow(VideoCore::Surface::PixelFormat pixel_format format_info.bytes_per_block; } +inline MTL::VertexFormat VertexFormat(Maxwell::VertexAttribute::Type type, Maxwell::VertexAttribute::Size size) { + const MTL::VertexFormat format{([&]() { + switch (type) { + case Maxwell::VertexAttribute::Type::UnusedEnumDoNotUseBecauseItWillGoAway: + ASSERT_MSG(false, "Invalid vertex attribute type!"); + break; + case Maxwell::VertexAttribute::Type::UNorm: + switch (size) { + case Maxwell::VertexAttribute::Size::Size_R8: + case Maxwell::VertexAttribute::Size::Size_A8: + return MTL::VertexFormatUCharNormalized; + case Maxwell::VertexAttribute::Size::Size_R8_G8: + case Maxwell::VertexAttribute::Size::Size_G8_R8: + return MTL::VertexFormatUChar2Normalized; + case Maxwell::VertexAttribute::Size::Size_R8_G8_B8: + return MTL::VertexFormatUChar3Normalized; + case Maxwell::VertexAttribute::Size::Size_R8_G8_B8_A8: + case Maxwell::VertexAttribute::Size::Size_X8_B8_G8_R8: + return MTL::VertexFormatUChar4Normalized; + case Maxwell::VertexAttribute::Size::Size_R16: + return MTL::VertexFormatUShortNormalized; + case Maxwell::VertexAttribute::Size::Size_R16_G16: + return MTL::VertexFormatUShort2Normalized; + case Maxwell::VertexAttribute::Size::Size_R16_G16_B16: + return MTL::VertexFormatUShort3Normalized; + case Maxwell::VertexAttribute::Size::Size_R16_G16_B16_A16: + return MTL::VertexFormatUShort4Normalized; + case Maxwell::VertexAttribute::Size::Size_A2_B10_G10_R10: + return MTL::VertexFormatInvalid; // TODO: emulate + default: + break; + } + break; + case Maxwell::VertexAttribute::Type::SNorm: + switch (size) { + case Maxwell::VertexAttribute::Size::Size_R8: + case Maxwell::VertexAttribute::Size::Size_A8: + return MTL::VertexFormatCharNormalized; + case Maxwell::VertexAttribute::Size::Size_R8_G8: + case Maxwell::VertexAttribute::Size::Size_G8_R8: + return MTL::VertexFormatChar2Normalized; + case Maxwell::VertexAttribute::Size::Size_R8_G8_B8: + return MTL::VertexFormatChar3Normalized; + case Maxwell::VertexAttribute::Size::Size_R8_G8_B8_A8: + case Maxwell::VertexAttribute::Size::Size_X8_B8_G8_R8: + return MTL::VertexFormatChar4Normalized; + case Maxwell::VertexAttribute::Size::Size_R16: + return MTL::VertexFormatShortNormalized; + case Maxwell::VertexAttribute::Size::Size_R16_G16: + return MTL::VertexFormatShort2Normalized; + case Maxwell::VertexAttribute::Size::Size_R16_G16_B16: + return MTL::VertexFormatShort3Normalized; + case Maxwell::VertexAttribute::Size::Size_R16_G16_B16_A16: + return MTL::VertexFormatShort4Normalized; + case Maxwell::VertexAttribute::Size::Size_A2_B10_G10_R10: + return MTL::VertexFormatInvalid; // TODO: emulate + default: + break; + } + break; + case Maxwell::VertexAttribute::Type::UInt: + case Maxwell::VertexAttribute::Type::UScaled: + switch (size) { + case Maxwell::VertexAttribute::Size::Size_R8: + case Maxwell::VertexAttribute::Size::Size_A8: + return MTL::VertexFormatUChar; + case Maxwell::VertexAttribute::Size::Size_R8_G8: + case Maxwell::VertexAttribute::Size::Size_G8_R8: + return MTL::VertexFormatUChar2; + case Maxwell::VertexAttribute::Size::Size_R8_G8_B8: + return MTL::VertexFormatUChar3; + case Maxwell::VertexAttribute::Size::Size_R8_G8_B8_A8: + case Maxwell::VertexAttribute::Size::Size_X8_B8_G8_R8: + return MTL::VertexFormatUChar4; + case Maxwell::VertexAttribute::Size::Size_R16: + return MTL::VertexFormatUShort; + case Maxwell::VertexAttribute::Size::Size_R16_G16: + return MTL::VertexFormatUShort2; + case Maxwell::VertexAttribute::Size::Size_R16_G16_B16: + return MTL::VertexFormatUShort3; + case Maxwell::VertexAttribute::Size::Size_R16_G16_B16_A16: + return MTL::VertexFormatUShort4; + case Maxwell::VertexAttribute::Size::Size_R32: + return MTL::VertexFormatUInt; + case Maxwell::VertexAttribute::Size::Size_R32_G32: + return MTL::VertexFormatUInt2; + case Maxwell::VertexAttribute::Size::Size_R32_G32_B32: + return MTL::VertexFormatUInt3; + case Maxwell::VertexAttribute::Size::Size_R32_G32_B32_A32: + return MTL::VertexFormatUInt4; + case Maxwell::VertexAttribute::Size::Size_A2_B10_G10_R10: + return MTL::VertexFormatInvalid; // TODO: emulate + default: + break; + } + break; + case Maxwell::VertexAttribute::Type::SInt: + case Maxwell::VertexAttribute::Type::SScaled: + switch (size) { + case Maxwell::VertexAttribute::Size::Size_R8: + case Maxwell::VertexAttribute::Size::Size_A8: + return MTL::VertexFormatChar; + case Maxwell::VertexAttribute::Size::Size_R8_G8: + case Maxwell::VertexAttribute::Size::Size_G8_R8: + return MTL::VertexFormatChar2; + case Maxwell::VertexAttribute::Size::Size_R8_G8_B8: + return MTL::VertexFormatChar3; + case Maxwell::VertexAttribute::Size::Size_R8_G8_B8_A8: + case Maxwell::VertexAttribute::Size::Size_X8_B8_G8_R8: + return MTL::VertexFormatChar4; + case Maxwell::VertexAttribute::Size::Size_R16: + return MTL::VertexFormatShort; + case Maxwell::VertexAttribute::Size::Size_R16_G16: + return MTL::VertexFormatShort2; + case Maxwell::VertexAttribute::Size::Size_R16_G16_B16: + return MTL::VertexFormatShort3; + case Maxwell::VertexAttribute::Size::Size_R16_G16_B16_A16: + return MTL::VertexFormatShort4; + case Maxwell::VertexAttribute::Size::Size_R32: + return MTL::VertexFormatInt; + case Maxwell::VertexAttribute::Size::Size_R32_G32: + return MTL::VertexFormatInt2; + case Maxwell::VertexAttribute::Size::Size_R32_G32_B32: + return MTL::VertexFormatInt3; + case Maxwell::VertexAttribute::Size::Size_R32_G32_B32_A32: + return MTL::VertexFormatInt4; + case Maxwell::VertexAttribute::Size::Size_A2_B10_G10_R10: + return MTL::VertexFormatInvalid; // TODO: emulate + default: + break; + } + break; + case Maxwell::VertexAttribute::Type::Float: + switch (size) { + case Maxwell::VertexAttribute::Size::Size_R16: + return MTL::VertexFormatHalf; + case Maxwell::VertexAttribute::Size::Size_R16_G16: + return MTL::VertexFormatHalf2; + case Maxwell::VertexAttribute::Size::Size_R16_G16_B16: + return MTL::VertexFormatHalf3; + case Maxwell::VertexAttribute::Size::Size_R16_G16_B16_A16: + return MTL::VertexFormatHalf4; + case Maxwell::VertexAttribute::Size::Size_R32: + return MTL::VertexFormatFloat; + case Maxwell::VertexAttribute::Size::Size_R32_G32: + return MTL::VertexFormatFloat2; + case Maxwell::VertexAttribute::Size::Size_R32_G32_B32: + return MTL::VertexFormatFloat3; + case Maxwell::VertexAttribute::Size::Size_R32_G32_B32_A32: + return MTL::VertexFormatFloat4; + case Maxwell::VertexAttribute::Size::Size_B10_G11_R11: + return MTL::VertexFormatInvalid; // TODO: emulate + default: + break; + } + break; + } + + return MTL::VertexFormatInvalid; + })()}; + + if (format == MTL::VertexFormatInvalid) { + UNIMPLEMENTED_MSG("Unimplemented vertex format of type={} and size={}", type, size); + } + + return format; +} + } // namespace Metal::MaxwellToMTL diff --git a/src/video_core/renderer_metal/mtl_graphics_pipeline.cpp b/src/video_core/renderer_metal/mtl_graphics_pipeline.cpp index a13b044727..9c9d618d1c 100644 --- a/src/video_core/renderer_metal/mtl_graphics_pipeline.cpp +++ b/src/video_core/renderer_metal/mtl_graphics_pipeline.cpp @@ -18,6 +18,7 @@ #include "video_core/shader_notify.h" #include "video_core/texture_cache/texture_cache.h" #include "video_core/texture_cache/texture_cache_base.h" +#include "video_core/renderer_metal/maxwell_to_mtl.h" namespace Metal { namespace { @@ -56,7 +57,6 @@ GraphicsPipeline::GraphicsPipeline(const Device& device_, CommandRecorder& comma LOG_DEBUG(Render_Metal, "framebuffer not available"); return; } - MakePipeline(framebuffer->GetHandle()); } void GraphicsPipeline::Configure(bool is_indexed) { @@ -203,16 +203,47 @@ void GraphicsPipeline::Configure(bool is_indexed) { } command_recorder.BeginOrContinueRenderPass(framebuffer->GetHandle()); + MakePipeline(framebuffer->GetHandle()); command_recorder.SetRenderPipelineState(pipeline_state); } void GraphicsPipeline::MakePipeline(MTL::RenderPassDescriptor* render_pass) { - MTL::RenderPipelineDescriptor* pipeline_descriptor = + const auto& regs{maxwell3d->regs}; + + // Shader stages + MTL::RenderPipelineDescriptor* desc = MTL::RenderPipelineDescriptor::alloc()->init(); - pipeline_descriptor->setVertexFunction(functions[0]); - pipeline_descriptor->setFragmentFunction(functions[4]); - // pipeline_descriptor->setVertexDescriptor(vertex_descriptor); - // TODO: get the attachment count from render pass descriptor + desc->setVertexFunction(functions[0]); + desc->setFragmentFunction(functions[4]); + + // Vertex descriptor + MTL::VertexDescriptor* vertex_descriptor = MTL::VertexDescriptor::alloc()->init(); + for (size_t index = 0; index < Maxwell::NumVertexArrays; ++index) { + const auto& array = regs.vertex_streams[index]; + if (!array.enable) + continue; + + ASSERT(index < MAX_BUFFERS); + + // TODO: instancing + auto layout = vertex_descriptor->layouts()->object(index); + layout->setStride(array.stride.Value()); + } + for (size_t index = 0; index < Maxwell::NumVertexAttributes; ++index) { + const auto& input = regs.vertex_attrib_format[index]; + // TODO: doesn't this need some special handling? + if (input.constant) + continue; + + auto attribute = vertex_descriptor->attributes()->object(index); + attribute->setBufferIndex(input.buffer); + attribute->setOffset(input.offset); + attribute->setFormat(MaxwellToMTL::VertexFormat(input.type.Value(), input.size.Value())); + } + desc->setVertexDescriptor(vertex_descriptor); + vertex_descriptor->release(); + + // Color attachments for (u32 index = 0; index < NUM_RT; index++) { auto* render_pass_attachment = render_pass->colorAttachments()->object(index); // TODO: is this the correct way to check if the attachment is valid? @@ -220,13 +251,14 @@ void GraphicsPipeline::MakePipeline(MTL::RenderPassDescriptor* render_pass) { continue; } - auto* color_attachment = pipeline_descriptor->colorAttachments()->object(index); + auto* color_attachment = desc->colorAttachments()->object(index); color_attachment->setPixelFormat(render_pass_attachment->texture()->pixelFormat()); // TODO: provide blend information } NS::Error* error = nullptr; - pipeline_state = device.GetDevice()->newRenderPipelineState(pipeline_descriptor, &error); + pipeline_state = device.GetDevice()->newRenderPipelineState(desc, &error); + desc->release(); if (error) { LOG_ERROR(Render_Metal, "failed to create pipeline state: {}", error->description()->cString(NS::ASCIIStringEncoding)); diff --git a/src/video_core/renderer_metal/mtl_graphics_pipeline.h b/src/video_core/renderer_metal/mtl_graphics_pipeline.h index ab11298c6d..9e18116705 100644 --- a/src/video_core/renderer_metal/mtl_graphics_pipeline.h +++ b/src/video_core/renderer_metal/mtl_graphics_pipeline.h @@ -118,6 +118,7 @@ private: VideoCommon::UniformBufferSizes uniform_buffer_sizes{}; // u32 num_textures{}; + // TODO: cache pipelines if state changes MTL::RenderPipelineState* pipeline_state{nullptr}; };