summaryrefslogtreecommitdiff
path: root/src/gpu
diff options
context:
space:
mode:
authorskal <pascal.massimino@gmail.com>2026-02-02 15:55:03 +0100
committerskal <pascal.massimino@gmail.com>2026-02-02 15:55:03 +0100
commitc194f59e171a1e58ce1704f37d99ffcd09a42433 (patch)
treef77a32f2c4c23b335209b8df11cc82920388b51a /src/gpu
parent316825883c705ed0fe927c32e072f98141d3eaa3 (diff)
fix(gpu): Resolve high-DPI squished rendering and 3D shadow bugs
- Implemented dynamic resolution support in all shaders and effects. - Added explicit viewport setting for all render passes to ensure correct scaling. - Fixed 3D shadow mapping by adding PLANE support and standardizing soft shadow logic. - Propagated resize events through the Effect hierarchy. - Applied project-wide code formatting.
Diffstat (limited to 'src/gpu')
-rw-r--r--src/gpu/effect.cc40
-rw-r--r--src/gpu/effect.h10
-rw-r--r--src/gpu/effects/chroma_aberration_effect.cc6
-rw-r--r--src/gpu/effects/distort_effect.cc6
-rw-r--r--src/gpu/effects/gaussian_blur_effect.cc6
-rw-r--r--src/gpu/effects/hybrid_3d_effect.cc2
-rw-r--r--src/gpu/effects/hybrid_3d_effect.h2
-rw-r--r--src/gpu/effects/moving_ellipse_effect.cc6
-rw-r--r--src/gpu/effects/particle_spray_effect.cc6
-rw-r--r--src/gpu/effects/passthrough_effect.cc6
-rw-r--r--src/gpu/effects/shaders.cc28
-rw-r--r--src/gpu/effects/solarize_effect.cc6
-rw-r--r--src/gpu/gpu.cc10
-rw-r--r--src/gpu/gpu.h4
14 files changed, 99 insertions, 39 deletions
diff --git a/src/gpu/effect.cc b/src/gpu/effect.cc
index f115ac5..f24fa96 100644
--- a/src/gpu/effect.cc
+++ b/src/gpu/effect.cc
@@ -150,13 +150,17 @@ void MainSequence::init(WGPUDevice d, WGPUQueue q, WGPUTextureFormat f,
device = d;
queue = q;
format = f;
+ width_ = width;
+ height_ = height;
create_framebuffers(width, height);
passthrough_effect_ =
std::make_unique<PassthroughEffect>(device, queue, format);
+ passthrough_effect_->resize(width, height);
for (ActiveSequence& entry : sequences_) {
entry.seq->init(this);
+ entry.seq->resize(width, height);
}
}
@@ -166,6 +170,7 @@ void MainSequence::add_sequence(std::shared_ptr<Sequence> seq, float start_time,
// If MainSequence is already initialized, init the new sequence immediately
if (device) {
seq->init(this);
+ seq->resize(width_, height_);
}
std::sort(sequences_.begin(), sequences_.end(),
[](const ActiveSequence& a, const ActiveSequence& b) {
@@ -174,17 +179,29 @@ void MainSequence::add_sequence(std::shared_ptr<Sequence> seq, float start_time,
}
void MainSequence::resize(int width, int height) {
+ width_ = width;
+ height_ = height;
// Release old resources
- if (framebuffer_view_a_) wgpuTextureViewRelease(framebuffer_view_a_);
- if (framebuffer_a_) wgpuTextureRelease(framebuffer_a_);
- if (framebuffer_view_b_) wgpuTextureViewRelease(framebuffer_view_b_);
- if (framebuffer_b_) wgpuTextureRelease(framebuffer_b_);
- if (depth_view_) wgpuTextureViewRelease(depth_view_);
- if (depth_texture_) wgpuTextureRelease(depth_texture_);
+ if (framebuffer_view_a_)
+ wgpuTextureViewRelease(framebuffer_view_a_);
+ if (framebuffer_a_)
+ wgpuTextureRelease(framebuffer_a_);
+ if (framebuffer_view_b_)
+ wgpuTextureViewRelease(framebuffer_view_b_);
+ if (framebuffer_b_)
+ wgpuTextureRelease(framebuffer_b_);
+ if (depth_view_)
+ wgpuTextureViewRelease(depth_view_);
+ if (depth_texture_)
+ wgpuTextureRelease(depth_texture_);
// Recreate with new size
create_framebuffers(width, height);
+ if (passthrough_effect_) {
+ passthrough_effect_->resize(width, height);
+ }
+
// Propagate to all sequences
for (ActiveSequence& entry : sequences_) {
entry.seq->resize(width, height);
@@ -193,6 +210,11 @@ void MainSequence::resize(int width, int height) {
void MainSequence::render_frame(float global_time, float beat, float peak,
float aspect_ratio, WGPUSurface surface) {
+ static bool first_frame = true;
+ if (first_frame) {
+ printf("MainSequence First Frame: %dx%d\n", width_, height_);
+ first_frame = false;
+ }
WGPUCommandEncoder encoder = wgpuDeviceCreateCommandEncoder(device, nullptr);
std::vector<SequenceItem*> scene_effects;
@@ -242,6 +264,8 @@ void MainSequence::render_frame(float global_time, float beat, float peak,
&depth_attachment};
WGPURenderPassEncoder scene_pass =
wgpuCommandEncoderBeginRenderPass(encoder, &scene_desc);
+ wgpuRenderPassEncoderSetViewport(scene_pass, 0.0f, 0.0f, (float)width_,
+ (float)height_, 0.0f, 1.0f);
for (const SequenceItem* item : scene_effects) {
item->effect->render(scene_pass, global_time - item->start_time, beat, peak,
aspect_ratio);
@@ -273,6 +297,8 @@ void MainSequence::render_frame(float global_time, float beat, float peak,
.colorAttachmentCount = 1, .colorAttachments = &final_attachment};
WGPURenderPassEncoder final_pass =
wgpuCommandEncoderBeginRenderPass(encoder, &final_desc);
+ wgpuRenderPassEncoderSetViewport(final_pass, 0.0f, 0.0f, (float)width_,
+ (float)height_, 0.0f, 1.0f);
passthrough_effect_->render(final_pass, 0, 0, 0, aspect_ratio);
wgpuRenderPassEncoderEnd(final_pass);
} else {
@@ -307,6 +333,8 @@ void MainSequence::render_frame(float global_time, float beat, float peak,
.colorAttachments = &pp_attachment};
WGPURenderPassEncoder pp_pass =
wgpuCommandEncoderBeginRenderPass(encoder, &pp_desc);
+ wgpuRenderPassEncoderSetViewport(pp_pass, 0.0f, 0.0f, (float)width_,
+ (float)height_, 0.0f, 1.0f);
pp->render(pp_pass, global_time - post_effects[i]->start_time, beat, peak,
aspect_ratio);
wgpuRenderPassEncoderEnd(pp_pass);
diff --git a/src/gpu/effect.h b/src/gpu/effect.h
index e7453c7..7e5e2ce 100644
--- a/src/gpu/effect.h
+++ b/src/gpu/effect.h
@@ -33,7 +33,10 @@ class Effect {
}
virtual void render(WGPURenderPassEncoder pass, float time, float beat,
float intensity, float aspect_ratio) = 0;
- virtual void resize(int width, int height) {}
+ virtual void resize(int width, int height) {
+ width_ = width;
+ height_ = height;
+ }
virtual void end() {
}
@@ -46,6 +49,8 @@ class Effect {
WGPUDevice device_;
WGPUQueue queue_;
GpuBuffer uniforms_;
+ int width_ = 1280;
+ int height_ = 720;
};
class PostProcessEffect : public Effect {
@@ -123,6 +128,9 @@ class MainSequence {
};
std::vector<ActiveSequence> sequences_;
+ int width_ = 1280;
+ int height_ = 720;
+
WGPUTexture framebuffer_a_ = nullptr;
WGPUTextureView framebuffer_view_a_ = nullptr;
WGPUTexture framebuffer_b_ = nullptr;
diff --git a/src/gpu/effects/chroma_aberration_effect.cc b/src/gpu/effects/chroma_aberration_effect.cc
index ef9e963..6e64988 100644
--- a/src/gpu/effects/chroma_aberration_effect.cc
+++ b/src/gpu/effects/chroma_aberration_effect.cc
@@ -10,7 +10,7 @@ ChromaAberrationEffect::ChromaAberrationEffect(WGPUDevice device,
WGPUTextureFormat format)
: PostProcessEffect(device, queue) {
uniforms_ =
- gpu_create_buffer(device_, sizeof(float) * 4,
+ gpu_create_buffer(device_, sizeof(float) * 6,
WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst);
pipeline_ = create_post_process_pipeline(device_, format,
chroma_aberration_shader_wgsl);
@@ -18,8 +18,8 @@ ChromaAberrationEffect::ChromaAberrationEffect(WGPUDevice device,
void ChromaAberrationEffect::render(WGPURenderPassEncoder pass, float t,
float b, float i, float a) {
struct {
- float t, b, i, a;
- } u = {t, b, i, a};
+ float t, b, i, a, w, h;
+ } u = {t, b, i, a, (float)width_, (float)height_};
wgpuQueueWriteBuffer(queue_, uniforms_.buffer, 0, &u, sizeof(u));
PostProcessEffect::render(pass, t, b, i, a);
}
diff --git a/src/gpu/effects/distort_effect.cc b/src/gpu/effects/distort_effect.cc
index d9aa308..0d4bb36 100644
--- a/src/gpu/effects/distort_effect.cc
+++ b/src/gpu/effects/distort_effect.cc
@@ -9,7 +9,7 @@ DistortEffect::DistortEffect(WGPUDevice device, WGPUQueue queue,
WGPUTextureFormat format)
: PostProcessEffect(device, queue) {
uniforms_ =
- gpu_create_buffer(device_, sizeof(float) * 4,
+ gpu_create_buffer(device_, sizeof(float) * 6,
WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst);
pipeline_ =
create_post_process_pipeline(device_, format, distort_shader_wgsl);
@@ -17,8 +17,8 @@ DistortEffect::DistortEffect(WGPUDevice device, WGPUQueue queue,
void DistortEffect::render(WGPURenderPassEncoder pass, float t, float b,
float i, float a) {
struct {
- float t, b, i, a;
- } u = {t, b, i, a};
+ float t, b, i, a, w, h;
+ } u = {t, b, i, a, (float)width_, (float)height_};
wgpuQueueWriteBuffer(queue_, uniforms_.buffer, 0, &u, sizeof(u));
PostProcessEffect::render(pass, t, b, i, a);
}
diff --git a/src/gpu/effects/gaussian_blur_effect.cc b/src/gpu/effects/gaussian_blur_effect.cc
index 28f5b97..ad9bf4b 100644
--- a/src/gpu/effects/gaussian_blur_effect.cc
+++ b/src/gpu/effects/gaussian_blur_effect.cc
@@ -9,7 +9,7 @@ GaussianBlurEffect::GaussianBlurEffect(WGPUDevice device, WGPUQueue queue,
WGPUTextureFormat format)
: PostProcessEffect(device, queue) {
uniforms_ =
- gpu_create_buffer(device_, sizeof(float) * 4,
+ gpu_create_buffer(device_, sizeof(float) * 6,
WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst);
pipeline_ =
create_post_process_pipeline(device_, format, gaussian_blur_shader_wgsl);
@@ -17,8 +17,8 @@ GaussianBlurEffect::GaussianBlurEffect(WGPUDevice device, WGPUQueue queue,
void GaussianBlurEffect::render(WGPURenderPassEncoder pass, float t, float b,
float i, float a) {
struct {
- float t, b, i, a;
- } u = {t, b, i, a};
+ float t, b, i, a, w, h;
+ } u = {t, b, i, a, (float)width_, (float)height_};
wgpuQueueWriteBuffer(queue_, uniforms_.buffer, 0, &u, sizeof(u));
PostProcessEffect::render(pass, t, b, i, a);
}
diff --git a/src/gpu/effects/hybrid_3d_effect.cc b/src/gpu/effects/hybrid_3d_effect.cc
index af956cd..ee2dd57 100644
--- a/src/gpu/effects/hybrid_3d_effect.cc
+++ b/src/gpu/effects/hybrid_3d_effect.cc
@@ -10,7 +10,7 @@
Hybrid3DEffect::Hybrid3DEffect(WGPUDevice device, WGPUQueue queue,
WGPUTextureFormat format)
- : Effect(device, queue), width_(1280), height_(720) {
+ : Effect(device, queue) {
(void)format; // Passed to base, not directly used here.
}
diff --git a/src/gpu/effects/hybrid_3d_effect.h b/src/gpu/effects/hybrid_3d_effect.h
index 8eedeb2..8e2fef9 100644
--- a/src/gpu/effects/hybrid_3d_effect.h
+++ b/src/gpu/effects/hybrid_3d_effect.h
@@ -25,6 +25,4 @@ class Hybrid3DEffect : public Effect {
TextureManager texture_manager_;
Scene scene_;
Camera camera_;
- int width_ = 1280;
- int height_ = 720;
};
diff --git a/src/gpu/effects/moving_ellipse_effect.cc b/src/gpu/effects/moving_ellipse_effect.cc
index b46eecd..3b73697 100644
--- a/src/gpu/effects/moving_ellipse_effect.cc
+++ b/src/gpu/effects/moving_ellipse_effect.cc
@@ -9,7 +9,7 @@ MovingEllipseEffect::MovingEllipseEffect(WGPUDevice device, WGPUQueue queue,
WGPUTextureFormat format)
: Effect(device, queue) {
uniforms_ =
- gpu_create_buffer(device_, sizeof(float) * 4,
+ gpu_create_buffer(device_, sizeof(float) * 6,
WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst);
ResourceBinding bindings[] = {{uniforms_, WGPUBufferBindingType_Uniform}};
pass_ =
@@ -19,8 +19,8 @@ MovingEllipseEffect::MovingEllipseEffect(WGPUDevice device, WGPUQueue queue,
void MovingEllipseEffect::render(WGPURenderPassEncoder pass, float t, float b,
float i, float a) {
struct {
- float t, b, i, a;
- } u = {t, b, i, a};
+ float t, b, i, a, w, h;
+ } u = {t, b, i, a, (float)width_, (float)height_};
wgpuQueueWriteBuffer(queue_, uniforms_.buffer, 0, &u, sizeof(u));
wgpuRenderPassEncoderSetPipeline(pass, pass_.pipeline);
wgpuRenderPassEncoderSetBindGroup(pass, 0, pass_.bind_group, 0, nullptr);
diff --git a/src/gpu/effects/particle_spray_effect.cc b/src/gpu/effects/particle_spray_effect.cc
index b5c5f42..e8ead0a 100644
--- a/src/gpu/effects/particle_spray_effect.cc
+++ b/src/gpu/effects/particle_spray_effect.cc
@@ -10,7 +10,7 @@ ParticleSprayEffect::ParticleSprayEffect(WGPUDevice device, WGPUQueue queue,
WGPUTextureFormat format)
: Effect(device, queue) {
uniforms_ =
- gpu_create_buffer(device_, sizeof(float) * 4,
+ gpu_create_buffer(device_, sizeof(float) * 6,
WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst);
std::vector<Particle> init_p(NUM_PARTICLES);
for (Particle& p : init_p)
@@ -34,8 +34,8 @@ ParticleSprayEffect::ParticleSprayEffect(WGPUDevice device, WGPUQueue queue,
void ParticleSprayEffect::compute(WGPUCommandEncoder e, float t, float b,
float i, float a) {
struct {
- float i, a, t, b;
- } u = {i, a, t, b};
+ float i, a, t, b, w, h;
+ } u = {i, a, t, b, (float)width_, (float)height_};
wgpuQueueWriteBuffer(queue_, uniforms_.buffer, 0, &u, sizeof(u));
WGPUComputePassEncoder pass = wgpuCommandEncoderBeginComputePass(e, nullptr);
wgpuComputePassEncoderSetPipeline(pass, compute_pass_.pipeline);
diff --git a/src/gpu/effects/passthrough_effect.cc b/src/gpu/effects/passthrough_effect.cc
index cb92ba1..7825c0a 100644
--- a/src/gpu/effects/passthrough_effect.cc
+++ b/src/gpu/effects/passthrough_effect.cc
@@ -9,11 +9,15 @@ PassthroughEffect::PassthroughEffect(WGPUDevice device, WGPUQueue queue,
WGPUTextureFormat format)
: PostProcessEffect(device, queue) {
uniforms_ =
- gpu_create_buffer(device_, sizeof(float) * 4,
+ gpu_create_buffer(device_, sizeof(float) * 6,
WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst);
pipeline_ =
create_post_process_pipeline(device_, format, passthrough_shader_wgsl);
}
void PassthroughEffect::update_bind_group(WGPUTextureView input_view) {
+ struct {
+ float t, b, i, a, w, h;
+ } u = {0, 0, 0, 0, (float)width_, (float)height_};
+ wgpuQueueWriteBuffer(queue_, uniforms_.buffer, 0, &u, sizeof(u));
pp_update_bind_group(device_, pipeline_, &bind_group_, input_view, uniforms_);
}
diff --git a/src/gpu/effects/shaders.cc b/src/gpu/effects/shaders.cc
index 0e80230..ac0bba9 100644
--- a/src/gpu/effects/shaders.cc
+++ b/src/gpu/effects/shaders.cc
@@ -122,6 +122,15 @@ const char* passthrough_shader_wgsl = R"(
@group(0) @binding(0) var smplr: sampler;
@group(0) @binding(1) var txt: texture_2d<f32>;
+struct Uniforms {
+ time: f32,
+ beat: f32,
+ intensity: f32,
+ aspect_ratio: f32,
+ resolution: vec2<f32>,
+};
+@group(0) @binding(2) var<uniform> uniforms: Uniforms;
+
@vertex fn vs_main(@builtin(vertex_index) i: u32) -> @builtin(position) vec4<f32> {
var pos = array<vec2<f32>, 3>(
vec2<f32>(-1, -1),
@@ -132,7 +141,7 @@ const char* passthrough_shader_wgsl = R"(
}
@fragment fn fs_main(@builtin(position) p: vec4<f32>) -> @location(0) vec4<f32> {
- return textureSample(txt, smplr, p.xy / vec2<f32>(1280.0, 720.0));
+ return textureSample(txt, smplr, p.xy / uniforms.resolution);
})";
const char* ellipse_shader_wgsl = R"(
@@ -141,6 +150,7 @@ struct Uniforms {
beat: f32,
intensity: f32,
aspect_ratio: f32,
+ resolution: vec2<f32>,
};
@group(0) @binding(0) var<uniform> uniforms: Uniforms;
@@ -187,7 +197,7 @@ fn sdEllipse(p: vec2<f32>, ab: vec2<f32>) -> f32 {
}
@fragment fn fs_main(@builtin(position) p: vec4<f32>) -> @location(0) vec4<f32> {
- let uv = (p.xy / vec2<f32>(1280.0, 720.0) - 0.5) * 2.0;
+ let uv = (p.xy / uniforms.resolution - 0.5) * 2.0;
let movement = vec2<f32>(sin(uniforms.time * 0.7), cos(uniforms.time * 0.5));
let d = sdEllipse((uv * vec2<f32>(uniforms.aspect_ratio, 1.0)) - movement, vec2<f32>(0.5, 0.3) * (1.0 + uniforms.beat * 0.2));
return mix(vec4<f32>(0.2, 0.8, 0.4, 1.0), vec4<f32>(0.0), smoothstep(0.0, 0.01, d));
@@ -244,6 +254,7 @@ struct Uniforms {
beat: f32,
intensity: f32,
aspect_ratio: f32,
+ resolution: vec2<f32>,
};
@group(0) @binding(2) var<uniform> uniforms: Uniforms;
@@ -258,12 +269,12 @@ struct Uniforms {
}
@fragment fn fs_main(@builtin(position) p: vec4<f32>) -> @location(0) vec4<f32> {
- let uv = p.xy / vec2<f32>(1280.0, 720.0);
+ let uv = p.xy / uniforms.resolution;
var res = vec4<f32>(0.0);
let size = 5.0 * uniforms.intensity;
for (var x: f32 = -2.0; x <= 2.0; x += 1.0) {
for (var y: f32 = -2.0; y <= 2.0; y += 1.0) {
- res += textureSample(txt, smplr, uv + vec2<f32>(x, y) * size / 1280.0);
+ res += textureSample(txt, smplr, uv + vec2<f32>(x, y) * size / uniforms.resolution.x);
}
}
return res / 25.0;
@@ -278,6 +289,7 @@ struct Uniforms {
beat: f32,
intensity: f32,
aspect_ratio: f32,
+ resolution: vec2<f32>,
};
@group(0) @binding(2) var<uniform> uniforms: Uniforms;
@@ -292,7 +304,7 @@ struct Uniforms {
}
@fragment fn fs_main(@builtin(position) p: vec4<f32>) -> @location(0) vec4<f32> {
- let uv = p.xy / vec2<f32>(1280.0, 720.0);
+ let uv = p.xy / uniforms.resolution;
var col = textureSample(txt, smplr, uv);
let thr = 0.5 + 0.3 * sin(uniforms.time);
if (col.r < thr) {
@@ -316,6 +328,7 @@ struct Uniforms {
beat: f32,
intensity: f32,
aspect_ratio: f32,
+ resolution: vec2<f32>,
};
@group(0) @binding(2) var<uniform> uniforms: Uniforms;
@@ -330,7 +343,7 @@ struct Uniforms {
}
@fragment fn fs_main(@builtin(position) p: vec4<f32>) -> @location(0) vec4<f32> {
- let uv = p.xy / vec2<f32>(1280.0, 720.0);
+ let uv = p.xy / uniforms.resolution;
let dist = 0.1 * uniforms.intensity * sin(uv.y * 20.0 + uniforms.time * 5.0);
return textureSample(txt, smplr, uv + vec2<f32>(dist, 0.0));
})";
@@ -344,6 +357,7 @@ struct Uniforms {
beat: f32,
intensity: f32,
aspect_ratio: f32,
+ resolution: vec2<f32>,
};
@group(0) @binding(2) var<uniform> uniforms: Uniforms;
@@ -358,7 +372,7 @@ struct Uniforms {
}
@fragment fn fs_main(@builtin(position) p: vec4<f32>) -> @location(0) vec4<f32> {
- let uv = p.xy / vec2<f32>(1280.0, 720.0);
+ let uv = p.xy / uniforms.resolution;
let off = 0.02 * uniforms.intensity;
let r = textureSample(txt, smplr, uv + vec2<f32>(off, 0.0)).r;
let g = textureSample(txt, smplr, uv).g;
diff --git a/src/gpu/effects/solarize_effect.cc b/src/gpu/effects/solarize_effect.cc
index f8a7f33..a0bc971 100644
--- a/src/gpu/effects/solarize_effect.cc
+++ b/src/gpu/effects/solarize_effect.cc
@@ -9,7 +9,7 @@ SolarizeEffect::SolarizeEffect(WGPUDevice device, WGPUQueue queue,
WGPUTextureFormat format)
: PostProcessEffect(device, queue) {
uniforms_ =
- gpu_create_buffer(device_, sizeof(float) * 4,
+ gpu_create_buffer(device_, sizeof(float) * 6,
WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst);
pipeline_ =
create_post_process_pipeline(device_, format, solarize_shader_wgsl);
@@ -17,8 +17,8 @@ SolarizeEffect::SolarizeEffect(WGPUDevice device, WGPUQueue queue,
void SolarizeEffect::render(WGPURenderPassEncoder pass, float t, float b,
float i, float a) {
struct {
- float t, b, i, a;
- } u = {t, b, i, a};
+ float t, b, i, a, w, h;
+ } u = {t, b, i, a, (float)width_, (float)height_};
wgpuQueueWriteBuffer(queue_, uniforms_.buffer, 0, &u, sizeof(u));
PostProcessEffect::render(pass, t, b, i, a);
}
diff --git a/src/gpu/gpu.cc b/src/gpu/gpu.cc
index 7b8e012..5537433 100644
--- a/src/gpu/gpu.cc
+++ b/src/gpu/gpu.cc
@@ -367,6 +367,7 @@ void gpu_init(PlatformState* platform_state) {
g_config.usage = WGPUTextureUsage_RenderAttachment;
g_config.width = platform_state->width;
g_config.height = platform_state->height;
+ printf("WebGPU Init: %dx%d\n", g_config.width, g_config.height);
g_config.presentMode = WGPUPresentMode_Fifo;
g_config.alphaMode = WGPUCompositeAlphaMode_Opaque;
wgpuSurfaceConfigure(g_surface, &g_config);
@@ -381,6 +382,15 @@ void gpu_draw(float audio_peak, float aspect_ratio, float time, float beat) {
g_main_sequence.render_frame(time, beat, audio_peak, aspect_ratio, g_surface);
}
+void gpu_resize(int width, int height) {
+ if (width <= 0 || height <= 0)
+ return;
+ g_config.width = width;
+ g_config.height = height;
+ wgpuSurfaceConfigure(g_surface, &g_config);
+ g_main_sequence.resize(width, height);
+}
+
#if !defined(STRIP_ALL)
void gpu_simulate_until(float time) {
g_main_sequence.simulate_until(time, 1.0f / 60.0f);
diff --git a/src/gpu/gpu.h b/src/gpu/gpu.h
index 768b238..f47355c 100644
--- a/src/gpu/gpu.h
+++ b/src/gpu/gpu.h
@@ -100,9 +100,7 @@ struct RenderPass {
void gpu_init(PlatformState* platform_state);
void gpu_draw(float audio_peak, float aspect_ratio, float time, float beat);
-#if !defined(STRIP_ALL)
-void gpu_simulate_until(float time);
-#endif /* !defined(STRIP_ALL) */
+void gpu_resize(int width, int height);
void gpu_shutdown();
// Helper functions (exposed for internal/future use)