diff options
| author | skal <pascal.massimino@gmail.com> | 2026-02-09 13:52:37 +0100 |
|---|---|---|
| committer | skal <pascal.massimino@gmail.com> | 2026-02-09 13:52:37 +0100 |
| commit | c712874ece1ca7073904f5fb84cc866d28084de0 (patch) | |
| tree | f46727b58d3ac0e4ba3f36d50ea147c086282232 /tools/asset_packer.cc | |
| parent | 0151a43cd179bd08584347e13327a3a722bddf2a (diff) | |
feat(gpu): Add GPU procedural texture generation system
Phase 1 implementation complete:
- GPU compute shader for noise generation (gen_noise.wgsl)
- TextureManager extensions: create_gpu_noise_texture(), dispatch_noise_compute()
- Asset packer PROC_GPU() syntax support with validation
- ShaderComposer integration for #include resolution
- Zero CPU memory overhead (GPU-only textures)
- Init-time and on-demand generation modes
Technical details:
- 8×8 workgroup size for 256×256 textures
- UniformBuffer for params (width, height, seed, frequency)
- Storage texture binding (rgba8unorm, write-only)
- Lazy pipeline compilation on first use
- ~300 bytes code (Phase 1)
Testing:
- New test: test_gpu_procedural.cc (passes)
- All 34 tests passing (100%)
Future phases:
- Phase 2: Add gen_perlin, gen_grid compute shaders
- Phase 3: Variable dimensions, async generation
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Diffstat (limited to 'tools/asset_packer.cc')
| -rw-r--r-- | tools/asset_packer.cc | 61 |
1 files changed, 58 insertions, 3 deletions
diff --git a/tools/asset_packer.cc b/tools/asset_packer.cc index 0d26cf6..72592ae 100644 --- a/tools/asset_packer.cc +++ b/tools/asset_packer.cc @@ -52,6 +52,7 @@ struct AssetBuildInfo { std::string name; std::string filename; // Original filename for static assets bool is_procedural; + bool is_gpu_procedural; std::string proc_func_name; // Function name string std::vector<float> proc_params; // Parameters for procedural function @@ -182,9 +183,62 @@ int main(int argc, char* argv[]) { info.params_array_name = "ASSET_PROC_PARAMS_" + info.name; info.func_name_str_name = "ASSET_PROC_FUNC_STR_" + info.name; info.is_procedural = false; + info.is_gpu_procedural = false; - if (compression_type_str.rfind("PROC(", 0) == 0) { + if (compression_type_str.rfind("PROC_GPU(", 0) == 0) { info.is_procedural = true; + info.is_gpu_procedural = true; + size_t open_paren = compression_type_str.find('('); + size_t close_paren = compression_type_str.rfind(')'); + if (open_paren == std::string::npos || + close_paren == std::string::npos) { + fprintf(stderr, + "Error: Invalid PROC_GPU() syntax for asset: %s, string: [%s]\n", + info.name.c_str(), compression_type_str.c_str()); + return 1; + } + std::string func_and_params_str = compression_type_str.substr( + open_paren + 1, close_paren - open_paren - 1); + + size_t params_start = func_and_params_str.find(','); + if (params_start != std::string::npos) { + std::string params_str = func_and_params_str.substr(params_start + 1); + info.proc_func_name = func_and_params_str.substr(0, params_start); + + size_t current_pos = 0; + while (current_pos < params_str.length()) { + size_t comma_pos = params_str.find(',', current_pos); + std::string param_val_str = + (comma_pos == std::string::npos) + ? params_str.substr(current_pos) + : params_str.substr(current_pos, comma_pos - current_pos); + param_val_str.erase(0, param_val_str.find_first_not_of(" \t\r\n")); + param_val_str.erase(param_val_str.find_last_not_of(" \t\r\n") + 1); + try { + info.proc_params.push_back(std::stof(param_val_str)); + } catch (...) { + fprintf(stderr, "Error: Invalid proc param for %s: %s\n", + info.name.c_str(), param_val_str.c_str()); + return 1; + } + if (comma_pos == std::string::npos) + break; + current_pos = comma_pos + 1; + } + } else { + info.proc_func_name = func_and_params_str; + } + + // Validate GPU procedural function name + if (info.proc_func_name != "gen_noise") { + fprintf(stderr, + "Error: PROC_GPU only supports gen_noise, got: %s for asset: %s\n", + info.proc_func_name.c_str(), info.name.c_str()); + return 1; + } + } else if (compression_type_str.rfind("PROC(", 0) == 0) { + info.is_procedural = true; + info.is_gpu_procedural = false; size_t open_paren = compression_type_str.find('('); size_t close_paren = compression_type_str.rfind(')'); if (open_paren == std::string::npos || @@ -500,12 +554,13 @@ int main(int argc, char* argv[]) { for (const auto& info : asset_build_infos) { fprintf(assets_data_cc_file, " { "); if (info.is_procedural) { - fprintf(assets_data_cc_file, "nullptr, 0, true, %s, %s, %zu", + fprintf(assets_data_cc_file, "nullptr, 0, true, %s, %s, %s, %zu", + info.is_gpu_procedural ? "true" : "false", info.func_name_str_name.c_str(), info.params_array_name.c_str(), info.proc_params.size()); } else { fprintf(assets_data_cc_file, - "%s, ASSET_SIZE_%s, false, nullptr, nullptr, 0", + "%s, ASSET_SIZE_%s, false, false, nullptr, nullptr, 0", info.data_array_name.c_str(), info.name.c_str()); } fprintf(assets_data_cc_file, " },\n"); |
