Mangled WHLSL names don't need to allocate Strings
[WebKit-https.git] / Source / WebCore / platform / graphics / gpu / cocoa / GPURenderPipelineMetal.mm
1 /*
2  * Copyright (C) 2018 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27 #import "GPURenderPipeline.h"
28
29 #if ENABLE(WEBGPU)
30
31 #import "GPUDevice.h"
32 #import "GPULimits.h"
33 #import "GPUPipelineMetalConvertLayout.h"
34 #import "GPUUtils.h"
35 #import "WHLSLPrepare.h"
36 #import "WHLSLVertexBufferIndexCalculator.h"
37 #import <Metal/Metal.h>
38 #import <wtf/BlockObjCExceptions.h>
39 #import <wtf/CheckedArithmetic.h>
40 #import <wtf/HashSet.h>
41 #import <wtf/OptionSet.h>
42 #import <wtf/Optional.h>
43 #import <wtf/text/StringConcatenate.h>
44
45 namespace WebCore {
46
47 static RetainPtr<MTLDepthStencilState> tryCreateMtlDepthStencilState(const GPUDepthStencilStateDescriptor& descriptor, const GPUDevice& device, GPUErrorScopes& errorScopes)
48 {
49     RetainPtr<MTLDepthStencilDescriptor> mtlDescriptor;
50
51     BEGIN_BLOCK_OBJC_EXCEPTIONS;
52
53     mtlDescriptor = adoptNS([MTLDepthStencilDescriptor new]);
54
55     END_BLOCK_OBJC_EXCEPTIONS;
56
57     if (!mtlDescriptor) {
58         errorScopes.generatePrefixedError("Unable to create MTLDepthStencilDescriptor!");
59         return nullptr;
60     }
61
62     auto mtlDepthCompare = static_cast<MTLCompareFunction>(platformCompareFunctionForGPUCompareFunction(descriptor.depthCompare));
63     [mtlDescriptor setDepthCompareFunction:mtlDepthCompare];
64     [mtlDescriptor setDepthWriteEnabled:descriptor.depthWriteEnabled];
65
66     // FIXME: Implement back/frontFaceStencil.
67
68     RetainPtr<MTLDepthStencilState> state;
69
70     BEGIN_BLOCK_OBJC_EXCEPTIONS;
71
72     state = adoptNS([device.platformDevice() newDepthStencilStateWithDescriptor:mtlDescriptor.get()]);
73
74     END_BLOCK_OBJC_EXCEPTIONS;
75
76     if (!state) {
77         errorScopes.generatePrefixedError("Error creating MTLDepthStencilState!");
78         return nullptr;
79     }
80
81     return state;
82 }
83
84 static WHLSL::VertexFormat convertVertexFormat(GPUVertexFormat vertexFormat)
85 {
86     switch (vertexFormat) {
87     case GPUVertexFormat::Float4:
88         return WHLSL::VertexFormat::FloatR32G32B32A32;
89     case GPUVertexFormat::Float3:
90         return WHLSL::VertexFormat::FloatR32G32B32;
91     case GPUVertexFormat::Float2:
92         return WHLSL::VertexFormat::FloatR32G32;
93     default:
94         ASSERT(vertexFormat == GPUVertexFormat::Float);
95         return WHLSL::VertexFormat::FloatR32;
96     }
97 }
98
99 static Optional<WHLSL::TextureFormat> convertTextureFormat(GPUTextureFormat format)
100 {
101     switch (format) {
102     case GPUTextureFormat::Rgba8unorm:
103         return WHLSL::TextureFormat::RGBA8Unorm;
104     case GPUTextureFormat::Bgra8unorm:
105         return WHLSL::TextureFormat::BGRA8Unorm;
106     case GPUTextureFormat::Depth32floatStencil8:
107         return WTF::nullopt; // FIXME: Figure out what to do with this.
108     case GPUTextureFormat::Bgra8unormSRGB:
109         return WHLSL::TextureFormat::BGRA8UnormSrgb;
110     case GPUTextureFormat::Rgba16float:
111         return WHLSL::TextureFormat::RGBA16Float;
112     default:
113         return WTF::nullopt;
114     }
115 }
116
117 static MTLVertexFormat mtlVertexFormatForGPUVertexFormat(GPUVertexFormat format)
118 {
119     switch (format) {
120     case GPUVertexFormat::Float:
121         return MTLVertexFormatFloat;
122     case GPUVertexFormat::Float2:
123         return MTLVertexFormatFloat2;
124     case GPUVertexFormat::Float3:
125         return MTLVertexFormatFloat3;
126     case GPUVertexFormat::Float4:
127         return MTLVertexFormatFloat4;
128     }
129
130     ASSERT_NOT_REACHED();
131 }
132
133 static MTLVertexStepFunction mtlStepFunctionForGPUInputStepMode(GPUInputStepMode mode)
134 {
135     switch (mode) {
136     case GPUInputStepMode::Vertex:
137         return MTLVertexStepFunctionPerVertex;
138     case GPUInputStepMode::Instance:
139         return MTLVertexStepFunctionPerInstance;
140     }
141
142     ASSERT_NOT_REACHED();
143 }
144
145 // FIXME: Move this into GPULimits when that is implemented properly.
146 constexpr unsigned maxVertexAttributes = 16;
147
148 static bool trySetVertexInput(const GPUVertexInputDescriptor& descriptor, MTLRenderPipelineDescriptor *mtlDescriptor, Optional<WHLSL::RenderPipelineDescriptor>& whlslDescriptor, GPUErrorScopes& errorScopes)
149 {
150     const auto& buffers = descriptor.vertexBuffers;
151
152     if (buffers.size() > maxVertexBuffers) {
153         errorScopes.generatePrefixedError("Too many GPUVertexBufferDescriptors!");
154         return false;
155     }
156
157     auto mtlVertexDescriptor = adoptNS([MTLVertexDescriptor new]);
158
159     auto layoutArray = retainPtr(mtlVertexDescriptor.get().layouts);
160     auto attributeArray = retainPtr(mtlVertexDescriptor.get().attributes);
161
162     // Attribute shaderLocations must be uniquely flat-mapped to [0, {max number of vertex attributes}].
163     unsigned attributeIndex = 0;
164     HashSet<unsigned, IntHash<unsigned>, WTF::UnsignedWithZeroKeyHashTraits<unsigned>> locations;
165
166     for (size_t index = 0; index < buffers.size(); ++index) {
167         if (!buffers[index])
168             continue;
169
170         const auto& attributes = buffers[index]->attributeSet;
171
172         if (attributes.size() + attributeIndex > maxVertexAttributes) {
173             errorScopes.generatePrefixedError("Too many GPUVertexAttributeDescriptors!");
174             return false;
175         }
176
177         NSUInteger inputStride = 0;
178         if (!WTF::convertSafely(buffers[index]->stride, inputStride)) {
179             errorScopes.generatePrefixedError(makeString("Stride for GPUVertexBufferDescriptor ", index, " is too large!"));
180             return false;
181         }
182
183         auto convertedBufferIndex = WHLSL::Metal::calculateVertexBufferIndex(index);
184
185         BEGIN_BLOCK_OBJC_EXCEPTIONS;
186         auto mtlLayoutDesc = retainPtr([layoutArray objectAtIndexedSubscript:convertedBufferIndex]);
187         [mtlLayoutDesc setStepFunction:mtlStepFunctionForGPUInputStepMode(buffers[index]->stepMode)];
188         [mtlLayoutDesc setStride:inputStride];
189         END_BLOCK_OBJC_EXCEPTIONS;
190
191         for (const auto& attribute : attributes) {
192             if (!locations.add(attribute.shaderLocation).isNewEntry) {
193                 errorScopes.generatePrefixedError(makeString("Duplicate shaderLocation ", attribute.shaderLocation, " for vertex attribute!"));
194                 return false;
195             }
196
197             NSUInteger offset = 0;
198             if (!WTF::convertSafely(attribute.offset, offset)) {
199                 errorScopes.generatePrefixedError(makeString("Buffer offset for vertex attribute ", attribute.shaderLocation, " is too large!"));
200                 return false;
201             }
202
203             BEGIN_BLOCK_OBJC_EXCEPTIONS;
204             auto mtlAttributeDesc = retainPtr([attributeArray objectAtIndexedSubscript:attributeIndex]);
205             [mtlAttributeDesc setFormat:mtlVertexFormatForGPUVertexFormat(attribute.format)];
206             [mtlAttributeDesc setOffset:offset];
207             [mtlAttributeDesc setBufferIndex:convertedBufferIndex];
208             END_BLOCK_OBJC_EXCEPTIONS;
209
210             if (whlslDescriptor)
211                 whlslDescriptor->vertexAttributes.append({ convertVertexFormat(attribute.format), attribute.shaderLocation, attributeIndex });
212
213             ++attributeIndex;
214         }
215     }
216
217     [mtlDescriptor setVertexDescriptor:mtlVertexDescriptor.get()];
218
219     return true;
220 }
221
222 static MTLColorWriteMask mtlColorWriteMaskForGPUColorWriteFlags(GPUColorWriteFlags flags)
223 {
224     if (flags == static_cast<GPUColorWriteFlags>(GPUColorWriteBits::Flags::All))
225         return MTLColorWriteMaskAll;
226
227     auto options = OptionSet<GPUColorWriteBits::Flags>::fromRaw(flags);
228
229     MTLColorWriteMask mask = MTLColorWriteMaskNone;
230     if (options & GPUColorWriteBits::Flags::Red)
231         mask |= MTLColorWriteMaskRed;
232     if (options & GPUColorWriteBits::Flags::Green)
233         mask |= MTLColorWriteMaskGreen;
234     if (options & GPUColorWriteBits::Flags::Blue)
235         mask |= MTLColorWriteMaskBlue;
236     if (options & GPUColorWriteBits::Flags::Alpha)
237         mask |= MTLColorWriteMaskAlpha;
238
239     return mask;
240 }
241
242 static MTLBlendOperation mtlBlendOperationForGPUBlendOperation(GPUBlendOperation op)
243 {
244     switch (op) {
245     case GPUBlendOperation::Add:
246         return MTLBlendOperationAdd;
247     case GPUBlendOperation::Subtract:
248         return MTLBlendOperationSubtract;
249     case GPUBlendOperation::ReverseSubtract:
250         return MTLBlendOperationReverseSubtract;
251     case GPUBlendOperation::Min:
252         return MTLBlendOperationMin;
253     case GPUBlendOperation::Max:
254         return MTLBlendOperationMax;
255     }
256
257     ASSERT_NOT_REACHED();
258 }
259
260 static MTLBlendFactor mtlBlendFactorForGPUBlendFactor(GPUBlendFactor factor)
261 {
262     switch (factor) {
263     case GPUBlendFactor::Zero:
264         return MTLBlendFactorZero;
265     case GPUBlendFactor::One:
266         return MTLBlendFactorOne;
267     case GPUBlendFactor::SrcColor:
268         return MTLBlendFactorSourceColor;
269     case GPUBlendFactor::OneMinusSrcColor:
270         return MTLBlendFactorOneMinusSourceColor;
271     case GPUBlendFactor::SrcAlpha:
272         return MTLBlendFactorSourceAlpha;
273     case GPUBlendFactor::OneMinusSrcAlpha:
274         return MTLBlendFactorOneMinusSourceAlpha;
275     case GPUBlendFactor::DstColor:
276         return MTLBlendFactorDestinationColor;
277     case GPUBlendFactor::OneMinusDstColor:
278         return MTLBlendFactorOneMinusDestinationColor;
279     case GPUBlendFactor::DstAlpha:
280         return MTLBlendFactorDestinationAlpha;
281     case GPUBlendFactor::OneMinusDstAlpha:
282         return MTLBlendFactorOneMinusDestinationAlpha;
283     case GPUBlendFactor::SrcAlphaSaturated:
284         return MTLBlendFactorSourceAlpha;
285     case GPUBlendFactor::BlendColor:
286         return MTLBlendFactorBlendColor;
287     case GPUBlendFactor::OneMinusBlendColor:
288         return MTLBlendFactorOneMinusBlendColor;
289     }
290
291     ASSERT_NOT_REACHED();
292 }
293
294 static bool trySetColorStates(const Vector<GPUColorStateDescriptor>& colorStates, MTLRenderPipelineColorAttachmentDescriptorArray* array, Optional<WHLSL::RenderPipelineDescriptor>& whlslDescriptor, GPUErrorScopes& errorScopes)
295 {
296     // FIXME: Replace with maximum number of color attachments per render pass from GPULimits.
297     if (colorStates.size() > 4) {
298         errorScopes.generatePrefixedError("Too many GPUColorStateDescriptors!");
299         return false;
300     }
301
302     BEGIN_BLOCK_OBJC_EXCEPTIONS;
303
304     for (unsigned i = 0; i < colorStates.size(); ++i) {
305         auto& state = colorStates[i];
306         auto descriptor = retainPtr([array objectAtIndexedSubscript:i]);
307         [descriptor setPixelFormat:static_cast<MTLPixelFormat>(platformTextureFormatForGPUTextureFormat(state.format))];
308         [descriptor setWriteMask:mtlColorWriteMaskForGPUColorWriteFlags(state.writeMask)];
309         [descriptor setBlendingEnabled:YES];
310         [descriptor setAlphaBlendOperation:mtlBlendOperationForGPUBlendOperation(state.alphaBlend.operation)];
311         [descriptor setRgbBlendOperation:mtlBlendOperationForGPUBlendOperation(state.colorBlend.operation)];
312         [descriptor setDestinationAlphaBlendFactor:mtlBlendFactorForGPUBlendFactor(state.alphaBlend.dstFactor)];
313         [descriptor setDestinationRGBBlendFactor:mtlBlendFactorForGPUBlendFactor(state.colorBlend.dstFactor)];
314         [descriptor setSourceAlphaBlendFactor:mtlBlendFactorForGPUBlendFactor(state.alphaBlend.srcFactor)];
315         [descriptor setSourceRGBBlendFactor:mtlBlendFactorForGPUBlendFactor(state.colorBlend.srcFactor)];
316
317         if (whlslDescriptor) {
318             if (auto format = convertTextureFormat(state.format))
319                 whlslDescriptor->attachmentsStateDescriptor.attachmentDescriptors.append({*format, i});
320             else {
321                 errorScopes.generatePrefixedError(makeString("Invalid GPUTextureFormat for GPUColorStateDescriptor ", i, "!"));
322                 return false;
323             }
324         }
325     }
326
327     END_BLOCK_OBJC_EXCEPTIONS;
328
329     return true;
330 }
331
332 static bool trySetMetalFunctions(MTLLibrary *vertexMetalLibrary, MTLLibrary *fragmentMetalLibrary, MTLRenderPipelineDescriptor *mtlDescriptor, const String& vertexEntryPointName, const String& fragmentEntryPointName, GPUErrorScopes& errorScopes)
333 {
334     {
335         BEGIN_BLOCK_OBJC_EXCEPTIONS;
336
337         // Metal requires a vertex shader in all render pipelines.
338         if (!vertexMetalLibrary) {
339             errorScopes.generatePrefixedError("MTLLibrary for vertex stage does not exist!");
340             return false;
341         }
342
343         auto function = adoptNS([vertexMetalLibrary newFunctionWithName:vertexEntryPointName]);
344         if (!function) {
345             errorScopes.generatePrefixedError(makeString("Cannot create vertex MTLFunction '", vertexEntryPointName, "'!"));
346             return false;
347         }
348
349         [mtlDescriptor setVertexFunction:function.get()];
350
351         END_BLOCK_OBJC_EXCEPTIONS;
352     }
353
354     {
355         BEGIN_BLOCK_OBJC_EXCEPTIONS;
356
357         // However, fragment shaders are optional.
358         if (!fragmentMetalLibrary)
359             return true;
360
361         auto function = adoptNS([fragmentMetalLibrary newFunctionWithName:fragmentEntryPointName]);
362
363         if (!function) {
364             errorScopes.generatePrefixedError(makeString("Cannot create fragment MTLFunction '", fragmentEntryPointName, "'!"));
365             return false;
366         }
367
368         [mtlDescriptor setFragmentFunction:function.get()];
369         return true;
370
371         END_BLOCK_OBJC_EXCEPTIONS;
372     }
373
374     return false;
375 }
376
377 static bool trySetFunctions(const GPUPipelineStageDescriptor& vertexStage, const Optional<GPUPipelineStageDescriptor>& fragmentStage, const GPUDevice& device, MTLRenderPipelineDescriptor* mtlDescriptor, Optional<WHLSL::RenderPipelineDescriptor>& whlslDescriptor, GPUErrorScopes& errorScopes)
378 {
379     RetainPtr<MTLLibrary> vertexLibrary, fragmentLibrary;
380     String vertexEntryPoint, fragmentEntryPoint;
381
382     if (whlslDescriptor) {
383         // WHLSL functions are compiled to MSL first.
384         String whlslSource = vertexStage.module->whlslSource();
385         ASSERT(!whlslSource.isNull());
386
387         whlslDescriptor->vertexEntryPointName = vertexStage.entryPoint;
388         if (fragmentStage)
389             whlslDescriptor->fragmentEntryPointName = fragmentStage->entryPoint;
390
391         auto whlslCompileResult = WHLSL::prepare(whlslSource, *whlslDescriptor);
392         if (!whlslCompileResult) {
393             errorScopes.generatePrefixedError(makeString("WHLSL compile error: ", whlslCompileResult.error()));
394             return false;
395         }
396
397         NSError *error = nil;
398
399         BEGIN_BLOCK_OBJC_EXCEPTIONS;
400         vertexLibrary = adoptNS([device.platformDevice() newLibraryWithSource:whlslCompileResult->metalSource options:nil error:&error]);
401         END_BLOCK_OBJC_EXCEPTIONS;
402
403         if (!vertexLibrary && error) {
404             errorScopes.generatePrefixedError(error.localizedDescription.UTF8String);
405 #ifndef NDEBUG
406             NSLog(@"%@", error);
407 #endif
408         }
409
410         ASSERT(vertexLibrary);
411         // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195771 Once we zero-fill variables, there should be no warnings, so we should be able to ASSERT(!error) here.
412
413         fragmentLibrary = vertexLibrary;
414         vertexEntryPoint = whlslCompileResult->mangledVertexEntryPointName.toString();
415         fragmentEntryPoint = whlslCompileResult->mangledFragmentEntryPointName.toString();
416     } else {
417         vertexLibrary = vertexStage.module->platformShaderModule();
418         vertexEntryPoint = vertexStage.entryPoint;
419         if (fragmentStage) {
420             fragmentLibrary = fragmentStage->module->platformShaderModule();
421             fragmentEntryPoint = fragmentStage->entryPoint;
422         }
423     }
424
425     return trySetMetalFunctions(vertexLibrary.get(), fragmentLibrary.get(), mtlDescriptor, vertexEntryPoint, fragmentEntryPoint, errorScopes);
426 }
427
428 static RetainPtr<MTLRenderPipelineDescriptor> convertRenderPipelineDescriptor(const GPURenderPipelineDescriptor& descriptor, const GPUDevice& device, GPUErrorScopes& errorScopes)
429 {
430     RetainPtr<MTLRenderPipelineDescriptor> mtlDescriptor;
431
432     BEGIN_BLOCK_OBJC_EXCEPTIONS;
433
434     mtlDescriptor = adoptNS([MTLRenderPipelineDescriptor new]);
435
436     END_BLOCK_OBJC_EXCEPTIONS;
437
438     if (!mtlDescriptor) {
439         errorScopes.generatePrefixedError("Error creating MTLDescriptor!");
440         return nullptr;
441     }
442
443     // Determine if shader source is in WHLSL or MSL.
444     const auto& vertexStage = descriptor.vertexStage;
445     const auto& fragmentStage = descriptor.fragmentStage;
446
447     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195446 Allow WHLSL shaders to come from different programs.
448     bool isWhlsl = !vertexStage.module->whlslSource().isNull() && (!fragmentStage || vertexStage.module.ptr() == fragmentStage->module.ptr());
449
450     // Set data for the Metal pipeline descriptor (and WHLSL's, if needed).
451     Optional<WHLSL::RenderPipelineDescriptor> whlslDescriptor;
452     if (isWhlsl)
453         whlslDescriptor = WHLSL::RenderPipelineDescriptor();
454
455     if (!trySetVertexInput(descriptor.vertexInput, mtlDescriptor.get(), whlslDescriptor, errorScopes))
456         return nullptr;
457
458     if (!trySetColorStates(descriptor.colorStates, mtlDescriptor.get().colorAttachments, whlslDescriptor, errorScopes))
459         return nullptr;
460
461     if (descriptor.layout && whlslDescriptor) {
462         if (auto layout = convertLayout(*descriptor.layout))
463             whlslDescriptor->layout = WTFMove(*layout);
464         else {
465             errorScopes.generatePrefixedError("Error converting GPUPipelineLayout!");
466             return nullptr;
467         }
468     }
469
470     if (!trySetFunctions(vertexStage, fragmentStage, device, mtlDescriptor.get(), whlslDescriptor, errorScopes))
471         return nullptr;
472
473     return mtlDescriptor;
474 }
475
476 static RetainPtr<MTLRenderPipelineState> tryCreateMtlRenderPipelineState(const GPURenderPipelineDescriptor& descriptor, const GPUDevice& device, GPUErrorScopes& errorScopes)
477 {
478     if (!device.platformDevice()) {
479         errorScopes.generatePrefixedError("Invalid GPUDevice!");
480         return nullptr;
481     }
482
483     auto mtlDescriptor = convertRenderPipelineDescriptor(descriptor, device, errorScopes);
484     if (!mtlDescriptor)
485         return nullptr;
486
487     RetainPtr<MTLRenderPipelineState> pipeline;
488
489     BEGIN_BLOCK_OBJC_EXCEPTIONS;
490
491     NSError *error = nil;
492     pipeline = adoptNS([device.platformDevice() newRenderPipelineStateWithDescriptor:mtlDescriptor.get() error:&error]);
493     if (!pipeline)
494         errorScopes.generatePrefixedError(error.localizedDescription.UTF8String);
495
496     END_BLOCK_OBJC_EXCEPTIONS;
497
498     return pipeline;
499 }
500
501 RefPtr<GPURenderPipeline> GPURenderPipeline::tryCreate(const GPUDevice& device, const GPURenderPipelineDescriptor& descriptor, GPUErrorScopes& errorScopes)
502 {
503     if (!device.platformDevice()) {
504         errorScopes.generatePrefixedError("Invalid GPUDevice!");
505         return nullptr;
506     }
507
508     RetainPtr<MTLDepthStencilState> depthStencil;
509
510     if (descriptor.depthStencilState && !(depthStencil = tryCreateMtlDepthStencilState(*descriptor.depthStencilState, device, errorScopes)))
511         return nullptr;
512
513     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198387 depthStencilAttachmentDescriptor isn't implemented yet for WHLSL compiler.
514
515     auto pipeline = tryCreateMtlRenderPipelineState(descriptor, device, errorScopes);
516     if (!pipeline)
517         return nullptr;
518
519     return adoptRef(new GPURenderPipeline(WTFMove(depthStencil), WTFMove(pipeline), descriptor.primitiveTopology, descriptor.vertexInput.indexFormat, errorScopes));
520 }
521
522 GPURenderPipeline::GPURenderPipeline(RetainPtr<MTLDepthStencilState>&& depthStencil, RetainPtr<MTLRenderPipelineState>&& pipeline, GPUPrimitiveTopology topology, Optional<GPUIndexFormat> format, GPUErrorScopes& errorScopes)
523     : GPUObjectBase(makeRef(errorScopes))
524     , m_depthStencilState(WTFMove(depthStencil))
525     , m_platformRenderPipeline(WTFMove(pipeline))
526     , m_primitiveTopology(topology)
527     , m_indexFormat(format)
528 {
529 }
530
531 } // namespace WebCore
532
533 #endif // ENABLE(WEBGPU)