From dc2f0eac3060faaec976ff676cdd34c0fad92749 Mon Sep 17 00:00:00 2001 From: Dynamitos Date: Sun, 14 Apr 2024 11:35:37 +0200 Subject: [PATCH] Metal is impossible to debug, thanks apple --- src/Engine/Graphics/Metal/Buffer.mm | 2 - src/Engine/Graphics/Metal/Command.h | 6 +- src/Engine/Graphics/Metal/Command.mm | 148 +++++++++++---------- src/Engine/Graphics/Metal/Descriptor.h | 5 +- src/Engine/Graphics/Metal/Descriptor.mm | 1 + src/Engine/Graphics/Metal/Enums.h | 7 +- src/Engine/Graphics/Metal/Enums.mm | 51 ++++++- src/Engine/Graphics/Metal/Graphics.h | 2 + src/Engine/Graphics/Metal/Graphics.mm | 27 ++-- src/Engine/Graphics/Metal/Pipeline.h | 27 ++-- src/Engine/Graphics/Metal/Pipeline.mm | 23 ++-- src/Engine/Graphics/Metal/PipelineCache.h | 2 +- src/Engine/Graphics/Metal/PipelineCache.mm | 130 ++++++++++++++++-- src/Engine/Graphics/Metal/Shader.mm | 32 +++-- 14 files changed, 325 insertions(+), 138 deletions(-) diff --git a/src/Engine/Graphics/Metal/Buffer.mm b/src/Engine/Graphics/Metal/Buffer.mm index 33b41c9..ebb4aeb 100644 --- a/src/Engine/Graphics/Metal/Buffer.mm +++ b/src/Engine/Graphics/Metal/Buffer.mm @@ -3,8 +3,6 @@ #include "Graphics/Buffer.h" #include "Graphics/Enums.h" #include "Graphics/Initializer.h" -#include "Metal/MTLResource.hpp" - using namespace Seele; using namespace Seele::Metal; diff --git a/src/Engine/Graphics/Metal/Command.h b/src/Engine/Graphics/Metal/Command.h index 00ed3e3..40cc22c 100644 --- a/src/Engine/Graphics/Metal/Command.h +++ b/src/Engine/Graphics/Metal/Command.h @@ -1,6 +1,6 @@ #pragma once #include "Graphics/Command.h" -#include "Metal/MTLCommandBuffer.hpp" +#include "Buffer.h" #include "RenderPass.h" #include "Resources.h" @@ -10,6 +10,8 @@ DECLARE_REF(CommandQueue) DECLARE_REF(ComputeCommand) DECLARE_REF(RenderCommand) DECLARE_REF(Graphics) +DECLARE_REF(IndexBuffer) +DECLARE_REF(GraphicsPipeline) class Command { public: @@ -56,6 +58,8 @@ public: virtual void drawMesh(uint32 groupX, uint32 groupY, uint32 groupZ) override; private: MTL::RenderCommandEncoder* encoder; + PIndexBuffer boundIndexBuffer; + PGraphicsPipeline boundPipeline; }; DEFINE_REF(RenderCommand) class ComputeCommand : public Gfx::ComputeCommand diff --git a/src/Engine/Graphics/Metal/Command.mm b/src/Engine/Graphics/Metal/Command.mm index f68a8ee..3d1e72f 100644 --- a/src/Engine/Graphics/Metal/Command.mm +++ b/src/Engine/Graphics/Metal/Command.mm @@ -1,30 +1,28 @@ #include "Command.h" +#include "Buffer.h" +#include "Descriptor.h" +#include "Enums.h" +#include "Graphics/Enums.h" #include "Graphics/Graphics.h" -#include "Graphics/Metal/Resources.h" -#include "Metal/MTLCommandBuffer.hpp" -#include "Metal/MTLIOCommandQueue.hpp" -#include "Metal/MTLRenderCommandEncoder.hpp" +#include "Pipeline.h" +#include "Resources.h" #include "Window.h" using namespace Seele; using namespace Seele::Metal; Command::Command(PGraphics graphics, MTL::CommandBuffer* cmdBuffer) - : graphics(graphics), completed(new Event(graphics)), - cmdBuffer(cmdBuffer), renderEncoder(nullptr) {} + : graphics(graphics), completed(new Event(graphics)), cmdBuffer(cmdBuffer), renderEncoder(nullptr) {} Command::~Command() { cmdBuffer->release(); } void Command::beginRenderPass(PRenderPass renderPass) { - renderEncoder = - cmdBuffer->parallelRenderCommandEncoder(renderPass->getDescriptor()); + renderEncoder = cmdBuffer->parallelRenderCommandEncoder(renderPass->getDescriptor()); } void Command::endRenderPass() { renderEncoder->endEncoding(); } -void Command::present(MTL::Drawable *drawable) { - cmdBuffer->presentDrawable(drawable); -} +void Command::present(MTL::Drawable* drawable) { cmdBuffer->presentDrawable(drawable); } void Command::end(PEvent signal) { if (signal != nullptr) { @@ -35,14 +33,14 @@ void Command::end(PEvent signal) { } void Command::executeCommands(Array commands) { - for (auto &command : commands) { + for (auto& command : commands) { auto cmd = Gfx::PRenderCommand(command).cast(); cmd->end(); } } void Command::executeCommands(Array commands) { - for (auto &command : commands) { + for (auto& command : commands) { auto cmd = Gfx::PComputeCommand(command).cast(); cmd->end(); } @@ -50,16 +48,11 @@ void Command::executeCommands(Array commands) { void Command::waitDeviceIdle() { cmdBuffer->waitUntilCompleted(); } -void Command::signalEvent(PEvent event) { - cmdBuffer->encodeSignalEvent(event->getHandle(), 1); -} +void Command::signalEvent(PEvent event) { cmdBuffer->encodeSignalEvent(event->getHandle(), 1); } -void Command::waitForEvent(PEvent event) { - cmdBuffer->encodeWait(event->getHandle(), 1); -} +void Command::waitForEvent(PEvent event) { cmdBuffer->encodeWait(event->getHandle(), 1); } -RenderCommand::RenderCommand(MTL::RenderCommandEncoder *encoder) - : encoder(encoder) {} +RenderCommand::RenderCommand(MTL::RenderCommandEncoder* encoder) : encoder(encoder) {} RenderCommand::~RenderCommand() { encoder->release(); } @@ -78,98 +71,109 @@ void RenderCommand::setViewport(Gfx::PViewport viewport) { } void RenderCommand::bindPipeline(Gfx::PGraphicsPipeline pipeline) { - // encoder->setRenderPipelineState( - // pipeline.cast()->getState()); + boundPipeline = pipeline.cast(); + encoder->setRenderPipelineState(boundPipeline->getHandle()); } void RenderCommand::bindDescriptor(Gfx::PDescriptorSet descriptorSet) { + encoder->setVertexBuffer(descriptorSet.cast()->getBuffer(), 0, descriptorSet->getSetIndex()); + encoder->setFragmentBuffer(descriptorSet.cast()->getBuffer(), 0, descriptorSet->getSetIndex()); + encoder->setMeshBuffer(descriptorSet.cast()->getBuffer(), 0, descriptorSet->getSetIndex()); + encoder->setObjectBuffer(descriptorSet.cast()->getBuffer(), 0, descriptorSet->getSetIndex()); } -void RenderCommand::bindDescriptor( - const Array &descriptorSets) { - // encoder->set ? ? ? ? ? +void RenderCommand::bindDescriptor(const Array& descriptorSets) { + for (auto set : descriptorSets) { + bindDescriptor(set); + } } -void RenderCommand::bindVertexBuffer(const Array &buffers) { - // encoder->setVertexBuffers(); +void RenderCommand::bindVertexBuffer(const Array& buffers) { + uint32 i = 0; + for (auto buffer : buffers) { + encoder->setVertexBuffer(buffer.cast()->getHandle(), 0, i++); + } } -void RenderCommand::bindIndexBuffer(Gfx::PIndexBuffer indexBuffer) { - // encoder->setObjectBuffer(??, NS::UInteger offset, NS::UInteger index) +void RenderCommand::bindIndexBuffer(Gfx::PIndexBuffer gfxIndexBuffer) { + boundIndexBuffer = gfxIndexBuffer.cast(); } -void RenderCommand::pushConstants(Gfx::PPipelineLayout layout, - Gfx::SeShaderStageFlags stage, uint32 offset, - uint32 size, const void *data) { - // ? ? ? +void RenderCommand::pushConstants(Gfx::PPipelineLayout, Gfx::SeShaderStageFlags stage, uint32 offset, uint32 size, + const void* data) { + if (stage & Gfx::SE_SHADER_STAGE_VERTEX_BIT) { + encoder->setVertexBytes((char*)data + offset, size, 0); + } + if (stage & Gfx::SE_SHADER_STAGE_FRAGMENT_BIT) { + encoder->setFragmentBytes((char*)data + offset, size, 0); + } } -void RenderCommand::draw(uint32 vertexCount, uint32 instanceCount, - int32 firstVertex, uint32 firstInstance) { - // encoder->drawPrimitives(???, firstVertex, vertexCount, instanceCount, firstInstance); +void RenderCommand::draw(uint32 vertexCount, uint32 instanceCount, int32 firstVertex, uint32 firstInstance) { + encoder->drawPrimitives(boundPipeline->getPrimitive(), firstVertex, vertexCount, instanceCount, firstInstance); } -void RenderCommand::drawIndexed(uint32 indexCount, uint32 instanceCount, - int32 firstIndex, uint32 vertexOffset, +void RenderCommand::drawIndexed(uint32 indexCount, uint32 instanceCount, int32 firstIndex, uint32 vertexOffset, uint32 firstInstance) { - // encoder->drawIndexedPrimitives(???, indexCount, indexbuffer->getType(), indexBuffer->getBuffer(), firstIndex, instanceCount, vertexOffset, firstInstance); + encoder->drawIndexedPrimitives(boundPipeline->getPrimitive(), indexCount, cast(boundIndexBuffer->getIndexType()), + boundIndexBuffer->getHandle(), firstIndex, instanceCount, vertexOffset, firstInstance); } -void RenderCommand::drawMesh(uint32 groupX, uint32 groupY, uint32 groupZ){ - // encoder->drawMeshThreads(MTL::Size threadsPerGrid, - // MTL::Size threadsPerObjectThreadgroup, - // MTL::Size threadsPerMeshThreadgroup) - } +void RenderCommand::drawMesh(uint32 groupX, uint32 groupY, uint32 groupZ) { + //TODO: + encoder->drawMeshThreadgroups(MTL::Size(groupX, groupY, groupZ), MTL::Size(128, 128, 128), MTL::Size(32, 32, 32)); +} -ComputeCommand::ComputeCommand(MTL::ComputeCommandEncoder *encoder) - : encoder(encoder) {} +ComputeCommand::ComputeCommand(MTL::ComputeCommandEncoder* encoder) : encoder(encoder) {} ComputeCommand::~ComputeCommand() { encoder->release(); } void ComputeCommand::end() { encoder->endEncoding(); } void ComputeCommand::bindPipeline(Gfx::PComputePipeline pipeline) { - // encoder->setComputePipelineState(pipeline.cast()); + encoder->setComputePipelineState(pipeline.cast()->getHandle()); } void ComputeCommand::bindDescriptor(Gfx::PDescriptorSet set) { - // encoder->set ? ? ? + encoder->setBuffer(set.cast()->getBuffer(), 0, set->getSetIndex()); } -void ComputeCommand::bindDescriptor(const Array &sets) { - // encoder->set ? ? ? +void ComputeCommand::bindDescriptor(const Array& sets) { + for (auto& set : sets) { + bindDescriptor(set); + } } -void ComputeCommand::pushConstants(Gfx::PPipelineLayout layout, - Gfx::SeShaderStageFlags stage, uint32 offset, - uint32 size, const void *data) { - // ? ? ? +void ComputeCommand::pushConstants(Gfx::PPipelineLayout, Gfx::SeShaderStageFlags, uint32 offset, + uint32 size, const void* data) { + encoder->setBytes((char*)data + offset, size, 0); } void ComputeCommand::dispatch(uint32 threadX, uint32 threadY, uint32 threadZ) { - // encoder->dispatchThreadgroups(???); + //TODO + encoder->dispatchThreadgroups(MTL::Size(threadX, threadY, threadZ), MTL::Size(32, 32, 32)); } CommandQueue::CommandQueue(PGraphics graphics) : graphics(graphics) { - queue = graphics->getDevice()->newCommandQueue(); - activeCommand = new Command(graphics, queue->commandBuffer()); + queue = graphics->getDevice()->newCommandQueue(); + activeCommand = new Command(graphics, queue->commandBuffer()); } CommandQueue::~CommandQueue() { queue->release(); } -ORenderCommand CommandQueue::getRenderCommand(const std::string &name) { - return new RenderCommand(activeCommand->createRenderEncoder()); +ORenderCommand CommandQueue::getRenderCommand(const std::string& name) { + return new RenderCommand(activeCommand->createRenderEncoder()); } -OComputeCommand CommandQueue::getComputeCommand(const std::string &name) { - return new ComputeCommand(activeCommand->createComputeEncoder()); +OComputeCommand CommandQueue::getComputeCommand(const std::string& name) { + return new ComputeCommand(activeCommand->createComputeEncoder()); } void CommandQueue::submitCommands(PEvent signalSemaphore) { - activeCommand->end(signalSemaphore); - PEvent prevCmdEvent = activeCommand->getCompletedEvent(); - activeCommand = new Command(graphics, queue->commandBuffer()); - activeCommand->waitForEvent(prevCmdEvent); + activeCommand->end(signalSemaphore); + PEvent prevCmdEvent = activeCommand->getCompletedEvent(); + activeCommand = new Command(graphics, queue->commandBuffer()); + activeCommand->waitForEvent(prevCmdEvent); } IOCommandQueue::IOCommandQueue(PGraphics graphics) : graphics(graphics) { @@ -177,16 +181,16 @@ IOCommandQueue::IOCommandQueue(PGraphics graphics) : graphics(graphics) { desc->setType(MTL::IOCommandQueueTypeConcurrent); desc->setPriority(MTL::IOPriorityNormal); queue = graphics->getDevice()->newIOCommandQueue(desc, nullptr); - //activeCommand = new Command(graphics, queue->commandBuffer()); + // activeCommand = new Command(graphics, queue->commandBuffer()); desc->release(); } IOCommandQueue::~IOCommandQueue() { queue->release(); } void IOCommandQueue::submitCommands(PEvent signalSemaphore) { - //TODO: scratch buffer - activeCommand->end(signalSemaphore); - PEvent prevCmdEvent = activeCommand->getCompletedEvent(); - //activeCommand = new Command(graphics, queue->commandBuffer()); - activeCommand->waitForEvent(prevCmdEvent); + // TODO: scratch buffer + activeCommand->end(signalSemaphore); + PEvent prevCmdEvent = activeCommand->getCompletedEvent(); + // activeCommand = new Command(graphics, queue->commandBuffer()); + activeCommand->waitForEvent(prevCmdEvent); } diff --git a/src/Engine/Graphics/Metal/Descriptor.h b/src/Engine/Graphics/Metal/Descriptor.h index 1dcd5c3..ed74601 100644 --- a/src/Engine/Graphics/Metal/Descriptor.h +++ b/src/Engine/Graphics/Metal/Descriptor.h @@ -1,9 +1,8 @@ #pragma once -#include "Foundation/NSArray.hpp" #include "Graphics/Descriptor.h" #include "Graphics/Initializer.h" -#include "Metal/MTLArgumentEncoder.hpp" #include "MinimalEngine.h" +#include "Buffer.h" namespace Seele { namespace Metal { @@ -58,6 +57,8 @@ public: constexpr void allocate() { currentlyInUse = true; } constexpr void free() { currentlyInUse = false; } + constexpr MTL::Buffer* getBuffer() const { return buffer; } + private: PGraphics graphics; PDescriptorPool owner; diff --git a/src/Engine/Graphics/Metal/Descriptor.mm b/src/Engine/Graphics/Metal/Descriptor.mm index d17cc8d..64550f1 100644 --- a/src/Engine/Graphics/Metal/Descriptor.mm +++ b/src/Engine/Graphics/Metal/Descriptor.mm @@ -47,6 +47,7 @@ void DescriptorLayout::create() { descriptors.add(desc); } arguments = NS::Array::array(descriptors.data(), descriptors.size()); + pool = new DescriptorPool(graphics, this); } DescriptorPool::DescriptorPool(PGraphics graphics, PDescriptorLayout layout) : graphics(graphics), layout(layout) {} diff --git a/src/Engine/Graphics/Metal/Enums.h b/src/Engine/Graphics/Metal/Enums.h index 31b600b..24febe6 100644 --- a/src/Engine/Graphics/Metal/Enums.h +++ b/src/Engine/Graphics/Metal/Enums.h @@ -1,7 +1,6 @@ #pragma once #include "Graphics/Enums.h" -#include "Metal/MTLDepthStencil.hpp" -#include "Metal/MTLSampler.hpp" +#include "Metal/MTLStageInputOutputDescriptor.hpp" #include "Resources.h" namespace Seele @@ -26,5 +25,9 @@ MTL::SamplerMipFilter cast(Gfx::SeSamplerMipmapMode filter); Gfx::SeSamplerMipmapMode cast(MTL::SamplerMipFilter filter); MTL::SamplerAddressMode cast(Gfx::SeSamplerAddressMode mode); Gfx::SeSamplerAddressMode cast(MTL::SamplerAddressMode mode); +MTL::PrimitiveTopologyClass cast(Gfx::SePrimitiveTopology topology); +Gfx::SePrimitiveTopology cast(MTL::PrimitiveTopologyClass topology); +MTL::IndexType cast(Gfx::SeIndexType indexType); +Gfx::SeIndexType cast(MTL::IndexType indexType); } } \ No newline at end of file diff --git a/src/Engine/Graphics/Metal/Enums.mm b/src/Engine/Graphics/Metal/Enums.mm index 5aff205..4abc893 100644 --- a/src/Engine/Graphics/Metal/Enums.mm +++ b/src/Engine/Graphics/Metal/Enums.mm @@ -1,8 +1,6 @@ #include "Enums.h" #include "Graphics/Enums.h" -#include "Metal/MTLArgument.hpp" -#include "Metal/MTLDepthStencil.hpp" -#include "Metal/MTLSampler.hpp" +#include "Metal/MTLStageInputOutputDescriptor.hpp" #include using namespace Seele; @@ -768,3 +766,50 @@ Gfx::SeSamplerAddressMode Seele::Metal::cast(MTL::SamplerAddressMode mode) { return Gfx::SE_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; } } + +MTL::PrimitiveTopologyClass Seele::Metal::cast(Gfx::SePrimitiveTopology topology) { + switch (topology) { + case Gfx::SE_PRIMITIVE_TOPOLOGY_POINT_LIST: + return MTL::PrimitiveTopologyClassPoint; + case Gfx::SE_PRIMITIVE_TOPOLOGY_LINE_LIST: + return MTL::PrimitiveTopologyClassLine; + case Gfx::SE_PRIMITIVE_TOPOLOGY_LINE_STRIP: + return MTL::PrimitiveTopologyClassLine; + case Gfx::SE_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: + return MTL::PrimitiveTopologyClassTriangle; + case Gfx::SE_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: + return MTL::PrimitiveTopologyClassTriangle; + case Gfx::SE_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN: + return MTL::PrimitiveTopologyClassTriangle; + case Gfx::SE_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY: + return MTL::PrimitiveTopologyClassLine; + case Gfx::SE_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY: + return MTL::PrimitiveTopologyClassLine; + case Gfx::SE_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY: + return MTL::PrimitiveTopologyClassTriangle; + case Gfx::SE_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY: + return MTL::PrimitiveTopologyClassTriangle; + case Gfx::SE_PRIMITIVE_TOPOLOGY_PATCH_LIST: + return MTL::PrimitiveTopologyClassUnspecified; + } +} + +MTL::IndexType Seele::Metal::cast(Gfx::SeIndexType indexType) { + switch (indexType) { + case Gfx::SE_INDEX_TYPE_UINT16: + return MTL::IndexTypeUInt16; + case Gfx::SE_INDEX_TYPE_UINT32: + return MTL::IndexTypeUInt32; + default: + throw std::logic_error("Not implemented"); + } +} + +Gfx::SeIndexType Seele::Metal::cast(MTL::IndexType indexType) { + switch (indexType) { + case MTL::IndexTypeUInt16: + return Gfx::SE_INDEX_TYPE_UINT16; + case MTL::IndexTypeUInt32: + return Gfx::SE_INDEX_TYPE_UINT32; + } +} diff --git a/src/Engine/Graphics/Metal/Graphics.h b/src/Engine/Graphics/Metal/Graphics.h index a79c062..fbf6d10 100644 --- a/src/Engine/Graphics/Metal/Graphics.h +++ b/src/Engine/Graphics/Metal/Graphics.h @@ -8,6 +8,7 @@ namespace Metal { DECLARE_REF(CommandQueue) DECLARE_REF(IOCommandQueue) +DECLARE_REF(PipelineCache) class Graphics : public Gfx::Graphics { public: @@ -61,6 +62,7 @@ protected: MTL::Device* device; OCommandQueue queue; OIOCommandQueue ioQueue; + OPipelineCache cache; }; DEFINE_REF(Graphics) } // namespace Metal diff --git a/src/Engine/Graphics/Metal/Graphics.mm b/src/Engine/Graphics/Metal/Graphics.mm index 460b00d..156caee 100644 --- a/src/Engine/Graphics/Metal/Graphics.mm +++ b/src/Engine/Graphics/Metal/Graphics.mm @@ -1,7 +1,12 @@ #include "Graphics.h" #include "Graphics/Initializer.h" +#include "Graphics/Metal/Descriptor.h" +#include "Graphics/Metal/Pipeline.h" +#include "Graphics/Metal/PipelineCache.h" +#include "Graphics/Metal/Resources.h" #include "Shader.h" #include "RenderPass.h" +#include "Resources.h" #include "Command.h" #include "Window.h" #include "Buffer.h" @@ -24,6 +29,7 @@ void Graphics::init(GraphicsInitializer) device = MTL::CreateSystemDefaultDevice(); queue = new CommandQueue(this); ioQueue = new IOCommandQueue(this); + cache = new PipelineCache(this, "pipelines.metal"); } Gfx::OWindow Graphics::createWindow(const WindowCreateInfo &createInfo) @@ -118,12 +124,14 @@ Gfx::OVertexShader Graphics::createVertexShader(const ShaderCreateInfo& createIn result->create(createInfo); return result; } + Gfx::OFragmentShader Graphics::createFragmentShader(const ShaderCreateInfo& createInfo) { OFragmentShader result = new FragmentShader(this); result->create(createInfo); return result; } + Gfx::OComputeShader Graphics::createComputeShader(const ShaderCreateInfo& createInfo) { OComputeShader result = new ComputeShader(this); @@ -137,6 +145,7 @@ Gfx::OMeshShader Graphics::createMeshShader(const ShaderCreateInfo& createInfo) result->create(createInfo); return result; } + Gfx::OTaskShader Graphics::createTaskShader(const ShaderCreateInfo& createInfo) { OTaskShader result = new TaskShader(this); @@ -146,39 +155,41 @@ Gfx::OTaskShader Graphics::createTaskShader(const ShaderCreateInfo& createInfo) Gfx::PGraphicsPipeline Graphics::createGraphicsPipeline(Gfx::LegacyPipelineCreateInfo createInfo) { - + return cache->createPipeline(std::move(createInfo)); } Gfx::PGraphicsPipeline Graphics::createGraphicsPipeline(Gfx::MeshPipelineCreateInfo createInfo) { - + return cache->createPipeline(std::move(createInfo)); } + Gfx::PComputePipeline Graphics::createComputePipeline(Gfx::ComputePipelineCreateInfo createInfo) { - + return cache->createPipeline(std::move(createInfo)); } + Gfx::OSampler Graphics::createSampler(const SamplerCreateInfo& createInfo) { - + return new Sampler(this, createInfo); } Gfx::ODescriptorLayout Graphics::createDescriptorLayout(const std::string& name) { - + return new DescriptorLayout(this, name); } + Gfx::OPipelineLayout Graphics::createPipelineLayout(Gfx::PPipelineLayout baseLayout) { - + return new PipelineLayout(this, baseLayout); } Gfx::OVertexInput Graphics::createVertexInput(VertexInputStateCreateInfo createInfo) { - + return new VertexInput(createInfo); } void Graphics::resolveTexture(Gfx::PTexture source, Gfx::PTexture destination) { - } diff --git a/src/Engine/Graphics/Metal/Pipeline.h b/src/Engine/Graphics/Metal/Pipeline.h index bc50f63..481b020 100644 --- a/src/Engine/Graphics/Metal/Pipeline.h +++ b/src/Engine/Graphics/Metal/Pipeline.h @@ -1,37 +1,40 @@ #pragma once #include "Graphics/Initializer.h" #include "Graphics/Pipeline.h" -#include "Resources.h" #include "MinimalEngine.h" +#include "Resources.h" namespace Seele { namespace Metal { -class VertexInput : public Gfx::VertexInput -{ +class VertexInput : public Gfx::VertexInput { public: VertexInput(VertexInputStateCreateInfo createInfo); virtual ~VertexInput(); }; DECLARE_REF(PipelineLayout) DECLARE_REF(Graphics) -class GraphicsPipeline : public Gfx::GraphicsPipeline -{ +class GraphicsPipeline : public Gfx::GraphicsPipeline { public: - GraphicsPipeline(PGraphics graphics, Gfx::LegacyPipelineCreateInfo createInfo); - GraphicsPipeline(PGraphics graphics, Gfx::MeshPipelineCreateInfo createInfo); + GraphicsPipeline(PGraphics graphics, MTL::PrimitiveType primitive, MTL::RenderPipelineState* pipeline, Gfx::OPipelineLayout createInfo); virtual ~GraphicsPipeline(); + constexpr MTL::RenderPipelineState* getHandle() const { return state; } + constexpr MTL::PrimitiveType getPrimitive() const { return primitiveType; } private: + PGraphics graphics; MTL::RenderPipelineState* state; + MTL::PrimitiveType primitiveType; }; DEFINE_REF(GraphicsPipeline) -class ComputePipeline : public Gfx::ComputePipeline -{ +class ComputePipeline : public Gfx::ComputePipeline { public: - ComputePipeline(PGraphics graphics, Gfx::ComputePipelineCreateInfo createInfo); + ComputePipeline(PGraphics graphics, MTL::ComputePipelineState* pipeline, Gfx::OPipelineLayout); virtual ~ComputePipeline(); + constexpr MTL::ComputePipelineState* getHandle() const { return state; } + private: + PGraphics graphics; MTL::ComputePipelineState* state; }; DEFINE_REF(ComputePipeline) -} -} \ No newline at end of file +} // namespace Metal +} // namespace Seele \ No newline at end of file diff --git a/src/Engine/Graphics/Metal/Pipeline.mm b/src/Engine/Graphics/Metal/Pipeline.mm index 7ce73e1..0fcaf0d 100644 --- a/src/Engine/Graphics/Metal/Pipeline.mm +++ b/src/Engine/Graphics/Metal/Pipeline.mm @@ -1,17 +1,24 @@ #include "Pipeline.h" #include "Graphics/Initializer.h" #include "Graphics/Metal/Graphics.h" +#include "Graphics/Pipeline.h" #include "Graphics/Resources.h" -#include "Metal/MTLRenderPipeline.hpp" using namespace Seele; using namespace Seele::Metal; -VertexInput::VertexInput(VertexInputStateCreateInfo createInfo) - : Gfx::VertexInput(createInfo) -{ -} +VertexInput::VertexInput(VertexInputStateCreateInfo createInfo) : Gfx::VertexInput(createInfo) {} -VertexInput::~VertexInput() -{ -} +VertexInput::~VertexInput() {} + +GraphicsPipeline::GraphicsPipeline(PGraphics graphics, MTL::PrimitiveType primitive, MTL::RenderPipelineState* pipeline, + Gfx::OPipelineLayout createInfo) + : Gfx::GraphicsPipeline(std::move(createInfo)), graphics(graphics), state(pipeline), primitiveType(primitive) {} + +GraphicsPipeline::~GraphicsPipeline() {} + +ComputePipeline::ComputePipeline(PGraphics graphics, MTL::ComputePipelineState* pipeline, + Gfx::OPipelineLayout createInfo) + : Gfx::ComputePipeline(std::move(createInfo)), graphics(graphics), state(pipeline) {} + +ComputePipeline::~ComputePipeline() {} diff --git a/src/Engine/Graphics/Metal/PipelineCache.h b/src/Engine/Graphics/Metal/PipelineCache.h index 189eee2..a856de7 100644 --- a/src/Engine/Graphics/Metal/PipelineCache.h +++ b/src/Engine/Graphics/Metal/PipelineCache.h @@ -15,7 +15,7 @@ public: private: PGraphics graphics; Map graphicsPipelines; - Map computePipeline; + Map computePipelines; std::string cacheFile; }; DEFINE_REF(PipelineCache) diff --git a/src/Engine/Graphics/Metal/PipelineCache.mm b/src/Engine/Graphics/Metal/PipelineCache.mm index 578b4ce..644b2e3 100644 --- a/src/Engine/Graphics/Metal/PipelineCache.mm +++ b/src/Engine/Graphics/Metal/PipelineCache.mm @@ -1,11 +1,18 @@ #include "PipelineCache.h" #include "Descriptor.h" +#include "Enums.h" +#include "Foundation/NSError.hpp" #include "Graphics.h" -#include "Shader.h" #include "Graphics/Descriptor.h" #include "Graphics/Enums.h" +#include "Graphics/Metal/Pipeline.h" +#include "Metal/MTLComputePipeline.hpp" +#include "Metal/MTLDevice.hpp" +#include "Metal/MTLRenderCommandEncoder.hpp" #include "Metal/MTLRenderPipeline.hpp" #include "Metal/MTLVertexDescriptor.hpp" +#include "Shader.h" +#include "Texture.h" using namespace Seele; using namespace Seele::Metal; @@ -16,15 +23,12 @@ PipelineCache::~PipelineCache() {} PGraphicsPipeline PipelineCache::createPipeline(Gfx::LegacyPipelineCreateInfo createInfo) { PPipelineLayout layout = Gfx::PPipelineLayout(createInfo.pipelineLayout).cast(); - uint32 hash = layout->getHash(); + MTL::RenderPipelineDescriptor* pipelineDescriptor = MTL::RenderPipelineDescriptor::alloc()->init(); MTL::VertexDescriptor* vertexDescriptor = MTL::VertexDescriptor::alloc()->init(); - MTL::VertexAttributeDescriptorArray* attributes = vertexDescriptor->attributes(); - const auto& vertexInfo = createInfo.vertexInput->getInfo(); - for (size_t attr = 0; attr < vertexInfo.attributes.size(); ++attr) { MTL::VertexAttributeDescriptor* attribute = MTL::VertexAttributeDescriptor::alloc()->init(); attribute->setBufferIndex(vertexInfo.attributes[attr].binding); @@ -40,7 +44,6 @@ PGraphicsPipeline PipelineCache::createPipeline(Gfx::LegacyPipelineCreateInfo cr } MTL::VertexBufferLayoutDescriptorArray* bufferLayout = vertexDescriptor->layouts(); - for (size_t binding = 0; binding < vertexInfo.bindings.size(); ++binding) { MTL::VertexBufferLayoutDescriptor* buffer = MTL::VertexBufferLayoutDescriptor::alloc()->init(); buffer->setStride(vertexInfo.bindings[binding].stride); @@ -55,16 +58,123 @@ PGraphicsPipeline PipelineCache::createPipeline(Gfx::LegacyPipelineCreateInfo cr } bufferLayout->setObject(buffer, binding); } - pipelineDescriptor->setVertexDescriptor(vertexDescriptor); pipelineDescriptor->setVertexFunction(createInfo.vertexShader.cast()->getFunction()); - + if (createInfo.fragmentShader != nullptr) { + pipelineDescriptor->setFragmentFunction(createInfo.fragmentShader.cast()->getFunction()); + } + pipelineDescriptor->setInputPrimitiveTopology(cast(createInfo.topology)); + if (createInfo.renderPass->getLayout().depthAttachment.getTexture() != nullptr) { + pipelineDescriptor->setDepthAttachmentPixelFormat( + cast(createInfo.renderPass->getLayout().depthAttachment.getTexture().cast()->getFormat())); + } + pipelineDescriptor->setAlphaToCoverageEnabled(createInfo.multisampleState.alphaCoverageEnable); + pipelineDescriptor->setAlphaToOneEnabled(createInfo.multisampleState.alphaToOneEnable); + pipelineDescriptor->setRasterSampleCount(createInfo.multisampleState.samples); + pipelineDescriptor->setRasterizationEnabled(!createInfo.rasterizationState.rasterizerDiscardEnable); + + uint32 hash = pipelineDescriptor->hash(); + + if (graphicsPipelines.contains(hash)) { + return graphicsPipelines[hash]; + } + MTL::PrimitiveType type = MTL::PrimitiveTypeTriangle; + switch (createInfo.topology) { + case Gfx::SE_PRIMITIVE_TOPOLOGY_POINT_LIST: + type = MTL::PrimitiveTypePoint; + break; + case Gfx::SE_PRIMITIVE_TOPOLOGY_LINE_LIST: + type = MTL::PrimitiveTypeLine; + break; + case Gfx::SE_PRIMITIVE_TOPOLOGY_LINE_STRIP: + type = MTL::PrimitiveTypeLineStrip; + break; + case Gfx::SE_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: + type = MTL::PrimitiveTypeTriangle; + break; + case Gfx::SE_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: + type = MTL::PrimitiveTypeTriangleStrip; + break; + case Gfx::SE_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN: + type = MTL::PrimitiveTypeTriangle; + break; + case Gfx::SE_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY: + type = MTL::PrimitiveTypeLine; + break; + case Gfx::SE_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY: + type = MTL::PrimitiveTypeLineStrip; + break; + case Gfx::SE_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY: + type = MTL::PrimitiveTypeTriangle; + break; + case Gfx::SE_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY: + type = MTL::PrimitiveTypeTriangleStrip; + break; + case Gfx::SE_PRIMITIVE_TOPOLOGY_PATCH_LIST: + type = MTL::PrimitiveTypeTriangle; + break; + } + + NS::Error* error; + graphicsPipelines[hash] = + new GraphicsPipeline(graphics, type, graphics->getDevice()->newRenderPipelineState(pipelineDescriptor, &error), + std::move(createInfo.pipelineLayout)); + assert(!error); vertexDescriptor->release(); pipelineDescriptor->release(); + return graphicsPipelines[hash]; } -PGraphicsPipeline PipelineCache::createPipeline(Gfx::MeshPipelineCreateInfo createInfo) {} +PGraphicsPipeline PipelineCache::createPipeline(Gfx::MeshPipelineCreateInfo createInfo) { + MTL::MeshRenderPipelineDescriptor* pipelineDescriptor = MTL::MeshRenderPipelineDescriptor::alloc()->init(); -PComputePipeline PipelineCache::createPipeline(Gfx::ComputePipelineCreateInfo createInfo) {} + pipelineDescriptor->setMeshFunction(createInfo.meshShader.cast()->getFunction()); + if (createInfo.taskShader != nullptr) { + pipelineDescriptor->setObjectFunction(createInfo.taskShader.cast()->getFunction()); + } + if (createInfo.fragmentShader != nullptr) { + pipelineDescriptor->setFragmentFunction(createInfo.fragmentShader.cast()->getFunction()); + } + if (createInfo.renderPass->getLayout().depthAttachment.getTexture() != nullptr) { + pipelineDescriptor->setDepthAttachmentPixelFormat( + cast(createInfo.renderPass->getLayout().depthAttachment.getTexture().cast()->getFormat())); + } + pipelineDescriptor->setAlphaToCoverageEnabled(createInfo.multisampleState.alphaCoverageEnable); + pipelineDescriptor->setAlphaToOneEnabled(createInfo.multisampleState.alphaToOneEnable); + pipelineDescriptor->setRasterSampleCount(createInfo.multisampleState.samples); + pipelineDescriptor->setRasterizationEnabled(!createInfo.rasterizationState.rasterizerDiscardEnable); + + uint32 hash = pipelineDescriptor->hash(); + + if (graphicsPipelines.contains(hash)) { + return graphicsPipelines[hash]; + } + + graphics->getDevice()->newRenderPipelineState( + pipelineDescriptor, MTL::PipelineOptionNone, + [&](MTL::RenderPipelineState* state, MTL::RenderPipelineReflection*, NS::Error* error) { + assert(!error); + graphicsPipelines[hash] = + new GraphicsPipeline(graphics, MTL::PrimitiveTypeLine, state, std::move(createInfo.pipelineLayout)); + }); + + pipelineDescriptor->release(); + return graphicsPipelines[hash]; +} + +PComputePipeline PipelineCache::createPipeline(Gfx::ComputePipelineCreateInfo createInfo) { + PComputeShader shader = createInfo.computeShader.cast(); + uint32 hash = shader->getShaderHash(); + if (computePipelines.contains(hash)) { + return computePipelines[hash]; + } + + NS::Error* error; + computePipelines[hash] = + new ComputePipeline(graphics, graphics->getDevice()->newComputePipelineState(shader->getFunction(), &error), + std::move(createInfo.pipelineLayout)); + assert(!error); + return computePipelines[hash]; +} diff --git a/src/Engine/Graphics/Metal/Shader.mm b/src/Engine/Graphics/Metal/Shader.mm index 80a0a5f..db3b400 100644 --- a/src/Engine/Graphics/Metal/Shader.mm +++ b/src/Engine/Graphics/Metal/Shader.mm @@ -14,8 +14,8 @@ using namespace Seele; using namespace Seele::Metal; -Shader::Shader(PGraphics graphics, Gfx::SeShaderStageFlags stage) - : stage(stage), graphics(graphics) {} +Shader::Shader(PGraphics graphics, Gfx::SeShaderStageFlags stage) : stage(stage), graphics(graphics) {} + Shader::~Shader() { if (function) { function->release(); @@ -23,29 +23,27 @@ Shader::~Shader() { } } -void Shader::create(const ShaderCreateInfo &createInfo) { - Slang::ComPtr kernelBlob = - generateShader(createInfo, SLANG_SPIRV); - spirv_cross::CompilerMSL comp((const uint32 *)kernelBlob->getBufferPointer(), - kernelBlob->getBufferSize() / 4); +void Shader::create(const ShaderCreateInfo& createInfo) { + Slang::ComPtr kernelBlob = generateShader(createInfo, SLANG_SPIRV); + hash = CRC::Calculate(kernelBlob->getBufferPointer(), kernelBlob->getBufferSize(), CRC::CRC_32()); + spirv_cross::CompilerMSL comp((const uint32*)kernelBlob->getBufferPointer(), kernelBlob->getBufferSize() / 4); auto options = comp.get_msl_options(); options.argument_buffers = true; - options.argument_buffers_tier = - spirv_cross::CompilerMSL::Options::ArgumentBuffersTier::Tier2; + options.argument_buffers_tier = spirv_cross::CompilerMSL::Options::ArgumentBuffersTier::Tier2; options.set_msl_version(3); comp.set_msl_options(options); std::string metalCode = comp.compile(); - NS::Error *error = nullptr; - MTL::CompileOptions *mtlOptions = MTL::CompileOptions::alloc()->init(); + NS::Error* error = nullptr; + MTL::CompileOptions* mtlOptions = MTL::CompileOptions::alloc()->init(); - library = graphics->getDevice()->newLibrary( - NS::String::string(metalCode.c_str(), NS::ASCIIStringEncoding), - mtlOptions, &error); + library = graphics->getDevice()->newLibrary(NS::String::string(metalCode.c_str(), NS::ASCIIStringEncoding), + mtlOptions, &error); if (error) { std::cout << error->debugDescription() << std::endl; assert(false); } - function = - library->newFunction(NS::String::string("main", NS::ASCIIStringEncoding)); + function = library->newFunction(NS::String::string("main", NS::ASCIIStringEncoding)); mtlOptions->release(); -} \ No newline at end of file +} + +uint32 Shader::getShaderHash() const { return hash; } \ No newline at end of file