23 wgpu::Instance instance;
24 wgpu::Adapter adapter;
28 bool adapter_ready =
false;
29 bool device_ready =
false;
30 bool gpu_initialized =
false;
34 bool validate_device() {
39 wgpu::BufferDescriptor desc = {};
41 desc.usage = wgpu::BufferUsage::CopyDst;
43 wgpu::Buffer test = device.CreateBuffer(&desc);
44 return test !=
nullptr;
49 static GPU& getClassInstance() {
50 static GPU gpuInstance;
54 const wgpu::Device& get_device() {
58 const wgpu::Instance& get_instance() {
62 const wgpu::Queue& get_queue() {
66 bool is_initialized() {
67 return gpu_initialized;
72 GPU& operator=(
const GPU&) =
delete;
74 GPU& operator=(
GPU&&) =
delete;
76 std::string readWGSLFile(std::string_view shader_id) {
78 for (
const auto& entry : embedded_shaders::shaders) {
79 if (entry.id == shader_id) {
81 return std::string(entry.source);
89 wgpu::ComputePipeline createPipeline(
const std::string& filename,
const std::string& label) {
90 wgpu::ShaderSourceWGSL wgsl;
91 std::string shaderCode = readWGSLFile(filename);
92 wgsl.code = shaderCode.c_str();
93 wgpu::ShaderModuleDescriptor md = {};
94 md.nextInChain = &wgsl;
95 md.label = label.c_str();
96 wgpu::ShaderModule sm = device.CreateShaderModule(&md);
98 wgpu::ComputePipelineDescriptor cpd = {};
99 cpd.compute.module = sm;
100 cpd.compute.entryPoint =
"main";
101 return device.CreateComputePipeline(&cpd);
104 static uint32_t getAlignedBytesPerRow(uint32_t width, uint32_t bytesPerPixel = 4) {
105 uint32_t unaligned = width * bytesPerPixel;
106 uint32_t align = 256;
107 return (unaligned + align - 1) & ~(align - 1);
110 static void printShaderError(wgpu::ShaderModule shaderModule) {
111 shaderModule.GetCompilationInfo(
113 wgpu::CallbackMode::AllowProcessEvents,
115 [](wgpu::CompilationInfoRequestStatus status,
const wgpu::CompilationInfo* info) {
116 if (status != wgpu::CompilationInfoRequestStatus::Success || !info)
119 for (uint32_t i = 0; i < info->messageCount; ++i) {
120 const auto& msg = info->messages[i];
122 "Shader Error [{}] Line {}:{} - {}",
123 msg.type == wgpu::CompilationMessageType::Error ?
"ERR" :
"WARN",
124 msg.lineNum, msg.linePos,
126 msg.message.data ? msg.message.data :
"", msg.message.length
138 wgpu::InstanceDescriptor instanceDesc = {};
139 instance = wgpu::CreateInstance(&instanceDesc);
142 IMG2NUM_LOG_INFO(
"Fatal: WebGPU instance creation failed.");
149 IMG2NUM_LOG_INFO(
"Requesting Adapter...");
150 adapter_ready =
false;
152 instance.RequestAdapter(
154 wgpu::CallbackMode::AllowProcessEvents,
155 [
this](wgpu::RequestAdapterStatus status, wgpu::Adapter a, wgpu::StringView msg) {
156 if (status == wgpu::RequestAdapterStatus::Success) {
157 adapter = std::move(a);
158 IMG2NUM_LOG_INFO(
"Adapter Acquired");
161 "Adapter Failed: {}", std::string_view(msg.data ? msg.data :
"", msg.length)
164 adapter_ready =
true;
169 while (!adapter_ready) {
170 instance.ProcessEvents();
171#if defined(__EMSCRIPTEN__)
172 emscripten_sleep(10);
177 IMG2NUM_LOG_INFO(
"Fatal: Could not get WebGPU Adapter.");
184 IMG2NUM_LOG_INFO(
"Requesting Device...");
185 device_ready =
false;
187 wgpu::DeviceDescriptor deviceDesc = {};
188 deviceDesc.SetUncapturedErrorCallback([](
const wgpu::Device&, wgpu::ErrorType type,
189 wgpu::StringView msg) {
191 std::string err_str = (msg.data && msg.length > 0) ? std::string(msg.data, msg.length)
192 :
"Unknown Error (Null message)";
196 "\n[WEBGPU FATAL ERROR] Type: {} | Msg: {}\n",
static_cast<uint32_t
>(type), err_str
199 deviceDesc.SetDeviceLostCallback(
200 wgpu::CallbackMode::AllowProcessEvents,
201 [](
const wgpu::Device&, wgpu::DeviceLostReason reason, wgpu::StringView msg) {
202 std::string err_msg = (msg.data && msg.length > 0)
203 ? std::string(msg.data, msg.length)
204 :
"Unknown device lost reason";
206 if (reason == wgpu::DeviceLostReason::CallbackCancelled) {
210 "[DEVICE LOST] Reason: {} Msg: {}",
static_cast<int>(reason), err_msg
216 wgpu::Limits supportedLimits;
217 wgpu::Limits requiredLimits;
218 if (adapter.GetLimits(&supportedLimits)) {
222 requiredLimits = supportedLimits;
224 IMG2NUM_LOG_INFO(
"maxBufferSize: {}", requiredLimits.maxBufferSize);
226 "maxStorageBufferBindingSize: {}", requiredLimits.maxStorageBufferBindingSize
229 deviceDesc.requiredLimits = &requiredLimits;
232 adapter.RequestDevice(
234 wgpu::CallbackMode::AllowProcessEvents,
235 [
this](wgpu::RequestDeviceStatus status, wgpu::Device d, wgpu::StringView msg) {
236 if (status == wgpu::RequestDeviceStatus::Success) {
237 device = std::move(d);
238 IMG2NUM_LOG_INFO(
"Device Acquired");
241 "Device Failed: {}", msg.data && msg.length > 0
242 ? std::string(msg.data, msg.length)
251 while (!device_ready) {
252 instance.ProcessEvents();
253#if defined(__EMSCRIPTEN__)
254 emscripten_sleep(10);
259 IMG2NUM_LOG_INFO(
"Fatal: Could not get WebGPU Device.");
263 if (!validate_device()) {
264 IMG2NUM_LOG_INFO(
"Fatal: Could not get WebGPU Device.");
268 queue = device.GetQueue();
269 gpu_initialized =
true;
270 IMG2NUM_LOG_INFO(
"GPU Fully Initialized.");
278 gpu_initialized =
false;