blob: c55fcbef31fb1e460f7431c8494a0c31eb14cd7b [file] [log] [blame]
Ben Vanike7c2cba2021-07-19 15:45:39 -07001// Copyright 2021 The IREE Authors
2//
3// Licensed under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
7#include "experimental/webgpu/pipeline_layout.h"
8
9#include <stddef.h>
10
11#include "iree/base/api.h"
12#include "iree/base/internal/inline_array.h"
Ben Vanike7c2cba2021-07-19 15:45:39 -070013
14//===----------------------------------------------------------------------===//
15// iree_hal_webgpu_descriptor_set_layout_t
16//===----------------------------------------------------------------------===//
17
18typedef struct iree_hal_webgpu_descriptor_set_layout_t {
19 iree_hal_resource_t resource;
20 iree_allocator_t host_allocator;
21 WGPUBindGroupLayout handle;
22 iree_hal_webgpu_binding_mask_t binding_mask;
23} iree_hal_webgpu_descriptor_set_layout_t;
24
25extern const iree_hal_descriptor_set_layout_vtable_t
26 iree_hal_webgpu_descriptor_set_layout_vtable;
27
28static iree_hal_webgpu_descriptor_set_layout_t*
29iree_hal_webgpu_descriptor_set_layout_cast(
30 iree_hal_descriptor_set_layout_t* base_value) {
31 IREE_HAL_ASSERT_TYPE(base_value,
32 &iree_hal_webgpu_descriptor_set_layout_vtable);
33 return (iree_hal_webgpu_descriptor_set_layout_t*)base_value;
34}
35
36iree_status_t iree_hal_webgpu_descriptor_set_layout_create(
37 WGPUDevice device, iree_hal_descriptor_set_layout_flags_t flags,
38 iree_host_size_t binding_count,
39 const iree_hal_descriptor_set_layout_binding_t* bindings,
40 iree_allocator_t host_allocator,
41 iree_hal_descriptor_set_layout_t** out_descriptor_set_layout) {
42 IREE_ASSERT_ARGUMENT(device);
43 IREE_ASSERT_ARGUMENT(!binding_count || bindings);
44 IREE_ASSERT_ARGUMENT(out_descriptor_set_layout);
45 *out_descriptor_set_layout = NULL;
46 IREE_TRACE_ZONE_BEGIN(z0);
47
48 iree_inline_array(WGPUBindGroupLayoutEntry, entries, binding_count,
49 host_allocator);
50 iree_hal_webgpu_binding_mask_t binding_mask = 0;
51 for (iree_host_size_t i = 0; i < binding_count; ++i) {
52 if (bindings[i].binding >=
53 IREE_HAL_WEBGPU_MAX_DESCRIPTOR_SET_BINDING_COUNT) {
54 iree_inline_array_deinitialize(entries);
55 IREE_TRACE_ZONE_END(z0);
56 return iree_make_status(IREE_STATUS_OUT_OF_RANGE,
57 "bindings must be in the range of 0-%d; binding "
Scott Todd60b07642023-06-15 09:41:01 -070058 "%" PRIhsz " is has ordinal %d",
Ben Vanike7c2cba2021-07-19 15:45:39 -070059 IREE_HAL_WEBGPU_MAX_DESCRIPTOR_SET_BINDING_COUNT,
60 i, bindings[i].binding);
61 }
62 binding_mask |= 1u << bindings[i].binding;
63
64 // TODO(benvanik): make all dynamic? this would let us reuse bind groups.
65 WGPUBufferBindingType binding_type = WGPUBufferBindingType_Undefined;
66 bool has_dynamic_offset = false;
67 switch (bindings[i].type) {
68 case IREE_HAL_DESCRIPTOR_TYPE_STORAGE_BUFFER:
69 binding_type = WGPUBufferBindingType_Storage;
70 break;
71 case IREE_HAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
72 binding_type = WGPUBufferBindingType_Uniform;
73 break;
74 }
75 *iree_inline_array_at(entries, i) = (WGPUBindGroupLayoutEntry){
76 .nextInChain = NULL,
77 .binding = bindings[i].binding,
78 .visibility = WGPUShaderStage_Compute,
79 .buffer =
80 {
81 .nextInChain = NULL,
82 .type = binding_type,
83 .hasDynamicOffset = has_dynamic_offset,
84 .minBindingSize = 0,
85 },
86 };
87 }
88 const WGPUBindGroupLayoutDescriptor descriptor = {
89 .nextInChain = NULL,
90 .label = NULL,
91 .entryCount = (uint32_t)binding_count,
92 .entries = iree_inline_array_at(entries, 0),
93 };
94 WGPUBindGroupLayout handle =
95 wgpuDeviceCreateBindGroupLayout(device, &descriptor);
96 iree_inline_array_deinitialize(entries);
97 if (!handle) {
98 IREE_TRACE_ZONE_END(z0);
99 return iree_make_status(IREE_STATUS_INTERNAL,
100 "wgpuDeviceCreateBindGroupLayout failed");
101 }
102
103 iree_hal_webgpu_descriptor_set_layout_t* descriptor_set_layout = NULL;
104 iree_status_t status =
105 iree_allocator_malloc(host_allocator, sizeof(*descriptor_set_layout),
106 (void**)&descriptor_set_layout);
107 if (iree_status_is_ok(status)) {
108 iree_hal_resource_initialize(&iree_hal_webgpu_descriptor_set_layout_vtable,
109 &descriptor_set_layout->resource);
110 descriptor_set_layout->host_allocator = host_allocator;
111 descriptor_set_layout->handle = handle;
112 descriptor_set_layout->binding_mask = binding_mask;
113 *out_descriptor_set_layout =
114 (iree_hal_descriptor_set_layout_t*)descriptor_set_layout;
115 } else {
116 iree_wgpuBindGroupLayoutDrop(handle);
117 }
118
119 IREE_TRACE_ZONE_END(z0);
120 return status;
121}
122
123static void iree_hal_webgpu_descriptor_set_layout_destroy(
124 iree_hal_descriptor_set_layout_t* base_descriptor_set_layout) {
125 iree_hal_webgpu_descriptor_set_layout_t* descriptor_set_layout =
126 iree_hal_webgpu_descriptor_set_layout_cast(base_descriptor_set_layout);
127 iree_allocator_t host_allocator = descriptor_set_layout->host_allocator;
128 IREE_TRACE_ZONE_BEGIN(z0);
129
130 iree_wgpuBindGroupLayoutDrop(descriptor_set_layout->handle);
131 iree_allocator_free(host_allocator, descriptor_set_layout);
132
133 IREE_TRACE_ZONE_END(z0);
134}
135
136WGPUBindGroupLayout iree_hal_webgpu_descriptor_set_layout_handle(
137 iree_hal_descriptor_set_layout_t* layout) {
138 IREE_ASSERT_ARGUMENT(layout);
139 return iree_hal_webgpu_descriptor_set_layout_cast(layout)->handle;
140}
141
142iree_hal_webgpu_binding_mask_t
143iree_hal_webgpu_descriptor_set_layout_binding_mask(
144 iree_hal_descriptor_set_layout_t* layout) {
145 IREE_ASSERT_ARGUMENT(layout);
146 return iree_hal_webgpu_descriptor_set_layout_cast(layout)->binding_mask;
147}
148
149const iree_hal_descriptor_set_layout_vtable_t
150 iree_hal_webgpu_descriptor_set_layout_vtable = {
151 .destroy = iree_hal_webgpu_descriptor_set_layout_destroy,
152};
153
154//===----------------------------------------------------------------------===//
155// iree_hal_webgpu_pipeline_layout_t
156//===----------------------------------------------------------------------===//
157
158typedef struct iree_hal_webgpu_pipeline_layout_t {
159 iree_hal_resource_t resource;
160 iree_allocator_t host_allocator;
161 WGPUPipelineLayout handle;
Ben Vanike2a2b2b2024-08-22 11:56:59 -0700162 iree_host_size_t constant_count;
Ben Vanike7c2cba2021-07-19 15:45:39 -0700163 iree_hal_webgpu_set_binding_info_t set_binding_info;
164 iree_host_size_t set_layout_count;
165 iree_hal_descriptor_set_layout_t* set_layouts[];
166} iree_hal_webgpu_pipeline_layout_t;
167
168extern const iree_hal_pipeline_layout_vtable_t
169 iree_hal_webgpu_pipeline_layout_vtable;
170
171static iree_hal_webgpu_pipeline_layout_t* iree_hal_webgpu_pipeline_layout_cast(
172 iree_hal_pipeline_layout_t* base_value) {
173 IREE_HAL_ASSERT_TYPE(base_value, &iree_hal_webgpu_pipeline_layout_vtable);
174 return (iree_hal_webgpu_pipeline_layout_t*)base_value;
175}
176
177iree_status_t iree_hal_webgpu_pipeline_layout_create(
178 WGPUDevice device, iree_host_size_t set_layout_count,
179 iree_hal_descriptor_set_layout_t* const* set_layouts,
Ben Vanike2a2b2b2024-08-22 11:56:59 -0700180 iree_host_size_t constant_count,
Ben Vanike7c2cba2021-07-19 15:45:39 -0700181 iree_hal_webgpu_staging_buffer_t* staging_buffer,
182 iree_allocator_t host_allocator,
183 iree_hal_pipeline_layout_t** out_pipeline_layout) {
184 IREE_ASSERT_ARGUMENT(device);
185 IREE_ASSERT_ARGUMENT(!set_layout_count || set_layouts);
186 IREE_ASSERT_ARGUMENT(out_pipeline_layout);
187 *out_pipeline_layout = NULL;
188 IREE_TRACE_ZONE_BEGIN(z0);
189
190 if (set_layout_count > IREE_HAL_WEBGPU_PARAMS_BIND_GROUP_INDEX) {
191 IREE_TRACE_ZONE_END(z0);
192 return iree_make_status(
193 IREE_STATUS_OUT_OF_RANGE,
194 "set_layout_count must be <= %d, as bind group index %d is reserved",
195 IREE_HAL_WEBGPU_PARAMS_BIND_GROUP_INDEX,
196 IREE_HAL_WEBGPU_PARAMS_BIND_GROUP_INDEX);
197 }
198
199 // Pad to IREE_HAL_WEBGPU_PARAMS_BIND_GROUP_INDEX for push constant emulation.
200 iree_host_size_t bind_group_layouts_count =
Ben Vanike2a2b2b2024-08-22 11:56:59 -0700201 constant_count > 0 ? IREE_HAL_WEBGPU_PARAMS_BIND_GROUP_INDEX + 1
202 : set_layout_count;
Ben Vanike7c2cba2021-07-19 15:45:39 -0700203
204 // Populate a WGPUBindGroupLayout array with the provided set layouts, then
205 // set the staging buffer's bind group layout at the right index, padding
206 // with an empty bind layout as needed.
207 iree_inline_array(WGPUBindGroupLayout, bind_group_layouts,
208 bind_group_layouts_count, host_allocator);
209 for (iree_host_size_t i = 0; i < set_layout_count; ++i) {
210 *iree_inline_array_at(bind_group_layouts, i) =
211 iree_hal_webgpu_descriptor_set_layout_handle(set_layouts[i]);
212 }
213 for (iree_host_size_t i = set_layout_count; i < bind_group_layouts_count - 1;
214 ++i) {
215 *iree_inline_array_at(bind_group_layouts, i) =
216 staging_buffer->empty_bind_group_layout;
217 }
Ben Vanike2a2b2b2024-08-22 11:56:59 -0700218 if (constant_count > 0) {
Ben Vanike7c2cba2021-07-19 15:45:39 -0700219 *iree_inline_array_at(bind_group_layouts,
220 IREE_HAL_WEBGPU_PARAMS_BIND_GROUP_INDEX) =
221 staging_buffer->bind_group_layout;
222 }
223 const WGPUPipelineLayoutDescriptor descriptor = {
224 .nextInChain = NULL,
225 .label = NULL,
226 .bindGroupLayoutCount = (uint32_t)bind_group_layouts_count,
227 .bindGroupLayouts = iree_inline_array_at(bind_group_layouts, 0),
228 };
229 WGPUPipelineLayout handle =
230 wgpuDeviceCreatePipelineLayout(device, &descriptor);
231 iree_inline_array_deinitialize(bind_group_layouts);
232
233 if (!handle) {
234 IREE_TRACE_ZONE_END(z0);
235 return iree_make_status(IREE_STATUS_INTERNAL,
236 "wgpuDeviceCreatePipelineLayout failed");
237 }
238
239 iree_hal_webgpu_pipeline_layout_t* pipeline_layout = NULL;
240 iree_host_size_t total_size =
241 sizeof(*pipeline_layout) +
242 set_layout_count * sizeof(*pipeline_layout->set_layouts);
243 iree_status_t status = iree_allocator_malloc(host_allocator, total_size,
244 (void**)&pipeline_layout);
245 if (iree_status_is_ok(status)) {
246 iree_hal_resource_initialize(&iree_hal_webgpu_pipeline_layout_vtable,
247 &pipeline_layout->resource);
248 pipeline_layout->host_allocator = host_allocator;
249 pipeline_layout->handle = handle;
Ben Vanike2a2b2b2024-08-22 11:56:59 -0700250 pipeline_layout->constant_count = constant_count;
Ben Vanike7c2cba2021-07-19 15:45:39 -0700251
252 pipeline_layout->set_layout_count = set_layout_count;
253 pipeline_layout->set_binding_info.set_count = set_layout_count;
254 for (iree_host_size_t i = 0; i < set_layout_count; ++i) {
255 pipeline_layout->set_layouts[i] = set_layouts[i];
256 iree_hal_descriptor_set_layout_retain(set_layouts[i]);
257 pipeline_layout->set_binding_info.set_layouts[i] =
258 iree_hal_webgpu_descriptor_set_layout_handle(set_layouts[i]);
259 pipeline_layout->set_binding_info.set_masks[i] =
260 iree_hal_webgpu_descriptor_set_layout_binding_mask(set_layouts[i]);
261 }
262 // Note: not tracking the empty/padding layout or the staging buffer layout.
263
264 *out_pipeline_layout = (iree_hal_pipeline_layout_t*)pipeline_layout;
265 } else {
266 iree_wgpuPipelineLayoutDrop(handle);
267 }
268
269 IREE_TRACE_ZONE_END(z0);
270 return status;
271}
272
273static void iree_hal_webgpu_pipeline_layout_destroy(
274 iree_hal_pipeline_layout_t* base_pipeline_layout) {
275 iree_hal_webgpu_pipeline_layout_t* pipeline_layout =
276 iree_hal_webgpu_pipeline_layout_cast(base_pipeline_layout);
277 iree_allocator_t host_allocator = pipeline_layout->host_allocator;
278 IREE_TRACE_ZONE_BEGIN(z0);
279
280 iree_wgpuPipelineLayoutDrop(pipeline_layout->handle);
281 for (iree_host_size_t i = 0; i < pipeline_layout->set_layout_count; ++i) {
282 iree_hal_descriptor_set_layout_release(pipeline_layout->set_layouts[i]);
283 }
284 iree_allocator_free(host_allocator, pipeline_layout);
285
286 IREE_TRACE_ZONE_END(z0);
287}
288
289WGPUPipelineLayout iree_hal_webgpu_pipeline_layout_handle(
290 iree_hal_pipeline_layout_t* layout) {
291 IREE_ASSERT_ARGUMENT(layout);
292 return iree_hal_webgpu_pipeline_layout_cast(layout)->handle;
293}
294
Ben Vanike2a2b2b2024-08-22 11:56:59 -0700295iree_host_size_t iree_hal_webgpu_pipeline_layout_constant_count(
Ben Vanike7c2cba2021-07-19 15:45:39 -0700296 iree_hal_pipeline_layout_t* layout) {
297 IREE_ASSERT_ARGUMENT(layout);
Ben Vanike2a2b2b2024-08-22 11:56:59 -0700298 return iree_hal_webgpu_pipeline_layout_cast(layout)->constant_count;
Ben Vanike7c2cba2021-07-19 15:45:39 -0700299}
300
301const iree_hal_webgpu_set_binding_info_t*
302iree_hal_webgpu_pipeline_layout_set_binding_info(
303 iree_hal_pipeline_layout_t* base_layout) {
304 IREE_ASSERT_ARGUMENT(base_layout);
305 iree_hal_webgpu_pipeline_layout_t* layout =
306 iree_hal_webgpu_pipeline_layout_cast(base_layout);
307 return &layout->set_binding_info;
308}
309
310const iree_hal_pipeline_layout_vtable_t iree_hal_webgpu_pipeline_layout_vtable =
311 {
312 .destroy = iree_hal_webgpu_pipeline_layout_destroy,
313};