UFO 1.0.0
An Efficient Probabilistic 3D Mapping Framework That Embraces the Unknown
Loading...
Searching...
No Matches
compute.cpp
1
42// UFO
43#include <ufo/compute/compute.hpp>
44
45// STL
46#include <cassert>
47#include <cstring>
48#include <format>
49#include <fstream>
50#include <iostream>
51#include <string>
52#include <string_view>
53
54namespace ufo::compute
55{
56WGPUInstance createInstance(WGPUInstanceDescriptor const* descriptor)
57{
58 WGPUInstance instance = wgpuCreateInstance(descriptor);
59 assert(nullptr != instance);
60 return instance;
61}
62
63WGPUAdapter createAdapter(WGPUInstance instance, WGPUSurface compatible_surface,
64 WGPUPowerPreference power_preference,
65 WGPUBackendType backend_type, WGPUBool force_fallback_adapter)
66{
67 assert(nullptr != instance);
68
69 WGPUAdapter adapter = nullptr;
70 bool request_ended = false;
71
72 WGPURequestAdapterOptions options = WGPU_REQUEST_ADAPTER_OPTIONS_INIT;
73 options.powerPreference = power_preference;
74 options.compatibleSurface = compatible_surface;
75 options.backendType = backend_type;
76 options.forceFallbackAdapter = force_fallback_adapter;
77
78 WGPURequestAdapterCallbackInfo callback_info = WGPU_REQUEST_ADAPTER_CALLBACK_INFO_INIT;
79
80 callback_info.callback = [](WGPURequestAdapterStatus status, WGPUAdapter adapter,
81 WGPUStringView message, void* userdata1, void* userdata2) {
82 if (WGPURequestAdapterStatus_Success == status) {
83 *static_cast<WGPUAdapter*>(userdata1) = adapter;
84 } else {
85 std::cerr << "Could not get WebGPU adapter: " << message.data << std::endl;
86 }
87 *static_cast<bool*>(userdata2) = true;
88 };
89 callback_info.userdata1 = static_cast<void*>(&adapter);
90 callback_info.userdata2 = static_cast<void*>(&request_ended);
91
92 wgpuInstanceRequestAdapter(instance, &options, callback_info);
93
94 // We wait until request_ended gets true
95#ifdef __EMSCRIPTEN__
96 while (!request_ended) {
97 emscripten_sleep(100);
98 }
99#endif // __EMSCRIPTEN__
100
101 assert(request_ended);
102 assert(nullptr != adapter);
103
104 return adapter;
105}
106
107WGPUDevice createDevice(WGPUAdapter adapter, WGPULimits const* required_limits)
108{
109 assert(nullptr != adapter);
110
111 WGPUDevice device = nullptr;
112 bool request_ended = false;
113
114 WGPUDeviceDescriptor desc = WGPU_DEVICE_DESCRIPTOR_INIT;
115 // desc.label = (window_name_ + " Device").c_str();
116 // desc.requiredFeatureCount = 0;
117 // desc.requiredFeatures = nullptr;
118
119 desc.requiredLimits = required_limits;
120
121 // desc.defaultQueue.label = (window_name_ + " Default Queue").c_str();
122
123 // TODO: Fix
124 // desc.deviceLostCallbackInfo.callback =
125 // [](WGPUDeviceImpl* const, WGPUDeviceLostReason reason, WGPUStringView message,
126 // void* /* userdata1 */, void* /* userdata2 */) {
127 // std::cout << "Device lost: reason " << reason;
128 // if (0 < message.length) {
129 // std::cout << " (" << message.data << ")";
130 // }
131 // std::cout << std::endl;
132 // };
133
134 // desc.uncapturedErrorCallbackInfo.nextInChain = nullptr;
135 // desc.uncapturedErrorCallbackInfo.userdata = nullptr;
136 // desc.uncapturedErrorCallbackInfo.callback = nullptr;
137
138 WGPURequestDeviceCallbackInfo callback_info = WGPU_REQUEST_DEVICE_CALLBACK_INFO_INIT;
139
140 callback_info.callback = [](WGPURequestDeviceStatus status, WGPUDevice device,
141 WGPUStringView message, void* userdata1, void* userdata2) {
142 if (WGPURequestDeviceStatus_Success == status) {
143 *static_cast<WGPUDevice*>(userdata1) = device;
144 } else {
145 std::cout << "Could not get WebGPU device: " << message.data << std::endl;
146 }
147 *static_cast<bool*>(userdata2) = true;
148 };
149 callback_info.userdata1 = static_cast<void*>(&device);
150 callback_info.userdata2 = static_cast<void*>(&request_ended);
151
152 wgpuAdapterRequestDevice(adapter, &desc, callback_info);
153
154 // We wait until request_ended gets true
155#ifdef __EMSCRIPTEN__
156 while (!request_ended) {
157 emscripten_sleep(100);
158 }
159#endif // __EMSCRIPTEN__
160
161 assert(request_ended);
162 assert(nullptr != device);
163
164 return device;
165}
166
167WGPUQueue queue(WGPUDevice device)
168{
169 assert(nullptr != device);
170 return wgpuDeviceGetQueue(device);
171}
172
173std::size_t bufferPaddedSize(std::size_t size)
174{
175 static constexpr std::size_t const COPY_BUFFER_ALIGNMENT = 4;
176 static constexpr std::size_t const align_mask = COPY_BUFFER_ALIGNMENT - 1;
177 return std::max((size + align_mask) & ~align_mask, COPY_BUFFER_ALIGNMENT);
178}
179
180std::size_t bufferPaddedSize(std::size_t width, std::size_t bytes_per_pixel)
181{
182 static constexpr std::size_t const COPY_BYTES_PER_ROW_ALIGNMENT = 256;
183
184 std::size_t const unpadded_bytes_per_row = width * bytes_per_pixel;
185 std::size_t const padded_bytes_per_row_padding =
186 (COPY_BYTES_PER_ROW_ALIGNMENT -
187 unpadded_bytes_per_row % COPY_BYTES_PER_ROW_ALIGNMENT) %
188 COPY_BYTES_PER_ROW_ALIGNMENT;
189 return unpadded_bytes_per_row + padded_bytes_per_row_padding;
190}
191
192WGPUBuffer createBuffer(WGPUDevice device, std::string label, std::size_t size,
193 WGPUBufferUsage usage, bool mapped_at_creation)
194{
195 std::size_t padded_size = bufferPaddedSize(size);
196
197 WGPUBufferDescriptor desc = WGPU_BUFFER_DESCRIPTOR_INIT;
198 desc.label = {label.c_str(), label.length()};
199 desc.size = padded_size;
200 desc.usage = usage;
201 desc.mappedAtCreation = mapped_at_creation;
202 return wgpuDeviceCreateBuffer(device, &desc);
203}
204
205WGPUBuffer createBufferInit(WGPUDevice device, std::string label, WGPUBufferUsage usage,
206 void* content, std::size_t content_size)
207{
208 if (0 == content_size) {
209 return createBuffer(device, label, 0, usage, false);
210 }
211
212 WGPUBuffer buffer = createBuffer(device, label, content_size, usage, true);
213
214 assert(nullptr != buffer);
215
216 void* buf = wgpuBufferGetMappedRange(buffer, 0, content_size);
217 std::memcpy(buf, content, content_size);
218 wgpuBufferUnmap(buffer);
219
220 return buffer;
221}
222
223WGPUSurfaceCapabilities surfaceCapabilities(WGPUSurface surface, WGPUAdapter adapter)
224{
225 WGPUSurfaceCapabilities surface_capabilities = WGPU_SURFACE_CAPABILITIES_INIT;
226 wgpuSurfaceGetCapabilities(surface, adapter, &surface_capabilities);
227 return surface_capabilities;
228}
229
230WGPUShaderModule loadShaderModule(WGPUDevice device, std::filesystem::path const& path)
231{
232 std::ifstream file(path);
233 if (!file.is_open()) {
234 return nullptr;
235 }
236
237 file.seekg(0, std::ios::end);
238 std::size_t size = file.tellg();
239 std::string shader_source(size, ' ');
240 file.seekg(0);
241 file.read(shader_source.data(), size);
242
243 WGPUShaderSourceWGSL shader_wgsl = WGPU_SHADER_SOURCE_WGSL_INIT;
244 shader_wgsl.chain.sType = WGPUSType_ShaderSourceWGSL;
245 // FIXME: Should this be `shader_source.length()`?
246 shader_wgsl.code = {shader_source.c_str(), WGPU_STRLEN};
247
248 WGPUShaderModuleDescriptor shader_desc = WGPU_SHADER_MODULE_DESCRIPTOR_INIT;
249 // TODO: shader_code_desc.label
250 shader_desc.nextInChain = reinterpret_cast<WGPUChainedStruct const*>(&shader_wgsl);
251
252 return wgpuDeviceCreateShaderModule(device, &shader_desc);
253}
254
255// Release
256
257void release(WGPUInstance instance) { wgpuInstanceRelease(instance); }
258
259void release(WGPUSurface surface) { wgpuSurfaceRelease(surface); }
260
261void release(WGPUAdapter adapter) { wgpuAdapterRelease(adapter); }
262
263void release(WGPUDevice device) { wgpuDeviceRelease(device); }
264
265void release(WGPUQueue queue) { wgpuQueueRelease(queue); }
266
267void release(WGPUShaderModule shader_module) { wgpuShaderModuleRelease(shader_module); }
268
269void release(WGPUBindGroupLayout bind_group_layout)
270{
271 wgpuBindGroupLayoutRelease(bind_group_layout);
272}
273
274void release(WGPUPipelineLayout pipeline_layout)
275{
276 wgpuPipelineLayoutRelease(pipeline_layout);
277}
278
279void release(WGPURenderPipeline render_pipeline)
280{
281 wgpuRenderPipelineRelease(render_pipeline);
282}
283
284void release(WGPUTexture texture) { wgpuTextureRelease(texture); }
285
286void release(WGPUTextureView texture_view) { wgpuTextureViewRelease(texture_view); }
287
288void release(WGPURenderPassEncoder render_pass_encoder)
289{
290 wgpuRenderPassEncoderRelease(render_pass_encoder);
291}
292
293void release(WGPUCommandEncoder command_encoder)
294{
295 wgpuCommandEncoderRelease(command_encoder);
296}
297
298void release(WGPUCommandBuffer command_buffer)
299{
300 wgpuCommandBufferRelease(command_buffer);
301}
302
303void release(WGPUSampler sampler) { wgpuSamplerRelease(sampler); }
304
305GPUInfo gpuInfo(WGPUAdapter adapter)
306{
307 bool const adapter_was_passed = (nullptr != adapter);
308
309 WGPUInstance instance = nullptr;
310 if (!adapter_was_passed) {
311 instance = createInstance();
312 if (nullptr == instance) {
313 return GPUInfo{};
314 }
315
316 adapter = createAdapter(instance);
317 if (nullptr == adapter) {
318 release(instance);
319 return GPUInfo{};
320 }
321 }
322
323 WGPUAdapterInfo info = {};
324 wgpuAdapterGetInfo(adapter, &info);
325
326 GPUInfo gpu_info = {};
327 gpu_info.name = std::string_view(info.device.data, info.device.length);
328 gpu_info.architecture =
329 std::string_view(info.architecture.data, info.architecture.length);
330 gpu_info.description = std::string_view(info.description.data, info.description.length);
331
332 gpu_info.vendor = [id = info.vendorID, v = info.vendor.data] {
333 switch (id) {
334 case 0x10DE: return "NVIDIA";
335 case 0x1002: return "AMD";
336 case 0x8086: return "Intel";
337 case 0x13B5: return "ARM";
338 case 0x5143: return "Qualcomm";
339 case 0x106B: return "Apple";
340 default: return v;
341 }
342 }();
343
344 gpu_info.type = [t = info.adapterType] {
345 switch (t) {
346 case WGPUAdapterType_DiscreteGPU: return "Discrete GPU";
347 case WGPUAdapterType_IntegratedGPU: return "Integrated GPU";
348 case WGPUAdapterType_CPU: return "CPU";
349 case WGPUAdapterType_Unknown: return "Unknown";
350 default: return "Other";
351 }
352 }();
353
354 gpu_info.backend = [b = info.backendType] {
355 switch (b) {
356 case WGPUBackendType_WebGPU: return "WebGPU";
357 case WGPUBackendType_D3D11: return "D3D11";
358 case WGPUBackendType_D3D12: return "D3D12";
359 case WGPUBackendType_Metal: return "Metal";
360 case WGPUBackendType_Vulkan: return "Vulkan";
361 case WGPUBackendType_OpenGL: return "OpenGL";
362 case WGPUBackendType_OpenGLES: return "OpenGLES";
363 default: return "Unknown";
364 }
365 }();
366
367 wgpuAdapterInfoFreeMembers(info);
368 if (!adapter_was_passed) {
369 release(adapter);
370 release(instance);
371 }
372
373 return gpu_info;
374}
375
376std::vector<GPUInfo> gpusInfo()
377{
378 WGPUInstance instance = createInstance();
379 if (nullptr == instance) {
380 return {};
381 }
382
383 size_t count = wgpuInstanceEnumerateAdapters(instance, nullptr, nullptr);
384 if (0 == count) {
385 release(instance);
386 return {};
387 }
388
389 std::vector<WGPUAdapter> adapters(count);
390 wgpuInstanceEnumerateAdapters(instance, nullptr, adapters.data());
391
392 std::vector<GPUInfo> res;
393 res.reserve(count);
394 for (auto adapter : adapters) {
395 res.push_back(gpuInfo(adapter));
396 release(adapter);
397 }
398
399 release(instance);
400
401 return res;
402}
403} // namespace ufo::compute
constexpr T b(Lab< T, Flags > color) noexcept
Returns the un-weighted blue–yellow axis value.
Definition lab.hpp:326