1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.h"
6
7 #include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
8 #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_blend_descriptor.h"
9 #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_color_state_descriptor.h"
10 #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_depth_stencil_state_descriptor.h"
11 #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_rasterization_state_descriptor.h"
12 #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_render_pipeline_descriptor.h"
13 #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_stencil_state_face_descriptor.h"
14 #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_vertex_attribute_descriptor.h"
15 #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_vertex_buffer_layout_descriptor.h"
16 #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_vertex_state_descriptor.h"
17 #include "third_party/blink/renderer/modules/webgpu/dawn_conversions.h"
18 #include "third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.h"
19 #include "third_party/blink/renderer/modules/webgpu/gpu_device.h"
20 #include "third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.h"
21 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
22 #include "third_party/blink/renderer/platform/bindings/script_state.h"
23
24 namespace blink {
25
26 namespace {
27
AsDawnType(const GPUBlendDescriptor * webgpu_desc)28 WGPUBlendDescriptor AsDawnType(const GPUBlendDescriptor* webgpu_desc) {
29 DCHECK(webgpu_desc);
30
31 WGPUBlendDescriptor dawn_desc = {};
32 dawn_desc.dstFactor = AsDawnEnum<WGPUBlendFactor>(webgpu_desc->dstFactor());
33 dawn_desc.srcFactor = AsDawnEnum<WGPUBlendFactor>(webgpu_desc->srcFactor());
34 dawn_desc.operation =
35 AsDawnEnum<WGPUBlendOperation>(webgpu_desc->operation());
36
37 return dawn_desc;
38 }
39
40 } // anonymous namespace
41
AsDawnType(const GPUColorStateDescriptor * webgpu_desc)42 WGPUColorStateDescriptor AsDawnType(
43 const GPUColorStateDescriptor* webgpu_desc) {
44 DCHECK(webgpu_desc);
45
46 WGPUColorStateDescriptor dawn_desc = {};
47 dawn_desc.nextInChain = nullptr;
48 dawn_desc.alphaBlend = AsDawnType(webgpu_desc->alphaBlend());
49 dawn_desc.colorBlend = AsDawnType(webgpu_desc->colorBlend());
50 dawn_desc.writeMask =
51 AsDawnEnum<WGPUColorWriteMask>(webgpu_desc->writeMask());
52 dawn_desc.format = AsDawnEnum<WGPUTextureFormat>(webgpu_desc->format());
53
54 return dawn_desc;
55 }
56
57 namespace {
58
AsDawnType(const GPUStencilStateFaceDescriptor * webgpu_desc)59 WGPUStencilStateFaceDescriptor AsDawnType(
60 const GPUStencilStateFaceDescriptor* webgpu_desc) {
61 DCHECK(webgpu_desc);
62
63 WGPUStencilStateFaceDescriptor dawn_desc = {};
64 dawn_desc.compare = AsDawnEnum<WGPUCompareFunction>(webgpu_desc->compare());
65 dawn_desc.depthFailOp =
66 AsDawnEnum<WGPUStencilOperation>(webgpu_desc->depthFailOp());
67 dawn_desc.failOp = AsDawnEnum<WGPUStencilOperation>(webgpu_desc->failOp());
68 dawn_desc.passOp = AsDawnEnum<WGPUStencilOperation>(webgpu_desc->passOp());
69
70 return dawn_desc;
71 }
72
AsDawnType(const GPUDepthStencilStateDescriptor * webgpu_desc)73 WGPUDepthStencilStateDescriptor AsDawnType(
74 const GPUDepthStencilStateDescriptor* webgpu_desc) {
75 DCHECK(webgpu_desc);
76
77 WGPUDepthStencilStateDescriptor dawn_desc = {};
78 dawn_desc.nextInChain = nullptr;
79 dawn_desc.depthCompare =
80 AsDawnEnum<WGPUCompareFunction>(webgpu_desc->depthCompare());
81 dawn_desc.depthWriteEnabled = webgpu_desc->depthWriteEnabled();
82 dawn_desc.format = AsDawnEnum<WGPUTextureFormat>(webgpu_desc->format());
83 dawn_desc.stencilBack = AsDawnType(webgpu_desc->stencilBack());
84 dawn_desc.stencilFront = AsDawnType(webgpu_desc->stencilFront());
85 dawn_desc.stencilReadMask = webgpu_desc->stencilReadMask();
86 dawn_desc.stencilWriteMask = webgpu_desc->stencilWriteMask();
87
88 return dawn_desc;
89 }
90
91 using WGPUVertexStateInfo = std::tuple<WGPUVertexStateDescriptor,
92 Vector<WGPUVertexBufferLayoutDescriptor>,
93 Vector<WGPUVertexAttributeDescriptor>>;
94
GPUVertexStateAsWGPUVertexState(v8::Isolate * isolate,const GPUVertexStateDescriptor * descriptor,ExceptionState & exception_state)95 WGPUVertexStateInfo GPUVertexStateAsWGPUVertexState(
96 v8::Isolate* isolate,
97 const GPUVertexStateDescriptor* descriptor,
98 ExceptionState& exception_state) {
99 WGPUVertexStateDescriptor dawn_desc = {};
100 dawn_desc.indexFormat =
101 AsDawnEnum<WGPUIndexFormat>(descriptor->indexFormat());
102 dawn_desc.vertexBufferCount = 0;
103 dawn_desc.vertexBuffers = nullptr;
104
105 Vector<WGPUVertexBufferLayoutDescriptor> dawn_vertex_buffers;
106 Vector<WGPUVertexAttributeDescriptor> dawn_vertex_attributes;
107
108 if (descriptor->hasVertexBuffers()) {
109 // TODO(crbug.com/951629): Use a sequence of nullable descriptors.
110 v8::Local<v8::Value> vertex_buffers_value =
111 descriptor->vertexBuffers().V8Value();
112 if (!vertex_buffers_value->IsArray()) {
113 exception_state.ThrowTypeError("vertexBuffers must be an array");
114
115 return std::make_tuple(dawn_desc, std::move(dawn_vertex_buffers),
116 std::move(dawn_vertex_attributes));
117 }
118
119 v8::Local<v8::Context> context = isolate->GetCurrentContext();
120 v8::Local<v8::Array> vertex_buffers = vertex_buffers_value.As<v8::Array>();
121
122 // First we collect all the descriptors but we don't set
123 // WGPUVertexBufferLayoutDescriptor::attributes
124 // TODO(cwallez@chromium.org): Should we validate the Length() first so we
125 // don't risk creating HUGE vectors of WGPUVertexBufferLayoutDescriptor from
126 // the sparse array?
127 for (uint32_t i = 0; i < vertex_buffers->Length(); ++i) {
128 // This array can be sparse. Skip empty slots.
129 v8::MaybeLocal<v8::Value> maybe_value = vertex_buffers->Get(context, i);
130 v8::Local<v8::Value> value;
131 if (!maybe_value.ToLocal(&value) || value.IsEmpty() ||
132 value->IsNullOrUndefined()) {
133 WGPUVertexBufferLayoutDescriptor dawn_vertex_buffer = {};
134 dawn_vertex_buffer.arrayStride = 0;
135 dawn_vertex_buffer.stepMode = WGPUInputStepMode_Vertex;
136 dawn_vertex_buffer.attributeCount = 0;
137 dawn_vertex_buffer.attributes = nullptr;
138 dawn_vertex_buffers.push_back(dawn_vertex_buffer);
139 continue;
140 }
141
142 GPUVertexBufferLayoutDescriptor* vertex_buffer =
143 NativeValueTraits<GPUVertexBufferLayoutDescriptor>::NativeValue(
144 isolate, value, exception_state);
145 if (exception_state.HadException()) {
146 return std::make_tuple(dawn_desc, std::move(dawn_vertex_buffers),
147 std::move(dawn_vertex_attributes));
148 }
149
150 WGPUVertexBufferLayoutDescriptor dawn_vertex_buffer = {};
151 dawn_vertex_buffer.arrayStride = vertex_buffer->arrayStride();
152 dawn_vertex_buffer.stepMode =
153 AsDawnEnum<WGPUInputStepMode>(vertex_buffer->stepMode());
154 dawn_vertex_buffer.attributeCount =
155 static_cast<uint32_t>(vertex_buffer->attributes().size());
156 dawn_vertex_buffer.attributes = nullptr;
157 dawn_vertex_buffers.push_back(dawn_vertex_buffer);
158
159 for (wtf_size_t j = 0; j < vertex_buffer->attributes().size(); ++j) {
160 const GPUVertexAttributeDescriptor* attribute =
161 vertex_buffer->attributes()[j];
162 WGPUVertexAttributeDescriptor dawn_vertex_attribute = {};
163 dawn_vertex_attribute.shaderLocation = attribute->shaderLocation();
164 dawn_vertex_attribute.offset = attribute->offset();
165 dawn_vertex_attribute.format =
166 AsDawnEnum<WGPUVertexFormat>(attribute->format());
167 dawn_vertex_attributes.push_back(dawn_vertex_attribute);
168 }
169 }
170
171 // Set up pointers in DawnVertexBufferLayoutDescriptor::attributes only
172 // after we stopped appending to the vector so the pointers aren't
173 // invalidated.
174 uint32_t attributeIndex = 0;
175 for (WGPUVertexBufferLayoutDescriptor& buffer : dawn_vertex_buffers) {
176 if (buffer.attributeCount == 0) {
177 continue;
178 }
179 buffer.attributes = &dawn_vertex_attributes[attributeIndex];
180 attributeIndex += buffer.attributeCount;
181 }
182 }
183
184 dawn_desc.vertexBufferCount =
185 static_cast<uint32_t>(dawn_vertex_buffers.size());
186 dawn_desc.vertexBuffers = dawn_vertex_buffers.data();
187
188 return std::make_tuple(dawn_desc, std::move(dawn_vertex_buffers),
189 std::move(dawn_vertex_attributes));
190 }
191
AsDawnType(const GPURasterizationStateDescriptor * webgpu_desc)192 WGPURasterizationStateDescriptor AsDawnType(
193 const GPURasterizationStateDescriptor* webgpu_desc) {
194 DCHECK(webgpu_desc);
195
196 WGPURasterizationStateDescriptor dawn_desc = {};
197 dawn_desc.nextInChain = nullptr;
198 dawn_desc.frontFace = AsDawnEnum<WGPUFrontFace>(webgpu_desc->frontFace());
199 dawn_desc.cullMode = AsDawnEnum<WGPUCullMode>(webgpu_desc->cullMode());
200 dawn_desc.depthBias = webgpu_desc->depthBias();
201 dawn_desc.depthBiasSlopeScale = webgpu_desc->depthBiasSlopeScale();
202 dawn_desc.depthBiasClamp = webgpu_desc->depthBiasClamp();
203
204 return dawn_desc;
205 }
206
207 } // anonymous namespace
208
209 // static
Create(ScriptState * script_state,GPUDevice * device,const GPURenderPipelineDescriptor * webgpu_desc)210 GPURenderPipeline* GPURenderPipeline::Create(
211 ScriptState* script_state,
212 GPUDevice* device,
213 const GPURenderPipelineDescriptor* webgpu_desc) {
214 DCHECK(device);
215 DCHECK(webgpu_desc);
216
217 WGPURenderPipelineDescriptor dawn_desc = {};
218 dawn_desc.nextInChain = nullptr;
219 if (webgpu_desc->hasLayout()) {
220 dawn_desc.layout = AsDawnType(webgpu_desc->layout());
221 }
222 if (webgpu_desc->hasLabel()) {
223 dawn_desc.label = webgpu_desc->label().Utf8().data();
224 }
225
226 OwnedProgrammableStageDescriptor vertex_stage_info =
227 AsDawnType(webgpu_desc->vertexStage());
228 dawn_desc.vertexStage = std::get<0>(vertex_stage_info);
229 OwnedProgrammableStageDescriptor fragment_stage_info;
230 if (webgpu_desc->hasFragmentStage()) {
231 fragment_stage_info = AsDawnType(webgpu_desc->fragmentStage());
232 dawn_desc.fragmentStage = &std::get<0>(fragment_stage_info);
233 } else {
234 dawn_desc.fragmentStage = nullptr;
235 }
236
237 v8::Isolate* isolate = script_state->GetIsolate();
238 ExceptionState exception_state(isolate, ExceptionState::kConstructionContext,
239 "GPUVertexStateDescriptor");
240 WGPUVertexStateInfo vertex_state_info = GPUVertexStateAsWGPUVertexState(
241 isolate, webgpu_desc->vertexState(), exception_state);
242 dawn_desc.vertexState = &std::get<0>(vertex_state_info);
243
244 if (exception_state.HadException()) {
245 return nullptr;
246 }
247
248 dawn_desc.primitiveTopology =
249 AsDawnEnum<WGPUPrimitiveTopology>(webgpu_desc->primitiveTopology());
250
251 WGPURasterizationStateDescriptor rasterization_state;
252 rasterization_state = AsDawnType(webgpu_desc->rasterizationState());
253 dawn_desc.rasterizationState = &rasterization_state;
254
255 dawn_desc.sampleCount = webgpu_desc->sampleCount();
256
257 WGPUDepthStencilStateDescriptor depth_stencil_state = {};
258 if (webgpu_desc->hasDepthStencilState()) {
259 depth_stencil_state = AsDawnType(webgpu_desc->depthStencilState());
260 dawn_desc.depthStencilState = &depth_stencil_state;
261 } else {
262 dawn_desc.depthStencilState = nullptr;
263 }
264
265 std::unique_ptr<WGPUColorStateDescriptor[]> color_states =
266 AsDawnType(webgpu_desc->colorStates());
267 dawn_desc.colorStateCount =
268 static_cast<uint32_t>(webgpu_desc->colorStates().size());
269
270 dawn_desc.colorStates = color_states.get();
271
272 dawn_desc.sampleMask = webgpu_desc->sampleMask();
273 dawn_desc.alphaToCoverageEnabled = webgpu_desc->alphaToCoverageEnabled();
274
275 return MakeGarbageCollected<GPURenderPipeline>(
276 device, device->GetProcs().deviceCreateRenderPipeline(device->GetHandle(),
277 &dawn_desc));
278 }
279
GPURenderPipeline(GPUDevice * device,WGPURenderPipeline render_pipeline)280 GPURenderPipeline::GPURenderPipeline(GPUDevice* device,
281 WGPURenderPipeline render_pipeline)
282 : DawnObject<WGPURenderPipeline>(device, render_pipeline) {}
283
~GPURenderPipeline()284 GPURenderPipeline::~GPURenderPipeline() {
285 if (IsDawnControlClientDestroyed()) {
286 return;
287 }
288 GetProcs().renderPipelineRelease(GetHandle());
289 }
290
getBindGroupLayout(uint32_t index)291 GPUBindGroupLayout* GPURenderPipeline::getBindGroupLayout(uint32_t index) {
292 return MakeGarbageCollected<GPUBindGroupLayout>(
293 device_, GetProcs().renderPipelineGetBindGroupLayout(GetHandle(), index));
294 }
295
296 } // namespace blink
297