Fermat
pathtracer_impl.h
1 /*
2  * Fermat
3  *
4  * Copyright (c) 2016-2019, NVIDIA CORPORATION. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * * Neither the name of the NVIDIA CORPORATION nor the
14  * names of its contributors may be used to endorse or promote products
15  * derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #pragma once
30 
31 #include <pathtracer.h>
32 #include <renderer.h>
33 #include <rt.h>
34 #include <mesh/MeshStorage.h>
35 #include <cugar/basic/timer.h>
36 #include <cugar/basic/primitives.h>
37 #include <cugar/basic/memory_arena.h>
38 #include <pathtracer_core.h>
39 #include <pathtracer_queues.h>
40 #include <pathtracer_kernels.h>
41 #include <pathtracer_vertex_processor.h>
42 
43 #define SHIFT_RES 256
44 
47 
51 
55 
56 namespace {
57 
59  // the internal path tracing context
60  //
61  template <typename TDirectLightingSampler>
62  struct PathTracingContext : PTContextBase<PTOptions>, PTContextQueues
63  {
64  TDirectLightingSampler dl;
65  };
67 
68  // initialize the RL storage for mesh VTLs
69  void init(ClusteredRLStorage* vtls_rl, const MeshVTLStorage* mesh_vtls)
70  {
71  vtls_rl->init(
72  VTL_RL_HASH_SIZE,
73  mesh_vtls->get_bvh_clusters_count(),
74  mesh_vtls->get_bvh_cluster_offsets());
75  }
76  // initialize the RL storage for mesh VTLs
77  void init(AdaptiveClusteredRLStorage* vtls_rl, const MeshVTLStorage* mesh_vtls)
78  {
79  vtls_rl->init(
80  VTL_RL_HASH_SIZE,
81  mesh_vtls->get_bvh_nodes(),
82  mesh_vtls->get_bvh_parents(),
83  mesh_vtls->get_bvh_ranges(),
84  mesh_vtls->get_bvh_clusters_count(),
85  mesh_vtls->get_bvh_clusters(),
86  mesh_vtls->get_bvh_cluster_offsets());
87  }
88 
89 } // anonymous namespace
90 
91 PathTracer::PathTracer() :
92  m_generator(32, cugar::LFSRGeneratorMatrix::GOOD_PROJECTIONS),
93  m_random(&m_generator, 1u, 1351u)
94 {
95  m_mesh_vtls = new MeshVTLStorage;
96  m_vtls_rl = new VTLRLStorage;
97 }
98 
99 void PathTracer::init(int argc, char** argv, RenderingContext& renderer)
100 {
101  const uint2 res = renderer.res();
102  const uint32 n_pixels = res.x * res.y;
103 
104  // parse the options
105  m_options.parse(argc, argv);
106 
107  const char* nee_alg[] = { "mesh", "vpl", "rl" };
108 
109  fprintf(stderr, " PT settings:\n");
110  fprintf(stderr, " path-length : %u\n", m_options.max_path_length);
111  fprintf(stderr, " direct-nee : %u\n", m_options.direct_lighting_nee ? 1 : 0);
112  fprintf(stderr, " direct-bsdf : %u\n", m_options.direct_lighting_bsdf ? 1 : 0);
113  fprintf(stderr, " indirect-nee : %u\n", m_options.indirect_lighting_nee ? 1 : 0);
114  fprintf(stderr, " indirect-bsdf : %u\n", m_options.indirect_lighting_bsdf ? 1 : 0);
115  fprintf(stderr, " visible-lights : %u\n", m_options.visible_lights ? 1 : 0);
116  fprintf(stderr, " direct lighting : %u\n", m_options.direct_lighting ? 1 : 0);
117  fprintf(stderr, " diffuse : %u\n", m_options.diffuse_scattering ? 1 : 0);
118  fprintf(stderr, " glossy : %u\n", m_options.glossy_scattering ? 1 : 0);
119  fprintf(stderr, " indirect glossy : %u\n", m_options.indirect_glossy ? 1 : 0);
120  fprintf(stderr, " RR : %u\n", m_options.rr ? 1 : 0);
121  fprintf(stderr, " nee algorithm : %s\n", nee_alg[ m_options.nee_type ]);
122 
123  // pre-alloc queue storage
124  {
125  // determine how much storage we will need
126  cugar::memory_arena arena;
127 
128  PTRayQueue input_queue;
129  PTRayQueue scatter_queue;
130  PTRayQueue shadow_queue;
131 
132  alloc_queues(
133  m_options,
134  n_pixels,
135  input_queue,
136  scatter_queue,
137  shadow_queue,
138  arena );
139 
140  // alloc space for device timers
141  arena.alloc<int64>( 16 );
142 
143  fprintf(stderr, " allocating queue storage: %.1f MB\n", float(arena.size) / (1024*1024));
144  m_memory_pool.alloc(arena.size);
145  }
146 
147  // build the set of shifts
148  const uint32 n_dimensions = 6 * (m_options.max_path_length + 1);
149  fprintf(stderr, " initializing sampler: %u dimensions\n", n_dimensions);
150  m_sequence.setup(n_dimensions, SHIFT_RES);
151 
152  const uint32 n_light_paths = n_pixels;
153 
154  fprintf(stderr, " creating mesh lights... started\n");
155 
156  // initialize the mesh lights sampler
157  renderer.get_mesh_lights().init( n_light_paths, renderer, 0u );
158 
159  fprintf(stderr, " creating mesh lights... done\n");
160 
161  // compute the scene bbox
162  m_bbox = renderer.compute_bbox();
163 
164  // disable smart algorithms if there are no emissive surfaces
165  if (renderer.get_mesh_lights().get_vpl_count() == 0)
166  m_options.nee_type = NEE_ALGORITHM_MESH;
167 
168  if (m_options.nee_type == NEE_ALGORITHM_RL)
169  {
170  fprintf(stderr, " creating mesh VTLs... started\n");
171  m_mesh_vtls->init(n_light_paths, renderer, 0u );
172  fprintf(stderr, " creating mesh VTLs... done (%u VTLs, %u clusters)\n", m_mesh_vtls->get_vtl_count(), m_mesh_vtls->get_bvh_clusters_count());
173 
174  fprintf(stderr, " initializing VTLs RL... started\n");
175  ::init( m_vtls_rl, m_mesh_vtls );
176  fprintf(stderr, " initializing VTLs RL... done (%.1f MB)\n", m_vtls_rl->needed_bytes(VTL_RL_HASH_SIZE, m_mesh_vtls->get_bvh_clusters_count()) / float(1024*1024));
177  }
178 }
179 
180 void PathTracer::update_vtls_rl(const uint32 instance)
181 {
182  if ((instance % 32) == 0)
183  {
184  // clear the RL hash tables after a bunch of iterations to avoid overflow...
185  m_vtls_rl->clear();
186  }
187  else
188  {
189  // update the vtl cdfs
190  m_vtls_rl->update();
191  CUDA_CHECK(cugar::cuda::sync_and_check_error("vtl-rl update"));
192  }
193 }
194 
197 void PathTracer::render(const uint32 instance, RenderingContext& renderer)
198 {
200  // pre-multiply the previous frame for blending
201  renderer.rescale_frame( instance );
202 
203  //fprintf(stderr, "render started (%u)\n", instance);
204  const uint2 res = renderer.res();
205  const uint32 n_pixels = res.x * res.y;
206 
207  cugar::memory_arena arena( m_memory_pool.ptr() );
208 
209  PTRayQueue in_queue;
210  PTRayQueue scatter_queue;
211  PTRayQueue shadow_queue;
212 
213  alloc_queues(
214  m_options,
215  n_pixels,
216  in_queue,
217  scatter_queue,
218  shadow_queue,
219  arena );
220 
221  // fetch a view of the renderer
222  RenderingContextView renderer_view = renderer.view(instance);
223 
225  // instantiate the vertex processor
226  PTVertexProcessor vertex_processor;
229 
230  // alloc space for device timers
231  uint64* device_timers = arena.alloc<uint64>( 16 );
232 
233  cugar::Timer timer;
234  timer.start();
235 
236  PTLoopStats stats;
237 
238  // update the direct-lighting VTLs Reinforcement-Learning tables
239  if (m_options.nee_type == NEE_ALGORITHM_RL)
240  update_vtls_rl( instance );
241 
242  // setup the samples for this frame
243  m_sequence.set_instance(instance);
244 
245  // use our PTLib pathtracer
246  {
248  // use the Reinforcement-Learning direct-lighting sampler
249  if (m_options.nee_type == NEE_ALGORITHM_RL)
250  {
251  // initialize the path-tracing context
252  PathTracingContext<DirectLightingRL> context;
253  context.options = m_options;
254  context.in_bounce = 0;
255  context.in_queue = in_queue;
256  context.scatter_queue = scatter_queue;
257  context.shadow_queue = shadow_queue;
258  context.sequence = m_sequence.view();
259  context.frame_weight = 1.0f / float(renderer_view.instance + 1);
260  context.device_timers = device_timers;
261  context.bbox = m_bbox;
262  context.dl = DirectLightingRL(
263  view( *m_vtls_rl ),
264  m_mesh_vtls->view() );
265 
266  // instantiate the actual path tracing loop
267  path_trace_loop( context, vertex_processor, renderer, renderer_view, stats );
268  }
269  else // use the regular mesh emitter direct-lighting sampler
270  {
271  // select which instantiation of the mesh light to use (VPLs or the plain mesh)
272  MeshLight mesh_light = m_options.nee_type == NEE_ALGORITHM_VPL ? renderer_view.mesh_vpls : renderer_view.mesh_light;
273 
274  // initialize the path-tracing context
275  PathTracingContext<DirectLightingMesh> context;
276  context.options = m_options;
277  context.in_bounce = 0;
278  context.in_queue = in_queue;
279  context.scatter_queue = scatter_queue;
280  context.shadow_queue = shadow_queue;
281  context.sequence = m_sequence.view();
282  context.frame_weight = 1.0f / float(renderer_view.instance + 1);
283  context.device_timers = device_timers;
284  context.bbox = m_bbox;
285  context.dl = DirectLightingMesh( mesh_light );
286 
287  // instantiate the actual path tracing loop
288  path_trace_loop( context, vertex_processor, renderer, renderer_view, stats );
289  }
291  }
292  timer.stop();
293  const float time = timer.seconds();
294  // clear the global timer at instance zero
295  if (instance == 0)
296  m_time = time;
297  else
298  m_time += time;
299 
300  fprintf(stderr, "\r %.1fs (%.1fms = rt[%.1fms + %.1fms + %.1fms] + shade[%.1fms + %.1fms] - %uK cells) ",
301  m_time,
302  time * 1000.0f,
303  stats.primary_rt_time * 1000.0f,
304  stats.path_rt_time * 1000.0f,
305  stats.shadow_rt_time * 1000.0f,
306  stats.path_shade_time * 1000.0f,
307  stats.shadow_shade_time * 1000.0f,
308  m_options.nee_type == NEE_ALGORITHM_RL ? m_vtls_rl->size() / 1000 : 0);
309 
310 #if defined(DEVICE_TIMING) && DEVICE_TIMING
311  if (instance % 64 == 0)
312  print_timer_stats( device_timers, stats );
313 #endif
314 
315  if (instance) // skip the first frame
316  {
317  m_stats.primary_rt_time += stats.primary_rt_time;
318  m_stats.path_rt_time += stats.path_rt_time;
319  m_stats.shadow_rt_time += stats.shadow_rt_time;
320  m_stats.path_shade_time += stats.path_shade_time;
321  m_stats.shadow_shade_time += stats.shadow_shade_time;
322  }
323  renderer.update_variances( instance );
324 }
325 
326 
327 void PathTracer::keyboard(unsigned char character, int x, int y, bool& invalidate)
328 {
329  invalidate = false;
330 
331  switch (character)
332  {
333  case 'i':
334  m_options.direct_lighting = !m_options.direct_lighting;
335  invalidate = true;
336  break;
337  }
338 }
339 
340 // dump some speed stats
341 //
343 {
344  fprintf(stats, "%f, %f, %f, %f, %f\n",
345  m_stats.primary_rt_time.mean() * 1000.0f,
346  m_stats.path_rt_time.mean() * 1000.0f,
347  m_stats.shadow_rt_time.mean() * 1000.0f,
348  m_stats.path_shade_time.mean() * 1000.0f,
349  m_stats.shadow_shade_time.mean() * 1000.0f);
350 }
351 
Definition: direct_lighting_rl.h:45
Definition: pathtracer_kernels.h:49
void init(int argc, char **argv, RenderingContext &renderer)
Definition: pathtracer_impl.h:99
float shadow_shade_time
time spent for shading shadow samples (i.e. in solve_occlusion)
Definition: pathtracer_kernels.h:303
void render(const uint32 instance, RenderingContext &renderer)
Definition: pathtracer_impl.h:197
void update_variances(const uint32 instance)
void start()
start timing
Definition: timer.cpp:116
Definition: lights.h:299
Definition: mesh_lights.h:59
Definition: direct_lighting_mesh.h:41
Definition: clustered_rl.h:161
CUGAR_HOST_DEVICE T * alloc(const uint64 sz, const uint64 alignment=sizeof(T))
Definition: memory_arena.h:69
Definition: timer.h:83
void dump_speed_stats(FILE *stats)
Definition: pathtracer_impl.h:342
Definition: pathtracer_vertex_processor.h:46
Definition: pathtracer_kernels.h:284
float path_rt_time
time spent for tracing scattering rays
Definition: pathtracer_kernels.h:300
MeshLightsStorage & get_mesh_lights()
float shadow_rt_time
time spent for tracing shadow rays
Definition: pathtracer_kernels.h:301
float primary_rt_time
time spent for tracing primary rays
Definition: pathtracer_kernels.h:299
Definition: pathtracer_core.h:570
RenderingContextView view(const uint32 instance)
Define a vector_view POD type and plain_view() for std::vector.
Definition: diff.h:38
void keyboard(unsigned char character, int x, int y, bool &invalidate)
Definition: pathtracer_impl.h:327
Definition: clustered_rl.h:87
uint2 res() const
void path_trace_loop(TPTContext &context, TPTVertexProcessor &vertex_processor, RenderingContext &renderer, RenderingContextView &renderer_view, PTLoopStats &stats)
Definition: pathtracer_kernels.h:310
Definition: renderer.h:52
void alloc_queues(PTOptions options, const uint32 n_pixels, PTRayQueue &input_queue, PTRayQueue &scatter_queue, PTRayQueue &shadow_queue, cugar::memory_arena &arena)
Definition: pathtracer_kernels.h:91
void rescale_frame(const uint32 instance)
Definition: memory_arena.h:44
Definition: renderer_view.h:80
Definition: pathtracer_queues.h:44
cugar::Bbox3f compute_bbox()
float path_shade_time
time spent for shading path vertices
Definition: pathtracer_kernels.h:302