| /* |
| * Copyright (C) 2018 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| * THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #import "config.h" |
| #import "GPURenderPipeline.h" |
| |
| #if ENABLE(WEBGPU) |
| |
| #import "GPUDevice.h" |
| #import "GPULimits.h" |
| #import "GPUPipelineMetalConvertLayout.h" |
| #import "GPUUtils.h" |
| #import "Logging.h" |
| #import "WHLSLPrepare.h" |
| #import "WHLSLVertexBufferIndexCalculator.h" |
| #import <Metal/Metal.h> |
| #import <wtf/BlockObjCExceptions.h> |
| #import <wtf/CheckedArithmetic.h> |
| #import <wtf/HashSet.h> |
| #import <wtf/OptionSet.h> |
| #import <wtf/Optional.h> |
| |
| namespace WebCore { |
| |
| static RetainPtr<MTLDepthStencilState> tryCreateMtlDepthStencilState(const char* const functionName, const GPUDepthStencilStateDescriptor& descriptor, const GPUDevice& device) |
| { |
| #if LOG_DISABLED |
| UNUSED_PARAM(functionName); |
| #endif |
| RetainPtr<MTLDepthStencilDescriptor> mtlDescriptor; |
| |
| BEGIN_BLOCK_OBJC_EXCEPTIONS; |
| |
| mtlDescriptor = adoptNS([MTLDepthStencilDescriptor new]); |
| |
| END_BLOCK_OBJC_EXCEPTIONS; |
| |
| if (!mtlDescriptor) { |
| LOG(WebGPU, "%s: Unable to create MTLDepthStencilDescriptor!", functionName); |
| return nullptr; |
| } |
| |
| auto mtlDepthCompare = static_cast<MTLCompareFunction>(platformCompareFunctionForGPUCompareFunction(descriptor.depthCompare)); |
| [mtlDescriptor setDepthCompareFunction:mtlDepthCompare]; |
| [mtlDescriptor setDepthWriteEnabled:descriptor.depthWriteEnabled]; |
| |
| // FIXME: Implement back/frontFaceStencil. |
| |
| RetainPtr<MTLDepthStencilState> state; |
| |
| BEGIN_BLOCK_OBJC_EXCEPTIONS; |
| |
| state = adoptNS([device.platformDevice() newDepthStencilStateWithDescriptor:mtlDescriptor.get()]); |
| |
| END_BLOCK_OBJC_EXCEPTIONS; |
| |
| if (!state) { |
| LOG(WebGPU, "%s: Error creating MTLDepthStencilState!", functionName); |
| return nullptr; |
| } |
| |
| return state; |
| } |
| |
| static WHLSL::VertexFormat convertVertexFormat(GPUVertexFormat vertexFormat) |
| { |
| switch (vertexFormat) { |
| case GPUVertexFormat::Float4: |
| return WHLSL::VertexFormat::FloatR32G32B32A32; |
| case GPUVertexFormat::Float3: |
| return WHLSL::VertexFormat::FloatR32G32B32; |
| case GPUVertexFormat::Float2: |
| return WHLSL::VertexFormat::FloatR32G32; |
| default: |
| ASSERT(vertexFormat == GPUVertexFormat::Float); |
| return WHLSL::VertexFormat::FloatR32; |
| } |
| } |
| |
| static Optional<WHLSL::TextureFormat> convertTextureFormat(GPUTextureFormat format) |
| { |
| switch (format) { |
| case GPUTextureFormat::Rgba8unorm: |
| return WHLSL::TextureFormat::RGBA8Unorm; |
| case GPUTextureFormat::Rgba8uint: |
| return WHLSL::TextureFormat::RGBA8Uint; |
| case GPUTextureFormat::Bgra8unorm: |
| return WHLSL::TextureFormat::BGRA8Unorm; |
| case GPUTextureFormat::Depth32floatStencil8: |
| return WTF::nullopt; // FIXME: Figure out what to do with this. |
| case GPUTextureFormat::Bgra8unormSRGB: |
| return WHLSL::TextureFormat::BGRA8UnormSrgb; |
| case GPUTextureFormat::Rgba16float: |
| return WHLSL::TextureFormat::RGBA16Float; |
| default: |
| return WTF::nullopt; |
| } |
| } |
| |
| static MTLVertexFormat mtlVertexFormatForGPUVertexFormat(GPUVertexFormat format) |
| { |
| switch (format) { |
| case GPUVertexFormat::Float: |
| return MTLVertexFormatFloat; |
| case GPUVertexFormat::Float2: |
| return MTLVertexFormatFloat2; |
| case GPUVertexFormat::Float3: |
| return MTLVertexFormatFloat3; |
| case GPUVertexFormat::Float4: |
| return MTLVertexFormatFloat4; |
| } |
| |
| ASSERT_NOT_REACHED(); |
| } |
| |
| static MTLVertexStepFunction mtlStepFunctionForGPUInputStepMode(GPUInputStepMode mode) |
| { |
| switch (mode) { |
| case GPUInputStepMode::Vertex: |
| return MTLVertexStepFunctionPerVertex; |
| case GPUInputStepMode::Instance: |
| return MTLVertexStepFunctionPerInstance; |
| } |
| |
| ASSERT_NOT_REACHED(); |
| } |
| |
| // FIXME: Move this into GPULimits when that is implemented properly. |
| constexpr unsigned maxVertexAttributes = 16; |
| |
| static bool trySetVertexInput(const char* const functionName, const GPUVertexInputDescriptor& descriptor, MTLRenderPipelineDescriptor *mtlDescriptor, Optional<WHLSL::RenderPipelineDescriptor>& whlslDescriptor) |
| { |
| #if LOG_DISABLED |
| UNUSED_PARAM(functionName); |
| #endif |
| const auto& buffers = descriptor.vertexBuffers; |
| |
| if (buffers.size() > maxVertexBuffers) { |
| LOG(WebGPU, "%s: Too many vertex input buffers!", functionName); |
| return false; |
| } |
| |
| auto mtlVertexDescriptor = adoptNS([MTLVertexDescriptor new]); |
| |
| auto layoutArray = retainPtr(mtlVertexDescriptor.get().layouts); |
| auto attributeArray = retainPtr(mtlVertexDescriptor.get().attributes); |
| |
| // Attribute shaderLocations must be uniquely flat-mapped to [0, {max number of vertex attributes}]. |
| unsigned attributeIndex = 0; |
| HashSet<unsigned, IntHash<unsigned>, WTF::UnsignedWithZeroKeyHashTraits<unsigned>> locations; |
| |
| for (size_t index = 0; index < buffers.size(); ++index) { |
| if (!buffers[index]) |
| continue; |
| |
| const auto& attributes = buffers[index]->attributeSet; |
| |
| if (attributes.size() + attributeIndex > maxVertexAttributes) { |
| LOG(WebGPU, "%s: Too many vertex attributes!", functionName); |
| return false; |
| } |
| |
| NSUInteger inputStride = 0; |
| if (!WTF::convertSafely(buffers[index]->stride, inputStride)) { |
| LOG(WebGPU, "%s: Stride for vertex input buffer %u is too large!", functionName, index); |
| return false; |
| } |
| |
| auto convertedBufferIndex = WHLSL::Metal::calculateVertexBufferIndex(index); |
| |
| BEGIN_BLOCK_OBJC_EXCEPTIONS; |
| auto mtlLayoutDesc = retainPtr([layoutArray objectAtIndexedSubscript:convertedBufferIndex]); |
| [mtlLayoutDesc setStepFunction:mtlStepFunctionForGPUInputStepMode(buffers[index]->stepMode)]; |
| [mtlLayoutDesc setStride:inputStride]; |
| END_BLOCK_OBJC_EXCEPTIONS; |
| |
| for (const auto& attribute : attributes) { |
| if (!locations.add(attribute.shaderLocation).isNewEntry) { |
| LOG(WebGPU, "%s: Duplicate shaderLocation %u for vertex attribute!", functionName, attribute.shaderLocation); |
| return false; |
| } |
| |
| NSUInteger offset = 0; |
| if (!WTF::convertSafely(attribute.offset, offset)) { |
| LOG(WebGPU, "%s: Buffer offset for vertex attribute %u is too large!", functionName, attribute.shaderLocation); |
| return false; |
| } |
| |
| BEGIN_BLOCK_OBJC_EXCEPTIONS; |
| auto mtlAttributeDesc = retainPtr([attributeArray objectAtIndexedSubscript:attributeIndex]); |
| [mtlAttributeDesc setFormat:mtlVertexFormatForGPUVertexFormat(attribute.format)]; |
| [mtlAttributeDesc setOffset:offset]; |
| [mtlAttributeDesc setBufferIndex:convertedBufferIndex]; |
| END_BLOCK_OBJC_EXCEPTIONS; |
| |
| if (whlslDescriptor) |
| whlslDescriptor->vertexAttributes.append({ convertVertexFormat(attribute.format), attribute.shaderLocation, attributeIndex }); |
| |
| ++attributeIndex; |
| } |
| } |
| |
| [mtlDescriptor setVertexDescriptor:mtlVertexDescriptor.get()]; |
| |
| return true; |
| } |
| |
| static MTLColorWriteMask mtlColorWriteMaskForGPUColorWriteFlags(GPUColorWriteFlags flags) |
| { |
| if (flags == static_cast<GPUColorWriteFlags>(GPUColorWriteBits::Flags::All)) |
| return MTLColorWriteMaskAll; |
| |
| auto options = OptionSet<GPUColorWriteBits::Flags>::fromRaw(flags); |
| |
| MTLColorWriteMask mask = MTLColorWriteMaskNone; |
| if (options & GPUColorWriteBits::Flags::Red) |
| mask |= MTLColorWriteMaskRed; |
| if (options & GPUColorWriteBits::Flags::Green) |
| mask |= MTLColorWriteMaskGreen; |
| if (options & GPUColorWriteBits::Flags::Blue) |
| mask |= MTLColorWriteMaskBlue; |
| if (options & GPUColorWriteBits::Flags::Alpha) |
| mask |= MTLColorWriteMaskAlpha; |
| |
| return mask; |
| } |
| |
| static MTLBlendOperation mtlBlendOperationForGPUBlendOperation(GPUBlendOperation op) |
| { |
| switch (op) { |
| case GPUBlendOperation::Add: |
| return MTLBlendOperationAdd; |
| case GPUBlendOperation::Subtract: |
| return MTLBlendOperationSubtract; |
| case GPUBlendOperation::ReverseSubtract: |
| return MTLBlendOperationReverseSubtract; |
| case GPUBlendOperation::Min: |
| return MTLBlendOperationMin; |
| case GPUBlendOperation::Max: |
| return MTLBlendOperationMax; |
| } |
| |
| ASSERT_NOT_REACHED(); |
| } |
| |
| static MTLBlendFactor mtlBlendFactorForGPUBlendFactor(GPUBlendFactor factor) |
| { |
| switch (factor) { |
| case GPUBlendFactor::Zero: |
| return MTLBlendFactorZero; |
| case GPUBlendFactor::One: |
| return MTLBlendFactorOne; |
| case GPUBlendFactor::SrcColor: |
| return MTLBlendFactorSourceColor; |
| case GPUBlendFactor::OneMinusSrcColor: |
| return MTLBlendFactorOneMinusSourceColor; |
| case GPUBlendFactor::SrcAlpha: |
| return MTLBlendFactorSourceAlpha; |
| case GPUBlendFactor::OneMinusSrcAlpha: |
| return MTLBlendFactorOneMinusSourceAlpha; |
| case GPUBlendFactor::DstColor: |
| return MTLBlendFactorDestinationColor; |
| case GPUBlendFactor::OneMinusDstColor: |
| return MTLBlendFactorOneMinusDestinationColor; |
| case GPUBlendFactor::DstAlpha: |
| return MTLBlendFactorDestinationAlpha; |
| case GPUBlendFactor::OneMinusDstAlpha: |
| return MTLBlendFactorOneMinusDestinationAlpha; |
| case GPUBlendFactor::SrcAlphaSaturated: |
| return MTLBlendFactorSourceAlpha; |
| case GPUBlendFactor::BlendColor: |
| return MTLBlendFactorBlendColor; |
| case GPUBlendFactor::OneMinusBlendColor: |
| return MTLBlendFactorOneMinusBlendColor; |
| } |
| |
| ASSERT_NOT_REACHED(); |
| } |
| |
| static bool trySetColorStates(const char* const functionName, const Vector<GPUColorStateDescriptor>& colorStates, MTLRenderPipelineColorAttachmentDescriptorArray* array, Optional<WHLSL::RenderPipelineDescriptor>& whlslDescriptor) |
| { |
| #if LOG_DISABLED |
| UNUSED_PARAM(functionName); |
| #endif |
| // FIXME: Replace with maximum number of color attachments per render pass from GPULimits. |
| if (colorStates.size() > 4) { |
| LOG(WebGPU, "%s: Invalid number of GPUColorStateDescriptors!", functionName); |
| return false; |
| } |
| |
| BEGIN_BLOCK_OBJC_EXCEPTIONS; |
| |
| for (unsigned i = 0; i < colorStates.size(); ++i) { |
| auto& state = colorStates[i]; |
| auto descriptor = retainPtr([array objectAtIndexedSubscript:i]); |
| [descriptor setPixelFormat:static_cast<MTLPixelFormat>(platformTextureFormatForGPUTextureFormat(state.format))]; |
| [descriptor setWriteMask:mtlColorWriteMaskForGPUColorWriteFlags(state.writeMask)]; |
| [descriptor setBlendingEnabled:YES]; |
| [descriptor setAlphaBlendOperation:mtlBlendOperationForGPUBlendOperation(state.alphaBlend.operation)]; |
| [descriptor setRgbBlendOperation:mtlBlendOperationForGPUBlendOperation(state.colorBlend.operation)]; |
| [descriptor setDestinationAlphaBlendFactor:mtlBlendFactorForGPUBlendFactor(state.alphaBlend.dstFactor)]; |
| [descriptor setDestinationRGBBlendFactor:mtlBlendFactorForGPUBlendFactor(state.colorBlend.dstFactor)]; |
| [descriptor setSourceAlphaBlendFactor:mtlBlendFactorForGPUBlendFactor(state.alphaBlend.srcFactor)]; |
| [descriptor setSourceRGBBlendFactor:mtlBlendFactorForGPUBlendFactor(state.colorBlend.srcFactor)]; |
| |
| if (whlslDescriptor) { |
| if (auto format = convertTextureFormat(state.format)) |
| whlslDescriptor->attachmentsStateDescriptor.attachmentDescriptors.append({*format, i}); |
| else { |
| LOG(WebGPU, "%s: Invalid texture format for color attachment %u!", functionName, i); |
| return false; |
| } |
| } |
| } |
| |
| END_BLOCK_OBJC_EXCEPTIONS; |
| |
| return true; |
| } |
| |
| static bool trySetMetalFunctions(const char* const functionName, MTLLibrary *vertexMetalLibrary, MTLLibrary *fragmentMetalLibrary, MTLRenderPipelineDescriptor *mtlDescriptor, const String& vertexEntryPointName, const String& fragmentEntryPointName) |
| { |
| #if LOG_DISABLED |
| UNUSED_PARAM(functionName); |
| #endif |
| |
| { |
| BEGIN_BLOCK_OBJC_EXCEPTIONS; |
| |
| // Metal requires a vertex shader in all render pipelines. |
| if (!vertexMetalLibrary) { |
| LOG(WebGPU, "%s: MTLLibrary for vertex stage does not exist!", functionName); |
| return false; |
| } |
| |
| auto function = adoptNS([vertexMetalLibrary newFunctionWithName:vertexEntryPointName]); |
| if (!function) { |
| LOG(WebGPU, "%s: Cannot create vertex MTLFunction \"%s\"!", functionName, vertexEntryPointName.utf8().data()); |
| return false; |
| } |
| |
| [mtlDescriptor setVertexFunction:function.get()]; |
| |
| END_BLOCK_OBJC_EXCEPTIONS; |
| } |
| |
| { |
| BEGIN_BLOCK_OBJC_EXCEPTIONS; |
| |
| // However, fragment shaders are optional. |
| if (!fragmentMetalLibrary) |
| return true; |
| |
| auto function = adoptNS([fragmentMetalLibrary newFunctionWithName:fragmentEntryPointName]); |
| |
| if (!function) { |
| LOG(WebGPU, "%s: Cannot create fragment MTLFunction \"%s\"!", functionName, fragmentEntryPointName.utf8().data()); |
| return false; |
| } |
| |
| [mtlDescriptor setFragmentFunction:function.get()]; |
| return true; |
| |
| END_BLOCK_OBJC_EXCEPTIONS; |
| } |
| |
| return false; |
| } |
| |
| static bool trySetFunctions(const char* const functionName, const GPUPipelineStageDescriptor& vertexStage, const Optional<GPUPipelineStageDescriptor>& fragmentStage, const GPUDevice& device, MTLRenderPipelineDescriptor* mtlDescriptor, Optional<WHLSL::RenderPipelineDescriptor>& whlslDescriptor) |
| { |
| #if LOG_DISABLED |
| UNUSED_PARAM(functionName); |
| #endif |
| RetainPtr<MTLLibrary> vertexLibrary, fragmentLibrary; |
| String vertexEntryPoint, fragmentEntryPoint; |
| |
| if (whlslDescriptor) { |
| // WHLSL functions are compiled to MSL first. |
| String whlslSource = vertexStage.module->whlslSource(); |
| ASSERT(!whlslSource.isNull()); |
| |
| whlslDescriptor->vertexEntryPointName = vertexStage.entryPoint; |
| if (fragmentStage) |
| whlslDescriptor->fragmentEntryPointName = fragmentStage->entryPoint; |
| |
| auto whlslCompileResult = WHLSL::prepare(whlslSource, *whlslDescriptor); |
| if (!whlslCompileResult) |
| return false; |
| |
| NSError *error = nil; |
| |
| BEGIN_BLOCK_OBJC_EXCEPTIONS; |
| vertexLibrary = adoptNS([device.platformDevice() newLibraryWithSource:whlslCompileResult->metalSource options:nil error:&error]); |
| END_BLOCK_OBJC_EXCEPTIONS; |
| |
| #ifndef NDEBUG |
| if (!vertexLibrary) |
| NSLog(@"%@", error); |
| #endif |
| ASSERT(vertexLibrary); |
| // 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. |
| |
| fragmentLibrary = vertexLibrary; |
| vertexEntryPoint = whlslCompileResult->mangledVertexEntryPointName; |
| fragmentEntryPoint = whlslCompileResult->mangledFragmentEntryPointName; |
| } else { |
| vertexLibrary = vertexStage.module->platformShaderModule(); |
| vertexEntryPoint = vertexStage.entryPoint; |
| if (fragmentStage) { |
| fragmentLibrary = fragmentStage->module->platformShaderModule(); |
| fragmentEntryPoint = fragmentStage->entryPoint; |
| } |
| } |
| |
| return trySetMetalFunctions(functionName, vertexLibrary.get(), fragmentLibrary.get(), mtlDescriptor, vertexEntryPoint, fragmentEntryPoint); |
| } |
| |
| static RetainPtr<MTLRenderPipelineDescriptor> convertRenderPipelineDescriptor(const char* const functionName, const GPURenderPipelineDescriptor& descriptor, const GPUDevice& device) |
| { |
| RetainPtr<MTLRenderPipelineDescriptor> mtlDescriptor; |
| |
| BEGIN_BLOCK_OBJC_EXCEPTIONS; |
| |
| mtlDescriptor = adoptNS([MTLRenderPipelineDescriptor new]); |
| |
| END_BLOCK_OBJC_EXCEPTIONS; |
| |
| if (!mtlDescriptor) { |
| LOG(WebGPU, "%s: Error creating MTLDescriptor!", functionName); |
| return nullptr; |
| } |
| |
| // Determine if shader source is in WHLSL or MSL. |
| const auto& vertexStage = descriptor.vertexStage; |
| const auto& fragmentStage = descriptor.fragmentStage; |
| |
| // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195446 Allow WHLSL shaders to come from different programs. |
| bool isWhlsl = !vertexStage.module->whlslSource().isNull() && (!fragmentStage || vertexStage.module.ptr() == fragmentStage->module.ptr()); |
| |
| // Set data for the Metal pipeline descriptor (and WHLSL's, if needed). |
| Optional<WHLSL::RenderPipelineDescriptor> whlslDescriptor; |
| if (isWhlsl) |
| whlslDescriptor = WHLSL::RenderPipelineDescriptor(); |
| |
| if (!trySetVertexInput(functionName, descriptor.vertexInput, mtlDescriptor.get(), whlslDescriptor)) |
| return nullptr; |
| |
| if (!trySetColorStates(functionName, descriptor.colorStates, mtlDescriptor.get().colorAttachments, whlslDescriptor)) |
| return nullptr; |
| |
| if (descriptor.layout && whlslDescriptor) { |
| if (auto layout = convertLayout(*descriptor.layout)) |
| whlslDescriptor->layout = WTFMove(*layout); |
| else { |
| LOG(WebGPU, "%s: Error converting GPUPipelineLayout!", functionName); |
| return nullptr; |
| } |
| } |
| |
| if (!trySetFunctions(functionName, vertexStage, fragmentStage, device, mtlDescriptor.get(), whlslDescriptor)) |
| return nullptr; |
| |
| return mtlDescriptor; |
| } |
| |
| static RetainPtr<MTLRenderPipelineState> tryCreateMtlRenderPipelineState(const char* const functionName, const GPURenderPipelineDescriptor& descriptor, const GPUDevice& device) |
| { |
| if (!device.platformDevice()) { |
| LOG(WebGPU, "GPUComputePipeline::tryCreate(): Invalid GPUDevice!"); |
| return nullptr; |
| } |
| |
| auto mtlDescriptor = convertRenderPipelineDescriptor(functionName, descriptor, device); |
| if (!mtlDescriptor) |
| return nullptr; |
| |
| RetainPtr<MTLRenderPipelineState> pipeline; |
| |
| BEGIN_BLOCK_OBJC_EXCEPTIONS; |
| |
| NSError *error = nil; |
| pipeline = adoptNS([device.platformDevice() newRenderPipelineStateWithDescriptor:mtlDescriptor.get() error:&error]); |
| if (!pipeline) |
| LOG(WebGPU, "%s: %s!", functionName, error.localizedDescription.UTF8String); |
| |
| END_BLOCK_OBJC_EXCEPTIONS; |
| |
| return pipeline; |
| } |
| |
| RefPtr<GPURenderPipeline> GPURenderPipeline::tryCreate(const GPUDevice& device, const GPURenderPipelineDescriptor& descriptor) |
| { |
| const char* const functionName = "GPURenderPipeline::create()"; |
| |
| if (!device.platformDevice()) { |
| LOG(WebGPU, "%s: Invalid GPUDevice!", functionName); |
| return nullptr; |
| } |
| |
| RetainPtr<MTLDepthStencilState> depthStencil; |
| |
| if (descriptor.depthStencilState && !(depthStencil = tryCreateMtlDepthStencilState(functionName, *descriptor.depthStencilState, device))) |
| return nullptr; |
| |
| // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198387 depthStencilAttachmentDescriptor isn't implemented yet for WHLSL compiler. |
| |
| auto pipeline = tryCreateMtlRenderPipelineState(functionName, descriptor, device); |
| if (!pipeline) |
| return nullptr; |
| |
| return adoptRef(new GPURenderPipeline(WTFMove(depthStencil), WTFMove(pipeline), descriptor.primitiveTopology, descriptor.vertexInput.indexFormat)); |
| } |
| |
| GPURenderPipeline::GPURenderPipeline(RetainPtr<MTLDepthStencilState>&& depthStencil, RetainPtr<MTLRenderPipelineState>&& pipeline, GPUPrimitiveTopology topology, Optional<GPUIndexFormat> format) |
| : m_depthStencilState(WTFMove(depthStencil)) |
| , m_platformRenderPipeline(WTFMove(pipeline)) |
| , m_primitiveTopology(topology) |
| , m_indexFormat(format) |
| { |
| } |
| |
| } // namespace WebCore |
| |
| #endif // ENABLE(WEBGPU) |