c946d5509d2228d45f064b0f6d35bcca860d7eaf
[WebKit-https.git] / Source / WebCore / Modules / webgpu / 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 "GPURenderPipelineDescriptor.h"
32 #import "Logging.h"
33
34 #import <Metal/Metal.h>
35 #import <wtf/BlockObjCExceptions.h>
36
37 namespace WebCore {
38
39 static bool setFunctionsForPipelineDescriptor(const char* const functionName, MTLRenderPipelineDescriptor *mtlDescriptor, GPURenderPipelineDescriptor&& descriptor)
40 {
41 #if LOG_DISABLED
42     UNUSED_PARAM(functionName);
43 #endif
44     // Metal requires a vertex shader in all render pipelines.
45     const auto& vertexStage = descriptor.vertexStage;
46     auto mtlLibrary = vertexStage.module->platformShaderModule();
47
48     if (!mtlLibrary) {
49         LOG(WebGPU, "%s: MTLLibrary for vertex stage does not exist!", functionName);
50         return false;
51     }
52
53     auto function = adoptNS([mtlLibrary newFunctionWithName:vertexStage.entryPoint]);
54
55     if (!function) {
56         LOG(WebGPU, "%s: Vertex MTLFunction \"%s\" not found!", functionName, vertexStage.entryPoint.utf8().data());
57         return false;
58     }
59
60     [mtlDescriptor setVertexFunction:function.get()];
61
62     // However, fragment shaders are optional.
63     const auto fragmentStage = descriptor.fragmentStage;
64     if (!fragmentStage.module || !fragmentStage.entryPoint)
65         return true;
66
67     mtlLibrary = fragmentStage.module->platformShaderModule();
68
69     if (!mtlLibrary) {
70         LOG(WebGPU, "%s: MTLLibrary for fragment stage does not exist!", functionName);
71         return false;
72     }
73
74     function = adoptNS([mtlLibrary newFunctionWithName:fragmentStage.entryPoint]);
75
76     if (!function) {
77         LOG(WebGPU, "%s: Fragment MTLFunction \"%s\" not found!", functionName, fragmentStage.entryPoint.utf8().data());
78         return false;
79     }
80
81     [mtlDescriptor setFragmentFunction:function.get()];
82
83     return true;
84 }
85
86 RefPtr<GPURenderPipeline> GPURenderPipeline::create(const GPUDevice& device, GPURenderPipelineDescriptor&& descriptor)
87 {
88     const char* const functionName = "GPURenderPipeline::create()";
89
90     if (!device.platformDevice()) {
91         LOG(WebGPU, "%s: MTLDevice does not exist!", functionName);
92         return nullptr;
93     }
94
95     RetainPtr<MTLRenderPipelineDescriptor> mtlDescriptor;
96
97     BEGIN_BLOCK_OBJC_EXCEPTIONS;
98
99     mtlDescriptor = adoptNS([MTLRenderPipelineDescriptor new]);
100
101     END_BLOCK_OBJC_EXCEPTIONS;
102
103     if (!mtlDescriptor) {
104         LOG(WebGPU, "%s: Error creating MTLDescriptor!", functionName);
105         return nullptr;
106     }
107
108     if (!setFunctionsForPipelineDescriptor(functionName, mtlDescriptor.get(), WTFMove(descriptor)))
109         return nullptr;
110
111     // FIXME: Get the pixelFormat as configured for the context/CAMetalLayer.
112     mtlDescriptor.get().colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
113
114     PlatformRenderPipelineSmartPtr pipeline;
115
116     BEGIN_BLOCK_OBJC_EXCEPTIONS;
117
118     pipeline = adoptNS([device.platformDevice() newRenderPipelineStateWithDescriptor:mtlDescriptor.get() error:nil]);
119
120     END_BLOCK_OBJC_EXCEPTIONS;
121
122     if (!pipeline) {
123         LOG(WebGPU, "%s: Error creating MTLRenderPipelineState!", functionName);
124         return nullptr;
125     }
126
127     return adoptRef(new GPURenderPipeline(WTFMove(pipeline)));
128 }
129
130 GPURenderPipeline::GPURenderPipeline(PlatformRenderPipelineSmartPtr&& pipeline)
131     : m_platformRenderPipeline(WTFMove(pipeline))
132 {
133 }
134
135 } // namespace WebCore
136
137 #endif // ENABLE(WEBGPU)