Skip to content

Commit d7a48ed

Browse files
authored
fix: interpolated int attributes wrong for batch shading (#1949)
Fix issue #1929 with batched execution forcing interpolated integer arguments to be boolean when their default value is 0 or 1. In actuality the renderer could assign any integer value, we update BatchedAnalysis to track the interpolated value as a write event which will disqualify forcing of boolean as well as ensure future writes are masked properly. Added new lockgeom test that reproduces the issue and verifies its fixed. --------- Signed-off-by: Alex M. Wells <[email protected]>
1 parent c048a33 commit d7a48ed

File tree

17 files changed

+154
-12
lines changed

17 files changed

+154
-12
lines changed

src/cmake/testing.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@ macro (osl_add_all_tests)
308308
layers-nonlazycopy layers-repeatedoutputs
309309
lazytrace
310310
length-reg linearstep
311+
lockgeom
311312
logic loop luminance-reg
312313
matrix matrix-reg matrix-arithmetic-reg
313314
matrix-compref-reg max-reg message message-no-closure message-reg

src/liboslexec/batched_analysis.cpp

Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1119,6 +1119,7 @@ class WriteEvent {
11191119
public:
11201120
static constexpr int InitialAssignmentOp() { return -1; }
11211121
static constexpr int UserDataPreplacementCopyOp() { return -2; }
1122+
static constexpr int UserDataInterpolatedOp() { return -3; }
11221123

11231124
WriteEvent(DependencyTreeTracker::Position pos_in_tree_, int op_num_,
11241125
int loop_op_index)
@@ -1134,7 +1135,8 @@ class WriteEvent {
11341135
, m_op_num(op_num_)
11351136
, m_loop_op_index(NoLoopIndex())
11361137
{
1137-
OSL_ASSERT(is_initial_assignment() || is_user_data_preplacement_copy());
1138+
OSL_ASSERT(is_initial_assignment() || is_user_data_preplacement_copy()
1139+
|| is_user_data_interpolated());
11381140
}
11391141

11401142
OSL_FORCEINLINE DependencyTreeTracker::Position pos_in_tree() const
@@ -1152,11 +1154,25 @@ class WriteEvent {
11521154
return m_op_num == UserDataPreplacementCopyOp();
11531155
}
11541156

1157+
OSL_FORCEINLINE bool is_user_data_interpolated() const
1158+
{
1159+
return m_op_num == UserDataInterpolatedOp();
1160+
}
1161+
11551162

11561163
OSL_FORCEINLINE int op_num() const
11571164
{
1158-
OSL_ASSERT(!is_initial_assignment()
1159-
&& !is_user_data_preplacement_copy());
1165+
#if 0 // For getting callstack in debugger
1166+
if(is_initial_assignment()
1167+
|| is_user_data_preplacement_copy()
1168+
|| is_user_data_interpolated()) {
1169+
// Caller's logic should of special cased these
1170+
// so logic bug exists
1171+
__builtin_trap();
1172+
}
1173+
#endif
1174+
OSL_ASSERT(!is_initial_assignment() && !is_user_data_preplacement_copy()
1175+
&& !is_user_data_interpolated());
11601176
return m_op_num;
11611177
}
11621178

@@ -1397,7 +1413,8 @@ struct Analyzer {
13971413
write_iter != write_end; ++write_iter) {
13981414
// We don't bother masking initial assignment
13991415
if (write_iter->is_initial_assignment()
1400-
|| write_iter->is_user_data_preplacement_copy()) {
1416+
|| write_iter->is_user_data_preplacement_copy()
1417+
|| write_iter->is_user_data_interpolated()) {
14011418
continue;
14021419
}
14031420

@@ -1568,7 +1585,9 @@ struct Analyzer {
15681585
// Then the current write needs to be masked
15691586
for (auto write_iter = write_chronology.begin();
15701587
write_iter != write_end; ++write_iter) {
1571-
if (write_iter->is_initial_assignment()) {
1588+
if (write_iter->is_initial_assignment()
1589+
|| write_iter->is_user_data_preplacement_copy()
1590+
|| write_iter->is_user_data_interpolated()) {
15721591
// The initial assignment of all parameters happens before any instructions are generated?
15731592
// perhaps there is an ordering issue here for init_ops which could have early outs
15741593
// although not sure what that would do to execution, certainly returns in init_ops would
@@ -2201,6 +2220,19 @@ struct Analyzer {
22012220
OSL_DEV_ONLY(std::cout
22022221
<< " bind_interpolated_param called for symbol: "
22032222
<< s.name() << std::endl);
2223+
2224+
// NOTE: as this is the initial assignment to a parameter
2225+
// there could be no other reads/write to deal with to the symbol
2226+
OSL_ASSERT(m_write_chronology_by_symbol.find(&s)
2227+
== m_write_chronology_by_symbol.end());
2228+
2229+
// bind_interpolated_param will have written to s
2230+
// so we need a write event to model that and prevent
2231+
// s from being forced to boolean
2232+
m_write_chronology_by_symbol[&s].push_back(
2233+
WriteEvent(m_conditional_symbol_stack.top_pos(),
2234+
WriteEvent::UserDataInterpolatedOp()));
2235+
22042236
// Interpolated params are handled by calling batched version of
22052237
// osl_bind_interpolated_param. It will return a mask indicating which
22062238
// lanes had such userdata was available.
@@ -2238,12 +2270,17 @@ struct Analyzer {
22382270

22392271
// NOTE: as this is the initial assignment to a parameter
22402272
// there could be no other reads/write to deal with to the symbol
2241-
if (m_write_chronology_by_symbol.find(&s)
2242-
!= m_write_chronology_by_symbol.end()) {
2243-
__builtin_trap();
2273+
// unless it was interpolated
2274+
#if 0 // For getting callstack in debugger
2275+
if (!interpolate_param
2276+
&& (m_write_chronology_by_symbol.find(&s)
2277+
!= m_write_chronology_by_symbol.end())) {
2278+
__builtin_trap();
22442279
}
2245-
OSL_ASSERT(m_write_chronology_by_symbol.find(&s)
2246-
== m_write_chronology_by_symbol.end());
2280+
#endif
2281+
OSL_ASSERT(interpolate_param
2282+
|| (m_write_chronology_by_symbol.find(&s)
2283+
== m_write_chronology_by_symbol.end()));
22472284

22482285
m_write_chronology_by_symbol[&s].push_back(
22492286
WriteEvent(m_conditional_symbol_stack.top_pos(),
@@ -2412,6 +2449,18 @@ struct Analyzer {
24122449
// no need to continue checking additional writes
24132450
break;
24142451
}
2452+
} else if (write_iter->is_user_data_interpolated()
2453+
|| write_iter
2454+
->is_user_data_preplacement_copy()) {
2455+
// the interpolated assignment should be the 1st write entry,
2456+
// so bool status should be unknown
2457+
OSL_ASSERT(b_status == BoolStatus::Unknown);
2458+
// The renderer could write any integer value, or
2459+
// the preplacement data could be any integer value
2460+
// so it can't be boolean!
2461+
b_status = BoolStatus::No;
2462+
// no need to continue checking additional writes
2463+
break;
24152464
} else {
24162465
int op_index = write_iter->op_num();
24172466
Opcode& opcode = m_opcodes[op_index];

src/testshade/batched_simplerend.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ struct UniqueStringCache {
2121
, red("red")
2222
, green("green")
2323
, blue("blue")
24+
, face_idx("face_idx")
2425
, lookupTable("lookupTable")
2526
, blahblah("blahblah")
2627
, options("options")
@@ -51,6 +52,7 @@ struct UniqueStringCache {
5152
ustring red;
5253
ustring green;
5354
ustring blue;
55+
ustring face_idx;
5456
ustring lookupTable;
5557
ustring blahblah;
5658
ustring options;
@@ -663,7 +665,15 @@ BatchedSimpleRenderer<WidthT>::get_userdata(ustringhash name,
663665

664666
// For testing of interactions with default values
665667
// may not provide data for all lanes
666-
if (name == ucache().s && Masked<float>::is(val)) {
668+
if (name == ucache().face_idx && Masked<int>::is(val)) {
669+
Masked<int> out(val);
670+
for (int i = 0; i < WidthT; ++i) {
671+
if (out[i].is_on()) {
672+
out[i] = int(4 * bsg->varying.u[i]);
673+
}
674+
}
675+
return out.mask();
676+
} else if (name == ucache().s && Masked<float>::is(val)) {
667677
Masked<float> out(val);
668678
for (int i = 0; i < WidthT; ++i) {
669679
// NOTE: assigning to out[i] will mask by itself

src/testshade/rs_simplerend.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,13 @@ rs_get_attribute(OSL::OpaqueExecContextPtr oec, OSL::ustringhash_pod object_,
555555
return false;
556556
}
557557

558+
OSL_RSOP OSL_HOSTDEVICE bool
559+
rs_get_interpolated_face_idx(OSL::OpaqueExecContextPtr ec, void* val)
560+
{
561+
((int*)val)[0] = int(4 * OSL::get_u(ec));
562+
return true;
563+
}
564+
558565
OSL_RSOP OSL_HOSTDEVICE bool
559566
rs_get_interpolated_s(OSL::OpaqueExecContextPtr ec, bool derivatives, void* val)
560567
{

src/testshade/rs_strdecls.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,5 @@ RS_STRDECL("t", t)
3737
RS_STRDECL("red", red)
3838
RS_STRDECL("green", green)
3939
RS_STRDECL("blue", blue)
40+
RS_STRDECL("face_idx", face_idx)
4041
RS_STRDECL("test", test)

src/testshade/simplerend.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,10 @@ SimpleRenderer::get_userdata(bool derivatives, ustringhash name, TypeDesc type,
508508
// look up something specific to the primitive, rather than have hard-
509509
// coded names.
510510

511+
if (name == RS::Hashes::face_idx && type == TypeInt) {
512+
((int*)val)[0] = int(4 * sg->u);
513+
return true;
514+
}
511515
if (name == RS::Hashes::s && type == TypeFloat) {
512516
((float*)val)[0] = sg->u;
513517
if (derivatives) {
@@ -682,6 +686,8 @@ SimpleRenderer::build_interpolated_getter(const ShaderGroup& group,
682686
TypeDesc type, bool derivatives,
683687
InterpolatedGetterSpec& spec)
684688
{
689+
static const OIIO::ustring rs_get_interpolated_face_idx(
690+
"rs_get_interpolated_face_idx");
685691
static const OIIO::ustring rs_get_interpolated_s("rs_get_interpolated_s");
686692
static const OIIO::ustring rs_get_interpolated_t("rs_get_interpolated_t");
687693
static const OIIO::ustring rs_get_interpolated_red(
@@ -711,7 +717,10 @@ SimpleRenderer::build_interpolated_getter(const ShaderGroup& group,
711717
static const OIIO::ustring rs_get_attribute_constant_float4(
712718
"rs_get_attribute_constant_float4");
713719

714-
if (param_name == RS::Hashes::s && type == OIIO::TypeFloat) {
720+
if (param_name == RS::Hashes::face_idx && type == OIIO::TypeInt) {
721+
spec.set(rs_get_interpolated_face_idx,
722+
InterpolatedSpecBuiltinArg::OpaqueExecutionContext);
723+
} else if (param_name == RS::Hashes::s && type == OIIO::TypeFloat) {
715724
spec.set(rs_get_interpolated_s,
716725
InterpolatedSpecBuiltinArg::OpaqueExecutionContext,
717726
InterpolatedSpecBuiltinArg::Derivatives);

testsuite/lockgeom/BATCHED

Whitespace-only changes.

testsuite/lockgeom/ref/out.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
Compiled test0.osl -> test0.oso
2+
Compiled test1.osl -> test1.oso
3+
Compiled test2.osl -> test2.oso
4+
Compiled test3.osl -> test3.oso
5+
6+
Output dst to out0.tif
7+
8+
Output dst to out1.tif
9+
10+
Output dst to out2.tif
11+
12+
Output dst to out3.tif

testsuite/lockgeom/ref/out0.tif

2.54 KB
Binary file not shown.

testsuite/lockgeom/ref/out1.tif

2.54 KB
Binary file not shown.

0 commit comments

Comments
 (0)