1 // Copyright Contributors to the Open Shading Language project.
2 // SPDX-License-Identifier: BSD-3-Clause
3 // https://github.com/AcademySoftwareFoundation/OpenShadingLanguage
4
5 #include <vector>
6 #include <string>
7 #include <cstdio>
8
9 #include <OpenImageIO/sysutil.h>
10 #include <OpenImageIO/timer.h>
11 #include <OpenImageIO/thread.h>
12
13 #include "oslexec_pvt.h"
14
15 OSL_NAMESPACE_ENTER
16
17 static mutex buffered_errors_mutex;
18
19
20
ShadingContext(ShadingSystemImpl & shadingsys,PerThreadInfo * threadinfo)21 ShadingContext::ShadingContext (ShadingSystemImpl &shadingsys,
22 PerThreadInfo *threadinfo)
23 : m_shadingsys(shadingsys), m_renderer(m_shadingsys.renderer()),
24 m_group(NULL), m_max_warnings(shadingsys.max_warnings_per_thread()), m_dictionary(NULL)
25 {
26 m_shadingsys.m_stat_contexts += 1;
27 m_threadinfo = threadinfo ? threadinfo : shadingsys.get_perthread_info ();
28 m_texture_thread_info = NULL;
29 }
30
31
32
~ShadingContext()33 ShadingContext::~ShadingContext ()
34 {
35 process_errors ();
36 m_shadingsys.m_stat_contexts -= 1;
37 free_dict_resources ();
38 }
39
40
41
42 bool
execute_init(ShaderGroup & sgroup,ShaderGlobals & ssg,bool run)43 ShadingContext::execute_init (ShaderGroup &sgroup, ShaderGlobals &ssg, bool run)
44 {
45 if (m_group)
46 execute_cleanup ();
47 m_group = &sgroup;
48 m_ticks = 0;
49
50 // Optimize if we haven't already
51 if (sgroup.nlayers()) {
52 sgroup.start_running ();
53 if (! sgroup.jitted()) {
54 auto ctx = shadingsys().get_context(thread_info());
55 shadingsys().optimize_group (sgroup, ctx, true /*do_jit*/);
56 if (shadingsys().m_greedyjit && shadingsys().m_groups_to_compile_count) {
57 // If we are greedily JITing, optimize/JIT everything now
58 shadingsys().optimize_all_groups ();
59 }
60 shadingsys().release_context(ctx);
61 }
62 if (sgroup.does_nothing())
63 return false;
64 } else {
65 // empty shader - nothing to do!
66 return false;
67 }
68
69 int profile = shadingsys().m_profile;
70 OIIO::Timer timer (profile ? OIIO::Timer::StartNow : OIIO::Timer::DontStartNow);
71
72 // Allocate enough space on the heap
73 size_t heap_size_needed = sgroup.llvm_groupdata_size();
74 reserve_heap(heap_size_needed);
75 // Zero out the heap memory we will be using
76 if (shadingsys().m_clearmemory)
77 memset (m_heap.get(), 0, heap_size_needed);
78
79 // Set up closure storage
80 m_closure_pool.clear();
81
82 // Clear the message blackboard
83 m_messages.clear ();
84
85 // Clear miscellaneous scratch space
86 m_scratch_pool.clear ();
87
88 // Zero out stats for this execution
89 clear_runtime_stats ();
90
91 if (run) {
92 RunLLVMGroupFunc run_func = sgroup.llvm_compiled_init();
93 if (!run_func)
94 return false;
95 ssg.context = this;
96 ssg.renderer = renderer();
97 ssg.Ci = NULL;
98 run_func (&ssg, m_heap.get());
99 }
100
101 if (profile)
102 m_ticks += timer.ticks();
103 return true;
104 }
105
106
107
108 bool
execute_layer(ShaderGlobals & ssg,int layernumber)109 ShadingContext::execute_layer (ShaderGlobals &ssg, int layernumber)
110 {
111 if (!group() || group()->nlayers() == 0 || group()->does_nothing())
112 return false;
113 OSL_DASSERT(ssg.context == this && ssg.renderer == renderer());
114
115 int profile = shadingsys().m_profile;
116 OIIO::Timer timer (profile ? OIIO::Timer::StartNow : OIIO::Timer::DontStartNow);
117
118 RunLLVMGroupFunc run_func = group()->llvm_compiled_layer (layernumber);
119 if (! run_func)
120 return false;
121
122 run_func (&ssg, m_heap.get());
123
124 if (profile)
125 m_ticks += timer.ticks();
126
127 return true;
128 }
129
130
131
132 bool
execute_cleanup()133 ShadingContext::execute_cleanup ()
134 {
135 if (! group()) {
136 errorf("execute_cleanup called again on a cleaned-up context");
137 return false;
138 }
139
140 // Process any queued up error messages, warnings, printfs from shaders
141 process_errors ();
142
143 if (shadingsys().m_profile) {
144 record_runtime_stats (); // Transfer runtime stats to the shadingsys
145 shadingsys().m_stat_total_shading_time_ticks += m_ticks;
146 group()->m_stat_total_shading_time_ticks += m_ticks;
147 }
148
149 return true;
150 }
151
152
153
154 bool
execute(ShaderGroup & sgroup,ShaderGlobals & ssg,bool run)155 ShadingContext::execute (ShaderGroup &sgroup, ShaderGlobals &ssg, bool run)
156 {
157 int n = sgroup.m_exec_repeat;
158 Vec3 Psave, Nsave; // for repeats
159 bool repeat = (n > 1);
160 if (repeat) {
161 // If we're going to repeat more than once, we need to save any
162 // globals that might get modified.
163 Psave = ssg.P;
164 Nsave = ssg.N;
165 if (! run)
166 n = 1;
167 }
168
169 bool result = true;
170 while (1) {
171 if (! execute_init (sgroup, ssg, run))
172 return false;
173 if (run && n)
174 execute_layer (ssg, group()->nlayers()-1);
175 result = execute_cleanup ();
176 if (--n < 1)
177 break; // done
178 if (repeat) {
179 // Going around for another pass... restore things as best as we
180 // can.
181 ssg.P = Psave;
182 ssg.N = Nsave;
183 ssg.Ci = NULL;
184 }
185 }
186 return result;
187 }
188
189
190
191 void
record_error(ErrorHandler::ErrCode code,const std::string & text) const192 ShadingContext::record_error (ErrorHandler::ErrCode code,
193 const std::string &text) const
194 {
195 m_buffered_errors.emplace_back(code,text);
196 // If we aren't buffering, just process immediately
197 if (! shadingsys().m_buffer_printf)
198 process_errors ();
199 }
200
201
202
203 void
process_errors() const204 ShadingContext::process_errors () const
205 {
206 size_t nerrors = m_buffered_errors.size();
207 if (! nerrors)
208 return;
209
210 // Use a mutex to make sure output from different threads stays
211 // together, at least for one shader invocation, rather than being
212 // interleaved with other threads.
213 lock_guard lock (buffered_errors_mutex);
214
215 for (size_t i = 0; i < nerrors; ++i) {
216 switch (m_buffered_errors[i].first) {
217 case ErrorHandler::EH_MESSAGE :
218 case ErrorHandler::EH_DEBUG :
219 shadingsys().message (m_buffered_errors[i].second);
220 break;
221 case ErrorHandler::EH_INFO :
222 shadingsys().info (m_buffered_errors[i].second);
223 break;
224 case ErrorHandler::EH_WARNING :
225 shadingsys().warning (m_buffered_errors[i].second);
226 break;
227 case ErrorHandler::EH_ERROR :
228 case ErrorHandler::EH_SEVERE :
229 shadingsys().error (m_buffered_errors[i].second);
230 break;
231 default:
232 break;
233 }
234 }
235 m_buffered_errors.clear();
236 }
237
238
239
240 const Symbol *
symbol(ustring layername,ustring symbolname) const241 ShadingContext::symbol (ustring layername, ustring symbolname) const
242 {
243 return group()->find_symbol (layername, symbolname);
244 }
245
246
247
248 const void *
symbol_data(const Symbol & sym) const249 ShadingContext::symbol_data (const Symbol &sym) const
250 {
251 const ShaderGroup &sgroup (*group());
252 if (! sgroup.optimized())
253 return NULL; // can't retrieve symbol if we didn't optimize it
254
255 if (sym.dataoffset() >= 0 && (int)m_heapsize > sym.dataoffset()) {
256 // lives on the heap
257 return m_heap.get() + sym.dataoffset();
258 }
259
260 // doesn't live on the heap
261 if ((sym.symtype() == SymTypeParam || sym.symtype() == SymTypeOutputParam) &&
262 (sym.valuesource() == Symbol::DefaultVal || sym.valuesource() == Symbol::InstanceVal)) {
263 return sym.data();
264 }
265
266 return NULL; // not something we can retrieve
267 }
268
269
270
271 const regex &
find_regex(ustring r)272 ShadingContext::find_regex (ustring r)
273 {
274 RegexMap::const_iterator found = m_regex_map.find (r);
275 if (found != m_regex_map.end())
276 return *found->second;
277 // otherwise, it wasn't found, add it
278 m_regex_map[r].reset (new regex(r.c_str()));
279 m_shadingsys.m_stat_regexes += 1;
280 // std::cerr << "Made new regex for " << r << "\n";
281 return *m_regex_map[r];
282 }
283
284
285
286 bool
osl_get_attribute(ShaderGlobals * sg,void * objdata,int dest_derivs,ustring obj_name,ustring attr_name,int array_lookup,int index,TypeDesc attr_type,void * attr_dest)287 ShadingContext::osl_get_attribute (ShaderGlobals *sg, void *objdata,
288 int dest_derivs,
289 ustring obj_name, ustring attr_name,
290 int array_lookup, int index,
291 TypeDesc attr_type, void *attr_dest)
292 {
293 #if 0
294 // Change the #if's below if you want to
295 OIIO::Timer timer;
296 #endif
297 bool ok;
298
299 if (array_lookup)
300 ok = renderer()->get_array_attribute (sg, dest_derivs,
301 obj_name, attr_type,
302 attr_name, index, attr_dest);
303 else
304 ok = renderer()->get_attribute (sg, dest_derivs,
305 obj_name, attr_type,
306 attr_name, attr_dest);
307
308 #if 0
309 double time = timer();
310 shadingsys().m_stat_getattribute_time += time;
311 if (!ok)
312 shadingsys().m_stat_getattribute_fail_time += time;
313 shadingsys().m_stat_getattribute_calls += 1;
314 #endif
315 // std::cout << "getattribute! '" << obj_name << "' " << attr_name << ' ' << attr_type.c_str() << " ok=" << ok << ", objdata was " << objdata << "\n";
316 return ok;
317 }
318
319
320
321 OSL_SHADEOP void
osl_incr_layers_executed(ShaderGlobals * sg)322 osl_incr_layers_executed (ShaderGlobals *sg)
323 {
324 ShadingContext *ctx = (ShadingContext *)sg->context;
325 ctx->incr_layers_executed ();
326 }
327
328
329 OSL_NAMESPACE_EXIT
330