summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/BACKLOG.md24
-rw-r--r--src/effects/hybrid3_d_effect.cc28
-rw-r--r--src/effects/rotating_cube_effect.cc20
-rw-r--r--src/gpu/sequence.cc16
-rw-r--r--src/gpu/sequence.h3
-rw-r--r--workspaces/test/assets.txt1
-rw-r--r--workspaces/test/timeline.seq8
7 files changed, 89 insertions, 11 deletions
diff --git a/doc/BACKLOG.md b/doc/BACKLOG.md
index 403ecc9..68995a7 100644
--- a/doc/BACKLOG.md
+++ b/doc/BACKLOG.md
@@ -150,6 +150,30 @@ Extend uniform parameter system to remaining effects.
**Estimated Impact**: ~200-300 bytes per effect
+### TODO MAYBE: Timeline Syntax for Buffer Operations
+Explicit timeline control for buffer clear/blit operations.
+
+**Current**: Effects decide behavior (e.g., RotatingCube checks if input is "source")
+
+**Proposed**: Timeline syntax for buffer operations
+- `[NONE]` - Shader samples input (post-process effects)
+- `[CLEAR r g b a]` - Clear to color before render (3D standalone)
+- `[BLIT]` - Copy input to output before render (3D composite)
+
+**Example**:
+```
+EFFECT + RotatingCube source -> temp1 [CLEAR 0 0 0 0] 0.0 4.0
+EFFECT + RotatingCube temp1 -> temp2 [BLIT] 2.0 16.0
+```
+
+**Trade-offs**:
+- Pro: Explicit, instance-specific control, self-documenting
+- Con: seq_compiler complexity, size cost, syntax bloat
+
+**Decision**: Effect-decides approach works for now. Only add if multiple 3D effects need per-instance control.
+
+**Priority**: Very Low (revisit if pattern becomes common)
+
### Task #52: Procedural SDF Font
Minimal bezier/spline set for [A-Z, 0-9] and SDF rendering.
diff --git a/src/effects/hybrid3_d_effect.cc b/src/effects/hybrid3_d_effect.cc
index 0e44853..c13c1e9 100644
--- a/src/effects/hybrid3_d_effect.cc
+++ b/src/effects/hybrid3_d_effect.cc
@@ -4,6 +4,7 @@
#include "util/fatal_error.h"
#include "effects/hybrid3_d_effect.h"
+#include "gpu/gpu.h"
#include <cmath>
Hybrid3D::Hybrid3D(const GpuContext& ctx,
@@ -113,6 +114,29 @@ void Hybrid3D::render(WGPUCommandEncoder encoder,
WGPUTextureView color_view = nodes.get_view(output_nodes_[0]);
WGPUTextureView depth_view = nodes.get_view(depth_node_);
- // Render 3D scene
- renderer_.render(scene_, camera_, params.time, color_view, depth_view);
+ // Render 3D scene using sequence encoder
+ WGPURenderPassColorAttachment color_attachment = {};
+#if !defined(DEMO_CROSS_COMPILE_WIN32)
+ color_attachment.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED;
+#endif
+ color_attachment.view = color_view;
+ color_attachment.loadOp = WGPULoadOp_Clear;
+ color_attachment.storeOp = WGPUStoreOp_Store;
+ color_attachment.clearValue = {0.05f, 0.05f, 0.05f, 1.0f};
+
+ WGPURenderPassDepthStencilAttachment depth_attachment = {};
+ depth_attachment.view = depth_view;
+ depth_attachment.depthLoadOp = WGPULoadOp_Clear;
+ depth_attachment.depthStoreOp = WGPUStoreOp_Store;
+ depth_attachment.depthClearValue = 1.0f;
+
+ WGPURenderPassDescriptor pass_desc = {};
+ pass_desc.colorAttachmentCount = 1;
+ pass_desc.colorAttachments = &color_attachment;
+ pass_desc.depthStencilAttachment = &depth_attachment;
+
+ WGPURenderPassEncoder pass = wgpuCommandEncoderBeginRenderPass(encoder, &pass_desc);
+ renderer_.draw(pass, scene_, camera_, params.time);
+ wgpuRenderPassEncoderEnd(pass);
+ wgpuRenderPassEncoderRelease(pass);
}
diff --git a/src/effects/rotating_cube_effect.cc b/src/effects/rotating_cube_effect.cc
index 1f56b8b..a91bc78 100644
--- a/src/effects/rotating_cube_effect.cc
+++ b/src/effects/rotating_cube_effect.cc
@@ -156,6 +156,21 @@ void RotatingCube::render(WGPUCommandEncoder encoder,
wgpuQueueWriteBuffer(ctx_.queue, object_buffer_.buffer, 0, &obj_data,
sizeof(ObjectData));
+ // Blit input to output if compositing (not reading from source)
+ if (!input_nodes_.empty() && input_nodes_[0] != "source") {
+ WGPUTexture input_tex = nodes.get_texture(input_nodes_[0]);
+ WGPUTexture output_tex = nodes.get_texture(output_nodes_[0]);
+ if (input_tex && output_tex) {
+ WGPUTexelCopyTextureInfo src = {
+ .texture = input_tex, .mipLevel = 0, .aspect = WGPUTextureAspect_All};
+ WGPUTexelCopyTextureInfo dst = {
+ .texture = output_tex, .mipLevel = 0, .aspect = WGPUTextureAspect_All};
+ WGPUExtent3D copy_size = {(uint32_t)params.resolution.x,
+ (uint32_t)params.resolution.y, 1};
+ wgpuCommandEncoderCopyTextureToTexture(encoder, &src, &dst, &copy_size);
+ }
+ }
+
// Get output views
WGPUTextureView color_view = nodes.get_view(output_nodes_[0]);
WGPUTextureView depth_view = nodes.get_view(depth_node_);
@@ -164,9 +179,10 @@ void RotatingCube::render(WGPUCommandEncoder encoder,
WGPURenderPassColorAttachment color_attachment = {
.view = color_view,
.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED,
- .loadOp = WGPULoadOp_Clear,
+// .loadOp = WGPULoadOp_Clear,
+ .loadOp = WGPULoadOp_Load,
.storeOp = WGPUStoreOp_Store,
- .clearValue = {0.0, 0.0, 0.0, 1.0}};
+ .clearValue = {0.0, 0.0, 0.0, 0.0}};
WGPURenderPassDepthStencilAttachment depth_attachment = {
.view = depth_view,
diff --git a/src/gpu/sequence.cc b/src/gpu/sequence.cc
index 62c2933..0a0cb1e 100644
--- a/src/gpu/sequence.cc
+++ b/src/gpu/sequence.cc
@@ -92,6 +92,16 @@ NodeRegistry::get_output_views(const std::vector<std::string>& names) {
return views;
}
+WGPUTexture NodeRegistry::get_texture(const std::string& name) {
+ auto alias_it = aliases_.find(name);
+ if (alias_it != aliases_.end()) {
+ return get_texture(alias_it->second);
+ }
+ auto it = nodes_.find(name);
+ FATAL_CHECK(it != nodes_.end(), "Node not found: %s\n", name.c_str());
+ return it->second.texture;
+}
+
void NodeRegistry::resize(int width, int height) {
default_width_ = width;
default_height_ = height;
@@ -141,15 +151,15 @@ void NodeRegistry::create_texture(Node& node) {
switch (node.type) {
case NodeType::U8X4_NORM:
format = WGPUTextureFormat_RGBA8Unorm;
- usage = (WGPUTextureUsage)(WGPUTextureUsage_RenderAttachment | WGPUTextureUsage_TextureBinding);
+ usage = (WGPUTextureUsage)(WGPUTextureUsage_RenderAttachment | WGPUTextureUsage_TextureBinding | WGPUTextureUsage_CopySrc | WGPUTextureUsage_CopyDst);
break;
case NodeType::F32X4:
format = WGPUTextureFormat_RGBA32Float;
- usage = (WGPUTextureUsage)(WGPUTextureUsage_RenderAttachment | WGPUTextureUsage_TextureBinding);
+ usage = (WGPUTextureUsage)(WGPUTextureUsage_RenderAttachment | WGPUTextureUsage_TextureBinding | WGPUTextureUsage_CopySrc | WGPUTextureUsage_CopyDst);
break;
case NodeType::F16X8:
format = WGPUTextureFormat_RGBA16Float; // WebGPU doesn't have 8-channel, use RGBA16
- usage = (WGPUTextureUsage)(WGPUTextureUsage_RenderAttachment | WGPUTextureUsage_TextureBinding);
+ usage = (WGPUTextureUsage)(WGPUTextureUsage_RenderAttachment | WGPUTextureUsage_TextureBinding | WGPUTextureUsage_CopySrc | WGPUTextureUsage_CopyDst);
break;
case NodeType::DEPTH24:
format = WGPUTextureFormat_Depth24Plus;
diff --git a/src/gpu/sequence.h b/src/gpu/sequence.h
index a33dedb..e96e183 100644
--- a/src/gpu/sequence.h
+++ b/src/gpu/sequence.h
@@ -62,6 +62,9 @@ class NodeRegistry {
std::vector<WGPUTextureView>
get_output_views(const std::vector<std::string>& names);
+ // Retrieve texture (for blits)
+ WGPUTexture get_texture(const std::string& name);
+
// Resize all nodes
void resize(int width, int height);
diff --git a/workspaces/test/assets.txt b/workspaces/test/assets.txt
index 68d0ab3..79f5e43 100644
--- a/workspaces/test/assets.txt
+++ b/workspaces/test/assets.txt
@@ -74,6 +74,7 @@ SHADER_POSTPROCESS_INLINE, NONE, ../../common/shaders/postprocess_inline.wgsl, "
SHADER_PASSTHROUGH_V2, NONE, ../../common/shaders/passthrough.wgsl, "Passthrough Shader"
SHADER_GAUSSIAN_BLUR_V2, NONE, ../../common/shaders/gaussian_blur.wgsl, "Gaussian Blur Shader"
SHADER_HEPTAGON_V2, NONE, ../../common/shaders/heptagon.wgsl, "Heptagon Shader"
+SHADER_ROTATING_CUBE_V2, NONE, ../main/shaders/rotating_cube.wgsl, "Rotating Cube Shader"
SHADER_FLASH, NONE, shaders/flash.wgsl, "Flash Shader"
# --- Test Assets (for test_assets.cc) ---
diff --git a/workspaces/test/timeline.seq b/workspaces/test/timeline.seq
index 98000f0..9f698fe 100644
--- a/workspaces/test/timeline.seq
+++ b/workspaces/test/timeline.seq
@@ -3,10 +3,10 @@
# BPM 120 (set in test_demo.track)
SEQUENCE 0.0 0 "MainLoop"
-EFFECT + RotatingCube source -> temp1 0.00 4.00
+EFFECT + Hybrid3D source -> temp1 0.00 4.00
EFFECT + GaussianBlur temp1 -> sink 0.00 4.00
SEQUENCE 4.0 0 "MainLoop"
-EFFECT + Flash source -> temp1 0.0 16.0
-EFFECT + GaussianBlur temp1 -> temp2 2.0 16.0
-EFFECT + PeakMeter temp2 -> sink 0.0 16.0
+EFFECT + Heptagon source -> temp1 0.0 16.0
+#EFFECT + RotatingCube temp1 -> temp2 2.0 16.0
+EFFECT + PeakMeter temp1 -> sink 4.0 16.0