diff options
Diffstat (limited to 'src/gpu')
| -rw-r--r-- | src/gpu/demo_effects.cc | 2 | ||||
| -rw-r--r-- | src/gpu/demo_effects.h | 12 | ||||
| -rw-r--r-- | src/gpu/effect.cc | 19 | ||||
| -rw-r--r-- | src/gpu/effect.h | 24 | ||||
| -rw-r--r-- | src/gpu/gpu.cc | 35 | ||||
| -rw-r--r-- | src/gpu/gpu.h | 29 | ||||
| -rw-r--r-- | src/gpu/post_process_helper.h | 16 | ||||
| -rw-r--r-- | src/gpu/sdf_effect.h | 9 | ||||
| -rw-r--r-- | src/gpu/sequence.h | 29 | ||||
| -rw-r--r-- | src/gpu/shader_composer.h | 7 | ||||
| -rw-r--r-- | src/gpu/uniform_helper.h | 7 | ||||
| -rw-r--r-- | src/gpu/wgpu_resource.h | 45 |
12 files changed, 152 insertions, 82 deletions
diff --git a/src/gpu/demo_effects.cc b/src/gpu/demo_effects.cc index d9c5964..5114e3a 100644 --- a/src/gpu/demo_effects.cc +++ b/src/gpu/demo_effects.cc @@ -1,6 +1,4 @@ // This file is part of the 64k demo project. // Central include for all effect implementations. -// Individual effects are in src/effects/*_v2.{h,cc} -// Timeline management is in src/generated/timeline.cc (v2) #include "gpu/demo_effects.h" diff --git a/src/gpu/demo_effects.h b/src/gpu/demo_effects.h index 85299ca..2825891 100644 --- a/src/gpu/demo_effects.h +++ b/src/gpu/demo_effects.h @@ -8,7 +8,7 @@ #include "3d/renderer.h" #include "3d/scene.h" -// Base effect classes (v2) +// Base effect classes #include "effects/shaders.h" #include "gpu/effect.h" #include "gpu/post_process_helper.h" @@ -16,7 +16,7 @@ #include "gpu/texture_manager.h" #include "gpu/uniform_helper.h" -// Individual Effect Headers (v2) +// Individual Effect Headers #include "effects/flash_effect.h" #include "effects/gaussian_blur_effect.h" #include "effects/heptagon_effect.h" @@ -26,14 +26,8 @@ #include "effects/peak_meter_effect.h" #include "effects/placeholder_effect.h" #include "effects/rotating_cube_effect.h" -// TODO: Port CNN effects to v2 +// TODO: Port CNN effects // #include "../../cnn_v1/src/cnn_v1_effect.h" // #include "../../cnn_v2/src/cnn_v2_effect.h" #include <memory> - -// Auto-generated functions from sequence compiler v2 -// See generated/timeline.h for: -// - InitializeV2Sequences() -// - GetActiveV2Sequence() -// - RenderV2Timeline() diff --git a/src/gpu/effect.cc b/src/gpu/effect.cc index 752dd84..d0693ec 100644 --- a/src/gpu/effect.cc +++ b/src/gpu/effect.cc @@ -14,6 +14,7 @@ Effect::Effect(const GpuContext& ctx, const std::vector<std::string>& inputs, FATAL_CHECK(!outputs.empty(), "Effect must have at least one output\n"); FATAL_CHECK(start_time <= end_time, "Invalid time range: %f > %f\n", start_time, end_time); + HEADLESS_RETURN_IF_NULL(ctx_.device); } void Effect::dispatch_render(WGPUCommandEncoder encoder, @@ -55,3 +56,21 @@ void Effect::blit_input_to_output(WGPUCommandEncoder encoder, wgpuCommandEncoderCopyTextureToTexture(encoder, &src_copy, &dst_copy, &extent); } + +void Effect::init_uniforms_buffer() { + uniforms_buffer_.init(ctx_.device); +} + +void Effect::create_linear_sampler() { + sampler_.set(gpu_create_linear_sampler(ctx_.device)); +} + +void Effect::create_nearest_sampler() { + sampler_.set(gpu_create_nearest_sampler(ctx_.device)); +} + +void Effect::create_dummy_scene_texture() { + TextureWithView dummy = gpu_create_dummy_scene_texture(ctx_.device); + dummy_texture_.set(dummy.texture); + dummy_texture_view_.set(dummy.view); +} diff --git a/src/gpu/effect.h b/src/gpu/effect.h index 0d7e35e..d47a8b7 100644 --- a/src/gpu/effect.h +++ b/src/gpu/effect.h @@ -6,6 +6,8 @@ #include "gpu/gpu.h" #include "gpu/sequence.h" +#include "gpu/uniform_helper.h" +#include "gpu/wgpu_resource.h" #include <string> #include <vector> @@ -23,17 +25,15 @@ class Effect { (void)registry; } - // Dispatch render with automatic passthrough outside [start, end] + // Automatic passthrough outside [start, end] void dispatch_render(WGPUCommandEncoder encoder, const UniformsSequenceParams& params, NodeRegistry& nodes); - // Render effect (multi-input/multi-output) - override in derived classes virtual void render(WGPUCommandEncoder encoder, const UniformsSequenceParams& params, NodeRegistry& nodes) = 0; - // Resize notification virtual void resize(int width, int height) { width_ = width; height_ = height; @@ -53,6 +53,24 @@ class Effect { int width_ = 1280; int height_ = 720; + // Common resources for most effects + UniformBuffer<UniformsSequenceParams> uniforms_buffer_; + Sampler sampler_; + Texture dummy_texture_; + TextureView dummy_texture_view_; + + // Helper: Initialize uniforms buffer (call in subclass constructor) + void init_uniforms_buffer(); + + // Helper: Create linear sampler (call in subclass constructor) + void create_linear_sampler(); + + // Helper: Create nearest sampler (call in subclass constructor) + void create_nearest_sampler(); + + // Helper: Create dummy texture for scene effects (call in subclass constructor) + void create_dummy_scene_texture(); + private: float start_time_; float end_time_; diff --git a/src/gpu/gpu.cc b/src/gpu/gpu.cc index 2226889..e743bf7 100644 --- a/src/gpu/gpu.cc +++ b/src/gpu/gpu.cc @@ -124,6 +124,41 @@ WGPUTextureView gpu_create_texture_view_2d(WGPUTexture texture, return wgpuTextureCreateView(texture, &view_desc); } +WGPUSampler gpu_create_linear_sampler(WGPUDevice device) { + WGPUSamplerDescriptor desc = {}; + desc.addressModeU = WGPUAddressMode_ClampToEdge; + desc.addressModeV = WGPUAddressMode_ClampToEdge; + desc.addressModeW = WGPUAddressMode_ClampToEdge; + desc.magFilter = WGPUFilterMode_Linear; + desc.minFilter = WGPUFilterMode_Linear; + desc.mipmapFilter = WGPUMipmapFilterMode_Nearest; + desc.maxAnisotropy = 1; + return wgpuDeviceCreateSampler(device, &desc); +} + +WGPUSampler gpu_create_nearest_sampler(WGPUDevice device) { + WGPUSamplerDescriptor desc = {}; + desc.addressModeU = WGPUAddressMode_ClampToEdge; + desc.addressModeV = WGPUAddressMode_ClampToEdge; + desc.magFilter = WGPUFilterMode_Nearest; + desc.minFilter = WGPUFilterMode_Nearest; + desc.maxAnisotropy = 1; + return wgpuDeviceCreateSampler(device, &desc); +} + +TextureWithView gpu_create_dummy_scene_texture(WGPUDevice device) { + WGPUTextureDescriptor desc = {}; + desc.size = {1, 1, 1}; + desc.format = WGPUTextureFormat_RGBA8Unorm; + desc.usage = WGPUTextureUsage_TextureBinding; + desc.dimension = WGPUTextureDimension_2D; + desc.mipLevelCount = 1; + desc.sampleCount = 1; + WGPUTexture texture = wgpuDeviceCreateTexture(device, &desc); + WGPUTextureView view = wgpuTextureCreateView(texture, nullptr); + return {texture, view}; +} + RenderPass gpu_create_render_pass(WGPUDevice device, WGPUTextureFormat format, const char* shader_code, ResourceBinding* bindings, int num_bindings) { diff --git a/src/gpu/gpu.h b/src/gpu/gpu.h index de6c5ba..d6c0255 100644 --- a/src/gpu/gpu.h +++ b/src/gpu/gpu.h @@ -1,27 +1,23 @@ // This file is part of the 64k demo project. -// It defines the public interface for the GPU rendering system. -// Coordinates WebGPU lifecycle and draw calls. +// GPU rendering system interface. #pragma once #include "platform/platform.h" -struct PlatformState; // Forward declaration +struct PlatformState; -// GPU context bundling device, queue, and surface format struct GpuContext { WGPUDevice device; WGPUQueue queue; WGPUTextureFormat format; }; -// Basic wrapper for WebGPU buffers struct GpuBuffer { WGPUBuffer buffer; size_t size; }; -// Encapsulates a compute operation struct ComputePass { WGPUComputePipeline pipeline; WGPUBindGroup bind_group; @@ -30,7 +26,6 @@ struct ComputePass { uint32_t workgroup_size_z; }; -// Encapsulates a render operation struct RenderPass { WGPURenderPipeline pipeline; WGPUBindGroup bind_group; @@ -48,18 +43,11 @@ WGPUSurface gpu_get_surface(); const GpuContext* gpu_get_context(); -// Placeholder for GPU performance capture. -// This define can be controlled via CMake to conditionally enable profiling -// code. #define ENABLE_GPU_PERF_CAPTURE - -// Helper functions (exposed for internal/future use) struct ResourceBinding { GpuBuffer buffer; - WGPUBufferBindingType type; // e.g., WGPUBufferBindingType_Uniform, - // WGPUBufferBindingType_Storage + WGPUBufferBindingType type; }; -// Cross-platform helper for color attachment initialization inline void gpu_init_color_attachment(WGPURenderPassColorAttachment& attachment, WGPUTextureView view) { attachment.view = view; @@ -71,13 +59,11 @@ inline void gpu_init_color_attachment(WGPURenderPassColorAttachment& attachment, #endif } -// Texture creation helper struct TextureWithView { WGPUTexture texture; WGPUTextureView view; }; -// Platform-abstracted texture copy types #if defined(DEMO_CROSS_COMPILE_WIN32) using GpuTextureCopyInfo = WGPUImageCopyTexture; using GpuTextureDataLayout = WGPUTextureDataLayout; @@ -111,4 +97,11 @@ RenderPass gpu_create_render_pass(WGPUDevice device, WGPUTextureFormat format, // Needed for render pipeline const char* shader_code, ResourceBinding* bindings, - int num_bindings);
\ No newline at end of file + int num_bindings); + +// Common sampler configurations +WGPUSampler gpu_create_linear_sampler(WGPUDevice device); +WGPUSampler gpu_create_nearest_sampler(WGPUDevice device); + +// Dummy 1x1 texture for scene effects (don't need texture input) +TextureWithView gpu_create_dummy_scene_texture(WGPUDevice device);
\ No newline at end of file diff --git a/src/gpu/post_process_helper.h b/src/gpu/post_process_helper.h index 9a71046..811d0e4 100644 --- a/src/gpu/post_process_helper.h +++ b/src/gpu/post_process_helper.h @@ -7,27 +7,21 @@ #include "gpu/sequence.h" #include "util/mini_math.h" -// Use UniformsSequenceParams (defined in sequence.h) for post-process effects - // Standard post-process bind group layout (group 0): -#define PP_BINDING_SAMPLER 0 // Sampler for input texture -#define PP_BINDING_TEXTURE 1 // Input texture (previous render pass) -#define PP_BINDING_UNIFORMS 2 // Custom uniforms buffer -#define PP_BINDING_EFFECT_PARAMS 3 // Effect-specific parameters +#define PP_BINDING_SAMPLER 0 +#define PP_BINDING_TEXTURE 1 +#define PP_BINDING_UNIFORMS 2 +#define PP_BINDING_EFFECT_PARAMS 3 -// Helper to create a standard post-processing pipeline -// Uniforms are accessible to both vertex and fragment shaders WGPURenderPipeline create_post_process_pipeline(WGPUDevice device, WGPUTextureFormat format, const char* shader_code); -// Helper to create a simple post-processing pipeline (no effect params, 3 -// bindings only) +// No effect params, 3 bindings only WGPURenderPipeline create_post_process_pipeline_simple(WGPUDevice device, WGPUTextureFormat format, const char* shader_code); -// Helper to update bind group for post-processing effects void pp_update_bind_group(WGPUDevice device, WGPURenderPipeline pipeline, WGPUBindGroup* bind_group, WGPUTextureView input_view, GpuBuffer uniforms, GpuBuffer effect_params); diff --git a/src/gpu/sdf_effect.h b/src/gpu/sdf_effect.h index aacea69..12ea556 100644 --- a/src/gpu/sdf_effect.h +++ b/src/gpu/sdf_effect.h @@ -1,5 +1,5 @@ // This file is part of the 64k demo project. -// It defines SDFEffect base class for raymarching effects. +// SDF raymarching effect base class. #pragma once @@ -8,11 +8,8 @@ #include "gpu/effect.h" #include "gpu/uniform_helper.h" -// Base class for SDF raymarching effects -// Provides CameraParams uniform buffer and helper methods -// // Binding convention: -// @group(0) @binding(2): UniformsSequenceParams (from Effect base) +// @group(0) @binding(2): UniformsSequenceParams // @group(0) @binding(3): CameraParams // @group(0) @binding(4+): Per-effect custom parameters class SDFEffect : public Effect { @@ -23,7 +20,6 @@ class SDFEffect : public Effect { virtual ~SDFEffect() = default; - // Populate camera parameters from Camera object void update_camera(const Camera& camera, float aspect_ratio) { CameraParams params; params.inv_view = camera.get_view_matrix().inverse(); @@ -34,7 +30,6 @@ class SDFEffect : public Effect { camera_params_.update(ctx_.queue, params); } - // Populate camera parameters with custom values void update_camera(const vec3& position, const vec3& target, const vec3& up, float fov, float near_plane, float far_plane, float aspect_ratio) { diff --git a/src/gpu/sequence.h b/src/gpu/sequence.h index 0f448ce..3bb770f 100644 --- a/src/gpu/sequence.h +++ b/src/gpu/sequence.h @@ -1,5 +1,4 @@ -// Sequence: Explicit node system with DAG effect routing -// DAG-based effect routing with ping-pong optimization +// Sequence: DAG-based effect routing with ping-pong optimization #ifndef SEQUENCE_H #define SEQUENCE_H @@ -16,11 +15,11 @@ class Effect; enum class NodeType { - U8X4_NORM, // RGBAu8 normalized (0-1) - default Source/Sink - F32X4, // RGBA float32 - F16X8, // 8-channel float16 - DEPTH24, // Depth buffer - COMPUTE_F32, // Compute buffer + U8X4_NORM, // RGBAu8 (default Source/Sink) + F32X4, + F16X8, + DEPTH24, + COMPUTE_F32, }; struct Node { @@ -49,29 +48,22 @@ class NodeRegistry { NodeRegistry(WGPUDevice device, int default_width, int default_height); ~NodeRegistry(); - // Declare new node with explicit type/dimensions void declare_node(const std::string& name, NodeType type, int width, int height); - // Declare aliased node (ping-pong optimization) void declare_aliased_node(const std::string& name, const std::string& alias_of); - // Retrieve views WGPUTextureView get_view(const std::string& name); 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); - // Check if node exists bool has_node(const std::string& name) const; - // Register external view (for source/sink managed externally) void set_external_view(const std::string& name, WGPUTextureView view); private: @@ -79,7 +71,7 @@ class NodeRegistry { int default_width_; int default_height_; std::map<std::string, Node> nodes_; - std::map<std::string, std::string> aliases_; // name -> backing node name + std::map<std::string, std::string> aliases_; void create_texture(Node& node); }; @@ -88,7 +80,7 @@ struct EffectDAGNode { std::shared_ptr<Effect> effect; std::vector<std::string> input_nodes; std::vector<std::string> output_nodes; - int execution_order; // Topologically sorted + int execution_order; }; class Sequence { @@ -96,7 +88,6 @@ class Sequence { Sequence(const GpuContext& ctx, int width, int height); virtual ~Sequence() = default; - // Virtual methods (most sequences use defaults) virtual void preprocess(float seq_time, float beat_time, float beat_phase, float audio_intensity); virtual void postprocess(WGPUCommandEncoder encoder); @@ -104,20 +95,16 @@ class Sequence { void resize(int width, int height); - // Initialize effect nodes (call at end of subclass constructor) void init_effect_nodes(); - // Set surface texture view for rendering (sink node) void set_sink_view(WGPUTextureView view) { nodes_.set_external_view("sink", view); } - // Set source texture view (input framebuffer) void set_source_view(WGPUTextureView view) { nodes_.set_external_view("source", view); } - // Test accessor const std::vector<EffectDAGNode>& get_effect_dag() const { return effect_dag_; } diff --git a/src/gpu/shader_composer.h b/src/gpu/shader_composer.h index d0972f2..90e1ec1 100644 --- a/src/gpu/shader_composer.h +++ b/src/gpu/shader_composer.h @@ -12,19 +12,16 @@ class ShaderComposer { public: static ShaderComposer& Get(); - // Register a snippet (e.g. "common_math", "sdf_primitives") void RegisterSnippet(const std::string& name, const std::string& code); using CompositionMap = std::map<std::string, std::string>; - // Assemble a final shader string by prepending required snippets - // and recursively resolving #include "snippet_name" directives. - // Optional substitutions: map "placeholder_name" -> "actual_snippet_name" + // Resolves #include directives recursively + // substitutions: map "placeholder_name" -> "actual_snippet_name" std::string Compose(const std::vector<std::string>& dependencies, const std::string& main_code, const CompositionMap& substitutions = {}); - // Verify all #include directives reference registered snippets void VerifyIncludes() const; private: diff --git a/src/gpu/uniform_helper.h b/src/gpu/uniform_helper.h index 8556c98..b2f3406 100644 --- a/src/gpu/uniform_helper.h +++ b/src/gpu/uniform_helper.h @@ -1,12 +1,10 @@ // This file is part of the 64k demo project. -// It provides a generic uniform buffer helper to reduce boilerplate. -// Templated on uniform struct type for type safety and automatic sizing. +// Generic uniform buffer helper. #pragma once #include "gpu/gpu.h" -// Generic uniform buffer helper // Usage: // UniformBuffer<MyUniforms> uniforms_; // uniforms_.init(device); @@ -15,18 +13,15 @@ template <typename T> class UniformBuffer { public: UniformBuffer() = default; - // Initialize the uniform buffer with the device void init(WGPUDevice device) { buffer_ = gpu_create_buffer( device, sizeof(T), WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst); } - // Update the uniform buffer with new data void update(WGPUQueue queue, const T& data) { wgpuQueueWriteBuffer(queue, buffer_.buffer, 0, &data, sizeof(T)); } - // Get the underlying GpuBuffer (for bind group creation) GpuBuffer& get() { return buffer_; } diff --git a/src/gpu/wgpu_resource.h b/src/gpu/wgpu_resource.h new file mode 100644 index 0000000..e448b18 --- /dev/null +++ b/src/gpu/wgpu_resource.h @@ -0,0 +1,45 @@ +// WGPU Resource RAII Wrapper +// Automatic release on destruction +// +// IMPORTANT: Field ordering matters for destruction order. +// Members are destroyed in reverse declaration order. +// Declare dependencies before dependents: +// RenderPipeline pipeline_; // Destroyed last +// BindGroup bind_group_; // Destroyed first (may reference pipeline) + +#pragma once +#include "platform/platform.h" +#include "util/fatal_error.h" + +template<typename T, void(*Release)(T)> +class WGPUResource { + public: + WGPUResource() : ptr_(nullptr) {} + ~WGPUResource() { if (ptr_) Release(ptr_); } + + void set(T ptr) { + FATAL_ASSERT(ptr_ == nullptr); + ptr_ = ptr; + } + + void replace(T ptr) { + if (ptr_) Release(ptr_); + ptr_ = ptr; + } + + T get() const { return ptr_; } + T* get_address() { return &ptr_; } + + private: + T ptr_; + WGPUResource(const WGPUResource&) = delete; + WGPUResource& operator=(const WGPUResource&) = delete; +}; + +using BindGroup = WGPUResource<WGPUBindGroup, wgpuBindGroupRelease>; +using RenderPipeline = WGPUResource<WGPURenderPipeline, wgpuRenderPipelineRelease>; +using ComputePipeline = WGPUResource<WGPUComputePipeline, wgpuComputePipelineRelease>; +using Sampler = WGPUResource<WGPUSampler, wgpuSamplerRelease>; +using Texture = WGPUResource<WGPUTexture, wgpuTextureRelease>; +using TextureView = WGPUResource<WGPUTextureView, wgpuTextureViewRelease>; +using Buffer = WGPUResource<WGPUBuffer, wgpuBufferRelease>; |
