Skip to content

Commit 666a78f

Browse files
committed
Add rs_allocate_debug_closure renderer customization point
Add a new free function rs_allocate_debug_closure that is called instead of rs_allocate_closure specifically when allocating the OSL debug() closure. This allows renderers to handle debug closure allocation differently from regular closures -- for example, allocating from a separate pool, returning nullptr to suppress debug closures in production, or tracking debug closure usage separately. The closure name is known at JIT compile time, so both the scalar (llvm_gen.cpp) and batched (batched_llvm_gen.cpp) codegen paths check for closure_name == "debug" and emit calls to the new osl_allocate_debug_closure_component / osl_allocate_weighted_debug_closure_component functions, which in turn call rs_allocate_debug_closure instead of rs_allocate_closure. All default/fallback implementations simply delegate to rs_allocate_closure, preserving existing behavior. Signed-off-by: Larry Gritz <lg@larrygritz.com> Assisted-by: Claude Code / Opus 4.6
1 parent f9121bb commit 666a78f

File tree

9 files changed

+112
-5
lines changed

9 files changed

+112
-5
lines changed

src/include/OSL/rs_free_function.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,16 @@ OSL_RSOP OSL_HOSTDEVICE void*
323323
rs_allocate_closure(OSL::OpaqueExecContextPtr oec, size_t size,
324324
size_t alignment);
325325

326+
/// Allocates memory for a debug closure specifically. This is called instead
327+
/// of rs_allocate_closure when the closure being allocated is the OSL
328+
/// `debug()` closure. Renderers can override this to handle debug closures
329+
/// differently (e.g., allocate from a separate pool, or return nullptr to
330+
/// suppress debug closures in production builds). The default fallback
331+
/// implementation simply delegates to rs_allocate_closure.
332+
OSL_RSOP OSL_HOSTDEVICE void*
333+
rs_allocate_debug_closure(OSL::OpaqueExecContextPtr oec, size_t size,
334+
size_t alignment);
335+
326336
/// Report errors, warnings, printf, and fprintf.
327337
/// Fmtlib style format specifier is used (vs. printf style)
328338
/// Arguments are represented as EncodedTypes (encodedtypes.h) and

src/liboslexec/batched_llvm_gen.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7347,8 +7347,13 @@ LLVMGEN(llvm_gen_closure)
73477347
llvm::Value* sg_ptr = rop.sg_void_ptr();
73487348
llvm::Value* id_int = rop.ll.constant(clentry->id);
73497349
llvm::Value* size_int = rop.ll.constant(clentry->struct_size);
7350-
FuncSpec func_spec(weighted ? "allocate_weighted_closure_component"
7351-
: "allocate_closure_component");
7350+
bool is_debug = (closure_name == "debug");
7351+
FuncSpec func_spec(weighted
7352+
? (is_debug
7353+
? "allocate_weighted_debug_closure_component"
7354+
: "allocate_weighted_closure_component")
7355+
: (is_debug ? "allocate_debug_closure_component"
7356+
: "allocate_closure_component"));
73527357
func_spec.mask();
73537358

73547359
// make sure that any temps created to widen uniform values

src/liboslexec/builtindecl.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ DECL(osl_mul_closure_float, "XXXf")
114114
DECL(osl_mul_closure_color, "XXXX")
115115
DECL(osl_allocate_closure_component, "XXii")
116116
DECL(osl_allocate_weighted_closure_component, "XXiiX")
117+
DECL(osl_allocate_debug_closure_component, "XXii")
118+
DECL(osl_allocate_weighted_debug_closure_component, "XXiiX")
117119
DECL(osl_closure_to_string, "sXX")
118120
DECL(osl_closure_to_ustringhash, "hXX")
119121

src/liboslexec/builtindecl_wide_xmacro.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,8 @@
170170

171171
DECL(__OSL_MASKED_OP(allocate_closure_component), "xXXiii")
172172
DECL(__OSL_MASKED_OP(allocate_weighted_closure_component), "xXXiiXi")
173+
DECL(__OSL_MASKED_OP(allocate_debug_closure_component), "xXXiii")
174+
DECL(__OSL_MASKED_OP(allocate_weighted_debug_closure_component), "xXXiiXi")
173175
DECL(__OSL_MASKED_OP(add_closure_closure), "xXXXXi")
174176
DECL(__OSL_MASKED_OP(mul_closure_float), "xXXXXi")
175177
DECL(__OSL_MASKED_OP(mul_closure_color), "xXXXXi")

