yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
b118451e3
master
1// metal-pipeline-state.cpp 2#include "metal-pipeline-state.h" 3 4#include "metal-device.h" 5#include "metal-shader-object-layout.h" 6#include "metal-shader-program.h" 7#include "metal-util.h" 8#include "metal-vertex-layout.h" 9 10namespace gfx 11{ 12 13using namespace Slang ; 14 15namespace metal 16{ 17 18PipelineStateImpl ::PipelineStateImpl (DeviceImpl * device ) 19 :m_device (device ) 20{ 21} 22 23PipelineStateImpl ::~PipelineStateImpl () {} 24 25void PipelineStateImpl ::init (const GraphicsPipelineStateDesc & desc ) 26{ 27PipelineStateDesc pipelineDesc ; 28pipelineDesc .type = PipelineType ::Graphics ; 29pipelineDesc .graphics = desc ; 30initializeBase (pipelineDesc ); 31} 32 33void PipelineStateImpl ::init (const ComputePipelineStateDesc & desc ) 34{ 35PipelineStateDesc pipelineDesc ; 36pipelineDesc .type = PipelineType ::Compute ; 37pipelineDesc .compute = desc ; 38initializeBase (pipelineDesc ); 39} 40 41void PipelineStateImpl ::init (const RayTracingPipelineStateDesc & desc ) 42{ 43PipelineStateDesc pipelineDesc ; 44pipelineDesc .type = PipelineType ::RayTracing ; 45pipelineDesc .rayTracing .set (desc ); 46initializeBase (pipelineDesc ); 47} 48 49Result PipelineStateImpl ::createMetalRenderPipelineState () 50{ 51auto programImpl = static_cast < ShaderProgramImpl *> (m_program .Ptr ()); 52if (!programImpl ) 53return SLANG_FAIL ; 54 55NS ::SharedPtr < MTL ::RenderPipelineDescriptor > pd = 56NS ::TransferPtr (MTL ::RenderPipelineDescriptor ::alloc ()-> init ()); 57 58for (const ShaderProgramImpl ::Module & module :programImpl -> m_modules ) 59 { 60auto functionName = MetalUtil ::createString (module .entryPointName .getBuffer ()); 61NS ::SharedPtr < MTL ::Function > function = 62NS ::TransferPtr (module .library -> newFunction (functionName .get ())); 63if (!function ) 64return SLANG_FAIL ; 65 66switch (module .stage ) 67 { 68case SLANG_STAGE_VERTEX : 69pd -> setVertexFunction (function .get ()); 70break ; 71case SLANG_STAGE_FRAGMENT : 72pd -> setFragmentFunction (function .get ()); 73break ; 74default : 75return SLANG_FAIL ; 76 } 77 } 78 79// Create a vertex descriptor with the vertex buffer binding indices being offset. 80// They need to be in a range not used by any buffers in the root object layout. 81// The +1 is to account for a potential constant buffer at index 0. 82m_vertexBufferOffset = programImpl -> m_rootObjectLayout -> getBufferCount ()+ 1 ; 83auto inputLayoutImpl = static_cast < InputLayoutImpl *> (desc .graphics .inputLayout ); 84NS ::SharedPtr < MTL ::VertexDescriptor > vertexDescriptor = 85inputLayoutImpl -> createVertexDescriptor (m_vertexBufferOffset ); 86pd -> setVertexDescriptor (vertexDescriptor .get ()); 87pd -> setInputPrimitiveTopology ( 88MetalUtil ::translatePrimitiveTopologyClass (desc .graphics .primitiveType )); 89 90// Set rasterization state 91auto framebufferLayoutImpl = 92static_cast < FramebufferLayoutImpl *> (desc .graphics .framebufferLayout ); 93const auto & blend = desc .graphics .blend ; 94GfxCount sampleCount = 1 ; 95 96pd -> setAlphaToCoverageEnabled (blend .alphaToCoverageEnable ); 97// pd->setAlphaToOneEnabled(); // Currently not supported by gfx 98// pd->setRasterizationEnabled(true); // Enabled by default 99 100for (Index i = 0 ;i < framebufferLayoutImpl -> m_renderTargets .getCount ();++ i ) 101 { 102const IFramebufferLayout ::TargetLayout & targetLayout = 103framebufferLayoutImpl -> m_renderTargets [i ]; 104MTL ::RenderPipelineColorAttachmentDescriptor * colorAttachment = 105pd -> colorAttachments ()-> object (i ); 106colorAttachment -> setPixelFormat (MetalUtil ::translatePixelFormat (targetLayout .format )); 107if (i < blend .targetCount ) 108 { 109const TargetBlendDesc & targetBlendDesc = blend .targets [i ]; 110colorAttachment -> setBlendingEnabled (targetBlendDesc .enableBlend ); 111colorAttachment -> setSourceRGBBlendFactor ( 112MetalUtil ::translateBlendFactor (targetBlendDesc .color .srcFactor )); 113colorAttachment -> setDestinationRGBBlendFactor ( 114MetalUtil ::translateBlendFactor (targetBlendDesc .color .dstFactor )); 115colorAttachment -> setRgbBlendOperation ( 116MetalUtil ::translateBlendOperation (targetBlendDesc .color .op )); 117colorAttachment -> setSourceAlphaBlendFactor ( 118MetalUtil ::translateBlendFactor (targetBlendDesc .alpha .srcFactor )); 119colorAttachment -> setDestinationAlphaBlendFactor ( 120MetalUtil ::translateBlendFactor (targetBlendDesc .alpha .dstFactor )); 121colorAttachment -> setAlphaBlendOperation ( 122MetalUtil ::translateBlendOperation (targetBlendDesc .alpha .op )); 123colorAttachment -> setWriteMask ( 124MetalUtil ::translateColorWriteMask (targetBlendDesc .writeMask )); 125 } 126sampleCount = Math ::Max (sampleCount ,targetLayout .sampleCount ); 127 } 128if (framebufferLayoutImpl -> m_depthStencil .format != Format ::Unknown ) 129 { 130const IFramebufferLayout ::TargetLayout & depthStencil = 131framebufferLayoutImpl -> m_depthStencil ; 132MTL ::PixelFormat pixelFormat = MetalUtil ::translatePixelFormat (depthStencil .format ); 133if (MetalUtil ::isDepthFormat (pixelFormat )) 134 { 135pd -> setDepthAttachmentPixelFormat (MetalUtil ::translatePixelFormat (depthStencil .format )); 136 } 137if (MetalUtil ::isStencilFormat (pixelFormat )) 138 { 139pd -> setStencilAttachmentPixelFormat ( 140MetalUtil ::translatePixelFormat (depthStencil .format )); 141 } 142 } 143 144pd -> setRasterSampleCount (sampleCount ); 145 146NS ::Error * error ; 147m_renderPipelineState = 148NS ::TransferPtr (m_device -> m_device -> newRenderPipelineState (pd .get (),& error )); 149if (!m_renderPipelineState ) 150 { 151 std::cout <<error -> localizedDescription ()-> utf8String () << std::endl ; 152return SLANG_E_INVALID_ARG ; 153 } 154 155// Create depth stencil state 156auto createStencilDesc = [](const DepthStencilOpDesc & desc , 157uint32_t readMask , 158uint32_t writeMask )-> NS ::SharedPtr < MTL ::StencilDescriptor > 159 { 160NS ::SharedPtr < MTL ::StencilDescriptor > stencilDesc = 161NS ::TransferPtr (MTL ::StencilDescriptor ::alloc ()-> init ()); 162stencilDesc -> setStencilCompareFunction ( 163MetalUtil ::translateCompareFunction (desc .stencilFunc )); 164stencilDesc -> setStencilFailureOperation ( 165MetalUtil ::translateStencilOperation (desc .stencilFailOp )); 166stencilDesc -> setDepthFailureOperation ( 167MetalUtil ::translateStencilOperation (desc .stencilDepthFailOp )); 168stencilDesc -> setDepthStencilPassOperation ( 169MetalUtil ::translateStencilOperation (desc .stencilPassOp )); 170stencilDesc -> setReadMask (readMask ); 171stencilDesc -> setWriteMask (writeMask ); 172return stencilDesc ; 173 }; 174 175const auto & depthStencil = desc .graphics .depthStencil ; 176NS ::SharedPtr < MTL ::DepthStencilDescriptor > depthStencilDesc = 177NS ::TransferPtr (MTL ::DepthStencilDescriptor ::alloc ()-> init ()); 178m_depthStencilState = 179NS ::TransferPtr (m_device -> m_device -> newDepthStencilState (depthStencilDesc .get ())); 180if (!m_depthStencilState ) 181 { 182return SLANG_FAIL ; 183 } 184if (depthStencil .depthTestEnable ) 185 { 186depthStencilDesc -> setDepthCompareFunction ( 187MetalUtil ::translateCompareFunction (depthStencil .depthFunc )); 188 } 189depthStencilDesc -> setDepthWriteEnabled (depthStencil .depthWriteEnable ); 190if (depthStencil .stencilEnable ) 191 { 192depthStencilDesc -> setFrontFaceStencil (createStencilDesc ( 193depthStencil .frontFace , 194depthStencil .stencilReadMask , 195depthStencil .stencilWriteMask ) 196 .get ()); 197depthStencilDesc -> setBackFaceStencil (createStencilDesc ( 198depthStencil .backFace , 199depthStencil .stencilReadMask , 200depthStencil .stencilWriteMask ) 201 .get ()); 202 } 203 204return SLANG_OK ; 205} 206 207Result PipelineStateImpl ::createMetalComputePipelineState () 208{ 209auto programImpl = static_cast < ShaderProgramImpl *> (m_program .Ptr ()); 210if (!programImpl ) 211return SLANG_FAIL ; 212 213const ShaderProgramImpl ::Module & module = programImpl -> m_modules [0 ]; 214auto functionName = MetalUtil ::createString (module .entryPointName .getBuffer ()); 215NS ::SharedPtr < MTL ::Function > function = 216NS ::TransferPtr (module .library -> newFunction (functionName .get ())); 217if (!function ) 218return SLANG_FAIL ; 219 220NS ::Error * error ; 221m_computePipelineState = 222NS ::TransferPtr (m_device -> m_device -> newComputePipelineState (function .get (),& error )); 223 224// Query thread group size for use during dispatch. 225SlangUInt threadGroupSize [3 ]; 226programImpl -> linkedProgram -> getLayout ()-> getEntryPointByIndex (0 )-> getComputeThreadGroupSize ( 2273 , 228threadGroupSize ); 229m_threadGroupSize = MTL ::Size (threadGroupSize [0 ],threadGroupSize [1 ],threadGroupSize [2 ]); 230 231return m_computePipelineState ?SLANG_OK :SLANG_FAIL ; 232} 233 234Result PipelineStateImpl ::ensureAPIPipelineStateCreated () 235{ 236AUTORELEASEPOOL 237 238switch (desc .type ) 239 { 240case PipelineType ::Compute : 241return m_computePipelineState ?SLANG_OK :createMetalComputePipelineState (); 242case PipelineType ::Graphics : 243return m_renderPipelineState ?SLANG_OK :createMetalRenderPipelineState (); 244default : 245SLANG_UNREACHABLE ("Unknown pipeline type." ); 246return SLANG_FAIL ; 247 } 248return SLANG_OK ; 249} 250 251SLANG_NO_THROW Result SLANG_MCALL PipelineStateImpl ::getNativeHandle (InteropHandle * outHandle ) 252{ 253switch (desc .type ) 254 { 255case PipelineType ::Compute : 256outHandle -> api = InteropHandleAPI ::Metal ; 257outHandle -> handleValue = reinterpret_cast < intptr_t > (m_computePipelineState .get ()); 258return SLANG_OK ; 259case PipelineType ::Graphics : 260outHandle -> api = InteropHandleAPI ::Metal ; 261outHandle -> handleValue = reinterpret_cast < intptr_t > (m_renderPipelineState .get ()); 262return SLANG_OK ; 263 } 264return SLANG_FAIL ; 265} 266 267RayTracingPipelineStateImpl ::RayTracingPipelineStateImpl (DeviceImpl * device ) 268 :PipelineStateImpl (device ) 269{ 270} 271 272Result RayTracingPipelineStateImpl ::ensureAPIPipelineStateCreated () 273{ 274return SLANG_E_NOT_IMPLEMENTED ; 275} 276 277Result RayTracingPipelineStateImpl ::getNativeHandle (InteropHandle * outHandle ) 278{ 279return SLANG_E_NOT_IMPLEMENTED ; 280} 281 282 283}// namespace metal 284}// namespace gfx