OverviewFilesCommitsIssuesDocsReleasesPeers

dc-terrain commits / 3ddf576

gpu density: the SAME sampler bindings on the density_fill side
set_custom_sdf and set_custom_shader are handed the SAME generator body -- one compiles it into edge_intersect, the other into the density shader -- so adding sampler bindings to only edge_intersect would have failed to compile the moment a body referenced noiseVol. The previous commit did exactly that. Two things this side does differently, both discovered by reading the path rather than assuming it matched: - The density shader is NOT density_fill.glsl. That file is not compiled by anything; the shader is assembled in dc_shader_source.h as HEADER + body + MAIN, so the marker goes in the C++ string constant. - Binding 14 is already custom_data_tex, so the volumes sit at 15..22 here and 14..21 in edge_intersect. That is safe because the body names the volumes rather than numbering them, but it is a footgun worth stating. Same conditional rule as before: declared and bound only when the body mentions noiseVol, so presence and absence both agree between shader and uniform set. Verified on map_dc_erosion -- a large-view-distance map, not the small map_dc_terrain the previous commit used, which was the wrong baseline for anything about view distance. edge_intersect compiles twice (default, then the proc-nodes body), chunks mesh, no shader or uniform-set errors. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
3ddf57685dbd7de09d6e7191fbca65e7cbecf15c
by plankatron <fleeky@gmail.com> · 2026-09-07T22:28:25.000Z

Changed files (3) +55 -1

libdc/include/dc_shader_source.h +35 -1
……@@ -200,6 +200,13 @@ layout(set = 0, binding = 13, std430) readonly buffer CustomDataBuf {
200200// indices. The generator emits HBLK_ATLAS_W beside the block constants.
201201layout(set = 0, binding = 14, r32f) uniform readonly image2D custom_data_tex;
202202
203// GENERATOR_SAMPLER_BINDINGS
204// Bindings 15..22 (eight noise volumes) are injected HERE, and only when the
205// generator body samples them -- see _build_custom_shader. NOTE the numbers
206// differ from edge_intersect.glsl (14..21): binding 14 is already custom_data_tex
207// on this side. The body refers to the volumes BY NAME, so the two shaders need
208// not agree on numbering, only on the names.
209
203210// --- Mesh SDF helper functions ---
204211
205212float aabb_point_dist_sq(vec3 p, vec3 bmin, vec3 bmax) {
……@@ -741,8 +748,35 @@ static std::string _build_default_shader() {
741748}
742749
743750// Wrap custom evaluate_density() function body in compute shader template
751// True when a generator body samples the noise volumes, i.e. when the density
752// shader must declare bindings 15..22 and DCCompute must supply descriptors for
753// them. Declaring bindings the body never reads risks them being optimised out
754// of the SPIR-V, after which uniform_set_create is handed descriptors the shader
755// does not reflect and fails -- so absence has to agree too, not just presence.
756static bool _body_uses_noise_volumes(const char* custom_body) {
757 return custom_body != nullptr
758 && std::string(custom_body).find("noiseVol") != std::string::npos;
759}
760
744761static std::string _build_custom_shader(const char* custom_body) {
745 return std::string(DENSITY_GLSL_HEADER) + "\n" + custom_body + "\n" + DENSITY_GLSL_MAIN;
762 std::string header(DENSITY_GLSL_HEADER);
763 const std::string marker = "// GENERATOR_SAMPLER_BINDINGS";
764 size_t pos = header.find(marker);
765 if (pos != std::string::npos) {
766 std::string decls;
767 if (_body_uses_noise_volumes(custom_body)) {
768 for (int i = 0; i < 4; i++) {
769 decls += "layout(set = 0, binding = " + std::to_string(15 + i)
770 + ") uniform sampler3D noiseVol" + std::to_string(i) + ";\n";
771 }
772 for (int i = 0; i < 4; i++) {
773 decls += "layout(set = 0, binding = " + std::to_string(19 + i)
774 + ") uniform sampler3D packedNoiseVol" + std::to_string(i) + ";\n";
775 }
776 }
777 header.replace(pos, marker.length(), decls);
778 }
779 return header + "\n" + custom_body + "\n" + DENSITY_GLSL_MAIN;
746780}
747781
748782#endif // DC_SHADER_SOURCE_H
src/dc_compute.cpp +19 -0
……@@ -137,6 +137,9 @@ bool DCCompute::set_custom_shader(const char* glsl) {
137137 // Custom GLSL provides evaluate_density() + helpers but NOT the compute
138138 // shader boilerplate. Wrap it in the HEADER + MAIN template.
139139 // When glsl is null, rebuild the default shader.
140 // Must be set BEFORE _rebuild_uniform_set so the descriptors match what the
141 // header just declared.
142 sdf_uses_noise_ = _body_uses_noise_volumes(glsl);
140143 std::string full_shader = glsl ? _build_custom_shader(glsl) : _build_default_shader();
141144
142145 Ref<RDShaderSource> src;
……@@ -639,6 +642,21 @@ void DCCompute::_rebuild_uniform_set() {
639642 u12->set_binding(12);
640643 u12->add_id(convex_plane_buf_);
641644
645 // bindings 15..22: the eight noise volumes, present only when the generator
646 // body samples them (the header declares them under the same condition).
647 TypedArray<RDUniform> noise_uniforms;
648 if (sdf_uses_noise_) {
649 for (int i = 0; i < 8; i++) {
650 Ref<RDUniform> un;
651 un.instantiate();
652 un->set_uniform_type(RenderingDevice::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE);
653 un->set_binding(15 + i);
654 un->add_id(i < 4 ? noise_sampler_linear_ : noise_sampler_nearest_);
655 un->add_id(noise_tex_[i]);
656 noise_uniforms.push_back(un);
657 }
658 }
659
642660 TypedArray<RDUniform> uniforms;
643661 uniforms.push_back(u0);
644662 uniforms.push_back(u1);
……@@ -655,6 +673,7 @@ void DCCompute::_rebuild_uniform_set() {
655673 uniforms.push_back(u12);
656674 uniforms.push_back(u13);
657675 uniforms.push_back(u14);
676 for (int i = 0; i < noise_uniforms.size(); i++) uniforms.push_back(noise_uniforms[i]);
658677
659678 uniform_set_ = rd_->uniform_set_create(uniforms, shader_, 0);
660679 if (!uniform_set_.is_valid()) {
src/dc_compute.h +1 -0
……@@ -140,6 +140,7 @@ private:
140140 RID noise_sampler_nearest_;
141141 RID noise_tex_[8] = {};
142142 int noise_dim_ = 0;
143 bool sdf_uses_noise_ = false; // body samples the volumes -> declare + bind 15..22
143144 void _create_noise_placeholders();
144145 void _free_noise();
145146 // ---- ATLAS TRANSPORT for the same data, binding 14 ----------------------