yum-mirror/slang

Making it easier to work with shaders

git clone https://git.yummers.dev/yum-mirror/slang

Ellie HermaszewskaMove switch statement bodies to their own lines (#5493)b118451e3

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