diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e8a2d6..d6653f9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -77,15 +77,15 @@ target_link_libraries(Engine PUBLIC nlohmann_json::nlohmann_json) target_link_libraries(Engine PUBLIC crcpp) target_link_libraries(Engine PUBLIC fmt::fmt) target_link_libraries(Engine PUBLIC GPUOpen::VulkanMemoryAllocator) -target_link_libraries(Engine PUBLIC shader-slang) +target_link_libraries(Engine PUBLIC slang) target_link_libraries(Engine PUBLIC spirv-cross-glsl spirv-cross-msl) target_link_libraries(Engine PUBLIC glslang::glslang) if(APPLE) + target_include_directories(Engine PUBLIC /usr/local/include) + target_link_directories(Engine PUBLIC /usr/local/lib) + target_link_libraries(Engine PUBLIC metalirconverter) target_link_libraries(Engine PUBLIC metal) SET(CMAKE_OSX_DEPLOYMENT_TARGET 14.3) - install(FILES - ${EXTERNAL_ROOT}/dxc - DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) endif() if(UNIX) target_link_libraries(Engine PUBLIC Threads::Threads) @@ -121,8 +121,8 @@ else() endif() if(APPLE) #Metal lib throws that internally for some reason - target_compile_options(Engine PUBLIC -Wno-gnu-anonymous-struct) - target_compile_options(Editor PUBLIC -Wno-gnu-anonymous-struct) + target_compile_options(Engine PUBLIC -Wno-gnu-anonymous-struct -Wno-nested-anon-types) + target_compile_options(Editor PUBLIC -Wno-gnu-anonymous-struct -Wno-nested-anon-types) endif() target_compile_options(Engine PUBLIC "$<$:-DENABLE_VALIDATION>") target_compile_options(Engine PUBLIC "$<$:-DSEELE_DEBUG>") @@ -137,7 +137,7 @@ if(WIN32) DEPENDS Editor) elseif(APPLE) add_custom_target(dll_copy ALL - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${SLANG_ROOT}bin/libslang.dylib $ + COMMAND ${CMAKE_COMMAND} -E true COMMAND_EXPAND_LISTS DEPENDS Editor) else() @@ -157,6 +157,7 @@ install( Engine crcpp metal + slang EXPORT EngineTargets FILE_SET HEADERS diff --git a/cmake/SuperBuild.cmake b/cmake/SuperBuild.cmake index 01591e2..8197fe2 100644 --- a/cmake/SuperBuild.cmake +++ b/cmake/SuperBuild.cmake @@ -2,36 +2,37 @@ include (ExternalProject) #--------------SLang------------------------------ -add_library(shader-slang-glslang SHARED IMPORTED) -add_library(shader-slang SHARED IMPORTED) -if(WIN32) - set(SLANG_ROOT ${EXTERNAL_ROOT}/vcpkg/packages/shader-slang_x64-windows/) - set_target_properties(shader-slang-glslang PROPERTIES IMPORTED_LOCATION ${SLANG_ROOT}/bin/slang-glslang.dll) - set_target_properties(shader-slang-glslang PROPERTIES IMPORTED_IMPLIB ${SLANG_ROOT}/lib/slang.lib) - set_target_properties(shader-slang PROPERTIES IMPORTED_LOCATION ${SLANG_ROOT}/bin/slang.dll) - set_target_properties(shader-slang PROPERTIES IMPORTED_IMPLIB ${SLANG_ROOT}/lib/slang.lib) - target_link_libraries(shader-slang INTERFACE shader-slang-glslang) - install(FILES - ${SLANG_ROOT}/bin/slang-glslang.dll - ${SLANG_ROOT}/bin/slang.dll - DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) - install(FILES - ${SLANG_ROOT}/lib/slang.lib - DESTINATION ${CMAKE_INSTALL_PREFIX}/lib) -elseif(APPLE) - set(SLANG_ROOT ${EXTERNAL_ROOT}/vcpkg/packages/shader-slang_arm64-osx/) - set_target_properties(shader-slang-glslang PROPERTIES IMPORTED_LOCATION ${SLANG_ROOT}/bin/libslang-glslang.dylib) - set_target_properties(shader-slang PROPERTIES IMPORTED_LOCATION ${SLANG_ROOT}/bin/libslang.dylib) - target_link_libraries(shader-slang INTERFACE shader-slang-glslang) - install(FILES - ${SLANG_ROOT}/bin/libslang.dylib - ${SLANG_ROOT}/bin/libslang-glslang.dylib - DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) -endif() -target_include_directories(shader-slang INTERFACE - $ - $ -) +set(SLANG_ROOT ${EXTERNAL_ROOT}/slang) +#add_library(shader-slang SHARED IMPORTED) +#if(WIN32) +# add_library(shader-slang-glslang SHARED IMPORTED) +# set(SLANG_ROOT ${EXTERNAL_ROOT}/slang/bin/windows-x64/release/) +# set_target_properties(shader-slang-glslang PROPERTIES IMPORTED_LOCATION ${SLANG_ROOT}/bin/slang-glslang.dll) +# set_target_properties(shader-slang-glslang PROPERTIES IMPORTED_IMPLIB ${SLANG_ROOT}/lib/slang.lib) +# set_target_properties(shader-slang PROPERTIES IMPORTED_LOCATION ${SLANG_ROOT}/bin/slang.dll) +# set_target_properties(shader-slang PROPERTIES IMPORTED_IMPLIB ${SLANG_ROOT}/lib/slang.lib) +# target_link_libraries(shader-slang INTERFACE shader-slang-glslang) +# install(FILES +# ${SLANG_ROOT}/bin/slang-glslang.dll +# ${SLANG_ROOT}/bin/slang.dll +# DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) +# install(FILES +# ${SLANG_ROOT}/lib/slang.lib +# DESTINATION ${CMAKE_INSTALL_PREFIX}/lib) +#elseif(APPLE) +# set(BINARY_ROOT ${SLANG_ROOT}/bin/macosx-aarch64/release/) +# set_target_properties(shader-slang PROPERTIES IMPORTED_LOCATION ${BINARY_ROOT}/libslang.dylib) +# install(FILES +# ${BINARY_ROOT}/libslang.dylib +# DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) +#endif() +#target_include_directories(shader-slang INTERFACE +# $ +# $ +#) + +add_subdirectory(${SLANG_ROOT}) +target_compile_definitions(compiler-core PUBLIC SLANG_ENABLE_DXIL_SUPPORT=1) #--------------CRC++------------------------------ add_library(crcpp INTERFACE) diff --git a/external/slang b/external/slang index ec0224e..ee9d398 160000 --- a/external/slang +++ b/external/slang @@ -1 +1 @@ -Subproject commit ec0224edc3a867bbf059e790ad7b2a1a881a0705 +Subproject commit ee9d398ebfc7c67205a8d5c91834ae4882d0dc9b diff --git a/res/shaders/BasePass.slang b/res/shaders/BasePass.slang index e0c5f12..0770393 100644 --- a/res/shaders/BasePass.slang +++ b/res/shaders/BasePass.slang @@ -26,10 +26,10 @@ float4 fragmentMain(in FragmentParameter params) : SV_Target { result += pLightEnv.directionalLights[i].illuminate(lightingParams, brdf); } - for(uint i = 0; i < lightCount; ++i) + for(uint i = 0; i < pLightEnv.numPointLights; ++i) { - uint lightIndex = pLightCullingData.lightIndexList[startOffset + i]; - result += pLightEnv.pointLights[lightIndex].illuminate(lightingParams, brdf); + //uint lightIndex = pLightCullingData.lightIndexList[startOffset + i]; + result += pLightEnv.pointLights[i].illuminate(lightingParams, brdf); } return float4(params.vertexColor, 1.0f); } diff --git a/res/shaders/Debug.slang b/res/shaders/Debug.slang index a486c47..ddf6581 100644 --- a/res/shaders/Debug.slang +++ b/res/shaders/Debug.slang @@ -2,8 +2,8 @@ import Common; struct DebugVertex { - float3 position; - float3 color; + float3 position : POSITION; + float3 color : COLOR0; }; struct Params diff --git a/res/shaders/MeshletBasePass.slang b/res/shaders/MeshletBasePass.slang index 339558c..d29ea41 100644 --- a/res/shaders/MeshletBasePass.slang +++ b/res/shaders/MeshletBasePass.slang @@ -65,6 +65,12 @@ struct PrimitiveAttributes uint cull: SV_CullPrimitive; }; +uint unpackPrimitiveIndices(uint index) +{ + uint32_t packed = pScene.primitiveIndices[index / 4]; + return (packed >> (index % 4)) & 0xff; +} + [numthreads(MESH_GROUP_SIZE, 1, 1)] [outputtopology("triangle")] [shader("mesh")] @@ -84,9 +90,9 @@ void meshMain( { uint p = min(i, m.primitiveCount - 1); { - uint local_idx0 = pScene.primitiveIndices[m.primitiveOffset + (p * 3) + 0]; - uint local_idx1 = pScene.primitiveIndices[m.primitiveOffset + (p * 3) + 1]; - uint local_idx2 = pScene.primitiveIndices[m.primitiveOffset + (p * 3) + 2]; + uint local_idx0 = unpackPrimitiveIndices(m.primitiveOffset + (p * 3) + 0); + uint local_idx1 = unpackPrimitiveIndices(m.primitiveOffset + (p * 3) + 1); + uint local_idx2 = unpackPrimitiveIndices(m.primitiveOffset + (p * 3) + 2); indices[p] = uint3(local_idx0, local_idx1, local_idx2); } } diff --git a/res/shaders/lib/Scene.slang b/res/shaders/lib/Scene.slang index 82cd316..67f612d 100644 --- a/res/shaders/lib/Scene.slang +++ b/res/shaders/lib/Scene.slang @@ -14,12 +14,12 @@ struct MeshletDescription struct MeshData { BoundingSphere bounding; - uint32_t numMeshlets; - uint32_t meshletOffset; - uint32_t firstIndex; - uint32_t numIndices; - uint32_t indicesOffset; - uint32_t pad0[3]; + uint32_t numMeshlets; + uint32_t meshletOffset; + uint32_t firstIndex; + uint32_t numIndices; + uint32_t indicesOffset; + uint32_t pad0[3]; }; static const uint MAX_VERTICES = 64; @@ -38,7 +38,8 @@ struct Scene StructuredBuffer instances; StructuredBuffer meshData; StructuredBuffer meshletInfos; - StructuredBuffer primitiveIndices; + // uint8_t is not valid in DXIL + StructuredBuffer primitiveIndices; StructuredBuffer vertexIndices; }; diff --git a/src/Engine/Graphics/Enums.h b/src/Engine/Graphics/Enums.h index 3ebe399..8309979 100644 --- a/src/Engine/Graphics/Enums.h +++ b/src/Engine/Graphics/Enums.h @@ -1596,15 +1596,16 @@ typedef enum SeShaderStageFlagBits SE_SHADER_STAGE_COMPUTE_BIT = 0x00000020, SE_SHADER_STAGE_ALL_GRAPHICS = 0x0000001F, SE_SHADER_STAGE_ALL = 0x7FFFFFFF, - SE_SHADER_STAGE_RAYGEN_BIT_NV = 0x00000100, - SE_SHADER_STAGE_ANY_HIT_BIT_NV = 0x00000200, - SE_SHADER_STAGE_CLOSEST_HIT_BIT_NV = 0x00000400, - SE_SHADER_STAGE_MISS_BIT_NV = 0x00000800, - SE_SHADER_STAGE_INTERSECTION_BIT_NV = 0x00001000, - SE_SHADER_STAGE_CALLABLE_BIT_NV = 0x00002000, - SE_SHADER_STAGE_TASK_BIT_NV = 0x00000040, - SE_SHADER_STAGE_MESH_BIT_NV = 0x00000080, - SE_SHADER_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF + SE_SHADER_STAGE_RAYGEN_BIT_KHR = 0x00000100, + SE_SHADER_STAGE_ANY_HIT_BIT_KHR = 0x00000200, + SE_SHADER_STAGE_CLOSEST_HIT_BIT_KHR = 0x00000400, + SE_SHADER_STAGE_MISS_BIT_KHR = 0x00000800, + SE_SHADER_STAGE_INTERSECTION_BIT_KHR = 0x00001000, + SE_SHADER_STAGE_CALLABLE_BIT_KHR = 0x00002000, + SE_SHADER_STAGE_TASK_BIT_EXT = 0x00000040, + SE_SHADER_STAGE_MESH_BIT_EXT = 0x00000080, + SE_SHADER_STAGE_SUBPASS_SHADING_BIT_HUAWEI = 0x00004000, + SE_SHADER_STAGE_CLUSTER_CULLING_BIT_HUAWEI = 0x00080000, } SeShaderStageFlagBits; typedef SeFlags SePipelineVertexInputStateCreateFlags; typedef SeFlags SePipelineInputAssemblyStateCreateFlags; diff --git a/src/Engine/Graphics/Metal/Buffer.mm b/src/Engine/Graphics/Metal/Buffer.mm index ebb4aeb..afe9907 100644 --- a/src/Engine/Graphics/Metal/Buffer.mm +++ b/src/Engine/Graphics/Metal/Buffer.mm @@ -54,7 +54,9 @@ void VertexBuffer::download(Array& buffer) { void VertexBuffer::executeOwnershipBarrier(Gfx::QueueType newOwner) { currentOwner = newOwner; } void VertexBuffer::executePipelineBarrier(Gfx::SeAccessFlags srcAccess, Gfx::SePipelineStageFlags srcStage, - Gfx::SeAccessFlags dstAccess, Gfx::SePipelineStageFlags dstStage) {} + Gfx::SeAccessFlags dstAccess, Gfx::SePipelineStageFlags dstStage) { + +} IndexBuffer::IndexBuffer(PGraphics graphics, const IndexBufferCreateInfo& createInfo) : Gfx::IndexBuffer(graphics->getFamilyMapping(), createInfo.sourceData.size, createInfo.indexType, diff --git a/src/Engine/Graphics/Metal/Command.h b/src/Engine/Graphics/Metal/Command.h index 2b79270..c3e94f2 100644 --- a/src/Engine/Graphics/Metal/Command.h +++ b/src/Engine/Graphics/Metal/Command.h @@ -1,6 +1,10 @@ #pragma once -#include "Graphics/Command.h" #include "Buffer.h" +#include "Graphics/Command.h" +#include "Metal/MTLBlitCommandEncoder.hpp" +#include "Metal/MTLCommandBuffer.hpp" +#include "Metal/MTLComputeCommandEncoder.hpp" +#include "Metal/MTLRenderCommandEncoder.hpp" #include "RenderPass.h" #include "Resources.h" @@ -12,106 +16,111 @@ DECLARE_REF(RenderCommand) DECLARE_REF(Graphics) DECLARE_REF(IndexBuffer) DECLARE_REF(GraphicsPipeline) -class Command -{ +class Command { public: - Command(PGraphics graphics, MTL::CommandBuffer* cmdBuffer); - ~Command(); - void beginRenderPass(PRenderPass renderPass); - void endRenderPass(); - void present(MTL::Drawable* drawable); - void end(PEvent signal); - void executeCommands(Array commands); - void executeCommands(Array commands); - void waitDeviceIdle(); - void signalEvent(PEvent event); - void waitForEvent(PEvent event); - MTL::RenderCommandEncoder* createRenderEncoder() { return renderEncoder->renderCommandEncoder(); } - MTL::ComputeCommandEncoder* createComputeEncoder() { return cmdBuffer->computeCommandEncoder(); } - PEvent getCompletedEvent() const { return completed; } - constexpr MTL::CommandBuffer* getHandle() const + Command(PGraphics graphics, MTL::CommandBuffer* cmdBuffer); + ~Command(); + void beginRenderPass(PRenderPass renderPass); + void endRenderPass(); + void present(MTL::Drawable* drawable); + void end(PEvent signal); + void waitDeviceIdle(); + void signalEvent(PEvent event); + void waitForEvent(PEvent event); + MTL::RenderCommandEncoder* createRenderEncoder() { return parallelEncoder->renderCommandEncoder(); } + MTL::BlitCommandEncoder* getBlitEncoder() { + assert(!parallelEncoder); + if(blitEncoder == nullptr) { - return cmdBuffer; + blitEncoder = cmdBuffer->blitCommandEncoder(); } + return blitEncoder; + } + PEvent getCompletedEvent() const { return completed; } + constexpr MTL::CommandBuffer* getHandle() const { return cmdBuffer; } + private: - PGraphics graphics; - OEvent completed; - MTL::CommandBuffer* cmdBuffer; - MTL::ParallelRenderCommandEncoder* renderEncoder; + PGraphics graphics; + OEvent completed; + MTL::CommandBuffer* cmdBuffer; + MTL::ParallelRenderCommandEncoder* parallelEncoder = nullptr; + MTL::BlitCommandEncoder* blitEncoder = nullptr; }; DEFINE_REF(Command) -class RenderCommand : public Gfx::RenderCommand -{ +class RenderCommand : public Gfx::RenderCommand { public: - RenderCommand(MTL::RenderCommandEncoder* encoder); - virtual ~RenderCommand(); - void end(); - virtual void setViewport(Gfx::PViewport viewport) override; - virtual void bindPipeline(Gfx::PGraphicsPipeline pipeline) override; - virtual void bindDescriptor(Gfx::PDescriptorSet descriptorSet) override; - virtual void bindDescriptor(const Array& descriptorSets) override; - virtual void bindVertexBuffer(const Array& buffers) override; - virtual void bindIndexBuffer(Gfx::PIndexBuffer indexBuffer) override; - virtual void pushConstants(Gfx::PPipelineLayout layout, Gfx::SeShaderStageFlags stage, uint32 offset, uint32 size, const void* data) override; - virtual void draw(uint32 vertexCount, uint32 instanceCount, int32 firstVertex, uint32 firstInstance) override; - virtual void drawIndexed(uint32 indexCount, uint32 instanceCount, int32 firstIndex, uint32 vertexOffset, uint32 firstInstance) override; - virtual void drawMesh(uint32 groupX, uint32 groupY, uint32 groupZ) override; + RenderCommand(MTL::RenderCommandEncoder* encode, const std::string& name); + virtual ~RenderCommand(); + void end(); + virtual void setViewport(Gfx::PViewport viewport) override; + virtual void bindPipeline(Gfx::PGraphicsPipeline pipeline) override; + virtual void bindDescriptor(Gfx::PDescriptorSet descriptorSet) override; + virtual void bindDescriptor(const Array& descriptorSets) override; + virtual void bindVertexBuffer(const Array& buffers) override; + virtual void bindIndexBuffer(Gfx::PIndexBuffer indexBuffer) override; + virtual void pushConstants(Gfx::PPipelineLayout layout, Gfx::SeShaderStageFlags stage, uint32 offset, uint32 size, + const void* data) override; + virtual void draw(uint32 vertexCount, uint32 instanceCount, int32 firstVertex, uint32 firstInstance) override; + virtual void drawIndexed(uint32 indexCount, uint32 instanceCount, int32 firstIndex, uint32 vertexOffset, + uint32 firstInstance) override; + virtual void drawMesh(uint32 groupX, uint32 groupY, uint32 groupZ) override; + private: - MTL::RenderCommandEncoder* encoder; - PIndexBuffer boundIndexBuffer; - PGraphicsPipeline boundPipeline; + MTL::RenderCommandEncoder* encoder; + PIndexBuffer boundIndexBuffer; + PGraphicsPipeline boundPipeline; + std::string name; }; DEFINE_REF(RenderCommand) -class ComputeCommand : public Gfx::ComputeCommand -{ +class ComputeCommand : public Gfx::ComputeCommand { public: - ComputeCommand(MTL::ComputeCommandEncoder* encoder); - virtual ~ComputeCommand(); - void end(); - virtual void bindPipeline(Gfx::PComputePipeline pipeline) override; - virtual void bindDescriptor(Gfx::PDescriptorSet set) override; - virtual void bindDescriptor(const Array& sets) override; - virtual void pushConstants(Gfx::PPipelineLayout layout, Gfx::SeShaderStageFlags stage, uint32 offset, uint32 size, const void* data) override; - virtual void dispatch(uint32 threadX, uint32 threadY, uint32 threadZ) override; + ComputeCommand(MTL::CommandBuffer* cmdBuffer, const std::string& name); + virtual ~ComputeCommand(); + void end(); + virtual void bindPipeline(Gfx::PComputePipeline pipeline) override; + virtual void bindDescriptor(Gfx::PDescriptorSet set) override; + virtual void bindDescriptor(const Array& sets) override; + virtual void pushConstants(Gfx::PPipelineLayout layout, Gfx::SeShaderStageFlags stage, uint32 offset, uint32 size, + const void* data) override; + virtual void dispatch(uint32 threadX, uint32 threadY, uint32 threadZ) override; + private: - MTL::ComputeCommandEncoder* encoder; + MTL::CommandBuffer* commandBuffer; + MTL::ComputeCommandEncoder* encoder; + std::string name; }; DEFINE_REF(ComputeCommand) -class CommandQueue -{ +class CommandQueue { public: - CommandQueue(PGraphics graphics); - ~CommandQueue(); - constexpr MTL::CommandQueue* getHandle() - { - return queue; - } - PCommand getCommands() {return activeCommand;} //TODO - ORenderCommand getRenderCommand(const std::string& name); - OComputeCommand getComputeCommand(const std::string& name); - void submitCommands(PEvent signal = nullptr); + CommandQueue(PGraphics graphics); + ~CommandQueue(); + constexpr MTL::CommandQueue* getHandle() { return queue; } + PCommand getCommands() { return activeCommand; } + ORenderCommand getRenderCommand(const std::string& name); + OComputeCommand getComputeCommand(const std::string& name); + void executeCommands(Array commands); + void executeCommands(Array commands); + void submitCommands(PEvent signal = nullptr); + private: - PGraphics graphics; - MTL::CommandQueue* queue; - OCommand activeCommand; - Array pendingCommands; + PGraphics graphics; + MTL::CommandQueue* queue; + OCommand activeCommand; + Array pendingCommands; }; -class IOCommandQueue -{ +class IOCommandQueue { public: IOCommandQueue(PGraphics graphics); ~IOCommandQueue(); - constexpr MTL::IOCommandQueue* getHandle() - { - return queue; - } - PCommand getCommands() {return activeCommand;} // TODO + constexpr MTL::IOCommandQueue* getHandle() { return queue; } + PCommand getCommands() { return activeCommand; } // TODO void submitCommands(PEvent signal = nullptr); + private: PGraphics graphics; MTL::IOCommandQueue* queue; OCommand activeCommand; }; DEFINE_REF(IOCommandQueue) -} -} \ No newline at end of file +} // namespace Metal +} // namespace Seele \ No newline at end of file diff --git a/src/Engine/Graphics/Metal/Command.mm b/src/Engine/Graphics/Metal/Command.mm index 9fefbcc..9c3c1fb 100644 --- a/src/Engine/Graphics/Metal/Command.mm +++ b/src/Engine/Graphics/Metal/Command.mm @@ -1,31 +1,43 @@ #include "Command.h" #include "Buffer.h" +#include "Containers/Array.h" #include "Descriptor.h" #include "Enums.h" +#include "Graphics/Command.h" #include "Graphics/Enums.h" #include "Graphics/Graphics.h" -#include "Metal/MTLCommandBuffer.hpp" +#include "Graphics/Resources.h" #include "Pipeline.h" #include "Resources.h" #include "Window.h" +#include 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) {} -Command::~Command() { cmdBuffer->release(); } +Command::~Command() {} void Command::beginRenderPass(PRenderPass renderPass) { - renderEncoder = cmdBuffer->parallelRenderCommandEncoder(renderPass->getDescriptor()); + if (blitEncoder) { + blitEncoder->endEncoding(); + blitEncoder = nullptr; + } + parallelEncoder = cmdBuffer->parallelRenderCommandEncoder(renderPass->getDescriptor()); } -void Command::endRenderPass() { renderEncoder->endEncoding(); } +void Command::endRenderPass() { + parallelEncoder->endEncoding(); + parallelEncoder = nullptr; +} void Command::present(MTL::Drawable* drawable) { cmdBuffer->presentDrawable(drawable); } void Command::end(PEvent signal) { + assert(!parallelEncoder); + blitEncoder->endEncoding(); if (signal != nullptr) { cmdBuffer->encodeSignalEvent(signal->getHandle(), 1); } @@ -33,29 +45,16 @@ void Command::end(PEvent signal) { cmdBuffer->commit(); } -void Command::executeCommands(Array commands) { - for (auto& command : commands) { - auto cmd = Gfx::PRenderCommand(command).cast(); - cmd->end(); - } -} - -void Command::executeCommands(Array commands) { - for (auto& command : commands) { - auto cmd = Gfx::PComputeCommand(command).cast(); - cmd->end(); - } -} - void Command::waitDeviceIdle() { cmdBuffer->waitUntilCompleted(); } void Command::signalEvent(PEvent event) { cmdBuffer->encodeSignalEvent(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, const std::string& name) + : encoder(encoder), name(name) {} -RenderCommand::~RenderCommand() { encoder->release(); } +RenderCommand::~RenderCommand() {} void RenderCommand::end() { encoder->endEncoding(); } @@ -88,11 +87,10 @@ void RenderCommand::bindDescriptor(const Array& descriptorS bindDescriptor(set); } } - void RenderCommand::bindVertexBuffer(const Array& buffers) { uint32 i = 0; for (auto buffer : buffers) { - encoder->setVertexBuffer(buffer.cast()->getHandle(), 0, i++); + encoder->setVertexBuffer(buffer.cast()->getHandle(), 0, METAL_VERTEXBUFFER_OFFSET + i++); } } @@ -125,11 +123,15 @@ void RenderCommand::drawMesh(uint32 groupX, uint32 groupY, uint32 groupZ) { 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::CommandBuffer* cmdBuffer, const std::string& name) + : commandBuffer(cmdBuffer), encoder(cmdBuffer->computeCommandEncoder()), name(name) {} -ComputeCommand::~ComputeCommand() { encoder->release(); } +ComputeCommand::~ComputeCommand() {} -void ComputeCommand::end() { encoder->endEncoding(); } +void ComputeCommand::end() { + encoder->endEncoding(); + commandBuffer->commit(); +} void ComputeCommand::bindPipeline(Gfx::PComputePipeline pipeline) { encoder->setComputePipelineState(pipeline.cast()->getHandle()); @@ -159,34 +161,52 @@ void ComputeCommand::dispatch(uint32 threadX, uint32 threadY, uint32 threadZ) { CommandQueue::CommandQueue(PGraphics graphics) : graphics(graphics) { queue = graphics->getDevice()->newCommandQueue(); - activeCommand = new Command(graphics, queue->commandBuffer()); + MTL::CommandBufferDescriptor* descriptor = MTL::CommandBufferDescriptor::alloc()->init(); + descriptor->setErrorOptions(MTL::CommandBufferErrorOptionEncoderExecutionStatus); + activeCommand = new Command(graphics, queue->commandBuffer(descriptor)); } CommandQueue::~CommandQueue() { queue->release(); } ORenderCommand CommandQueue::getRenderCommand(const std::string& name) { - return new RenderCommand(activeCommand->createRenderEncoder()); + return new RenderCommand(activeCommand->createRenderEncoder(), name); } OComputeCommand CommandQueue::getComputeCommand(const std::string& name) { - return new ComputeCommand(activeCommand->createComputeEncoder()); + return new ComputeCommand(queue->commandBuffer(), name); +} + +void CommandQueue::executeCommands(Array commands) { + for (auto& command : commands) { + auto metalCmd = Gfx::PRenderCommand(command).cast(); + metalCmd->end(); + } +} + +void CommandQueue::executeCommands(Array commands) { + submitCommands(); + for (auto& command : commands) { + auto metalCmd = Gfx::PComputeCommand(command).cast(); + metalCmd->end(); + } } void CommandQueue::submitCommands(PEvent signalSemaphore) { activeCommand->getHandle()->addCompletedHandler(MTL::CommandBufferHandler([&](MTL::CommandBuffer* cmdBuffer) { - for(auto it = pendingCommands.begin(); it != pendingCommands.end(); it++) - { - if((*it)->getHandle() == cmdBuffer) - { + for (auto it = pendingCommands.begin(); it != pendingCommands.end(); it++) { + if ((*it)->getHandle() == cmdBuffer) { pendingCommands.remove(it); return; } } })); activeCommand->end(signalSemaphore); + activeCommand->waitDeviceIdle(); PEvent prevCmdEvent = activeCommand->getCompletedEvent(); pendingCommands.add(std::move(activeCommand)); - activeCommand = new Command(graphics, queue->commandBuffer()); + MTL::CommandBufferDescriptor* descriptor = MTL::CommandBufferDescriptor::alloc()->init(); + descriptor->setErrorOptions(MTL::CommandBufferErrorOptionEncoderExecutionStatus); + activeCommand = new Command(graphics, queue->commandBuffer(descriptor)); activeCommand->waitForEvent(prevCmdEvent); } diff --git a/src/Engine/Graphics/Metal/Enums.h b/src/Engine/Graphics/Metal/Enums.h index 24febe6..d601a48 100644 --- a/src/Engine/Graphics/Metal/Enums.h +++ b/src/Engine/Graphics/Metal/Enums.h @@ -7,6 +7,9 @@ namespace Seele { namespace Metal { +constexpr uint64 METAL_VERTEXBUFFER_OFFSET = 6;// something about metal vertex fetch +constexpr uint64 METAL_VERTEXATTRIBUTE_OFFSET = 11; + MTL::PixelFormat cast(Gfx::SeFormat format); Gfx::SeFormat cast(MTL::PixelFormat format); MTL::LoadAction cast(Gfx::SeAttachmentLoadOp loadOp); diff --git a/src/Engine/Graphics/Metal/Graphics.mm b/src/Engine/Graphics/Metal/Graphics.mm index ff30c83..6ad4d08 100644 --- a/src/Engine/Graphics/Metal/Graphics.mm +++ b/src/Engine/Graphics/Metal/Graphics.mm @@ -31,6 +31,7 @@ void Graphics::init(GraphicsInitializer) queue = new CommandQueue(this); ioQueue = new IOCommandQueue(this); cache = new PipelineCache(this, "pipelines.metal"); + meshShadingEnabled = true; } Gfx::OWindow Graphics::createWindow(const WindowCreateInfo &createInfo) @@ -65,12 +66,12 @@ void Graphics::waitDeviceIdle() void Graphics::executeCommands(Array commands) { - queue->getCommands()->executeCommands(std::move(commands)); + queue->executeCommands(std::move(commands)); } void Graphics::executeCommands(Array commands) { - queue->getCommands()->executeCommands(std::move(commands)); + queue->executeCommands(std::move(commands)); } Gfx::OTexture2D Graphics::createTexture2D(const TextureCreateInfo &createInfo) diff --git a/src/Engine/Graphics/Metal/PipelineCache.mm b/src/Engine/Graphics/Metal/PipelineCache.mm index 6f82584..ed5265b 100644 --- a/src/Engine/Graphics/Metal/PipelineCache.mm +++ b/src/Engine/Graphics/Metal/PipelineCache.mm @@ -2,6 +2,7 @@ #include "Descriptor.h" #include "Enums.h" #include "Foundation/NSError.hpp" +#include "Foundation/NSString.hpp" #include "Graphics.h" #include "Graphics/Descriptor.h" #include "Graphics/Enums.h" @@ -13,6 +14,7 @@ #include "Metal/MTLVertexDescriptor.hpp" #include "Shader.h" #include "Texture.h" +#include using namespace Seele; using namespace Seele::Metal; @@ -26,14 +28,13 @@ PGraphicsPipeline PipelineCache::createPipeline(Gfx::LegacyPipelineCreateInfo cr MTL::RenderPipelineDescriptor* pipelineDescriptor = MTL::RenderPipelineDescriptor::alloc()->init(); - MTL::VertexDescriptor* vertexDescriptor = MTL::VertexDescriptor::alloc()->init(); - MTL::VertexAttributeDescriptorArray* attributes = vertexDescriptor->attributes(); - if(createInfo.vertexInput != nullptr) - { + MTL::VertexDescriptor* vertexDescriptor = pipelineDescriptor->vertexDescriptor()->init(); + MTL::VertexAttributeDescriptorArray* attributes = vertexDescriptor->attributes()->init(); + if (createInfo.vertexInput != nullptr) { 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); + MTL::VertexAttributeDescriptor* attribute = attributes->object(attr + METAL_VERTEXATTRIBUTE_OFFSET)->init(); + attribute->setBufferIndex(vertexInfo.attributes[attr].binding + METAL_VERTEXBUFFER_OFFSET); switch (vertexInfo.attributes[attr].format) { case Gfx::SE_FORMAT_R32G32B32_SFLOAT: attribute->setFormat(MTL::VertexFormatFloat3); @@ -42,12 +43,11 @@ PGraphicsPipeline PipelineCache::createPipeline(Gfx::LegacyPipelineCreateInfo cr throw std::logic_error("TODO"); } attribute->setOffset(vertexInfo.attributes[attr].offset); - attributes->setObject(attribute, attr); } - MTL::VertexBufferLayoutDescriptorArray* bufferLayout = vertexDescriptor->layouts(); + MTL::VertexBufferLayoutDescriptorArray* bufferLayout = vertexDescriptor->layouts()->init(); for (size_t binding = 0; binding < vertexInfo.bindings.size(); ++binding) { - MTL::VertexBufferLayoutDescriptor* buffer = MTL::VertexBufferLayoutDescriptor::alloc()->init(); + MTL::VertexBufferLayoutDescriptor* buffer = bufferLayout->object(binding + METAL_VERTEXBUFFER_OFFSET)->init(); buffer->setStride(vertexInfo.bindings[binding].stride); buffer->setStepRate(1); switch (vertexInfo.bindings[binding].inputRate) { @@ -58,7 +58,6 @@ PGraphicsPipeline PipelineCache::createPipeline(Gfx::LegacyPipelineCreateInfo cr buffer->setStepFunction(MTL::VertexStepFunctionPerInstance); break; } - bufferLayout->setObject(buffer, binding); } } pipelineDescriptor->setVertexDescriptor(vertexDescriptor); @@ -118,14 +117,15 @@ PGraphicsPipeline PipelineCache::createPipeline(Gfx::LegacyPipelineCreateInfo cr type = MTL::PrimitiveTypeTriangle; break; } - NS::Error* error; graphicsPipelines[hash] = new GraphicsPipeline(graphics, type, graphics->getDevice()->newRenderPipelineState(pipelineDescriptor, &error), std::move(createInfo.pipelineLayout)); - assert(!error); + if (error) { + std::cout << error->localizedDescription()->cString(NS::ASCIIStringEncoding) << std::endl; + assert(false); + } - vertexDescriptor->release(); pipelineDescriptor->release(); return graphicsPipelines[hash]; } @@ -133,7 +133,7 @@ PGraphicsPipeline PipelineCache::createPipeline(Gfx::LegacyPipelineCreateInfo cr PGraphicsPipeline PipelineCache::createPipeline(Gfx::MeshPipelineCreateInfo createInfo) { MTL::MeshRenderPipelineDescriptor* pipelineDescriptor = MTL::MeshRenderPipelineDescriptor::alloc()->init(); - pipelineDescriptor->setMeshFunction(createInfo.meshShader.cast()->getFunction()); + pipelineDescriptor->setMeshFunction(createInfo.meshShader.cast()->getFunction()); if (createInfo.taskShader != nullptr) { pipelineDescriptor->setObjectFunction(createInfo.taskShader.cast()->getFunction()); } @@ -154,14 +154,12 @@ PGraphicsPipeline PipelineCache::createPipeline(Gfx::MeshPipelineCreateInfo crea 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)); - }); + NS::Error* error = nullptr; + MTL::AutoreleasedRenderPipelineReflection reflection; + graphicsPipelines[hash] = new GraphicsPipeline( + graphics, MTL::PrimitiveTypeTriangle, + graphics->getDevice()->newRenderPipelineState(pipelineDescriptor, MTL::PipelineOptionNone, &reflection, &error), + std::move(createInfo.pipelineLayout)); pipelineDescriptor->release(); return graphicsPipelines[hash]; diff --git a/src/Engine/Graphics/Metal/Shader.h b/src/Engine/Graphics/Metal/Shader.h index 1037a16..683ef26 100644 --- a/src/Engine/Graphics/Metal/Shader.h +++ b/src/Engine/Graphics/Metal/Shader.h @@ -37,8 +37,8 @@ public: using VertexShader = ShaderBase; using FragmentShader = ShaderBase; using ComputeShader = ShaderBase; -using TaskShader = ShaderBase; -using MeshShader = ShaderBase; +using TaskShader = ShaderBase; +using MeshShader = ShaderBase; DEFINE_REF(VertexShader) DEFINE_REF(FragmentShader) diff --git a/src/Engine/Graphics/Metal/Shader.mm b/src/Engine/Graphics/Metal/Shader.mm index 0ec0a0f..10baa03 100644 --- a/src/Engine/Graphics/Metal/Shader.mm +++ b/src/Engine/Graphics/Metal/Shader.mm @@ -8,9 +8,8 @@ #include "Metal/MTLLibrary.hpp" #include #include +#include #include -#include -#include using namespace Seele; using namespace Seele::Metal; @@ -25,33 +24,58 @@ Shader::~Shader() { } 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.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(); + Slang::ComPtr kernelBlob = generateShader(createInfo, SLANG_DXIL); - library = graphics->getDevice()->newLibrary(NS::String::string(metalCode.c_str(), NS::ASCIIStringEncoding), - mtlOptions, &error); - if (error) { - std::cout << error->debugDescription() << std::endl; - assert(false); + hash = CRC::Calculate(kernelBlob->getBufferPointer(), kernelBlob->getBufferSize(), CRC::CRC_32()); + IRCompiler* pCompiler = IRCompilerCreate(); + IRCompilerSetEntryPointName(pCompiler, "main"); + + IRObject* pDXIL = IRObjectCreateFromDXIL((const uint8*)kernelBlob->getBufferPointer(), kernelBlob->getBufferSize(), + IRBytecodeOwnershipNone); + + // Compile DXIL to Metal IR: + IRError* pError = nullptr; + IRObject* pOutIR = IRCompilerAllocCompileAndLink(pCompiler, NULL, pDXIL, &pError); + + if (!pOutIR) { + // Inspect pError to determine cause. + IRErrorDestroy(pError); } - function = library->newFunction(NS::String::string("main0", NS::ASCIIStringEncoding)); + IRShaderStage irStage; + switch (stage) { + case Gfx::SE_SHADER_STAGE_VERTEX_BIT: + irStage = IRShaderStageVertex; + break; + case Gfx::SE_SHADER_STAGE_FRAGMENT_BIT: + irStage = IRShaderStageFragment; + break; + case Gfx::SE_SHADER_STAGE_COMPUTE_BIT: + irStage = IRShaderStageCompute; + break; + case Gfx::SE_SHADER_STAGE_TASK_BIT_EXT: + irStage = IRShaderStageAmplification; + break; + case Gfx::SE_SHADER_STAGE_MESH_BIT_EXT: + irStage = IRShaderStageMesh; + break; + } + // Retrieve Metallib: + IRMetalLibBinary* pMetallib = IRMetalLibBinaryCreate(); + IRObjectGetMetalLibBinary(pOutIR, irStage, pMetallib); + dispatch_data_t data = IRMetalLibGetBytecodeData(pMetallib); + + // Store the metallib to custom format or disk, or use to create a MTLLibrary. + NS::Error* error; + library = graphics->getDevice()->newLibrary(data, &error); + function = library->newFunction(NS::String::string("main", NS::ASCIIStringEncoding)); if(!function) { - std::ofstream shaderFile("error.metal"); - shaderFile << metalCode; - shaderFile.close(); - assert(!function); + assert(false); } - mtlOptions->release(); + IRMetalLibBinaryDestroy(pMetallib); + IRObjectDestroy(pDXIL); + IRObjectDestroy(pOutIR); + IRCompilerDestroy(pCompiler); } uint32 Shader::getShaderHash() const { return hash; } \ No newline at end of file diff --git a/src/Engine/Graphics/VertexData.h b/src/Engine/Graphics/VertexData.h index 28898a2..3046749 100644 --- a/src/Engine/Graphics/VertexData.h +++ b/src/Engine/Graphics/VertexData.h @@ -99,7 +99,7 @@ protected: Map meshOffsets; Map meshVertexCounts; Array meshlets; - Array primitiveIndices; + Array primitiveIndices; Array vertexIndices; Array indices; Gfx::PGraphics graphics;