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