#include #include #include #include #include #include #include "renderer.h" constexpr int WINDOW_WIDTH = 1280; constexpr int WINDOW_HEIGHT = 720; class Application { public: Application() : window_(nullptr), instance_(nullptr), device_(nullptr), surface_(nullptr), adapter_(nullptr) {} ~Application() { cleanup(); } bool initialize() { if (!glfwInit()) { std::cerr << "Failed to initialize GLFW" << std::endl; return false; } glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); window_ = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "TimePlot - C++ WebGPU", nullptr, nullptr); if (!window_) { std::cerr << "Failed to create window" << std::endl; return false; } glfwSetWindowUserPointer(window_, this); glfwSetKeyCallback(window_, keyCallback); glfwSetFramebufferSizeCallback(window_, resizeCallback); if (!initWebGPU()) { return false; } renderer_ = std::make_unique(device_, surface_, WINDOW_WIDTH, WINDOW_HEIGHT); if (!renderer_->initialize()) { std::cerr << "Failed to initialize renderer" << std::endl; return false; } return true; } void run() { while (!glfwWindowShouldClose(window_)) { glfwPollEvents(); renderer_->update(); renderer_->render(); } } private: static void onAdapterRequestEnded(WGPURequestAdapterStatus status, WGPUAdapter adapter, WGPUStringView message, void* userdata1, void* userdata2) { if (status == WGPURequestAdapterStatus_Success) { *static_cast(userdata1) = adapter; } else { std::cerr << "Failed to get adapter: " << std::string(message.data, message.length) << std::endl; } } static void onDeviceRequestEnded(WGPURequestDeviceStatus status, WGPUDevice device, WGPUStringView message, void* userdata1, void* userdata2) { if (status == WGPURequestDeviceStatus_Success) { *static_cast(userdata1) = device; } else { std::cerr << "Failed to get device: " << std::string(message.data, message.length) << std::endl; } } bool initWebGPU() { // Create instance WGPUInstanceDescriptor instanceDesc = {}; instanceDesc.nextInChain = nullptr; instance_ = wgpuCreateInstance(&instanceDesc); if (!instance_) { std::cerr << "Failed to create WebGPU instance" << std::endl; return false; } // Create surface from GLFW window surface_ = glfwCreateWindowWGPUSurface(instance_, window_); if (!surface_) { std::cerr << "Failed to create surface" << std::endl; return false; } // Request adapter with callback WGPURequestAdapterOptions adapterOpts = {}; adapterOpts.nextInChain = nullptr; adapterOpts.compatibleSurface = surface_; adapterOpts.powerPreference = WGPUPowerPreference_HighPerformance; WGPURequestAdapterCallbackInfo adapterCallbackInfo = {}; adapterCallbackInfo.mode = WGPUCallbackMode_AllowSpontaneous; adapterCallbackInfo.callback = onAdapterRequestEnded; adapterCallbackInfo.userdata1 = &adapter_; adapterCallbackInfo.userdata2 = nullptr; wgpuInstanceRequestAdapter(instance_, &adapterOpts, adapterCallbackInfo); // Process events until adapter is ready while (!adapter_) { wgpuInstanceProcessEvents(instance_); } // Request device with callback WGPUDeviceDescriptor deviceDesc = {}; deviceDesc.nextInChain = nullptr; deviceDesc.label = {nullptr, WGPU_STRLEN}; deviceDesc.requiredFeatureCount = 0; deviceDesc.requiredLimits = nullptr; deviceDesc.defaultQueue.nextInChain = nullptr; deviceDesc.defaultQueue.label = {nullptr, WGPU_STRLEN}; deviceDesc.deviceLostCallbackInfo.nextInChain = nullptr; deviceDesc.deviceLostCallbackInfo.mode = WGPUCallbackMode_AllowSpontaneous; deviceDesc.deviceLostCallbackInfo.callback = nullptr; deviceDesc.uncapturedErrorCallbackInfo.nextInChain = nullptr; deviceDesc.uncapturedErrorCallbackInfo.callback = nullptr; WGPURequestDeviceCallbackInfo deviceCallbackInfo = {}; deviceCallbackInfo.mode = WGPUCallbackMode_AllowSpontaneous; deviceCallbackInfo.callback = onDeviceRequestEnded; deviceCallbackInfo.userdata1 = &device_; deviceCallbackInfo.userdata2 = nullptr; wgpuAdapterRequestDevice(adapter_, &deviceDesc, deviceCallbackInfo); // Process events until device is ready while (!device_) { wgpuInstanceProcessEvents(instance_); } return true; } void cleanup() { renderer_.reset(); if (device_) { wgpuDeviceRelease(device_); device_ = nullptr; } if (adapter_) { wgpuAdapterRelease(adapter_); adapter_ = nullptr; } if (surface_) { wgpuSurfaceRelease(surface_); surface_ = nullptr; } if (instance_) { wgpuInstanceRelease(instance_); instance_ = nullptr; } if (window_) { glfwDestroyWindow(window_); window_ = nullptr; } glfwTerminate(); } static void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) { auto* app = static_cast(glfwGetWindowUserPointer(window)); if (action == GLFW_PRESS) { if (key == GLFW_KEY_ESCAPE) { glfwSetWindowShouldClose(window, GLFW_TRUE); } else if (key == GLFW_KEY_G) { app->renderer_->toggleGrid(); } } } static void resizeCallback(GLFWwindow* window, int width, int height) { auto* app = static_cast(glfwGetWindowUserPointer(window)); app->renderer_->resize(width, height); } GLFWwindow* window_; WGPUInstance instance_; WGPUAdapter adapter_; WGPUDevice device_; WGPUSurface surface_; std::unique_ptr renderer_; }; int main() { Application app; if (!app.initialize()) { return EXIT_FAILURE; } app.run(); return EXIT_SUCCESS; }