22 wgpu::Instance instance;
23 wgpu::Adapter adapter;
27 bool adapter_ready =
false;
28 bool device_ready =
false;
29 bool gpu_initialized =
false;
33 bool validate_device() {
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)
118 for (uint32_t i = 0; i < info->messageCount; ++i) {
119 const auto& msg = info->messages[i];
120 std::cerr <<
"Shader Error ["
121 << (msg.type == wgpu::CompilationMessageType::Error ?
"ERR" :
"WARN")
123 <<
" Line " << msg.lineNum <<
":" << msg.linePos <<
" - "
135 wgpu::InstanceDescriptor instanceDesc = {};
136 instance = wgpu::CreateInstance(&instanceDesc);
139 std::cerr <<
"Fatal: WebGPU instance creation failed." << std::endl;
146 std::cout <<
"Requesting Adapter..." << std::endl;
147 adapter_ready =
false;
149 instance.RequestAdapter(
151 wgpu::CallbackMode::AllowProcessEvents,
152 [
this](wgpu::RequestAdapterStatus status, wgpu::Adapter a, wgpu::StringView msg) {
153 if (status == wgpu::RequestAdapterStatus::Success) {
154 adapter = std::move(a);
155 std::cout <<
"Adapter Acquired" << std::endl;
157 std::cerr <<
"Adapter Failed: "
158 << std::string_view(msg.data ? msg.data :
"", msg.length)
161 adapter_ready =
true;
166 while (!adapter_ready) {
167 instance.ProcessEvents();
168#if defined(__EMSCRIPTEN__)
169 emscripten_sleep(10);
174 std::cerr <<
"Fatal: Could not get WebGPU Adapter." << std::endl;
181 std::cout <<
"Requesting Device..." << std::endl;
182 device_ready =
false;
184 wgpu::DeviceDescriptor deviceDesc = {};
185 deviceDesc.SetUncapturedErrorCallback([](
const wgpu::Device&, wgpu::ErrorType type,
186 wgpu::StringView msg) {
188 std::string err_str = (msg.data && msg.length > 0) ? std::string(msg.data, msg.length)
189 :
"Unknown Error (Null message)";
192 std::cerr <<
"\n[WEBGPU FATAL ERROR] Type: " <<
static_cast<uint32_t
>(type)
193 <<
" | Msg: " << err_str <<
"\n"
196 deviceDesc.SetDeviceLostCallback(
197 wgpu::CallbackMode::AllowProcessEvents,
198 [](
const wgpu::Device&, wgpu::DeviceLostReason reason, wgpu::StringView msg) {
199 std::string err_msg = (msg.data && msg.length > 0)
200 ? std::string(msg.data, msg.length)
201 :
"Unknown device lost reason";
202 std::cerr <<
"[DEVICE LOST] Reason: " <<
static_cast<int>(reason)
203 <<
" Msg: " << err_msg << std::endl;
208 wgpu::Limits supportedLimits;
209 wgpu::Limits requiredLimits;
210 if (adapter.GetLimits(&supportedLimits)) {
214 requiredLimits = supportedLimits;
216 std::cout <<
"maxBufferSize: " << requiredLimits.maxBufferSize << std::endl;
217 std::cout <<
"maxStorageBufferBindingSize: "
218 << requiredLimits.maxStorageBufferBindingSize << std::endl;
220 deviceDesc.requiredLimits = &requiredLimits;
223 adapter.RequestDevice(
225 wgpu::CallbackMode::AllowProcessEvents,
226 [
this](wgpu::RequestDeviceStatus status, wgpu::Device d, wgpu::StringView msg) {
227 if (status == wgpu::RequestDeviceStatus::Success) {
228 device = std::move(d);
229 std::cout <<
"Device Acquired" << std::endl;
231 std::cerr <<
"Device Failed: "
232 << (msg.data && msg.length > 0 ? std::string(msg.data, msg.length)
241 while (!device_ready) {
242 instance.ProcessEvents();
243#if defined(__EMSCRIPTEN__)
244 emscripten_sleep(10);
249 std::cerr <<
"Fatal: Could not get WebGPU Device." << std::endl;
253 if (!validate_device()) {
254 std::cerr <<
"Fatal: Could not get WebGPU Device." << std::endl;
258 queue = device.GetQueue();
259 gpu_initialized =
true;
260 std::cout <<
"GPU Fully Initialized." << std::endl;
268 gpu_initialized =
false;