diff options
| author | skal <pascal.massimino@gmail.com> | 2026-02-06 01:38:51 +0100 |
|---|---|---|
| committer | skal <pascal.massimino@gmail.com> | 2026-02-06 01:38:51 +0100 |
| commit | ae4b03ef6f5ef07dcc80affd6877d17fceee7d29 (patch) | |
| tree | ab57453a320c90c76eeda3ca291e382ec6413a86 /src/3d/renderer.cc | |
| parent | 3581fa88300f0208c83f0f687b18479979dad035 (diff) | |
feat(perf): Add toggle for GPU BVH and fix fallback
Completed Task #18-B.
- Implemented GPU-side BVH traversal for scene queries, improving performance.
- Added a --no-bvh command-line flag to disable the feature for debugging and performance comparison.
- Fixed a shader compilation issue where the non-BVH fallback path failed to render objects.
Diffstat (limited to 'src/3d/renderer.cc')
| -rw-r--r-- | src/3d/renderer.cc | 60 |
1 files changed, 46 insertions, 14 deletions
diff --git a/src/3d/renderer.cc b/src/3d/renderer.cc index 684fda9..cf1a067 100644 --- a/src/3d/renderer.cc +++ b/src/3d/renderer.cc @@ -12,6 +12,7 @@ #if !defined(STRIP_ALL) bool Renderer3D::s_debug_enabled_ = false; +bool Renderer3D::s_bvh_enabled_ = true; // Enabled by default #endif void Renderer3D::init(WGPUDevice device, WGPUQueue queue, @@ -143,6 +144,8 @@ void Renderer3D::shutdown() { wgpuBufferRelease(global_uniform_buffer_); if (object_storage_buffer_) wgpuBufferRelease(object_storage_buffer_); + if (bvh_storage_buffer_) + wgpuBufferRelease(bvh_storage_buffer_); if (depth_view_) wgpuTextureViewRelease(depth_view_); if (depth_texture_) @@ -189,6 +192,10 @@ void Renderer3D::create_default_resources() { WGPUBufferUsage_Storage | WGPUBufferUsage_CopyDst, nullptr) .buffer; + bvh_storage_buffer_ = gpu_create_buffer( + device_, sizeof(BVHNode) * kMaxObjects * 2, // Capacity for a full tree + WGPUBufferUsage_Storage | WGPUBufferUsage_CopyDst, nullptr) + .buffer; } void Renderer3D::set_noise_texture(WGPUTextureView noise_view) { @@ -207,33 +214,44 @@ void Renderer3D::add_debug_aabb(const vec3& min, const vec3& max, } void Renderer3D::create_pipeline() { - WGPUBindGroupLayoutEntry entries[5] = {}; + WGPUBindGroupLayoutEntry entries[6] = {}; + // Binding 0: Global Uniforms entries[0].binding = 0; entries[0].visibility = WGPUShaderStage_Vertex | WGPUShaderStage_Fragment; entries[0].buffer.type = WGPUBufferBindingType_Uniform; entries[0].buffer.minBindingSize = sizeof(GlobalUniforms); + // Binding 1: Object Data entries[1].binding = 1; entries[1].visibility = WGPUShaderStage_Vertex | WGPUShaderStage_Fragment; entries[1].buffer.type = WGPUBufferBindingType_ReadOnlyStorage; entries[1].buffer.minBindingSize = sizeof(ObjectData) * kMaxObjects; + // Binding 2: BVH Nodes entries[2].binding = 2; entries[2].visibility = WGPUShaderStage_Fragment; - entries[2].texture.sampleType = WGPUTextureSampleType_Float; - entries[2].texture.viewDimension = WGPUTextureViewDimension_2D; + entries[2].buffer.type = WGPUBufferBindingType_ReadOnlyStorage; + entries[2].buffer.minBindingSize = sizeof(BVHNode) * kMaxObjects * 2; + // Binding 3: Noise Texture entries[3].binding = 3; entries[3].visibility = WGPUShaderStage_Fragment; - entries[3].sampler.type = WGPUSamplerBindingType_Filtering; + entries[3].texture.sampleType = WGPUTextureSampleType_Float; + entries[3].texture.viewDimension = WGPUTextureViewDimension_2D; + // Binding 4: Default Sampler entries[4].binding = 4; entries[4].visibility = WGPUShaderStage_Fragment; - entries[4].texture.sampleType = WGPUTextureSampleType_Float; - entries[4].texture.viewDimension = WGPUTextureViewDimension_2D; + entries[4].sampler.type = WGPUSamplerBindingType_Filtering; + + // Binding 5: Sky Texture + entries[5].binding = 5; + entries[5].visibility = WGPUShaderStage_Fragment; + entries[5].texture.sampleType = WGPUTextureSampleType_Float; + entries[5].texture.viewDimension = WGPUTextureViewDimension_2D; WGPUBindGroupLayoutDescriptor bgl_desc = {}; - bgl_desc.entryCount = 5; + bgl_desc.entryCount = 6; bgl_desc.entries = entries; WGPUBindGroupLayout bgl = wgpuDeviceCreateBindGroupLayout(device_, &bgl_desc); @@ -311,8 +329,8 @@ void Renderer3D::update_uniforms(const Scene& scene, const Camera& camera, globals.camera_pos_time = vec4(camera.position.x, camera.position.y, camera.position.z, time); globals.params = - vec4((float)std::min((size_t)kMaxObjects, scene.objects.size()), 0.0f, - 0.0f, 0.0f); + vec4((float)std::min((size_t)kMaxObjects, scene.objects.size()), + s_bvh_enabled_ ? 1.0f : 0.0f, 0.0f, 0.0f); globals.resolution = vec2((float)width_, (float)height_); globals.padding = vec2(0.0f, 0.0f); @@ -346,6 +364,16 @@ void Renderer3D::update_uniforms(const Scene& scene, const Camera& camera, wgpuQueueWriteBuffer(queue_, object_storage_buffer_, 0, obj_data.data(), obj_data.size() * sizeof(ObjectData)); } + + // Build and upload BVH if enabled + if (s_bvh_enabled_) { + BVHBuilder::build(cpu_bvh_, scene.objects); + if (!cpu_bvh_.nodes.empty()) { + wgpuQueueWriteBuffer(queue_, bvh_storage_buffer_, 0, + cpu_bvh_.nodes.data(), + cpu_bvh_.nodes.size() * sizeof(BVHNode)); + } + } } void Renderer3D::draw(WGPURenderPassEncoder pass, const Scene& scene, @@ -357,7 +385,7 @@ void Renderer3D::draw(WGPURenderPassEncoder pass, const Scene& scene, if (bind_group_) wgpuBindGroupRelease(bind_group_); - WGPUBindGroupEntry bg_entries[5] = {}; + WGPUBindGroupEntry bg_entries[6] = {}; bg_entries[0].binding = 0; bg_entries[0].buffer = global_uniform_buffer_; @@ -368,18 +396,22 @@ void Renderer3D::draw(WGPURenderPassEncoder pass, const Scene& scene, bg_entries[1].size = sizeof(ObjectData) * kMaxObjects; bg_entries[2].binding = 2; - bg_entries[2].textureView = noise_texture_view_; + bg_entries[2].buffer = bvh_storage_buffer_; + bg_entries[2].size = sizeof(BVHNode) * kMaxObjects * 2; bg_entries[3].binding = 3; - bg_entries[3].sampler = default_sampler_; + bg_entries[3].textureView = noise_texture_view_; bg_entries[4].binding = 4; - bg_entries[4].textureView = + bg_entries[4].sampler = default_sampler_; + + bg_entries[5].binding = 5; + bg_entries[5].textureView = sky_texture_view_ ? sky_texture_view_ : noise_texture_view_; // Fallback WGPUBindGroupDescriptor bg_desc = {}; bg_desc.layout = wgpuRenderPipelineGetBindGroupLayout(pipeline_, 0); - bg_desc.entryCount = 5; + bg_desc.entryCount = 6; bg_desc.entries = bg_entries; bind_group_ = wgpuDeviceCreateBindGroup(device_, &bg_desc); |
