OverviewFilesCommitsIssuesDocsReleasesPeers

proc-nodes commits / 7351194

gpu: emitted means WRITTEN; mesh: a non-indexed surface is still triangles
Two defects the bridged mountain found, one of them mine from the fusion. `n30_s0` UNDECLARED IDENTIFIER. compile_batch set ctx.emitted_nodes to the whole batch up front, so param() resolved a socket to a producer's local before that producer had emitted -- or when it had emitted NOTHING, because compile_glsl returned empty and the loop skips it. The consumer then named a local that does not exist and the whole shader failed to parse: ERROR: 0:46: 'n30_s0' : undeclared identifier WARNING: ProcNodes: GPU pipeline creation failed for SetPosition The list is built as the loop goes now, so a node can only name a producer that has already put its declaration above it. Execution order is topological, so a real producer is always there; anything else falls back to the push constant, which is what it did before the fusion existed. A NON-INDEXED SURFACE IS STILL TRIANGLES. ProcMesh::from_array_mesh copied ARRAY_INDEX only when present, so a surface without one produced a ProcMesh with positions and NO indices -- triangle_count() == 0, and every node downstream saw a mesh with no faces: proc-nodes: Mesh to SDF Grid got no triangles, so there is no surface proc-nodes: SDF Grid Fillet got no grid proc-nodes: Grid to Mesh got no grid ProcNodes [GPU=true]: execute=130.493ms to_array_mesh=0.0ms on a cage that had 60516 corners. blender-bridge builds exactly that shape: Blender exports per-loop-triangle CORNERS so modifier normals survive, and never writes an index array. For a non-indexed triangle list the fan IS the index array -- 0, 1, 2, ... -- and it is synthesised now. glsl_golden_gate 32/32 sdf_grid_gate 3/3 volume_mesh_gate 4/4 gpu_batch_gate 6/6 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
7351194747532b6af2bd2f34f5e3c31701e3b35d
by plankatron <fleeky@gmail.com> · 2026-09-06T20:04:58.000Z

Changed files (2) +32 -1

src/core/proc_mesh.cpp +16 -0
……@@ -415,6 +415,22 @@ Ref<ProcMesh> ProcMesh::from_array_mesh(const Ref<Mesh> &p_mesh) {
415415 }
416416 if (arrays.size() > Mesh::ARRAY_INDEX && arrays[Mesh::ARRAY_INDEX].get_type() != Variant::NIL) {
417417 out->indices = arrays[Mesh::ARRAY_INDEX];
418 } else {
419 // ⛔ A NON-INDEXED SURFACE IS STILL TRIANGLES. Without an index array
420 // this left `indices` empty, so triangle_count() was 0 and every node
421 // downstream saw a mesh with no faces -- "Mesh to SDF Grid got no
422 // triangles", on a cage that had 60516 corners. blender-bridge builds
423 // exactly this: Blender exports per-loop-triangle CORNERS so modifier
424 // normals survive, and never writes an index array. The fan IS the
425 // index array in that case: 0, 1, 2, ...
426 const int vcount = out->positions.size();
427 if (vcount >= 3) {
428 out->indices.resize(vcount - (vcount % 3));
429 int32_t *iw = out->indices.ptrw();
430 for (int i = 0; i < out->indices.size(); i++) {
431 iw[i] = i;
432 }
433 }
418434 }
419435 return out;
420436}
src/gpu/gpu_compiler.cpp +16 -1
……@@ -162,7 +162,21 @@ String GpuCompiler::compile_batch(
162162 // GraphExecutor refills it on every dispatch. See GlslEmitContext.
163163 ctx.push_constants = true;
164164 ctx.graph = p_graph;
165 ctx.emitted_nodes = p_node_indices;
165 // ⛔ EMITTED, NOT MERELY LISTED, AND ONLY IF ALREADY WRITTEN.
166 //
167 // This was set to the whole batch up front, so param() would resolve a
168 // socket to `nX_sY` for a producer that had not emitted yet -- or had
169 // emitted NOTHING, because compile_glsl returned empty and the loop below
170 // skips it. The consumer then referenced a local that does not exist:
171 //
172 // ERROR: 0:46: 'n30_s0' : undeclared identifier
173 // ProcNodes: GPU pipeline creation failed for SetPosition
174 //
175 // The list is built as the loop goes, so a node can only name a producer
176 // that has ALREADY put its declaration in the body above it. Execution
177 // order is topological, so a real producer is always there first; anything
178 // missing falls back to the push constant, which is what it did before.
179 ctx.emitted_nodes.clear();
166180
167181 String main_body;
168182 String preludes;
……@@ -196,6 +210,7 @@ String GpuCompiler::compile_batch(
196210
197211 main_body += " // Node " + itos(graph_idx) + ": " + node->get_node_title() + "\n";
198212 main_body += " " + glsl + "\n";
213 ctx.emitted_nodes.push_back(graph_idx);
199214 }
200215
201216 String shader = get_shader_template();