From 8398b3de477c45098ade454fe1eeff79a755a1fb Mon Sep 17 00:00:00 2001 From: skal Date: Mon, 9 Feb 2026 14:08:52 +0100 Subject: refactor: Unify TextureManager compute pipeline management Replace individual pipeline pointers with map-based system. - Changed from 3 pointers to std::map - Unified get_or_create_compute_pipeline() for lazy init - Unified dispatch_compute() for all shaders - Simplified create_gpu_*_texture() methods (~390 lines removed) handoff(Claude): GPU procedural texture refactoring complete --- src/gpu/texture_manager.cc | 499 ++++++++++++--------------------------------- src/gpu/texture_manager.h | 23 ++- 2 files changed, 150 insertions(+), 372 deletions(-) (limited to 'src') diff --git a/src/gpu/texture_manager.cc b/src/gpu/texture_manager.cc index 9a19957..2b83f63 100644 --- a/src/gpu/texture_manager.cc +++ b/src/gpu/texture_manager.cc @@ -21,9 +21,6 @@ void TextureManager::init(WGPUDevice device, WGPUQueue queue) { device_ = device; queue_ = queue; - noise_compute_pipeline_ = nullptr; - perlin_compute_pipeline_ = nullptr; - grid_compute_pipeline_ = nullptr; } void TextureManager::shutdown() { @@ -32,18 +29,13 @@ void TextureManager::shutdown() { wgpuTextureRelease(pair.second.texture); } textures_.clear(); - if (noise_compute_pipeline_) { - wgpuComputePipelineRelease(noise_compute_pipeline_); - noise_compute_pipeline_ = nullptr; - } - if (perlin_compute_pipeline_) { - wgpuComputePipelineRelease(perlin_compute_pipeline_); - perlin_compute_pipeline_ = nullptr; - } - if (grid_compute_pipeline_) { - wgpuComputePipelineRelease(grid_compute_pipeline_); - grid_compute_pipeline_ = nullptr; + + for (auto& pair : compute_pipelines_) { + if (pair.second.pipeline) { + wgpuComputePipelineRelease(pair.second.pipeline); + } } + compute_pipelines_.clear(); } void TextureManager::create_procedural_texture( @@ -131,99 +123,38 @@ WGPUTextureView TextureManager::get_texture_view(const std::string& name) { return nullptr; } -void TextureManager::dispatch_noise_compute(WGPUTexture target, - const GpuProceduralParams& params) { - // Lazy-init compute pipeline - if (!noise_compute_pipeline_) { - extern const char* gen_noise_compute_wgsl; - - // Resolve #include directives using ShaderComposer - ShaderComposer& composer = ShaderComposer::Get(); - std::string resolved_shader = composer.Compose({}, gen_noise_compute_wgsl); - - WGPUShaderSourceWGSL wgsl_src = {}; - wgsl_src.chain.sType = WGPUSType_ShaderSourceWGSL; - wgsl_src.code = str_view(resolved_shader.c_str()); - WGPUShaderModuleDescriptor shader_desc = {}; - shader_desc.nextInChain = &wgsl_src.chain; - WGPUShaderModule shader_module = - wgpuDeviceCreateShaderModule(device_, &shader_desc); - - // Bind group layout (storage texture + uniform) - WGPUBindGroupLayoutEntry bgl_entries[2] = {}; - bgl_entries[0].binding = 0; - bgl_entries[0].visibility = WGPUShaderStage_Compute; - bgl_entries[0].storageTexture.access = WGPUStorageTextureAccess_WriteOnly; - bgl_entries[0].storageTexture.format = WGPUTextureFormat_RGBA8Unorm; - bgl_entries[0].storageTexture.viewDimension = WGPUTextureViewDimension_2D; - - bgl_entries[1].binding = 1; - bgl_entries[1].visibility = WGPUShaderStage_Compute; - bgl_entries[1].buffer.type = WGPUBufferBindingType_Uniform; - bgl_entries[1].buffer.minBindingSize = 16; // sizeof(NoiseParams) - - WGPUBindGroupLayoutDescriptor bgl_desc = {}; - bgl_desc.entryCount = 2; - bgl_desc.entries = bgl_entries; - WGPUBindGroupLayout bind_group_layout = - wgpuDeviceCreateBindGroupLayout(device_, &bgl_desc); - - WGPUPipelineLayoutDescriptor pl_desc = {}; - pl_desc.bindGroupLayoutCount = 1; - pl_desc.bindGroupLayouts = &bind_group_layout; - WGPUPipelineLayout pipeline_layout = - wgpuDeviceCreatePipelineLayout(device_, &pl_desc); - - WGPUComputePipelineDescriptor pipeline_desc = {}; - pipeline_desc.layout = pipeline_layout; - pipeline_desc.compute.module = shader_module; - pipeline_desc.compute.entryPoint = str_view("main"); - - noise_compute_pipeline_ = - wgpuDeviceCreateComputePipeline(device_, &pipeline_desc); - - wgpuPipelineLayoutRelease(pipeline_layout); - wgpuBindGroupLayoutRelease(bind_group_layout); - wgpuShaderModuleRelease(shader_module); +WGPUComputePipeline TextureManager::get_or_create_compute_pipeline( + const std::string& func_name, const char* shader_code, + size_t uniform_size) { + auto it = compute_pipelines_.find(func_name); + if (it != compute_pipelines_.end()) { + return it->second.pipeline; } - // Create uniform buffer (width, height, seed, frequency) - struct NoiseParams { - uint32_t width; - uint32_t height; - float seed; - float frequency; - }; - NoiseParams uniform_data = {(uint32_t)params.width, (uint32_t)params.height, - params.params[0], params.params[1]}; - WGPUBufferDescriptor buf_desc = {}; - buf_desc.size = sizeof(NoiseParams); - buf_desc.usage = WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst; - buf_desc.mappedAtCreation = WGPUOptionalBool_True; - WGPUBuffer uniform_buf = wgpuDeviceCreateBuffer(device_, &buf_desc); - void* mapped = wgpuBufferGetMappedRange(uniform_buf, 0, sizeof(NoiseParams)); - memcpy(mapped, &uniform_data, sizeof(NoiseParams)); - wgpuBufferUnmap(uniform_buf); + // Create new pipeline + ShaderComposer& composer = ShaderComposer::Get(); + std::string resolved_shader = composer.Compose({}, shader_code); - // Create storage texture view - WGPUTextureViewDescriptor view_desc = {}; - view_desc.format = WGPUTextureFormat_RGBA8Unorm; - view_desc.dimension = WGPUTextureViewDimension_2D; - view_desc.mipLevelCount = 1; - view_desc.arrayLayerCount = 1; - WGPUTextureView target_view = wgpuTextureCreateView(target, &view_desc); + WGPUShaderSourceWGSL wgsl_src = {}; + wgsl_src.chain.sType = WGPUSType_ShaderSourceWGSL; + wgsl_src.code = str_view(resolved_shader.c_str()); + WGPUShaderModuleDescriptor shader_desc = {}; + shader_desc.nextInChain = &wgsl_src.chain; + WGPUShaderModule shader_module = + wgpuDeviceCreateShaderModule(device_, &shader_desc); - // Create bind group layout entries (must match pipeline) + // Bind group layout (storage texture + uniform) WGPUBindGroupLayoutEntry bgl_entries[2] = {}; bgl_entries[0].binding = 0; bgl_entries[0].visibility = WGPUShaderStage_Compute; bgl_entries[0].storageTexture.access = WGPUStorageTextureAccess_WriteOnly; bgl_entries[0].storageTexture.format = WGPUTextureFormat_RGBA8Unorm; bgl_entries[0].storageTexture.viewDimension = WGPUTextureViewDimension_2D; + bgl_entries[1].binding = 1; bgl_entries[1].visibility = WGPUShaderStage_Compute; bgl_entries[1].buffer.type = WGPUBufferBindingType_Uniform; - bgl_entries[1].buffer.minBindingSize = 16; + bgl_entries[1].buffer.minBindingSize = uniform_size; WGPUBindGroupLayoutDescriptor bgl_desc = {}; bgl_desc.entryCount = 2; @@ -231,165 +162,54 @@ void TextureManager::dispatch_noise_compute(WGPUTexture target, WGPUBindGroupLayout bind_group_layout = wgpuDeviceCreateBindGroupLayout(device_, &bgl_desc); - // Create bind group - WGPUBindGroupEntry bg_entries[2] = {}; - bg_entries[0].binding = 0; - bg_entries[0].textureView = target_view; - bg_entries[1].binding = 1; - bg_entries[1].buffer = uniform_buf; - bg_entries[1].size = sizeof(NoiseParams); - - WGPUBindGroupDescriptor bg_desc = {}; - bg_desc.layout = bind_group_layout; - bg_desc.entryCount = 2; - bg_desc.entries = bg_entries; - WGPUBindGroup bind_group = wgpuDeviceCreateBindGroup(device_, &bg_desc); + WGPUPipelineLayoutDescriptor pl_desc = {}; + pl_desc.bindGroupLayoutCount = 1; + pl_desc.bindGroupLayouts = &bind_group_layout; + WGPUPipelineLayout pipeline_layout = + wgpuDeviceCreatePipelineLayout(device_, &pl_desc); - // Dispatch compute - WGPUCommandEncoderDescriptor enc_desc = {}; - WGPUCommandEncoder encoder = wgpuDeviceCreateCommandEncoder(device_, &enc_desc); - WGPUComputePassEncoder pass = wgpuCommandEncoderBeginComputePass(encoder, nullptr); - wgpuComputePassEncoderSetPipeline(pass, noise_compute_pipeline_); - wgpuComputePassEncoderSetBindGroup(pass, 0, bind_group, 0, nullptr); - wgpuComputePassEncoderDispatchWorkgroups(pass, (params.width + 7) / 8, - (params.height + 7) / 8, 1); - wgpuComputePassEncoderEnd(pass); + WGPUComputePipelineDescriptor pipeline_desc = {}; + pipeline_desc.layout = pipeline_layout; + pipeline_desc.compute.module = shader_module; + pipeline_desc.compute.entryPoint = str_view("main"); - WGPUCommandBufferDescriptor cmd_desc = {}; - WGPUCommandBuffer cmd = wgpuCommandEncoderFinish(encoder, &cmd_desc); - wgpuQueueSubmit(queue_, 1, &cmd); + WGPUComputePipeline pipeline = + wgpuDeviceCreateComputePipeline(device_, &pipeline_desc); - // Cleanup - wgpuCommandBufferRelease(cmd); - wgpuCommandEncoderRelease(encoder); - wgpuComputePassEncoderRelease(pass); - wgpuBindGroupRelease(bind_group); + wgpuPipelineLayoutRelease(pipeline_layout); wgpuBindGroupLayoutRelease(bind_group_layout); - wgpuBufferRelease(uniform_buf); - wgpuTextureViewRelease(target_view); -} + wgpuShaderModuleRelease(shader_module); -void TextureManager::create_gpu_noise_texture( - const std::string& name, const GpuProceduralParams& params) { - // Create storage texture - WGPUTextureDescriptor tex_desc = {}; - tex_desc.usage = - WGPUTextureUsage_StorageBinding | WGPUTextureUsage_TextureBinding; - tex_desc.dimension = WGPUTextureDimension_2D; - tex_desc.size = {(uint32_t)params.width, (uint32_t)params.height, 1}; - tex_desc.format = WGPUTextureFormat_RGBA8Unorm; - tex_desc.mipLevelCount = 1; - tex_desc.sampleCount = 1; - WGPUTexture texture = wgpuDeviceCreateTexture(device_, &tex_desc); - - // Generate via compute - dispatch_noise_compute(texture, params); - - // Create view for sampling - WGPUTextureViewDescriptor view_desc = {}; - view_desc.format = WGPUTextureFormat_RGBA8Unorm; - view_desc.dimension = WGPUTextureViewDimension_2D; - view_desc.mipLevelCount = 1; - view_desc.arrayLayerCount = 1; - WGPUTextureView view = wgpuTextureCreateView(texture, &view_desc); - - // Store texture - GpuTexture gpu_tex; - gpu_tex.texture = texture; - gpu_tex.view = view; - gpu_tex.width = params.width; - gpu_tex.height = params.height; - textures_[name] = gpu_tex; + // Cache pipeline + ComputePipelineInfo info = {pipeline, shader_code, uniform_size}; + compute_pipelines_[func_name] = info; -#if !defined(STRIP_ALL) - printf("Generated GPU noise texture: %s (%dx%d)\n", name.c_str(), - params.width, params.height); -#endif + return pipeline; } -void TextureManager::dispatch_perlin_compute(WGPUTexture target, - const GpuProceduralParams& params) { - // Lazy-init compute pipeline - if (!perlin_compute_pipeline_) { - extern const char* gen_perlin_compute_wgsl; - ShaderComposer& composer = ShaderComposer::Get(); - std::string resolved_shader = composer.Compose({}, gen_perlin_compute_wgsl); - - WGPUShaderSourceWGSL wgsl_src = {}; - wgsl_src.chain.sType = WGPUSType_ShaderSourceWGSL; - wgsl_src.code = str_view(resolved_shader.c_str()); - WGPUShaderModuleDescriptor shader_desc = {}; - shader_desc.nextInChain = &wgsl_src.chain; - WGPUShaderModule shader_module = - wgpuDeviceCreateShaderModule(device_, &shader_desc); - - WGPUBindGroupLayoutEntry bgl_entries[2] = {}; - bgl_entries[0].binding = 0; - bgl_entries[0].visibility = WGPUShaderStage_Compute; - bgl_entries[0].storageTexture.access = WGPUStorageTextureAccess_WriteOnly; - bgl_entries[0].storageTexture.format = WGPUTextureFormat_RGBA8Unorm; - bgl_entries[0].storageTexture.viewDimension = WGPUTextureViewDimension_2D; - bgl_entries[1].binding = 1; - bgl_entries[1].visibility = WGPUShaderStage_Compute; - bgl_entries[1].buffer.type = WGPUBufferBindingType_Uniform; - bgl_entries[1].buffer.minBindingSize = 32; // sizeof(PerlinParams) - - WGPUBindGroupLayoutDescriptor bgl_desc = {}; - bgl_desc.entryCount = 2; - bgl_desc.entries = bgl_entries; - WGPUBindGroupLayout bind_group_layout = - wgpuDeviceCreateBindGroupLayout(device_, &bgl_desc); - - WGPUPipelineLayoutDescriptor pl_desc = {}; - pl_desc.bindGroupLayoutCount = 1; - pl_desc.bindGroupLayouts = &bind_group_layout; - WGPUPipelineLayout pipeline_layout = - wgpuDeviceCreatePipelineLayout(device_, &pl_desc); - - WGPUComputePipelineDescriptor pipeline_desc = {}; - pipeline_desc.layout = pipeline_layout; - pipeline_desc.compute.module = shader_module; - pipeline_desc.compute.entryPoint = str_view("main"); - - perlin_compute_pipeline_ = - wgpuDeviceCreateComputePipeline(device_, &pipeline_desc); - - wgpuPipelineLayoutRelease(pipeline_layout); - wgpuBindGroupLayoutRelease(bind_group_layout); - wgpuShaderModuleRelease(shader_module); +void TextureManager::dispatch_compute(const std::string& func_name, + WGPUTexture target, + const GpuProceduralParams& params, + const void* uniform_data, + size_t uniform_size) { + auto it = compute_pipelines_.find(func_name); + if (it == compute_pipelines_.end()) { + return; // Pipeline not created yet } - // Create uniform buffer - struct PerlinParams { - uint32_t width; - uint32_t height; - float seed; - float frequency; - float amplitude; - float amplitude_decay; - uint32_t octaves; - float _pad0; - }; - PerlinParams uniform_data = { - (uint32_t)params.width, - (uint32_t)params.height, - params.params[0], // seed - params.params[1], // frequency - params.num_params > 2 ? params.params[2] : 1.0f, // amplitude - params.num_params > 3 ? params.params[3] : 0.5f, // amplitude_decay - params.num_params > 4 ? (uint32_t)params.params[4] : 4u, // octaves - 0.0f // padding - }; + WGPUComputePipeline pipeline = it->second.pipeline; + // Create uniform buffer WGPUBufferDescriptor buf_desc = {}; - buf_desc.size = sizeof(PerlinParams); + buf_desc.size = uniform_size; buf_desc.usage = WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst; buf_desc.mappedAtCreation = WGPUOptionalBool_True; WGPUBuffer uniform_buf = wgpuDeviceCreateBuffer(device_, &buf_desc); - void* mapped = wgpuBufferGetMappedRange(uniform_buf, 0, sizeof(PerlinParams)); - memcpy(mapped, &uniform_data, sizeof(PerlinParams)); + void* mapped = wgpuBufferGetMappedRange(uniform_buf, 0, uniform_size); + memcpy(mapped, uniform_data, uniform_size); wgpuBufferUnmap(uniform_buf); + // Create storage texture view WGPUTextureViewDescriptor view_desc = {}; view_desc.format = WGPUTextureFormat_RGBA8Unorm; view_desc.dimension = WGPUTextureViewDimension_2D; @@ -397,6 +217,7 @@ void TextureManager::dispatch_perlin_compute(WGPUTexture target, view_desc.arrayLayerCount = 1; WGPUTextureView target_view = wgpuTextureCreateView(target, &view_desc); + // Create bind group layout entries (must match pipeline) WGPUBindGroupLayoutEntry bgl_entries[2] = {}; bgl_entries[0].binding = 0; bgl_entries[0].visibility = WGPUShaderStage_Compute; @@ -406,7 +227,7 @@ void TextureManager::dispatch_perlin_compute(WGPUTexture target, bgl_entries[1].binding = 1; bgl_entries[1].visibility = WGPUShaderStage_Compute; bgl_entries[1].buffer.type = WGPUBufferBindingType_Uniform; - bgl_entries[1].buffer.minBindingSize = 32; + bgl_entries[1].buffer.minBindingSize = uniform_size; WGPUBindGroupLayoutDescriptor bgl_desc = {}; bgl_desc.entryCount = 2; @@ -414,12 +235,13 @@ void TextureManager::dispatch_perlin_compute(WGPUTexture target, WGPUBindGroupLayout bind_group_layout = wgpuDeviceCreateBindGroupLayout(device_, &bgl_desc); + // Create bind group WGPUBindGroupEntry bg_entries[2] = {}; bg_entries[0].binding = 0; bg_entries[0].textureView = target_view; bg_entries[1].binding = 1; bg_entries[1].buffer = uniform_buf; - bg_entries[1].size = sizeof(PerlinParams); + bg_entries[1].size = uniform_size; WGPUBindGroupDescriptor bg_desc = {}; bg_desc.layout = bind_group_layout; @@ -427,10 +249,13 @@ void TextureManager::dispatch_perlin_compute(WGPUTexture target, bg_desc.entries = bg_entries; WGPUBindGroup bind_group = wgpuDeviceCreateBindGroup(device_, &bg_desc); + // Dispatch compute WGPUCommandEncoderDescriptor enc_desc = {}; - WGPUCommandEncoder encoder = wgpuDeviceCreateCommandEncoder(device_, &enc_desc); - WGPUComputePassEncoder pass = wgpuCommandEncoderBeginComputePass(encoder, nullptr); - wgpuComputePassEncoderSetPipeline(pass, perlin_compute_pipeline_); + WGPUCommandEncoder encoder = + wgpuDeviceCreateCommandEncoder(device_, &enc_desc); + WGPUComputePassEncoder pass = + wgpuCommandEncoderBeginComputePass(encoder, nullptr); + wgpuComputePassEncoderSetPipeline(pass, pipeline); wgpuComputePassEncoderSetBindGroup(pass, 0, bind_group, 0, nullptr); wgpuComputePassEncoderDispatchWorkgroups(pass, (params.width + 7) / 8, (params.height + 7) / 8, 1); @@ -440,6 +265,7 @@ void TextureManager::dispatch_perlin_compute(WGPUTexture target, WGPUCommandBuffer cmd = wgpuCommandEncoderFinish(encoder, &cmd_desc); wgpuQueueSubmit(queue_, 1, &cmd); + // Cleanup wgpuCommandBufferRelease(cmd); wgpuCommandEncoderRelease(encoder); wgpuComputePassEncoderRelease(pass); @@ -449,8 +275,11 @@ void TextureManager::dispatch_perlin_compute(WGPUTexture target, wgpuTextureViewRelease(target_view); } -void TextureManager::create_gpu_perlin_texture( +void TextureManager::create_gpu_noise_texture( const std::string& name, const GpuProceduralParams& params) { + extern const char* gen_noise_compute_wgsl; + get_or_create_compute_pipeline("gen_noise", gen_noise_compute_wgsl, 16); + WGPUTextureDescriptor tex_desc = {}; tex_desc.usage = WGPUTextureUsage_StorageBinding | WGPUTextureUsage_TextureBinding; @@ -461,7 +290,15 @@ void TextureManager::create_gpu_perlin_texture( tex_desc.sampleCount = 1; WGPUTexture texture = wgpuDeviceCreateTexture(device_, &tex_desc); - dispatch_perlin_compute(texture, params); + struct NoiseParams { + uint32_t width; + uint32_t height; + float seed; + float frequency; + }; + NoiseParams uniforms = {(uint32_t)params.width, (uint32_t)params.height, + params.params[0], params.params[1]}; + dispatch_compute("gen_noise", texture, params, &uniforms, sizeof(NoiseParams)); WGPUTextureViewDescriptor view_desc = {}; view_desc.format = WGPUTextureFormat_RGBA8Unorm; @@ -478,147 +315,73 @@ void TextureManager::create_gpu_perlin_texture( textures_[name] = gpu_tex; #if !defined(STRIP_ALL) - printf("Generated GPU perlin texture: %s (%dx%d)\n", name.c_str(), + printf("Generated GPU noise texture: %s (%dx%d)\n", name.c_str(), params.width, params.height); #endif } -void TextureManager::dispatch_grid_compute(WGPUTexture target, - const GpuProceduralParams& params) { - // Lazy-init compute pipeline - if (!grid_compute_pipeline_) { - extern const char* gen_grid_compute_wgsl; - ShaderComposer& composer = ShaderComposer::Get(); - std::string resolved_shader = composer.Compose({}, gen_grid_compute_wgsl); - - WGPUShaderSourceWGSL wgsl_src = {}; - wgsl_src.chain.sType = WGPUSType_ShaderSourceWGSL; - wgsl_src.code = str_view(resolved_shader.c_str()); - WGPUShaderModuleDescriptor shader_desc = {}; - shader_desc.nextInChain = &wgsl_src.chain; - WGPUShaderModule shader_module = - wgpuDeviceCreateShaderModule(device_, &shader_desc); - - WGPUBindGroupLayoutEntry bgl_entries[2] = {}; - bgl_entries[0].binding = 0; - bgl_entries[0].visibility = WGPUShaderStage_Compute; - bgl_entries[0].storageTexture.access = WGPUStorageTextureAccess_WriteOnly; - bgl_entries[0].storageTexture.format = WGPUTextureFormat_RGBA8Unorm; - bgl_entries[0].storageTexture.viewDimension = WGPUTextureViewDimension_2D; - bgl_entries[1].binding = 1; - bgl_entries[1].visibility = WGPUShaderStage_Compute; - bgl_entries[1].buffer.type = WGPUBufferBindingType_Uniform; - bgl_entries[1].buffer.minBindingSize = 16; // sizeof(GridParams) - - WGPUBindGroupLayoutDescriptor bgl_desc = {}; - bgl_desc.entryCount = 2; - bgl_desc.entries = bgl_entries; - WGPUBindGroupLayout bind_group_layout = - wgpuDeviceCreateBindGroupLayout(device_, &bgl_desc); - - WGPUPipelineLayoutDescriptor pl_desc = {}; - pl_desc.bindGroupLayoutCount = 1; - pl_desc.bindGroupLayouts = &bind_group_layout; - WGPUPipelineLayout pipeline_layout = - wgpuDeviceCreatePipelineLayout(device_, &pl_desc); - - WGPUComputePipelineDescriptor pipeline_desc = {}; - pipeline_desc.layout = pipeline_layout; - pipeline_desc.compute.module = shader_module; - pipeline_desc.compute.entryPoint = str_view("main"); - - grid_compute_pipeline_ = - wgpuDeviceCreateComputePipeline(device_, &pipeline_desc); - - wgpuPipelineLayoutRelease(pipeline_layout); - wgpuBindGroupLayoutRelease(bind_group_layout); - wgpuShaderModuleRelease(shader_module); - } +void TextureManager::create_gpu_perlin_texture( + const std::string& name, const GpuProceduralParams& params) { + extern const char* gen_perlin_compute_wgsl; + get_or_create_compute_pipeline("gen_perlin", gen_perlin_compute_wgsl, 32); - // Create uniform buffer - struct GridParams { + WGPUTextureDescriptor tex_desc = {}; + tex_desc.usage = + WGPUTextureUsage_StorageBinding | WGPUTextureUsage_TextureBinding; + tex_desc.dimension = WGPUTextureDimension_2D; + tex_desc.size = {(uint32_t)params.width, (uint32_t)params.height, 1}; + tex_desc.format = WGPUTextureFormat_RGBA8Unorm; + tex_desc.mipLevelCount = 1; + tex_desc.sampleCount = 1; + WGPUTexture texture = wgpuDeviceCreateTexture(device_, &tex_desc); + + struct PerlinParams { uint32_t width; uint32_t height; - uint32_t grid_size; - uint32_t thickness; + float seed; + float frequency; + float amplitude; + float amplitude_decay; + uint32_t octaves; + float _pad0; }; - GridParams uniform_data = { + PerlinParams uniforms = { (uint32_t)params.width, (uint32_t)params.height, - params.num_params > 0 ? (uint32_t)params.params[0] : 32u, // grid_size - params.num_params > 1 ? (uint32_t)params.params[1] : 2u // thickness - }; - - WGPUBufferDescriptor buf_desc = {}; - buf_desc.size = sizeof(GridParams); - buf_desc.usage = WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst; - buf_desc.mappedAtCreation = WGPUOptionalBool_True; - WGPUBuffer uniform_buf = wgpuDeviceCreateBuffer(device_, &buf_desc); - void* mapped = wgpuBufferGetMappedRange(uniform_buf, 0, sizeof(GridParams)); - memcpy(mapped, &uniform_data, sizeof(GridParams)); - wgpuBufferUnmap(uniform_buf); + params.params[0], + params.params[1], + params.num_params > 2 ? params.params[2] : 1.0f, + params.num_params > 3 ? params.params[3] : 0.5f, + params.num_params > 4 ? (uint32_t)params.params[4] : 4u, + 0.0f}; + dispatch_compute("gen_perlin", texture, params, &uniforms, + sizeof(PerlinParams)); WGPUTextureViewDescriptor view_desc = {}; view_desc.format = WGPUTextureFormat_RGBA8Unorm; view_desc.dimension = WGPUTextureViewDimension_2D; view_desc.mipLevelCount = 1; view_desc.arrayLayerCount = 1; - WGPUTextureView target_view = wgpuTextureCreateView(target, &view_desc); - - WGPUBindGroupLayoutEntry bgl_entries[2] = {}; - bgl_entries[0].binding = 0; - bgl_entries[0].visibility = WGPUShaderStage_Compute; - bgl_entries[0].storageTexture.access = WGPUStorageTextureAccess_WriteOnly; - bgl_entries[0].storageTexture.format = WGPUTextureFormat_RGBA8Unorm; - bgl_entries[0].storageTexture.viewDimension = WGPUTextureViewDimension_2D; - bgl_entries[1].binding = 1; - bgl_entries[1].visibility = WGPUShaderStage_Compute; - bgl_entries[1].buffer.type = WGPUBufferBindingType_Uniform; - bgl_entries[1].buffer.minBindingSize = 16; - - WGPUBindGroupLayoutDescriptor bgl_desc = {}; - bgl_desc.entryCount = 2; - bgl_desc.entries = bgl_entries; - WGPUBindGroupLayout bind_group_layout = - wgpuDeviceCreateBindGroupLayout(device_, &bgl_desc); - - WGPUBindGroupEntry bg_entries[2] = {}; - bg_entries[0].binding = 0; - bg_entries[0].textureView = target_view; - bg_entries[1].binding = 1; - bg_entries[1].buffer = uniform_buf; - bg_entries[1].size = sizeof(GridParams); - - WGPUBindGroupDescriptor bg_desc = {}; - bg_desc.layout = bind_group_layout; - bg_desc.entryCount = 2; - bg_desc.entries = bg_entries; - WGPUBindGroup bind_group = wgpuDeviceCreateBindGroup(device_, &bg_desc); - - WGPUCommandEncoderDescriptor enc_desc = {}; - WGPUCommandEncoder encoder = wgpuDeviceCreateCommandEncoder(device_, &enc_desc); - WGPUComputePassEncoder pass = wgpuCommandEncoderBeginComputePass(encoder, nullptr); - wgpuComputePassEncoderSetPipeline(pass, grid_compute_pipeline_); - wgpuComputePassEncoderSetBindGroup(pass, 0, bind_group, 0, nullptr); - wgpuComputePassEncoderDispatchWorkgroups(pass, (params.width + 7) / 8, - (params.height + 7) / 8, 1); - wgpuComputePassEncoderEnd(pass); + WGPUTextureView view = wgpuTextureCreateView(texture, &view_desc); - WGPUCommandBufferDescriptor cmd_desc = {}; - WGPUCommandBuffer cmd = wgpuCommandEncoderFinish(encoder, &cmd_desc); - wgpuQueueSubmit(queue_, 1, &cmd); + GpuTexture gpu_tex; + gpu_tex.texture = texture; + gpu_tex.view = view; + gpu_tex.width = params.width; + gpu_tex.height = params.height; + textures_[name] = gpu_tex; - wgpuCommandBufferRelease(cmd); - wgpuCommandEncoderRelease(encoder); - wgpuComputePassEncoderRelease(pass); - wgpuBindGroupRelease(bind_group); - wgpuBindGroupLayoutRelease(bind_group_layout); - wgpuBufferRelease(uniform_buf); - wgpuTextureViewRelease(target_view); +#if !defined(STRIP_ALL) + printf("Generated GPU perlin texture: %s (%dx%d)\n", name.c_str(), + params.width, params.height); +#endif } void TextureManager::create_gpu_grid_texture( const std::string& name, const GpuProceduralParams& params) { + extern const char* gen_grid_compute_wgsl; + get_or_create_compute_pipeline("gen_grid", gen_grid_compute_wgsl, 16); + WGPUTextureDescriptor tex_desc = {}; tex_desc.usage = WGPUTextureUsage_StorageBinding | WGPUTextureUsage_TextureBinding; @@ -629,7 +392,17 @@ void TextureManager::create_gpu_grid_texture( tex_desc.sampleCount = 1; WGPUTexture texture = wgpuDeviceCreateTexture(device_, &tex_desc); - dispatch_grid_compute(texture, params); + struct GridParams { + uint32_t width; + uint32_t height; + uint32_t grid_size; + uint32_t thickness; + }; + GridParams uniforms = { + (uint32_t)params.width, (uint32_t)params.height, + params.num_params > 0 ? (uint32_t)params.params[0] : 32u, + params.num_params > 1 ? (uint32_t)params.params[1] : 2u}; + dispatch_compute("gen_grid", texture, params, &uniforms, sizeof(GridParams)); WGPUTextureViewDescriptor view_desc = {}; view_desc.format = WGPUTextureFormat_RGBA8Unorm; diff --git a/src/gpu/texture_manager.h b/src/gpu/texture_manager.h index b2dea84..63c2947 100644 --- a/src/gpu/texture_manager.h +++ b/src/gpu/texture_manager.h @@ -61,16 +61,21 @@ class TextureManager { WGPUTextureView get_texture_view(const std::string& name); private: - void dispatch_noise_compute(WGPUTexture target, - const GpuProceduralParams& params); - void dispatch_perlin_compute(WGPUTexture target, - const GpuProceduralParams& params); - void dispatch_grid_compute(WGPUTexture target, - const GpuProceduralParams& params); + struct ComputePipelineInfo { + WGPUComputePipeline pipeline; + const char* shader_code; + size_t uniform_size; + }; + + WGPUComputePipeline get_or_create_compute_pipeline(const std::string& func_name, + const char* shader_code, + size_t uniform_size); + void dispatch_compute(const std::string& func_name, WGPUTexture target, + const GpuProceduralParams& params, const void* uniform_data, + size_t uniform_size); + WGPUDevice device_; WGPUQueue queue_; std::map textures_; - WGPUComputePipeline noise_compute_pipeline_ = nullptr; - WGPUComputePipeline perlin_compute_pipeline_ = nullptr; - WGPUComputePipeline grid_compute_pipeline_ = nullptr; + std::map compute_pipelines_; }; -- cgit v1.2.3