src/liboslexec/llvm_gen.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3854,13 +3854,18 @@ LLVMGEN(llvm_gen_closure)
38543854
llvm::Value* sg_ptr = rop.sg_void_ptr();
38553855
llvm::Value* id_int = rop.ll.constant(clentry->id);
38563856
llvm::Value* size_int = rop.ll.constant(clentry->struct_size);
3857+
bool is_debug = (closure_name == "debug");
38573858
llvm::Value* return_ptr
38583859
= weighted
3859-
? rop.ll.call_function("osl_allocate_weighted_closure_component",
3860+
? rop.ll.call_function(is_debug
3861+
? "osl_allocate_weighted_debug_closure_component"
3862+
: "osl_allocate_weighted_closure_component",
38603863
sg_ptr, id_int, size_int,
38613864
rop.llvm_void_ptr(*weight))
3862-
: rop.ll.call_function("osl_allocate_closure_component", sg_ptr,
3863-
id_int, size_int);
3865+
: rop.ll.call_function(is_debug
3866+
? "osl_allocate_debug_closure_component"
3867+
: "osl_allocate_closure_component",
3868+
sg_ptr, id_int, size_int);
38643869
llvm::Value* comp_void_ptr = return_ptr;
38653870

38663871
// We need a surrounding "if" so that it's safe for closure allocation to

src/liboslexec/opclosure.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,41 @@ osl_allocate_weighted_closure_component(OpaqueExecContextPtr oec, int id,
115115
return comp;
116116
}
117117

118+
OSL_SHADEOP OSL_HOSTDEVICE void*
119+
osl_allocate_debug_closure_component(OpaqueExecContextPtr oec, int id, int size)
120+
{
121+
const size_t needed = sizeof(ClosureComponent) + size;
122+
ClosureComponent* comp
123+
= (ClosureComponent*)rs_allocate_debug_closure(oec, needed,
124+
alignof(ClosureComponent));
125+
if (comp) {
126+
comp->id = id;
127+
comp->w = Color3(1.0f);
128+
}
129+
return comp;
130+
}
131+
132+
133+
134+
OSL_SHADEOP OSL_HOSTDEVICE void*
135+
osl_allocate_weighted_debug_closure_component(OpaqueExecContextPtr oec, int id,
136+
int size, const void* w_)
137+
{
138+
const Color3* w = (const Color3*)w_;
139+
if (w->x == 0.0f && w->y == 0.0f && w->z == 0.0f)
140+
return NULL;
141+
const size_t needed = sizeof(ClosureComponent) + size;
142+
ClosureComponent* comp
143+
= (ClosureComponent*)rs_allocate_debug_closure(oec, needed,
144+
alignof(ClosureComponent));
145+
if (comp) {
146+
comp->id = id;
147+
comp->w = *w;
148+
}
149+
return comp;
150+
}
151+
152+
118153
// Deprecated, remove when conversion from ustring to ustringhash is finished
119154
OSL_SHADEOP const char*
120155
osl_closure_to_string(OpaqueExecContextPtr oec, const void* c_)

src/liboslexec/rs_fallback.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,13 @@ rs_allocate_closure(OSL::OpaqueExecContextPtr exec_ctx, size_t size,
329329
#endif
330330
}
331331

332+
OSL_RSOP OSL_HOSTDEVICE void*
333+
rs_allocate_debug_closure(OSL::OpaqueExecContextPtr exec_ctx, size_t size,
334+
size_t alignment)
335+
{
336+
return rs_allocate_closure(exec_ctx, size, alignment);
337+
}
338+
332339
OSL_RSOP OSL_HOSTDEVICE void
333340
rs_errorfmt(OSL::OpaqueExecContextPtr exec_ctx,
334341
OSL::ustringhash fmt_specification, int32_t count,

src/liboslexec/wide/wide_opclosure.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,40 @@ __OSL_MASKED_OP(allocate_weighted_closure_component)(void* bsg_,
200200
init_closure_component(wComp, id, size, wWeight, comp_mem);
201201
}
202202

203+
OSL_BATCHOP void
204+
__OSL_MASKED_OP(allocate_debug_closure_component)(void* bsg_, void* wide_out_,
205+
int id, int size,
206+
unsigned int mask_value)
207+
{
208+
auto* bsg = reinterpret_cast<BatchedShaderGlobals*>(bsg_);
209+
210+
Masked<ClosureComponentPtr> wComp(wide_out_, Mask(mask_value));
211+
Block<Color3> one_block;
212+
assign_all(one_block, Color3(1.0f));
213+
Wide<const Color3> wWeight(&one_block);
214+
ClosureComponent* comp_mem
215+
= bsg->uniform.context->batched<__OSL_WIDTH>().closure_component_allot(
216+
size);
217+
init_closure_component(wComp, id, size, wWeight, comp_mem);
218+
}
219+
220+
221+
222+
OSL_BATCHOP void
223+
__OSL_MASKED_OP(allocate_weighted_debug_closure_component)(
224+
void* bsg_, void* wide_out_, int id, int size, void* wide_weight_,
225+
unsigned int mask_value)
226+
{
227+
// TODO return nullptr if all are 0 or masked?
228+
auto* bsg = reinterpret_cast<BatchedShaderGlobals*>(bsg_);
229+
Masked<ClosureComponentPtr> wComp(wide_out_, Mask(mask_value));
230+
Wide<const Color3> wWeight(wide_weight_);
231+
ClosureComponent* comp_mem
232+
= bsg->uniform.context->batched<__OSL_WIDTH>().closure_component_allot(
233+
size);
234+
init_closure_component(wComp, id, size, wWeight, comp_mem);
235+
}
236+
203237
// This currently duplicates the scalar version of the op, but
204238
// accesses the context through BatchedShaderGlobals instead of ShaderGlobals
205239
// future work would extend this to operate on a whole batch of closures at once

src/testshade/rs_simplerend.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,13 @@ rs_allocate_closure(OSL::OpaqueExecContextPtr ec, size_t size, size_t alignment)
391391
return rs->closure_pool->allocate(size, alignment);
392392
}
393393

394+
OSL_RSOP OSL_HOSTDEVICE void*
395+
rs_allocate_debug_closure(OSL::OpaqueExecContextPtr ec, size_t size,
396+
size_t alignment)
397+
{
398+
return rs_allocate_closure(ec, size, alignment);
399+
}
400+
394401
OSL_RSOP OSL_HOSTDEVICE bool
395402
rs_get_attribute_constant_string(OSL::ustringhash value, void* result)
396403
{

0 commit comments

Comments
 (0)