1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
#include <GLFW/glfw3.h>
#include <webgpu/webgpu.hpp>
#include <glfw3webgpu.h>
#include <iostream>
#include <memory>
#include <cstdlib>
#include "renderer.h"
constexpr int WINDOW_WIDTH = 1280;
constexpr int WINDOW_HEIGHT = 720;
class Application {
public:
Application() : window_(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<Renderer>(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:
bool initWebGPU() {
// Create instance
instance_ = wgpu::createInstance(wgpu::InstanceDescriptor{});
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 (synchronous version)
wgpu::RequestAdapterOptions adapterOpts{};
adapterOpts.compatibleSurface = surface_;
wgpu::Adapter adapter = instance_.requestAdapter(adapterOpts);
if (!adapter) {
std::cerr << "Failed to get adapter" << std::endl;
return false;
}
// Request device (synchronous version)
wgpu::DeviceDescriptor deviceDesc{};
device_ = adapter.requestDevice(deviceDesc);
if (!device_) {
std::cerr << "Failed to get device" << std::endl;
return false;
}
return true;
}
void cleanup() {
renderer_.reset();
if (window_) {
glfwDestroyWindow(window_);
window_ = nullptr;
}
glfwTerminate();
}
static void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) {
auto* app = static_cast<Application*>(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<Application*>(glfwGetWindowUserPointer(window));
app->renderer_->resize(width, height);
}
GLFWwindow* window_;
wgpu::Instance instance_;
wgpu::Device device_;
wgpu::Surface surface_;
std::unique_ptr<Renderer> renderer_;
};
int main() {
Application app;
if (!app.initialize()) {
return EXIT_FAILURE;
}
app.run();
return EXIT_SUCCESS;
}
|