From c5f5b1b1e540c7a98984c747730852b971985352 Mon Sep 17 00:00:00 2001 From: Thirulogeswaren Date: Mon, 19 Aug 2024 15:56:57 +0530 Subject: [PATCH] Implemented ShaderCompiler for Metal --- Core/Application/Application.cpp | 5 +- Core/Common.cpp | 10 + Core/Common.h | 9 +- Core/Graphics/Buffer.h | 6 +- Core/Graphics/RHI/METALCommon.h | 11 ++ Core/Graphics/RHI/Metal/METALConstantBuffer.h | 19 ++ Core/Graphics/RHI/Metal/METALIndexBuffer.h | 15 ++ .../RHI/Metal/METALPipelineHandler.cpp | 35 ++++ .../Graphics/RHI/Metal/METALPipelineHandler.h | 26 +++ Core/Graphics/RHI/Metal/METALPixelShader.h | 12 ++ Core/Graphics/RHI/Metal/METALRenderer.cpp | 183 +++++++++++++++--- Core/Graphics/RHI/Metal/METALRendererImpl.cpp | 56 +++--- Core/Graphics/RHI/Metal/METALRendererImpl.h | 59 +++--- Core/Graphics/RHI/Metal/METALVertexBuffer.h | 15 ++ Core/Graphics/RHI/Metal/METALVertexShader.h | 12 ++ Core/Graphics/Renderer.cpp | 28 ++- Core/Graphics/Renderer.h | 16 +- Core/Graphics/Shader/Shader.h | 1 + Core/Graphics/Shader/ShaderCompiler.cpp | 39 +++- Core/Graphics/Shader/ShaderCompiler.h | 6 + Core/Graphics/Types.h | 10 +- .../Assets/Metal/HelloTrianglePS.metal | 13 ++ .../Assets/Metal/HelloTriangleVS.metal | 30 +++ Samples/HelloTriangle/HelloTriangle.cpp | 6 +- 24 files changed, 524 insertions(+), 98 deletions(-) create mode 100644 Core/Common.cpp create mode 100644 Core/Graphics/RHI/METALCommon.h create mode 100644 Core/Graphics/RHI/Metal/METALConstantBuffer.h create mode 100644 Core/Graphics/RHI/Metal/METALIndexBuffer.h create mode 100644 Core/Graphics/RHI/Metal/METALPipelineHandler.cpp create mode 100644 Core/Graphics/RHI/Metal/METALPipelineHandler.h create mode 100644 Core/Graphics/RHI/Metal/METALPixelShader.h create mode 100644 Core/Graphics/RHI/Metal/METALVertexBuffer.h create mode 100644 Core/Graphics/RHI/Metal/METALVertexShader.h create mode 100644 Samples/HelloTriangle/Assets/Metal/HelloTrianglePS.metal create mode 100644 Samples/HelloTriangle/Assets/Metal/HelloTriangleVS.metal diff --git a/Core/Application/Application.cpp b/Core/Application/Application.cpp index 5b52810..2fb8a12 100644 --- a/Core/Application/Application.cpp +++ b/Core/Application/Application.cpp @@ -1,5 +1,4 @@ #include "Application.h" -#include #include #include @@ -10,8 +9,8 @@ namespace CGL::Core bool g_isTestMode{ false }; Application::Application(std::string_view name, i32 argc, char** argv) - : m_name(name) - , m_isRunning(true) + : m_isRunning(true) + , m_name(name) , m_window(nullptr) { // Parse command line arguments diff --git a/Core/Common.cpp b/Core/Common.cpp new file mode 100644 index 0000000..7f89cc5 --- /dev/null +++ b/Core/Common.cpp @@ -0,0 +1,10 @@ + +#if defined (CGL_RHI_METAL) +#define NS_PRIVATE_IMPLEMENTATION +#define CA_PRIVATE_IMPLEMENTATION +#define MTL_PRIVATE_IMPLEMENTATION + +#define EXCLUDE_STDHEADERS +#include + +#endif diff --git a/Core/Common.h b/Core/Common.h index a3102e5..4c814ab 100644 --- a/Core/Common.h +++ b/Core/Common.h @@ -1,5 +1,6 @@ #pragma once +#ifndef EXCLUDE_STDHEADERS #include #include #include @@ -12,4 +13,10 @@ #include #include -#include +#endif + +#if defined (CGL_RHI_METAL) +#include "Foundation/Foundation.hpp" +#include "QuartzCore/QuartzCore.hpp" +#include "Metal/Metal.hpp" +#endif diff --git a/Core/Graphics/Buffer.h b/Core/Graphics/Buffer.h index e9119f3..4823538 100644 --- a/Core/Graphics/Buffer.h +++ b/Core/Graphics/Buffer.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #if defined(CGL_RHI_DX11) @@ -23,6 +23,7 @@ #if defined(CGL_RHI_METAL) #include #include +#include #endif #if defined(CGL_RHI_VULKAN) @@ -55,10 +56,11 @@ namespace CGL::Graphics #elif defined(CGL_RHI_METAL) using VertexBuffer = METALVertexBuffer; using IndexBuffer = METALIndexBuffer; + template using ConstantBuffer = METALConstantBuffer; #elif defined(CGL_RHI_VULKAN) using VertexBuffer = VULKANVertexBuffer; using IndexBuffer = VULKANIndexBuffer; #else #error Unsupported buffer types for RHI #endif -} \ No newline at end of file +} diff --git a/Core/Graphics/RHI/METALCommon.h b/Core/Graphics/RHI/METALCommon.h new file mode 100644 index 0000000..24beca5 --- /dev/null +++ b/Core/Graphics/RHI/METALCommon.h @@ -0,0 +1,11 @@ +#pragma once + +#include "Metal/MTLLibrary.hpp" +#include +#include + +struct METALCompileObjects +{ + std::unique_ptr& library; + MTL::Device* device; +}; diff --git a/Core/Graphics/RHI/Metal/METALConstantBuffer.h b/Core/Graphics/RHI/Metal/METALConstantBuffer.h new file mode 100644 index 0000000..3951778 --- /dev/null +++ b/Core/Graphics/RHI/Metal/METALConstantBuffer.h @@ -0,0 +1,19 @@ +#pragma once + +#include "Metal/MTLBuffer.hpp" + +namespace CGL::Graphics +{ + template + struct METALConstantBuffer + { + using value_type = T; + + METALConstantBuffer() + { + static_assert((sizeof(T) % 16) == 0, "Constant buffer size must be 16-byte aligned."); + } + + MTL::Buffer* Buffer; + }; +} diff --git a/Core/Graphics/RHI/Metal/METALIndexBuffer.h b/Core/Graphics/RHI/Metal/METALIndexBuffer.h new file mode 100644 index 0000000..532c582 --- /dev/null +++ b/Core/Graphics/RHI/Metal/METALIndexBuffer.h @@ -0,0 +1,15 @@ +#pragma once + +#include "Foundation/NSTypes.hpp" +#include "Metal/MTLBuffer.hpp" + +namespace CGL::Graphics +{ + struct METALIndexBuffer + { + MTL::Buffer* Buffer; + + NS::UInteger Offset; + NS::UInteger Index; + }; +} diff --git a/Core/Graphics/RHI/Metal/METALPipelineHandler.cpp b/Core/Graphics/RHI/Metal/METALPipelineHandler.cpp new file mode 100644 index 0000000..2979e4a --- /dev/null +++ b/Core/Graphics/RHI/Metal/METALPipelineHandler.cpp @@ -0,0 +1,35 @@ +#include "METALPipelineHandler.h" +#include "Foundation/NSError.hpp" +#include "Foundation/NSString.hpp" + +namespace CGL::Graphics { + + CGL_DEFINE_LOG_CATEGORY(METALPipelineHandler); + + METALPipelineHandler::METALPipelineHandler() : m_rpDescriptor { nullptr }, m_rpState { nullptr } + { + m_rpDescriptor = MTL::RenderPipelineDescriptor::alloc()->init(); + + m_rpDescriptor->colorAttachments()->object(0)->setPixelFormat(MTL::PixelFormatRGBA8Unorm_sRGB); + + CGL_LOG(METALPipelineHandler, Info, "RenderPipelineDescriptor Initialized"); + } + + void METALPipelineHandler::CreateRenderPipelineState(MTL::Device* gpu_device) + { + if(!m_rpDescriptor) return; + + NS::Error* ns_error{}; + + m_rpState = gpu_device->newRenderPipelineState(m_rpDescriptor, &ns_error); + + if(!m_rpState) { + CGL_LOG(METALPipelineHandler, Error, ns_error->localizedDescription()->utf8String()); + return; + } + + CGL_LOG(METALPipelineHandler, Info, "RenderPipelineState Created"); + m_rpDescriptor->release(); + m_rpDescriptor = nullptr; + } +} diff --git a/Core/Graphics/RHI/Metal/METALPipelineHandler.h b/Core/Graphics/RHI/Metal/METALPipelineHandler.h new file mode 100644 index 0000000..f709451 --- /dev/null +++ b/Core/Graphics/RHI/Metal/METALPipelineHandler.h @@ -0,0 +1,26 @@ +#pragma once + +#include "Metal/MTLDevice.hpp" +#include "Metal/MTLRenderPipeline.hpp" + +#include "Core/Logging/Log.h" + +namespace CGL::Graphics +{ + CGL_DECLARE_LOG_CATEGORY(METALPipelineHandler); + + class METALPipelineHandler + { + public: + METALPipelineHandler(); + + inline auto GetRenderPipelineDescriptor() const { return m_rpDescriptor; } + inline auto GetRenderPipelineState() const { return m_rpState; } + + void CreateRenderPipelineState(MTL::Device* gpu_device); + + private: + MTL::RenderPipelineDescriptor* m_rpDescriptor; + MTL::RenderPipelineState* m_rpState; + }; +} diff --git a/Core/Graphics/RHI/Metal/METALPixelShader.h b/Core/Graphics/RHI/Metal/METALPixelShader.h new file mode 100644 index 0000000..abc60b2 --- /dev/null +++ b/Core/Graphics/RHI/Metal/METALPixelShader.h @@ -0,0 +1,12 @@ +#pragma once + +#include "Metal/MTLLibrary.hpp" + +namespace CGL::Graphics +{ + struct METALPixelShader + { + std::unique_ptr SourceContent; + MTL::Function* Shader; + }; +} diff --git a/Core/Graphics/RHI/Metal/METALRenderer.cpp b/Core/Graphics/RHI/Metal/METALRenderer.cpp index 0a1660e..447e751 100644 --- a/Core/Graphics/RHI/Metal/METALRenderer.cpp +++ b/Core/Graphics/RHI/Metal/METALRenderer.cpp @@ -1,66 +1,187 @@ #include "Core/Graphics/Renderer.h" #include "Core/Graphics/RHI/Metal/METALRendererImpl.h" -#include "Metal/MTLRenderPass.hpp" namespace CGL::Graphics { + void Renderer::Constructor_METAL(SDL_Window* window) { - this->m_impl = new METALRendererImpl(window); + this->m_impl = new METALRendererImpl(window); - CGL_LOG(Renderer, Info, "Metal Renderer Initialized"); + CGL_LOG(Renderer, Info, "Renderer Initialized"); } void Renderer::Destructor_METAL() { - delete static_cast(m_impl); - m_impl = nullptr; + delete static_cast(m_impl); + m_impl = nullptr; - CGL_LOG(Renderer, Info, "Metal Renderer Destroyed"); + CGL_LOG(Renderer, Info, "Renderer Destroyed"); } void Renderer::BeginFrame_METAL() { - GetImpl()->GetPoolRef()->alloc()->init(); - GetImpl()->SetDrawable(GetImpl()->GetMetalLayer()->nextDrawable()); - - GetImpl()->SetCmdBuffer(GetImpl()->GetQueue()->commandBuffer()); + assert(GetImpl()); - const f32 r = m_clearColor[0]; - const f32 g = m_clearColor[1]; - const f32 b = m_clearColor[2]; - const f32 a = m_clearColor[3]; + GetImpl()->InitAutoReleasePool(); - auto rpDescriptor = MTL::RenderPassDescriptor::alloc()->init(); - rpDescriptor->colorAttachments()->object(0)->setTexture(GetImpl()->GetDrawable()->texture()); - rpDescriptor->colorAttachments()->object(0)->setLoadAction(MTL::LoadActionClear); - rpDescriptor->colorAttachments()->object(0)->setClearColor(MTL::ClearColor{ r, g, b, a }); - rpDescriptor->colorAttachments()->object(0)->setStoreAction(MTL::StoreActionStore); + GetImpl()->SetNextDrawable(); + GetImpl()->SetCommandBuffer(); - auto rCmdEncoder = GetImpl()->GetCmdBuffer()->renderCommandEncoder(rpDescriptor); - - rCmdEncoder->endEncoding(); - rpDescriptor->release(); + GetImpl()->startEncoding(m_clearColor); } void Renderer::EndFrame_METAL() { - GetImpl()->GetCmdBuffer()->presentDrawable(GetImpl()->GetDrawable()); - GetImpl()->GetCmdBuffer()->commit(); + assert(GetImpl()); - GetImpl()->GetPoolRef()->release(); + GetImpl()->GetRenderCommandEncoder()->endEncoding(); + GetImpl()->GetCommandBuffer()->presentDrawable(GetImpl()->GetMetalContext()); + GetImpl()->GetCommandBuffer()->commit(); + GetImpl()->GetAutoReleasePool()->release(); } void Renderer::Resize_METAL(u32 width, u32 height) { - GetImpl()->GetMetalLayer()->setDrawableSize( - CGSize { (f32)width, (f32)height } - ); + assert(GetImpl()); + + GetImpl()->GetMetalLayer()->setDrawableSize( + CGSize { (f32)width, (f32)height } + ); } METALRendererImpl* Renderer::GetImpl() const { - assert(GetAPI() == RHIType::Metal); - return static_cast(m_impl); + return static_cast(m_impl); + } + + void Renderer::SetRenderPipeline_METAL() + { + GetImpl()->GetRenderPipelineHandler()->CreateRenderPipelineState(GetImpl()->GetDevice()); + GetImpl()->GetRenderCommandEncoder()->setRenderPipelineState( + GetImpl()->GetRenderPipelineHandler()->GetRenderPipelineState() + ); + } + + void Renderer::SetPrimitiveTopology_METAL(PrimitiveType topology) + { + static constexpr std::array MTLPrimitives = { + MTL::PrimitiveTypeTriangle, + MTL::PrimitiveTypeLine, + MTL::PrimitiveTypePoint, + MTL::PrimitiveTypeTriangleStrip, + MTL::PrimitiveTypeLineStrip + }; + + static_assert(MTLPrimitives.size() == (size_t)PrimitiveType::COUNT); + + GetImpl()->SetPrimitiveType(MTLPrimitives[size_t(topology)]); + } + + void Renderer::SetVertexShader_METAL(const VertexShader& shader) + { + const auto rpDescriptor = GetImpl()->GetRenderPipelineHandler()->GetRenderPipelineDescriptor(); + + rpDescriptor->setVertexFunction(shader.Shader); + } + + void Renderer::SetPixelShader_METAL(const PixelShader& shader) + { + const auto rpDescriptor = GetImpl()->GetRenderPipelineHandler()->GetRenderPipelineDescriptor(); + + rpDescriptor->setFragmentFunction(shader.Shader); + } + + void Renderer::SetVertexBuffer_METAL(const VertexBuffer& buffer) + { + GetImpl()->GetRenderCommandEncoder()->setVertexBuffer( + buffer.Buffer, buffer.Offset, buffer.Index + ); + } + + void Renderer::SetIndexBuffer_METAL(const IndexBuffer& buffer) + { + // TODO: implement index buffer + } + + ShaderCompileResult Renderer::CompileVertexShader_METAL(const ShaderSource& source, VertexShader* outShader) + { + assert(GetImpl() && GetImpl()->GetDevice() && outShader); + + CompileConfig Config; + + #ifdef CGL_BUILD_DEBUG + Config.Debug = true; + Config.Optimize = false; + #endif + + METALCompileObjects metal_object = { + .device = GetImpl()->GetDevice(), + .library = outShader->SourceContent + }; + + ShaderCompileResult result = ShaderCompiler::Compile(source, Config, metal_object); + + outShader->Shader = (*outShader->SourceContent)->newFunction( + NS::String::string(source.Name.c_str(), NS::StringEncoding::ASCIIStringEncoding) + ); + + return result; + } + + ShaderCompileResult Renderer::CompilePixelShader_METAL(const ShaderSource& source, PixelShader* outShader) + { + assert(GetImpl() && GetImpl()->GetDevice() && outShader); + + CompileConfig Config; + + #ifdef CGL_BUILD_DEBUG + Config.Debug = true; + Config.Optimize = false; + #endif + + METALCompileObjects metal_object = { + .device = GetImpl()->GetDevice(), + .library = outShader->SourceContent + }; + + ShaderCompileResult result = ShaderCompiler::Compile(source, Config, metal_object); + + + outShader->Shader = (*outShader->SourceContent)->newFunction( + NS::String::string(source.Name.c_str(), NS::StringEncoding::ASCIIStringEncoding) + ); + + return result; + } + + VertexBuffer Renderer::CreateVertexBuffer_METAL(const BufferSource& source) + { + assert(GetImpl() && GetImpl()->GetDevice()); + + const u32 sourceSZ = source.TypeSize * source.Count; + + return VertexBuffer { + .Buffer = GetImpl()->GetDevice()->newBuffer(source.Data, sourceSZ, MTL::ResourceStorageModeShared), + .Offset = 0, + .Index = 0 + }; + } + + IndexBuffer Renderer::CreateIndexBuffer_METAL(const BufferSource& source) + { + // TODO: implement Index Buffer + } + + void Renderer::Draw_METAL(u32 vertexCount, u32 startVertex) + { + GetImpl()->GetRenderCommandEncoder()->drawPrimitives( + GetImpl()->GetPrimitiveType(), startVertex, vertexCount + ); + } + + void Renderer::DrawIndexed_METAL(u32 indexCount, u32 startIndex, u32 baseVertex) + { + // TODO: implement indexed drawcall } } diff --git a/Core/Graphics/RHI/Metal/METALRendererImpl.cpp b/Core/Graphics/RHI/Metal/METALRendererImpl.cpp index 95a663c..dd18ce4 100644 --- a/Core/Graphics/RHI/Metal/METALRendererImpl.cpp +++ b/Core/Graphics/RHI/Metal/METALRendererImpl.cpp @@ -1,35 +1,45 @@ -#define NS_PRIVATE_IMPLEMENTATION -#define CA_PRIVATE_IMPLEMENTATION -#define MTL_PRIVATE_IMPLEMENTATION - -#include -#include -#include - #include "METALRendererImpl.h" namespace CGL::Graphics { - METALRendererImpl::METALRendererImpl(SDL_Window* window) - { - mView = SDL_Metal_CreateView(window); + CGL_DEFINE_LOG_CATEGORY(METALRendererImpl); + + METALRendererImpl::METALRendererImpl(SDL_Window* window) + { + m_view = SDL_Metal_CreateView(window); + + m_device = MTL::CreateSystemDefaultDevice(); + m_cmdQueue = m_device->newCommandQueue(); + + m_layer = static_cast(SDL_Metal_GetLayer(m_view)); + m_layer->setDevice(m_device); + m_layer->setPixelFormat(MTL::PixelFormatRGBA8Unorm_sRGB); + + CGL_LOG(METALRendererImpl, Info, m_device->name()->cString(NS::ASCIIStringEncoding)); + m_pipeline = std::make_unique(); - mLayer = static_cast(SDL_Metal_GetLayer(mView)); - mLayer->setDevice(MTL::CreateSystemDefaultDevice()); - mLayer->setPixelFormat(MTL::PixelFormatRGBA8Unorm_sRGB); + m_arpool = nullptr; + } - mDevice = mLayer->device(); + void METALRendererImpl::startEncoding(const std::array& clearcolor) + { + auto iRenderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init(); - mQueue = mDevice->newCommandQueue(); + const auto& [ r, g, b, a ] = clearcolor; - arPool = nullptr; + iRenderPassDescriptor->colorAttachments()->object(0)->setTexture(m_context->texture()); + iRenderPassDescriptor->colorAttachments()->object(0)->setLoadAction(MTL::LoadActionClear); + iRenderPassDescriptor->colorAttachments()->object(0)->setClearColor(MTL::ClearColor{ r, g, b, a }); + iRenderPassDescriptor->colorAttachments()->object(0)->setStoreAction(MTL::StoreActionStore); - } + this->m_rcmdEncoder = m_cmdBuffer->renderCommandEncoder(iRenderPassDescriptor); - METALRendererImpl::~METALRendererImpl() - { - mDevice->release(); - SDL_Metal_DestroyView(mView); - } + iRenderPassDescriptor->release(); + } + METALRendererImpl::~METALRendererImpl() + { + m_device->release(); + m_device = nullptr; + } } diff --git a/Core/Graphics/RHI/Metal/METALRendererImpl.h b/Core/Graphics/RHI/Metal/METALRendererImpl.h index edbfb78..f830a97 100644 --- a/Core/Graphics/RHI/Metal/METALRendererImpl.h +++ b/Core/Graphics/RHI/Metal/METALRendererImpl.h @@ -3,6 +3,7 @@ #include "Foundation/Foundation.hpp" #include "Metal/Metal.hpp" #include "QuartzCore/QuartzCore.hpp" +#include "METALPipelineHandler.h" #include "SDL2/SDL_metal.h" #include "SDL2/SDL_video.h" @@ -11,38 +12,48 @@ namespace CGL::Graphics { - CGL_DECLARE_LOG_CATEGORY(METALRendererImpl); + CGL_DECLARE_LOG_CATEGORY(METALRendererImpl); - class METALRendererImpl - { - public: - METALRendererImpl(SDL_Window* window); - ~METALRendererImpl(); + class METALRendererImpl + { + public: + explicit METALRendererImpl(SDL_Window* window); + ~METALRendererImpl(); - inline CA::MetalLayer* GetMetalLayer() const { return mLayer; } + inline CA::MetalLayer* GetMetalLayer() const { return m_layer; } + inline CA::MetalDrawable* GetMetalContext() const { return m_context; } - inline MTL::Device* GetDevice() const { return mDevice; } - inline MTL::CommandQueue* GetQueue() const { return mQueue; } + inline MTL::Device* GetDevice() const { return m_device; } + inline MTL::CommandQueue* GetCommandQueue() const { return m_cmdQueue; } + inline MTL::CommandBuffer* GetCommandBuffer() const { return m_cmdBuffer; } - inline void SetCmdBuffer(MTL::CommandBuffer* cBuffer) { cmdBuffer = cBuffer; } - inline MTL::CommandBuffer* GetCmdBuffer() { return cmdBuffer; } + inline MTL::RenderCommandEncoder* GetRenderCommandEncoder() const { return m_rcmdEncoder; } + inline MTL::PrimitiveType GetPrimitiveType() const { return m_primitiveType; } - inline NS::AutoreleasePool* GetPoolRef() const { return arPool; } + inline NS::AutoreleasePool* GetAutoReleasePool() const { return m_arpool; } + inline METALPipelineHandler* GetRenderPipelineHandler() const { return m_pipeline.get(); } - inline void SetDrawable(CA::MetalDrawable* drawable) { mDrawable = drawable; } - inline CA::MetalDrawable* GetDrawable() const { return mDrawable; } + inline void InitAutoReleasePool() { m_arpool = NS::AutoreleasePool::alloc()->init(); } + inline void SetPrimitiveType(MTL::PrimitiveType pType) { m_primitiveType = pType; } + inline void SetNextDrawable() { m_context = m_layer->nextDrawable(); } + inline void SetCommandBuffer() { m_cmdBuffer = m_cmdQueue->commandBuffer(); } - METALRendererImpl() = delete; + void startEncoding(const std::array& clearcolor = { 0.0f, 0.0f, 0.0f, 1.0f }); - private: - SDL_MetalView mView; - CA::MetalLayer* mLayer; - CA::MetalDrawable* mDrawable; + private: + SDL_MetalView m_view; + CA::MetalLayer* m_layer; + CA::MetalDrawable* m_context; - MTL::Device* mDevice; - MTL::CommandQueue* mQueue; - MTL::CommandBuffer* cmdBuffer; + MTL::Device* m_device; + MTL::CommandQueue* m_cmdQueue; + MTL::CommandBuffer* m_cmdBuffer; - NS::AutoreleasePool* arPool; - }; + MTL::RenderCommandEncoder* m_rcmdEncoder; + MTL::PrimitiveType m_primitiveType; + + NS::AutoreleasePool* m_arpool; + + std::unique_ptr m_pipeline; + }; } diff --git a/Core/Graphics/RHI/Metal/METALVertexBuffer.h b/Core/Graphics/RHI/Metal/METALVertexBuffer.h new file mode 100644 index 0000000..0d4fb17 --- /dev/null +++ b/Core/Graphics/RHI/Metal/METALVertexBuffer.h @@ -0,0 +1,15 @@ +#pragma once + +#include "Foundation/NSTypes.hpp" +#include "Metal/MTLBuffer.hpp" + +namespace CGL::Graphics +{ + struct METALVertexBuffer + { + MTL::Buffer* Buffer; + + NS::UInteger Offset; + NS::UInteger Index; + }; +} diff --git a/Core/Graphics/RHI/Metal/METALVertexShader.h b/Core/Graphics/RHI/Metal/METALVertexShader.h new file mode 100644 index 0000000..1a7eca9 --- /dev/null +++ b/Core/Graphics/RHI/Metal/METALVertexShader.h @@ -0,0 +1,12 @@ +#pragma once + +#include "Metal/MTLLibrary.hpp" + +namespace CGL::Graphics +{ + struct METALVertexShader + { + std::unique_ptr SourceContent; + MTL::Function* Shader; + }; +} diff --git a/Core/Graphics/Renderer.cpp b/Core/Graphics/Renderer.cpp index 907648f..dd568fe 100644 --- a/Core/Graphics/Renderer.cpp +++ b/Core/Graphics/Renderer.cpp @@ -47,7 +47,7 @@ namespace CGL::Graphics BeginFrame_D3D11(); #elif defined(CGL_RHI_OPENGL) BeginFrame_OPENGL(); -#elif defined(CGL_RHI_METAL_) +#elif defined(CGL_RHI_METAL) BeginFrame_METAL(); #endif } @@ -104,6 +104,8 @@ namespace CGL::Graphics SetVertexShader_D3D11(shader); #elif defined(CGL_RHI_OPENGL) SetVertexShader_OPENGL(shader); +#elif defined (CGL_RHI_METAL) + SetVertexShader_METAL(shader); #endif } @@ -113,6 +115,8 @@ namespace CGL::Graphics SetPixelShader_D3D11(shader); #elif defined(CGL_RHI_OPENGL) SetPixelShader_OPENGL(shader); +#elif defined (CGL_RHI_METAL) + SetPixelShader_METAL(shader); #endif } @@ -130,8 +134,10 @@ namespace CGL::Graphics #if defined(CGL_RHI_OPENGL) glUseProgram(material.m_id); +#elif defined (CGL_RHI_METAL) + SetRenderPipeline_METAL(); #endif - } + } void Renderer::SetVertexBuffer(const VertexBuffer& buffer) @@ -140,6 +146,8 @@ namespace CGL::Graphics SetVertexBuffer_D3D11(buffer); #elif defined(CGL_RHI_OPENGL) SetVertexBuffer_OPENGL(buffer); +#elif defined (CGL_RHI_METAL) + SetVertexBuffer_METAL(buffer); #endif } @@ -149,6 +157,8 @@ namespace CGL::Graphics SetIndexBuffer_D3D11(buffer); #elif defined(CGL_RHI_OPENGL) SetIndexBuffer_OPENGL(buffer); +#elif defined (CGL_RHI_METAL) + SetIndexBuffer_METAL(buffer); #endif } @@ -160,6 +170,8 @@ namespace CGL::Graphics ShaderCompileResult result = CompileVertexShader_D3D11(source, outShader); #elif defined(CGL_RHI_OPENGL) ShaderCompileResult result = CompileVertexShader_OPENGL(source, outShader); +#elif defined (CGL_RHI_METAL) + ShaderCompileResult result = CompileVertexShader_METAL(source, outShader); #endif ShaderCompiler::ReportResult(result, source.Name.data()); return result.Status == ShaderCompileStatus::Success || result.Status == ShaderCompileStatus::HasWarnings; @@ -173,6 +185,8 @@ namespace CGL::Graphics ShaderCompileResult result = CompilePixelShader_D3D11(source, outShader); #elif defined(CGL_RHI_OPENGL) ShaderCompileResult result = CompilePixelShader_OPENGL(source, outShader); +#elif defined (CGL_RHI_METAL) + ShaderCompileResult result = CompilePixelShader_METAL(source, outShader); #endif ShaderCompiler::ReportResult(result, source.Name.data()); return result.Status == ShaderCompileStatus::Success || result.Status == ShaderCompileStatus::HasWarnings; @@ -184,6 +198,8 @@ namespace CGL::Graphics return CreateVertexBuffer_D3D11(source); #elif defined(CGL_RHI_OPENGL) return CreateVertexBuffer_OPENGL(source); +#elif defined (CGL_RHI_METAL) + return CreateVertexBuffer_METAL(source); #endif } @@ -193,6 +209,8 @@ namespace CGL::Graphics return CreateIndexBuffer_D3D11(source); #elif defined(CGL_RHI_OPENGL) return CreateIndexBuffer_OPENGL(source); +#elif defined (CGL_RHI_METAL) + return CreateIndexBuffer_METAL(source); #endif } @@ -223,13 +241,15 @@ namespace CGL::Graphics // TODO: Add other shader types return result; } - + void Renderer::Draw(u32 vertexCount, u32 startVertex) { #if defined(CGL_RHI_DX11) Draw_D3D11(vertexCount, startVertex); #elif defined(CGL_RHI_OPENGL) Draw_OPENGL(vertexCount, startVertex); +#elif defined (CGL_RHI_METAL) + Draw_METAL(vertexCount, startVertex); #endif } @@ -239,6 +259,8 @@ namespace CGL::Graphics DrawIndexed_D3D11(indexCount, startIndex, baseVertex); #elif defined(CGL_RHI_OPENGL) DrawIndexed_OPENGL(indexCount, startIndex, baseVertex); +#elif defined (CGL_RHI_METAL) + DrawIndexed_METAL(indexCount, startIndex, baseVertex); #endif } } diff --git a/Core/Graphics/Renderer.h b/Core/Graphics/Renderer.h index 89aaf9a..4e87ea4 100644 --- a/Core/Graphics/Renderer.h +++ b/Core/Graphics/Renderer.h @@ -104,13 +104,25 @@ namespace CGL::Graphics void Draw_OPENGL(u32 vertexCount, u32 startVertex = 0); void DrawIndexed_OPENGL(u32 indexCount, u32 startIndex = 0, u32 baseVertex = 0); OPENGLRendererImpl* GetImpl() const; - + #elif defined(CGL_RHI_METAL) void Constructor_METAL(SDL_Window* window); void Destructor_METAL(); void BeginFrame_METAL(); void EndFrame_METAL(); void Resize_METAL(u32 width, u32 height); + void SetRenderPipeline_METAL(); + void SetPrimitiveTopology_METAL(PrimitiveType topology); + void SetVertexShader_METAL(const VertexShader& shader); + void SetPixelShader_METAL(const PixelShader& shader); + void SetVertexBuffer_METAL(const VertexBuffer& buffer); + void SetIndexBuffer_METAL(const IndexBuffer& buffer); + ShaderCompileResult CompileVertexShader_METAL(const ShaderSource& source, VertexShader* outShader); + ShaderCompileResult CompilePixelShader_METAL(const ShaderSource& source, PixelShader* outShader); + VertexBuffer CreateVertexBuffer_METAL(const BufferSource& source); + IndexBuffer CreateIndexBuffer_METAL(const BufferSource& source); + void Draw_METAL(u32 vertexCount, u32 startVertex = 0); + void DrawIndexed_METAL(u32 indexCount, u32 startIndex = 0, u32 baseVertex = 0); METALRendererImpl* GetImpl() const; #endif @@ -123,4 +135,4 @@ namespace CGL::Graphics } // Contains template bodies -#include "Renderer.inl" \ No newline at end of file +#include "Renderer.inl" diff --git a/Core/Graphics/Shader/Shader.h b/Core/Graphics/Shader/Shader.h index 7578f18..0204808 100644 --- a/Core/Graphics/Shader/Shader.h +++ b/Core/Graphics/Shader/Shader.h @@ -15,6 +15,7 @@ #if defined(CGL_RHI_METAL) #include +#include #endif #if defined(CGL_RHI_VULKAN) diff --git a/Core/Graphics/Shader/ShaderCompiler.cpp b/Core/Graphics/Shader/ShaderCompiler.cpp index 0283e9d..9d92d9a 100644 --- a/Core/Graphics/Shader/ShaderCompiler.cpp +++ b/Core/Graphics/Shader/ShaderCompiler.cpp @@ -152,5 +152,42 @@ namespace CGL::Graphics } } +#elif defined (CGL_RHI_METAL) + + ShaderCompileResult ShaderCompiler::Compile(const ShaderSource& shader, const CompileConfig& config, METALCompileObjects& outSource) + { + ShaderCompileResult result; + + if(shader.SourceData.empty()) + { + result.Status = ShaderCompileStatus::Failure; + result.Message = "Shader file path is empty"; + return result; + } + + NS::Error* ns_error{}; + + const auto& [library, device] = outSource; + + library = std::make_unique(); + + *library.get() = device->newLibrary( + NS::String::string(shader.SourceData.c_str(), NS::UTF8StringEncoding), + nullptr, &ns_error + ); + + if(!outSource.library) + { + result.Status = ShaderCompileStatus::HasWarnings; + result.Message = ns_error->localizedDescription()->utf8String(); + assert(false); + return result; + } + + result.Status = ShaderCompileStatus::Success; + result.Message = "Compiled successfully"; + return result; + } + #endif -} \ No newline at end of file +} diff --git a/Core/Graphics/Shader/ShaderCompiler.h b/Core/Graphics/Shader/ShaderCompiler.h index 5d0a527..ee2a03d 100644 --- a/Core/Graphics/Shader/ShaderCompiler.h +++ b/Core/Graphics/Shader/ShaderCompiler.h @@ -12,6 +12,10 @@ #include #endif +#if defined (CGL_RHI_METAL) +#include +#endif + namespace CGL::Graphics { CGL_DECLARE_LOG_CATEGORY(ShaderCompiler); @@ -37,6 +41,8 @@ namespace CGL::Graphics static ShaderCompileResult Compile(const ShaderSource& shader, const CompileConfig& config, ComPtr& outBlob); #elif defined(CGL_RHI_OPENGL) static ShaderCompileResult Compile(const ShaderSource& shader, const CompileConfig& config, GLuint& outBlob); +#elif defined (CGL_RHI_METAL) + static ShaderCompileResult Compile(const ShaderSource& shader, const CompileConfig& config, METALCompileObjects& outBlob); #endif }; } diff --git a/Core/Graphics/Types.h b/Core/Graphics/Types.h index e3751a2..b38d003 100644 --- a/Core/Graphics/Types.h +++ b/Core/Graphics/Types.h @@ -141,26 +141,26 @@ namespace CGL::Graphics { struct Position { - SM::Vector3 Position; + SM::Vector4 Position; }; struct PositionColor { - SM::Vector3 Position; + SM::Vector4 Position; SM::Vector4 Color; }; struct PositionTexture { - SM::Vector3 Position; + SM::Vector4 Position; SM::Vector2 Texture; }; struct PositionColorTexture { - SM::Vector3 Position; + SM::Vector4 Position; SM::Vector4 Color; SM::Vector2 Texture; }; } -} \ No newline at end of file +} diff --git a/Samples/HelloTriangle/Assets/Metal/HelloTrianglePS.metal b/Samples/HelloTriangle/Assets/Metal/HelloTrianglePS.metal new file mode 100644 index 0000000..b7f03c3 --- /dev/null +++ b/Samples/HelloTriangle/Assets/Metal/HelloTrianglePS.metal @@ -0,0 +1,13 @@ +#include +using namespace metal; + +struct VertexData +{ + float4 Position [[position]]; + float4 Color; +}; + +fragment float4 HelloTrianglePS(VertexData in [[stage_in]]) +{ + return in.Color; +} diff --git a/Samples/HelloTriangle/Assets/Metal/HelloTriangleVS.metal b/Samples/HelloTriangle/Assets/Metal/HelloTriangleVS.metal new file mode 100644 index 0000000..a0d0fe6 --- /dev/null +++ b/Samples/HelloTriangle/Assets/Metal/HelloTriangleVS.metal @@ -0,0 +1,30 @@ +#include +using namespace metal; + +struct VertexIn +{ + float3 Position; + float4 Color; +}; + +struct VertexData +{ + float4 Position [[position]]; + float4 Color; +}; + +vertex VertexData HelloTriangleVS(constant VertexIn* inData, uint vertexID [[vertex_id]]) +{ + VertexData out; + + out.Position = float4( + inData[vertexID].Position.x, + inData[vertexID].Position.y, + inData[vertexID].Position.z, + 1.0f + ); + + out.Color = float4(inData[vertexID].Color); + + return out; +} diff --git a/Samples/HelloTriangle/HelloTriangle.cpp b/Samples/HelloTriangle/HelloTriangle.cpp index 6af1c81..ee94c67 100644 --- a/Samples/HelloTriangle/HelloTriangle.cpp +++ b/Samples/HelloTriangle/HelloTriangle.cpp @@ -69,17 +69,17 @@ namespace CGL { Graphics::VertexTypes::PositionColor { - .Position = SM::Vector3( 0.0f, 0.5f, 0.0f ), + .Position = SM::Vector4( 0.0f, 0.5f, 0.0f, 1.0f ), .Color = SM::Vector4( 1.0f, 0.0f, 0.0f, 1.0f ), }, Graphics::VertexTypes::PositionColor { - .Position = SM::Vector3( 0.5f, -0.5f, 0.0f ), + .Position = SM::Vector4( 0.5f, -0.5f, 0.0f, 1.0f ), .Color = SM::Vector4( 0.0f, 1.0f, 0.0f, 1.0f ), }, Graphics::VertexTypes::PositionColor { - .Position = SM::Vector3( -0.5f, -0.5f, 0.0f ), + .Position = SM::Vector4( -0.5f, -0.5f, 0.0f, 1.0f ), .Color = SM::Vector4( 0.0f, 0.0f, 1.0f, 1.0f ), }, };