-
Notifications
You must be signed in to change notification settings - Fork 407
Expand file tree
/
Copy pathwide_opmessage.cpp
More file actions
453 lines (376 loc) · 16.8 KB
/
wide_opmessage.cpp
File metadata and controls
453 lines (376 loc) · 16.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
// Copyright Contributors to the Open Shading Language project.
// SPDX-License-Identifier: BSD-3-Clause
// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage
#include <OSL/oslconfig.h>
#include <OSL/batched_rendererservices.h>
#include <OSL/batched_shaderglobals.h>
#include "oslexec_pvt.h"
OSL_NAMESPACE_BEGIN
namespace __OSL_WIDE_PVT {
OSL_USING_DATA_WIDTH(__OSL_WIDTH)
using BatchedRendererServices = OSL::BatchedRendererServices<__OSL_WIDTH>;
using WidthTag = OSL::WidthOf<__OSL_WIDTH>;
#include "define_opname_macros.h"
struct MessageBlock {
MessageBlock(ustring name, const TypeDesc& type, MessageBlock* next)
: valid_mask(false)
, get_before_set_mask(false)
, name(name)
, data(nullptr)
, type(type)
, next(next)
{
}
MessageBlock(const MessageBlock&) = delete;
MessageBlock& operator=(const MessageBlock&) = delete;
/// Some messages don't have data because getmessage() was called before setmessage
/// (which is flagged as an error to avoid ambiguities caused by execution order)
///
bool has_data() const { return data != nullptr; }
// Place larger blocks at front of structure as they have alignment
// requirements which could cause excess padding if smaller members
// where placed ahead of them
Block<int> wlayeridx; ///< layer index where this was message was created
Block<ustring>
wsourcefile; ///< source code file that contains the call that created this message
Block<int>
wsourceline; ///< source code line that contains the call that created this message
Mask valid_mask; ///< which lanes of have been set
Mask get_before_set_mask; ///< which lanes had get called before a set, track to create errors if set is called later
ustring name; ///< name of this message
char* data; ///< actual data of the message (will never change once the message is created)
TypeDesc
type; ///< what kind of data is stored here? FIXME: should be TypeSpec
MessageBlock*
next; ///< linked list of messages (managed by MessageList below)
public:
void import_data(MaskedData wsrcval, Mask lanes_to_populate, int layeridx,
ustring sourcefile, int sourceline)
{
Masked<int> alayeridx(wlayeridx, lanes_to_populate);
Masked<ustring> asourcefile(wsourcefile, lanes_to_populate);
Masked<int> asourceline(wsourceline, lanes_to_populate);
OSL_OMP_PRAGMA(omp simd simdlen(__OSL_WIDTH))
for (int lane = 0; lane < __OSL_WIDTH; ++lane) {
alayeridx[lane] = layeridx;
asourcefile[lane] = sourcefile;
asourceline[lane] = sourceline;
}
if (!wsrcval.valid()) {
// We always needed to copy the debug info (sourcefile, line, layer)
// but we may not have any data to copy
get_before_set_mask |= lanes_to_populate;
return;
}
valid_mask |= lanes_to_populate;
MaskedData dest(wsrcval.type(), /*has_derivs=*/false, lanes_to_populate,
data);
dest.assign_val_from_wide(wsrcval.ptr());
}
void export_data(MaskedData wdestval)
{
wdestval.assign_val_from_wide(data);
}
};
struct BatchedMessageList {
private:
BatchedMessageBuffer& m_buffer;
public:
BatchedMessageList(BatchedMessageBuffer& buffer) : m_buffer(buffer) {}
BatchedMessageList(const BatchedMessageList&) = delete;
BatchedMessageList& operator=(const BatchedMessageList&) = delete;
MessageBlock* list_head() const
{
return reinterpret_cast<MessageBlock*>(m_buffer.list_head);
}
void set_list_head(MessageBlock* new_list_head)
{
m_buffer.list_head = new_list_head;
}
MessageBlock* find(ustring name) const
{
for (MessageBlock* m = list_head(); m != nullptr; m = m->next)
if (m->name == name)
return m; // name matches
return nullptr; // not found
}
void add(ustring name /*varying name*/, MaskedData wsrcval,
Mask lanes_to_populate, int layeridx, ustring sourcefile,
int sourceline)
{
constexpr size_t alignment = sizeof(float) * __OSL_WIDTH;
set_list_head(
new (m_buffer.message_data.alloc(sizeof(MessageBlock), alignment))
MessageBlock(name, wsrcval.type(), list_head()));
list_head()->data
= m_buffer.message_data.alloc(wsrcval.val_size_in_bytes(),
alignment);
list_head()->import_data(wsrcval, lanes_to_populate, layeridx,
sourcefile, sourceline);
}
};
namespace { // anonymous
OSL_NOINLINE void
impl_setmessage(BatchedShaderGlobals* bsg, ustring sourcefile, int sourceline,
MaskedData wsrcval, int layeridx, ustring name,
Mask matching_lanes)
{
TypeDesc type = wsrcval.type();
bool is_closure = (type.basetype
== TypeDesc::UNKNOWN); // secret code for closure
if (is_closure) {
OSL_ASSERT(0 && "Incomplete closure support for setmessage");
}
BatchedMessageList messages {
bsg->uniform.context->batched_messages_buffer()
};
auto* m = messages.find(name);
if (m != nullptr) {
OSL_DASSERT(m->name == name);
// message already exists?
Wide<const ustring> msg_wsourcefile(m->wsourcefile);
Wide<const int> msg_wsourceline(m->wsourceline);
OSL_ASSERT(m->has_data());
{
auto lanes_with_data = m->valid_mask & matching_lanes;
lanes_with_data.foreach ([=](ActiveLane lane) -> void {
ustring msg_sourcefile = msg_wsourcefile[lane];
int msg_sourceline = msg_wsourceline[lane];
bsg->uniform.context->batched<__OSL_WIDTH>().errorfmt(
lanes_with_data,
"message \"{}\" already exists (created here: {}:{})"
" cannot set again from {}:{}",
name, msg_sourcefile, msg_sourceline, sourcefile,
sourceline);
});
auto lanes_to_populate = (~m->valid_mask & matching_lanes)
& ~m->get_before_set_mask;
if (lanes_to_populate.any_on()) {
m->import_data(wsrcval, lanes_to_populate, layeridx, sourcefile,
sourceline);
}
}
Mask lanes_that_getmessage_called_on = m->get_before_set_mask
& matching_lanes;
lanes_that_getmessage_called_on.foreach ([=](ActiveLane lane) -> void {
ustring msg_sourcefile = msg_wsourcefile[lane];
int msg_sourceline = msg_wsourceline[lane];
bsg->uniform.context->batched<__OSL_WIDTH>().errorfmt(
Mask(Lane(lane)),
"message \"{}\" was queried before being set (queried here: {}:{})"
" setting it now ({}:{}) would lead to inconsistent results",
name, msg_sourcefile, msg_sourceline, sourcefile, sourceline);
});
} else {
// The message didn't exist - create it
messages.add(name, wsrcval, matching_lanes, layeridx, sourcefile,
sourceline);
}
}
} // namespace
OSL_BATCHOP void
__OSL_MASKED_OP2(setmessage, s, WX)(BatchedShaderGlobals* bsg_,
ustring_pod name_, long long type,
void* wvalue, int layeridx,
ustring_pod sourcefile_, int sourceline,
unsigned int mask_value)
{
Mask mask(mask_value);
OSL_ASSERT(mask.any_on());
ustring name = USTR(name_);
MaskedData wsrcval(TYPEDESC(type), false /*has_derivs*/, mask, wvalue);
ustring sourcefile = USTR(sourcefile_);
auto* bsg = reinterpret_cast<BatchedShaderGlobals*>(bsg_);
OSL_DASSERT(wsrcval.type().basetype
!= TypeDesc::UNKNOWN); // secret code for closure
#if 0 // TBD closure support
// recreate TypeDesc -- we just crammed it into an int!
TypeDesc type = TYPEDESC(type_);
bool is_closure = (type.basetype == TypeDesc::UNKNOWN); // secret code for closure
if (is_closure) {
OSL_ASSERT(0 && "Incomplete add closure support to setmessage");
type.basetype = TypeDesc::PTR;
}
// for closures, we store a pointer
#endif
impl_setmessage(bsg, sourcefile, sourceline, wsrcval, layeridx, name, mask);
}
OSL_BATCHOP void
__OSL_MASKED_OP2(setmessage, Ws, WX)(BatchedShaderGlobals* bsg_, void* wname,
long long type, void* wvalue, int layeridx,
ustring_pod sourcefile_, int sourceline,
unsigned int mask_value)
{
Mask mask(mask_value);
OSL_ASSERT(mask.any_on());
Wide<const ustring> wName(wname);
MaskedData wsrcval(TYPEDESC(type), false /*has_derivs*/, mask, wvalue);
ustring sourcefile = USTR(sourcefile_);
auto* bsg = reinterpret_cast<BatchedShaderGlobals*>(bsg_);
#if 0
// recreate TypeDesc -- we just crammed it into an int!
TypeDesc type = TYPEDESC(type_);
bool is_closure = (type.basetype == TypeDesc::UNKNOWN); // secret code for closure
if (is_closure) {
OSL_ASSERT(0 && "Incomplete add closure support to setmessage");
type.basetype = TypeDesc::PTR;
}
// for closures, we store a pointer
#else
OSL_DASSERT(wsrcval.type().basetype
!= TypeDesc::UNKNOWN); // secret code for closure
#endif
foreach_unique(wName, mask, [=](ustring name, Mask matching_lanes) -> void {
impl_setmessage(bsg, sourcefile, sourceline, wsrcval, layeridx, name,
matching_lanes);
});
}
OSL_BATCHOP void
__OSL_MASKED_OP(getmessage)(void* bsg_, void* result, ustring_pod source_,
ustring_pod name_, long long type_, void* val,
int derivs, int layeridx, ustring_pod sourcefile_,
int sourceline, unsigned int mask_value)
{
ustring source = USTR(source_);
ustring name = USTR(name_);
ustring sourcefile = USTR(sourcefile_);
Mask mask(mask_value);
auto* bsg = reinterpret_cast<BatchedShaderGlobals*>(bsg_);
Masked<int> wR(result, mask);
// recreate TypeDesc -- we just crammed it into an int!
TypeDesc type = TYPEDESC(type_);
bool is_closure = (type.basetype
== TypeDesc::UNKNOWN); // secret code for closure
if (is_closure) {
OSL_ASSERT(0 && "Incomplete add closure support to getmessage");
type.basetype = TypeDesc::PTR; // for closures, we store a pointer
}
static ustring ktrace("trace");
OSL_ASSERT(val != nullptr);
MaskedData valRef(type, derivs, mask, val);
if (USTR(source_) == ktrace) {
// Source types where we need to ask the renderer
return bsg->uniform.renderer->batched(WidthTag())
->getmessage(bsg, wR, source, name, valRef);
}
BatchedMessageList messages {
bsg->uniform.context->batched_messages_buffer()
};
MessageBlock* m = messages.find(name);
if (m != nullptr) {
Wide<const ustring> msg_wsourcefile(m->wsourcefile);
Wide<const int> msg_wsourceline(m->wsourceline);
Wide<const int> msg_wlayeridx(m->wlayeridx);
if (m->type != type) {
// found message, but types don't match
mask.foreach ([=](ActiveLane lane) -> void {
//int msg_layerid = msg_wlayeridx[lane];
ustring msg_sourcefile = msg_wsourcefile[lane];
int msg_sourceline = msg_wsourceline[lane];
// found message, but was set by a layer deeper than the one querying the message
bool has_data = m->has_data() ? m->valid_mask[lane] : false;
bsg->uniform.context->batched<__OSL_WIDTH>().errorfmt(
Mask(lane),
"type mismatch for message \"{}\" ({} as {} here: {}:{})"
" cannot fetch as {} from {}:{}",
name, has_data ? "created" : "queried",
m->type == TypeDesc::PTR ? "closure color"
: m->type.c_str(),
msg_sourcefile, msg_sourceline,
is_closure ? "closure color" : type.c_str(), sourcefile,
sourceline);
});
assign_all(wR, 0);
return;
}
OSL_ASSERT(m->has_data());
if (!m->has_data()) {
// getmessage ran before and found nothing - just return 0
assign_all(wR, 0);
return;
}
auto found_lanes = mask & m->valid_mask;
auto missing_lanes = mask & ~m->valid_mask & ~m->get_before_set_mask;
// Use int instead of Mask<> to allow reduction clause in openmp simd declaration
int lanes_set_by_deeper_layer_bits { 0 };
OSL_OMP_PRAGMA(omp simd simdlen(__OSL_WIDTH)
reduction(|
: lanes_set_by_deeper_layer_bits))
for (int lane = 0; lane < __OSL_WIDTH; ++lane) {
int msg_layerid = msg_wlayeridx[lane];
// NOTE: using bitwise & to avoid branches
if (found_lanes[lane] & (msg_layerid > layeridx)) {
// inline of Mask::set_on(lane)
lanes_set_by_deeper_layer_bits |= 1 << lane;
}
}
Mask lanes_set_by_deeper_layer(lanes_set_by_deeper_layer_bits);
lanes_set_by_deeper_layer.foreach ([=](ActiveLane lane) -> void {
int msg_layerid = msg_wlayeridx[lane];
ustring msg_sourcefile = msg_wsourcefile[lane];
int msg_sourceline = msg_wsourceline[lane];
// found message, but was set by a layer deeper than the one querying the message
bsg->uniform.context->batched<__OSL_WIDTH>().errorfmt(
Mask(lane),
"message \"{}\" was set by layer #{} ({}:{})"
" but is being queried by layer #{} ({}:{})"
" - messages may only be transferred from nodes "
"that appear earlier in the shading network",
name, msg_layerid, msg_sourcefile, msg_sourceline, layeridx,
sourcefile, sourceline);
wR[lane] = 0;
});
auto lanes_to_copy = found_lanes & ~lanes_set_by_deeper_layer;
if (lanes_to_copy.any_on()) {
m->export_data(valRef & lanes_to_copy);
assign_all(wR & lanes_to_copy, 1);
}
if (missing_lanes.any_on()) {
assign_all(wR & missing_lanes, 0);
if (bsg->uniform.context->shadingsys().strict_messages()) {
m->get_before_set_mask |= missing_lanes;
Masked<int> wlayeridx(m->wlayeridx, missing_lanes);
Masked<ustring> wsourcefile(m->wsourcefile, missing_lanes);
Masked<int> wsourceline(m->wsourceline, missing_lanes);
OSL_OMP_PRAGMA(omp simd simdlen(__OSL_WIDTH))
for (int lane = 0; lane < __OSL_WIDTH; ++lane) {
wlayeridx[lane] = layeridx;
wsourcefile[lane] = sourcefile;
wsourceline[lane] = sourceline;
}
}
}
return;
}
if (bsg->uniform.context->shadingsys().strict_messages()) {
// The message didn't exist - create it
MaskedData wsrcval(type, false /*has_derivs*/, mask, nullptr);
messages.add(name, wsrcval, mask, layeridx, sourcefile, sourceline);
}
assign_all(wR, 0);
return;
}
// Trace
// Utility: retrieve a pointer to the ShadingContext's trace options
// struct, also re-initialize its contents.
OSL_BATCHOP void
__OSL_MASKED_OP(trace)(void* bsg_, void* result, void* opt_, void* Pos_,
void* dPosdx_, void* dPosdy_, void* Dir_, void* dDirdx_,
void* dDirdy_, unsigned int mask_value)
{
auto* bsg = reinterpret_cast<BatchedShaderGlobals*>(bsg_);
auto* opt = reinterpret_cast<BatchedRendererServices::TraceOpt*>(opt_);
Masked<int> wR(result, Mask(mask_value));
Block<Vec3> zero_block;
assign_all(zero_block, Vec3(0.0f));
Wide<const Vec3> wP(Pos_);
Wide<const Vec3> wPdx(dPosdx_ ? dPosdx_ : &zero_block);
Wide<const Vec3> wPdy(dPosdy_ ? dPosdy_ : &zero_block);
Wide<const Vec3> wD(Dir_);
Wide<const Vec3> wDdx(dDirdx_ ? dDirdx_ : &zero_block);
Wide<const Vec3> wDdy(dDirdy_ ? dDirdy_ : &zero_block);
bsg->uniform.renderer->batched(WidthTag())
->trace(*opt, bsg, wR, wP, wPdx, wPdy, wD, wDdx, wDdy);
}
} // namespace __OSL_WIDE_PVT
OSL_NAMESPACE_END