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() {
35 if (!device)
return false;
38 wgpu::BufferDescriptor desc = {};
40 desc.usage = wgpu::BufferUsage::CopyDst;
42 wgpu::Buffer test = device.CreateBuffer(&desc);
43 return test !=
nullptr;
48 static GPU& getClassInstance() {
49 static GPU gpuInstance;
53 const wgpu::Device& get_device() {
57 const wgpu::Instance& get_instance() {
61 const wgpu::Queue& get_queue() {
65 bool is_initialized() {
66 return gpu_initialized;
71 GPU& operator=(
const GPU&) =
delete;
73 GPU& operator=(
GPU&&) =
delete;
75 std::string readWGSLFile(std::string_view shader_id) {
77 for (
const auto& entry : embedded_shaders::shaders) {
78 if (entry.id == shader_id) {
80 return std::string(entry.source);
88 wgpu::ComputePipeline createPipeline(
const std::string& filename,
const std::string& label) {
89 wgpu::ShaderSourceWGSL wgsl;
90 std::string shaderCode = readWGSLFile(filename);
91 wgsl.code = shaderCode.c_str();
92 wgpu::ShaderModuleDescriptor md = {};
93 md.nextInChain = &wgsl;
94 md.label = label.c_str();
95 wgpu::ShaderModule sm = device.CreateShaderModule(&md);
97 wgpu::ComputePipelineDescriptor cpd = {};
98 cpd.compute.module = sm;
99 cpd.compute.entryPoint =
"main";
100 return device.CreateComputePipeline(&cpd);
103 static uint32_t getAlignedBytesPerRow(uint32_t width, uint32_t bytesPerPixel = 4) {
104 uint32_t unaligned = width * bytesPerPixel;
105 uint32_t align = 256;
106 return (unaligned + align - 1) & ~(align - 1);
109 static void printShaderError(wgpu::ShaderModule shaderModule) {
110 shaderModule.GetCompilationInfo(
112 wgpu::CallbackMode::AllowProcessEvents,
114 [](wgpu::CompilationInfoRequestStatus status,
const wgpu::CompilationInfo* info) {
115 if (status != wgpu::CompilationInfoRequestStatus::Success || !info)
return;
117 for (uint32_t i = 0; i < info->messageCount; ++i) {
118 const auto& msg = info->messages[i];
119 std::cerr <<
"Shader Error ["
120 << (msg.type == wgpu::CompilationMessageType::Error ?
"ERR" :
"WARN")
122 <<
" Line " << msg.lineNum <<
":" << msg.linePos <<
" - "
131 if (gpu_initialized)
return;
133 wgpu::InstanceDescriptor instanceDesc = {};
134 instance = wgpu::CreateInstance(&instanceDesc);
137 std::cerr <<
"Fatal: WebGPU instance creation failed." << std::endl;
144 std::cout <<
"Requesting Adapter..." << std::endl;
145 adapter_ready =
false;
147 instance.RequestAdapter(
149 wgpu::CallbackMode::AllowProcessEvents,
150 [
this](wgpu::RequestAdapterStatus status, wgpu::Adapter a, wgpu::StringView msg) {
151 if (status == wgpu::RequestAdapterStatus::Success) {
152 adapter = std::move(a);
153 std::cout <<
"Adapter Acquired" << std::endl;
155 std::cerr <<
"Adapter Failed: "
156 << std::string_view(msg.data ? msg.data :
"", msg.length)
159 adapter_ready =
true;
163 while (!adapter_ready) {
164 instance.ProcessEvents();
165#if defined(__EMSCRIPTEN__)
166 emscripten_sleep(10);
171 std::cerr <<
"Fatal: Could not get WebGPU Adapter." << std::endl;
178 std::cout <<
"Requesting Device..." << std::endl;
179 device_ready =
false;
181 wgpu::DeviceDescriptor deviceDesc = {};
182 deviceDesc.SetUncapturedErrorCallback([](
const wgpu::Device&, wgpu::ErrorType type,
183 wgpu::StringView msg) {
185 std::string err_str = (msg.data && msg.length > 0) ? std::string(msg.data, msg.length)
186 :
"Unknown Error (Null message)";
189 std::cerr <<
"\n[WEBGPU FATAL ERROR] Type: " <<
static_cast<uint32_t
>(type)
190 <<
" | Msg: " << err_str <<
"\n"
193 deviceDesc.SetDeviceLostCallback(
194 wgpu::CallbackMode::AllowProcessEvents,
195 [](
const wgpu::Device&, wgpu::DeviceLostReason reason, wgpu::StringView msg) {
196 std::string err_msg = (msg.data && msg.length > 0)
197 ? std::string(msg.data, msg.length)
198 :
"Unknown device lost reason";
199 std::cerr <<
"[DEVICE LOST] Reason: " <<
static_cast<int>(reason)
200 <<
" Msg: " << err_msg << std::endl;
204 wgpu::Limits supportedLimits;
205 wgpu::Limits requiredLimits;
206 if (adapter.GetLimits(&supportedLimits)) {
210 requiredLimits = supportedLimits;
212 std::cout <<
"maxBufferSize: " << requiredLimits.maxBufferSize << std::endl;
213 std::cout <<
"maxStorageBufferBindingSize: "
214 << requiredLimits.maxStorageBufferBindingSize << std::endl;
216 deviceDesc.requiredLimits = &requiredLimits;
219 adapter.RequestDevice(
221 wgpu::CallbackMode::AllowProcessEvents,
222 [
this](wgpu::RequestDeviceStatus status, wgpu::Device d, wgpu::StringView msg) {
223 if (status == wgpu::RequestDeviceStatus::Success) {
224 device = std::move(d);
225 std::cout <<
"Device Acquired" << std::endl;
227 std::cerr <<
"Device Failed: " << msg.data << std::endl;
233 while (!device_ready) {
234 instance.ProcessEvents();
235#if defined(__EMSCRIPTEN__)
236 emscripten_sleep(10);
241 std::cerr <<
"Fatal: Could not get WebGPU Device." << std::endl;
245 if (!validate_device()) {
246 std::cerr <<
"Fatal: Could not get WebGPU Device." << std::endl;
250 queue = device.GetQueue();
251 gpu_initialized =
true;
252 std::cout <<
"GPU Fully Initialized." << std::endl;