NTrace
GPU ray tracing framework
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
App.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2009-2011, NVIDIA Corporation
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of NVIDIA Corporation nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include "App.hpp"
29 #include "base/Main.hpp"
30 #include "base/Random.hpp"
31 #include "gpu/GLContext.hpp"
32 #include "3d/Mesh.hpp"
33 #include "io/StateDump.hpp"
34 
35 #include <stdio.h>
36 #include <conio.h>
37 
38 using namespace FW;
39 
40 //------------------------------------------------------------------------
41 
42 static const char* const s_kernelDir = "src/rt/kernels";
43 static const char* const s_initialMeshDir = "scenes/rt/sibenik";
44 static const char* const s_defaultMeshFile = "scenes/rt/sibenik/sibenik.obj";
45 
46 //------------------------------------------------------------------------
47 
48 static const char* const s_defaultCameras[] =
49 {
50  "conference", "6omr/04j3200bR6Z/0/3ZEAz/x4smy19///c/05frY109Qx7w////m100",
51  "fairyforest", "cIxMx/sK/Ty/EFu3z/5m9mWx/YPA5z/8///m007toC10AnAHx///Uy200",
52  "sibenik", "ytIa02G35kz1i:ZZ/0//iSay/5W6Ex19///c/05frY109Qx7w////m100",
53  "sanmiguel", "Yciwz1oRQmz/Xvsm005CwjHx/b70nx18tVI7005frY108Y/:x/v3/z100",
54  NULL
55 };
56 
57 //------------------------------------------------------------------------
58 
59 static const char* const s_rayTypeNames[] =
60 {
61  "primary",
62  "AO",
63  "diffuse",
64  "textured",
65  "otracer"
66 };
67 
68 //------------------------------------------------------------------------
69 
70 static const char* const s_aboutText =
71  "\"Understanding the Efficiency of Ray Traversal on GPUs\",\n"
72  "Timo Aila and Samuli Laine,\n"
73  "Proc. High-Performance Graphics 2009\n"
74  "\n"
75  "Implementation by Tero Karras, Timo Aila, and Samuli Laine\n"
76  "Copyright 2009-2012 NVIDIA Corporation\n"
77  "\n"
78  "http://code.google.com/p/understanding-the-efficiency-of-ray-traversal-on-gpus/\n"
79 ;
80 
81 //------------------------------------------------------------------------
82 
83 static const char* const s_commandHelpText =
84  "\n"
85  "Usage: rt <mode> [options]\n"
86  "\n"
87  "Supported values for <mode>:\n"
88  "\n"
89  " interactive Start in interactive mode.\n"
90  " benchmark Run benchmark for given mesh.\n"
91  "\n"
92  "Common options:\n"
93  "\n"
94  " --log=<file.log> Log all output to file.\n"
95  " --size=<w>x<h> Frame size. Default is \"1024x768\".\n"
96  "\n"
97  "Options for \"rt interactive\":\n"
98  "\n"
99  " --state=<file.dat> Load state from the given file.\n"
100  "\n"
101  "Options for \"rt benchmark\":\n"
102  "\n"
103  " --mesh=<file.obj> Mesh to benchmark.\n"
104  " --camera=\"<sig>\" Camera signature. Can specify multiple times.\n"
105  " --kernel=<name> CUDA kernel. Can specify multiple. Default = all.\n"
106  " --sbvh-alpha=<value> SBVH alpha parameter. Default is \"1.0e-5\".\n"
107  " --ao-radius=<value> AO ray length. Default is \"5\".\n"
108  " --samples=<value> Secondary rays per pixel. Default is \"32\".\n"
109  " --sort=<1/0> Sort secondary rays. Default is \"1\".\n"
110  " --warmup-repeats=<num> Launches prior to measurement. Default is \"2\".\n"
111  " --measure-repeats=<num> Launches to measure per batch. Default is \"10\".\n"
112  "\n"
113 ;
114 
115 //------------------------------------------------------------------------
116 
117 static const char* const s_guiHelpText =
118  "General keys:\n"
119  "\n"
120  "\tF1\tHide this message\n"
121  "\tEsc\tExit (also Alt-F4)\n"
122  "\tTab\tShow all GUI controls\n"
123  "\tNum\tLoad numbered state\n"
124  "\tAlt-Num\tSave numbered state\n"
125  "\tF9\tShow/hide FPS counter\n"
126  "\tF10\tShow/hide GUI\n"
127  "\tF11\tToggle fullscreen mode\n"
128  "\tPrtScn\tSave screenshot\n"
129  "\n"
130  "Camera movement:\n"
131  "\n"
132  "\tDrag\tRotate (left), strafe (middle), zoom (right)\n"
133  "\tArrows\tRotate\n"
134  "\tW\tMove forward (also Alt-UpArrow)\n"
135  "\tS\tMove back (also Alt-DownArrow)\n"
136  "\tA\tStrafe left (also Alt-LeftArrow)\n"
137  "\tD\tStrafe right (also Alt-RightArrow)\n"
138  "\tR\tStrafe up (also PageUp)\n"
139  "\tF\tStrafe down (also PageDown)\n"
140  "\tWheel\tAdjust movement speed\n"
141  "\tSpace\tMove faster (hold)\n"
142  "\tCtrl\tMove slower (hold)\n"
143  "\n"
144  "Uncheck \"Retain camera alignment\" to enable:\n"
145  "\n"
146  "\tQ\tRoll counter-clockwise (also Insert)\n"
147  "\tE\tRoll clockwise (also Home)\n"
148 ;
149 
150 //------------------------------------------------------------------------
151 
152 App::App(void)
153 : m_commonCtrl (CommonControls::Feature_Default & ~CommonControls::Feature_RepaintOnF5),
154  m_cameraCtrl (&m_commonCtrl, CameraControls::Feature_Default & ~CameraControls::Feature_NearSlider),
155  m_action (Action_None),
156  m_mesh (NULL),
157 
158  m_rayType (Renderer::RayType_Primary),
159  m_aoRadius (1.0f),
160  m_numSamples (4),
161  m_kernelNameIdx (0),
162 
163  m_showHelp (false),
164  m_showCameraControls (false),
165  m_showKernelSelector (false),
166  m_guiDirty (false)
167 {
168  listKernels(m_kernelNames);
169  if (!m_kernelNames.getSize())
170  fail("No CUDA kernel sources found!");
171 
172  m_env = new AppEnvironment();
173  m_env->ReadEnvFile("config.conf");
174 
175  string bvh;
176  m_env->GetStringValue("AccelerationStructure", bvh);
177  if (bvh == "BVH")
178  {
179  m_renderer = new Renderer(Renderer::tBVH, m_env);
180  }
181  else if (bvh == "KDTree")
182  {
183  m_renderer = new Renderer(Renderer::tKDTree, m_env);
184  }
185 
186  m_commonCtrl.showFPS(true);
187  m_commonCtrl.addStateObject(this);
188  m_commonCtrl.setStateFilePrefix("state_rt_");
189 
190  m_window.setTitle("GPU Ray Traversal");
191  m_window.addListener(&m_cameraCtrl);
192  m_window.addListener(this);
193  m_window.addListener(&m_commonCtrl);
194 
195  rebuildGui();
196 }
197 
198 //------------------------------------------------------------------------
199 
201 {
202  delete m_mesh;
203 }
204 
205 //------------------------------------------------------------------------
206 
208 {
209  // Window closed => destroy app.
210 
211  if (ev.type == Window::EventType_Close)
212  {
213  printf("Exiting...\n");
214  m_window.showModalMessage("Exiting...");
215  delete this;
216  return true;
217  }
218 
219  // Update GUI controls.
220 
221  if (ev.type == Window::EventType_KeyDown && ev.key == FW_KEY_V)
222  {
223  m_renderer->toggleBVHVis();
224  }
225 
226  if (ev.type == Window::EventType_KeyDown && ev.key == FW_KEY_TAB)
227  {
228  bool v = (!m_showCameraControls || !m_showKernelSelector);
229  m_showCameraControls = v;
230  m_showKernelSelector = v;
231  m_guiDirty = true;
232  }
233 
234  if (m_guiDirty)
235  {
236  m_guiDirty = false;
237  rebuildGui();
238  }
239 
240  // Handle actions.
241 
242  Action action = m_action;
243  m_action = Action_None;
244  String name;
245 
246  switch (action)
247  {
248  case Action_None:
249  break;
250 
251  case Action_About:
252  m_window.showMessageDialog("About", s_aboutText);
253  break;
254 
255  case Action_LoadMesh:
256  name = m_window.showFileLoadDialog("Load mesh", getMeshImportFilter(), s_initialMeshDir);
257  if (name.getLength() && loadMesh(name))
258  resetCamera();
259  break;
260 
261  case Action_ResetCamera:
262  if (m_mesh)
263  {
264  resetCamera();
265  m_commonCtrl.message("Camera reset");
266  }
267  break;
268 
269  case Action_ExportCameraSignature:
270  m_window.setVisible(false);
271  printf("\nCamera signature:\n");
272  printf("%s\n", m_cameraCtrl.encodeSignature().getPtr());
273  waitKey();
274  break;
275 
276  case Action_ImportCameraSignature:
277  {
278  m_window.setVisible(false);
279  printf("\nEnter camera signature:\n");
280 
281  char buf[1024];
282  if (fgets(buf, FW_ARRAY_SIZE(buf), stdin) != NULL)
283  m_cameraCtrl.decodeSignature(buf);
284  else
285  setError("Signature too long!");
286 
287  if (!hasError())
288  printf("Done.\n\n");
289  else
290  {
291  printf("Error: %s\n", getError().getPtr());
292  clearError();
293  waitKey();
294  }
295  }
296  break;
297 
298  default:
299  FW_ASSERT(false);
300  break;
301  }
302 
303  // Repaint.
304 
305  m_window.setVisible(true);
306  if (ev.type == Window::EventType_Paint)
307  render(m_window.getGL());
308  m_window.repaint();
309  return false;
310 }
311 
312 //------------------------------------------------------------------------
313 
315 {
316  String meshFileName;
317  String kernelName;
318 
319  s.pushOwner("App");
320  s.get(meshFileName, "m_meshFileName");
321  s.get((S32&)m_rayType, "m_rayType");
322  s.get(m_aoRadius, "m_aoRadius");
323  s.get(m_numSamples, "m_numSamples");
324  s.get(kernelName, "m_kernelName");
325  s.popOwner();
326 
327  if (m_meshFileName != meshFileName && meshFileName.getLength())
328  loadMesh(meshFileName);
329  if (m_kernelNames.contains(kernelName))
330  m_kernelNameIdx = m_kernelNames.indexOf(kernelName);
331  rebuildGui();
332 }
333 
334 //------------------------------------------------------------------------
335 
337 {
338  s.pushOwner("App");
339  s.set(m_meshFileName, "m_meshFileName");
340  s.set((S32&)m_rayType, "m_rayType");
341  s.set(m_aoRadius, "m_aoRadius");
342  s.set(m_numSamples, "m_numSamples");
343  s.set(m_kernelNames[m_kernelNameIdx], "m_kernelName");
344  s.popOwner();
345 }
346 
347 //------------------------------------------------------------------------
348 
349 void App::rebuildGui(void)
350 {
351  CommonControls& cc = m_commonCtrl;
352  cc.resetControls();
353 
354  cc.setControlVisibility(true);
355  cc.addToggle(&m_showHelp, FW_KEY_F1, "Show help [F1]");
356  cc.addButton((S32*)&m_action, Action_About, FW_KEY_NONE, "About...");
357  cc.addButton((S32*)&m_action, Action_LoadMesh, FW_KEY_M, "Load mesh... [M]");
358  cc.addSeparator();
359 
360  cc.addToggle((S32*)&m_rayType, Renderer::RayType_Primary, FW_KEY_F2, "Trace primary rays [F2]", &m_guiDirty);
361  cc.addToggle((S32*)&m_rayType, Renderer::RayType_AO, FW_KEY_F3, "Trace ambient occlusion rays [F3]", &m_guiDirty);
362  cc.addToggle((S32*)&m_rayType, Renderer::RayType_Diffuse, FW_KEY_F4, "Trace diffuse rays [F4]", &m_guiDirty);
363  cc.addToggle((S32*)&m_rayType, Renderer::RayType_Textured, FW_KEY_F5, "Trace textured primary rays [F5]", &m_guiDirty);
364  cc.addToggle((S32*)&m_rayType, Renderer::RayType_PathTracing, FW_KEY_F6, "Rendering kernels show rays result [F6]", &m_guiDirty);
365  cc.addSeparator();
366 
367  cc.beginSliderStack();
369  cc.addSlider(&m_aoRadius, 1.0e-3f, 1.0e4f, true, FW_KEY_NONE, FW_KEY_NONE, "AO ray length = %g units");
371  cc.addSlider(&m_numSamples, 1, 64, false, FW_KEY_NONE, FW_KEY_NONE, "Secondary rays per pixel = %d");
372  cc.endSliderStack();
373 
374  cc.setControlVisibility(m_showCameraControls);
375  cc.addButton((S32*)&m_action, Action_ResetCamera, FW_KEY_NONE, "Reset camera");
376  cc.addButton((S32*)&m_action, Action_ExportCameraSignature, FW_KEY_NONE, "Export camera signature...");
377  cc.addButton((S32*)&m_action, Action_ImportCameraSignature, FW_KEY_NONE, "Import camera signature...");
378  m_cameraCtrl.addGUIControls();
379  cc.addSeparator();
380 
381  cc.setControlVisibility(m_showKernelSelector);
382  for (int i = 0; i < m_kernelNames.getSize(); i++)
383  cc.addToggle(&m_kernelNameIdx, i, FW_KEY_NONE, m_kernelNames[i]);
384  cc.addSeparator();
385 
386  cc.setControlVisibility(true);
387  cc.addToggle(&m_showCameraControls, FW_KEY_NONE, "Show camera controls", &m_guiDirty);
388  cc.addToggle(&m_showKernelSelector, FW_KEY_NONE, "Show kernel selector", &m_guiDirty);
389 }
390 
391 //------------------------------------------------------------------------
392 
393 void App::waitKey(void)
394 {
395  printf("Press any key to continue . . . ");
396  _getch();
397  printf("\n\n");
398 }
399 
400 //------------------------------------------------------------------------
401 
402 void App::render(GLContext* gl)
403 {
404  // No mesh => display message.
405 
406  if (!m_mesh)
407  {
408  gl->drawModalMessage("No mesh loaded!");
409  return;
410  }
411 
412  // Set parameters.
413 
415  params.kernelName = m_kernelNames[m_kernelNameIdx];
416  params.rayType = m_rayType;
417  params.aoRadius = m_aoRadius;
418  params.numSamples = m_numSamples;
419 
420  m_renderer->setParams(params);
421  m_renderer->setMessageWindow(&m_window);
422  m_renderer->setEnableRandom(true);
423 
424  // Render.
425 
426  m_renderer->setMesh(m_mesh);
427  F32 launchTime = m_renderer->renderFrame(gl, m_cameraCtrl);
428  int numRays = m_renderer->getTotalNumRays();
429 
430  // Show statistics.
431 
432  CudaAS* bvh = m_renderer->getCudaBVH();
433  S64 nodeBytes = bvh->getNodeBuffer().getSize();
434  S64 triBytes = bvh->getTriWoopBuffer().getSize() + bvh->getTriIndexBuffer().getSize();
435 
436  String rayStats = sprintf("%.2f million %s rays, %.2f ms, %.2f MRays/s",
437  (F32)numRays * 1.0e-6f,
438  s_rayTypeNames[m_rayType],
439  launchTime * 1.0e3f,
440  (F32)numRays * 1.0e-6f / launchTime);
441 
442  String bvhStats = sprintf("%.2f Mtris, %.2f MB (%.2f MB for nodes, %.2f MB for tris)",
443  (F32)m_mesh->numTriangles() * 1.0e-6f,
444  (F32)(nodeBytes + triBytes) * exp2(-20),
445  (F32)nodeBytes * exp2(-20),
446  (F32)triBytes * exp2(-20));
447 
448  m_commonCtrl.message(rayStats, "rayStats");
449  m_commonCtrl.message(bvhStats, "bvhStats");
450 
451  // Show help.
452 
453  if (m_showHelp)
454  renderGuiHelp(gl);
455 }
456 
457 //------------------------------------------------------------------------
458 
459 void App::renderGuiHelp(GLContext* gl)
460 {
461  S32 fontSize = 16;
462  F32 tabSize = 64.0f;
463 
464  Mat4f oldXform = gl->setVGXform(gl->xformMatchPixels());
465  gl->setFont("Arial", fontSize, GLContext::FontStyle_Bold);
466  Vec2f origin = Vec2f(8.0f, (F32)gl->getViewSize().y - 4.0f);
467 
468  String str = s_guiHelpText;
469  int startIdx = 0;
470  Vec2f pos = 0.0f;
471  while (startIdx < str.getLength())
472  {
473  if (str[startIdx] == '\n')
474  pos = Vec2f(0.0f, pos.y - (F32)fontSize);
475  else if (str[startIdx] == '\t')
476  pos.x += tabSize;
477 
478  int endIdx = startIdx;
479  while (endIdx < str.getLength() && str[endIdx] != '\n' && str[endIdx] != '\t')
480  endIdx++;
481 
482  gl->drawLabel(str.substring(startIdx, endIdx), pos + origin, Vec2f(0.0f, 1.0f), 0xFFFFFFFF);
483  startIdx = max(endIdx, startIdx + 1);
484  }
485 
486  gl->setVGXform(oldXform);
487  gl->setDefaultFont();
488 }
489 
490 //------------------------------------------------------------------------
491 
492 bool App::loadMesh(const String& fileName)
493 {
494  m_window.showModalMessage(sprintf("Loading mesh from '%s'...\nThis will take a few seconds.", fileName.getFileName().getPtr()));
495 
496  String oldError = clearError();
497  MeshBase* mesh = importMesh(fileName);
498  String newError = getError();
499 
500  if (restoreError(oldError))
501  {
502  delete mesh;
503  String msg = sprintf("Error while loading '%s': %s", fileName.getPtr(), newError.getPtr());
504  printf("%s\n", msg.getPtr());
505  m_commonCtrl.message(msg);
506  return false;
507  }
508 
509  m_renderer->setMesh(NULL);
510  delete m_mesh;
511  m_meshFileName = fileName;
512  m_mesh = mesh;
513  m_commonCtrl.message(sprintf("Loaded mesh from '%s'", fileName.getPtr()));
514  return true;
515 }
516 
517 //------------------------------------------------------------------------
518 
519 void App::resetCamera(void)
520 {
521  if (!m_mesh)
522  return;
523 
524  // Extract mesh name.
525 
526  String name = m_meshFileName;
527  int slashIdx = max(name.lastIndexOf('/'), name.lastIndexOf('\\'));
528  int dotIdx = name.lastIndexOf('.');
529  name = name.substring(slashIdx + 1, (dotIdx > slashIdx) ? dotIdx : name.getLength());
530 
531  // Look up default camera.
532 
533  for (const char* const* ptr = s_defaultCameras; ptr[0]; ptr += 2)
534  {
535  if (name == ptr[0])
536  {
537  m_cameraCtrl.decodeSignature(ptr[1]);
538  return;
539  }
540  }
541 
542  // Not found => initialize based on mesh bounds.
543 
544  m_cameraCtrl.initForMesh(m_mesh);
545 }
546 
547 //------------------------------------------------------------------------
548 
549 void App::firstTimeInit(void)
550 {
551  // Choose default kernel.
552 
553  String kernel = "tesla_persistent_while_while";
555  kernel = "tesla_persistent_speculative_while_while";
557  kernel = "fermi_speculative_while_while";
559  kernel = "kepler_dynamic_fetch";
560  if (m_kernelNames.contains(kernel))
561  m_kernelNameIdx = m_kernelNames.indexOf(kernel);
562 
563  // Load mesh.
564 
565  loadMesh(s_defaultMeshFile);
566  resetCamera();
567 
568  // Save state.
569 
570  m_commonCtrl.saveState(m_commonCtrl.getStateFileName(1));
571  failIfError();
572 }
573 
574 //------------------------------------------------------------------------
575 
576 void FW::listKernels(Array<String>& kernelNames)
577 {
578  WIN32_FIND_DATA fd;
579  HANDLE h = FindFirstFile(sprintf("%s/*.cu", s_kernelDir).getPtr(), &fd);
580  if (h != INVALID_HANDLE_VALUE)
581  {
582  do
583  {
584  String name = fd.cFileName;
585  kernelNames.add(name.substring(0, name.getLength() - 3));
586  }
587  while (FindNextFile(h, &fd) != 0);
588  FindClose(h);
589  }
590 }
591 
592 //------------------------------------------------------------------------
593 
594 void FW::runInteractive(const Vec2i& frameSize, const String& stateFile)
595 {
596  if (hasError())
597  return;
598 
599  // Launch.
600 
601  printf("Starting up...\n");
602  App* app = new App;
603  app->setWindowSize(frameSize);
604 
605  // Load state.
606 
607  if (!hasError() && !stateFile.getLength())
608  app->loadDefaultState();
609  else if (!hasError() && !app->loadState(stateFile))
610  setError("Unable to load state from '%s'!", stateFile.getPtr());
611 
612  // Error => close window.
613 
614  if (hasError())
615  delete app;
616  else
617  app->flashButtonTitles();
618 }
619 
620 //------------------------------------------------------------------------
621 
623  const Vec2i& frameSize,
624  const String& meshFile,
625  const Array<String>& cameras,
626  const Array<String>& kernels,
627  F32 sbvhAlpha,
628  F32 aoRadius,
629  int numSamples,
630  bool sortSecondary,
631  int warmupRepeats,
632  int measureRepeats)
633 {
634  int numRayTypes = Renderer::RayType_Max;
635 
636  // Print header.
637 
639  printf("Running benchmark for \"%s\".\n", meshFile.getPtr());
640  printf("\n");
641 
642  // Setup renderer.
643 
645  params.aoRadius = aoRadius;
646  params.numSamples = numSamples;
647  params.sortSecondary = sortSecondary;
648 
649  BVH::BuildParams buildParams;
650  buildParams.splitAlpha = sbvhAlpha;
651 
652  Renderer* renderer = new Renderer(Renderer::tBVH, NULL);
653  //Renderer* renderer = new Renderer(Renderer::tKDTree);
654  renderer->setBuildParams(buildParams);
655  renderer->setMesh(importMesh(meshFile));
656 
657  // Create window.
658 
659  Window window;
660  window.setSize(frameSize);
661  window.setVisible(false);
662  window.realize();
663  GLContext* gl = window.getGL();
664 
665  // Error => skip.
666 
667  if (hasError())
668  return;
669 
670  // Benchmark each combination.
671 
672  Array<F32> results;
673  for (int kernelIdx = 0; kernelIdx < kernels.getSize(); kernelIdx++)
674  {
675  for (int rayType = 0; rayType < numRayTypes; rayType++)
676  {
677  S64 totalRays = 0;
678  F32 totalLaunchTime = 0.0f;
679 
680  for (int cameraIdx = 0; cameraIdx < cameras.getSize(); cameraIdx++)
681  {
682  // Print status.
683 
684  String title = sprintf("%s, %s, camera %d", kernels[kernelIdx].getPtr(), s_rayTypeNames[rayType], cameraIdx);
685  printf("%s...\n", title.getPtr());
686  window.setTitle(title);
687 
688  // Setup rendering.
689 
690  params.kernelName = kernels[kernelIdx];
691  params.rayType = (Renderer::RayType)rayType;
692  renderer->setParams(params);
693 
694  CameraControls camera;
695  camera.decodeSignature(cameras[cameraIdx]);
696  renderer->beginFrame(gl, camera);
697  totalRays += (S64)renderer->getTotalNumRays() * measureRepeats;
698 
699  // Process each batch.
700 
701  while (renderer->nextBatch())
702  {
703  // Render and display result.
704 
705  renderer->traceBatch();
706  renderer->updateResult();
707  window.setVisible(true);
709  for (int i = 0; i < 3; i++)
710  {
711  renderer->displayResult(gl);
712  gl->swapBuffers();
713  }
714 
715  // Warm up and measure.
716 
717  for (int i = 0; i < warmupRepeats; i++)
718  renderer->traceBatch();
719  for (int i = 0; i < measureRepeats; i++)
720  totalLaunchTime += renderer->traceBatch();
721  }
722 
723  // Error => skip.
724 
725  if (hasError())
726  return;
727  }
728 
729  // Calculate Mrays/s.
730 
731  F32 mraysPerSec = (F32)totalRays / totalLaunchTime * 1.0e-6f;
732  results.add(mraysPerSec);
733  printf("Mrays/s = %.2f\n", mraysPerSec);
734  printf("\n");
735  }
736  }
737 
738  // Print summary table.
739 
740  printf("Done.\n");
741  printf("\n");
742 
743  printf("%-42s", "Kernel");
744  for (int i = 0; i < numRayTypes; i++)
745  printf("%-10s", s_rayTypeNames[i]);
746  printf("\n");
747 
748  printf("%-42s", "---");
749  for (int i = 0; i < numRayTypes; i++)
750  printf("%-10s", "---");
751  printf("\n");
752 
753  for (int i = 0; i < kernels.getSize(); i++)
754  {
755  printf("%-42s", kernels[i].getPtr());
756  for (int j = 0; j < numRayTypes; j++)
757  printf("%-10.2f", results[i * numRayTypes + j]);
758  printf("\n");
759  }
760 
761  printf("%-42s", "---");
762  for (int i = 0; i < numRayTypes; i++)
763  printf("%-10s", "---");
764  printf("\n");
765  printf("\n");
766 }
767 
768 //------------------------------------------------------------------------
769 
770 void FW::init(void)
771 {
772  // Parse mode.
773 
774  bool modeInteractive = false;
775  bool modeBenchmark = false;
776  bool showHelp = false;
777 
778  if (argc < 2)
779  {
780  printf("Specify \"--help\" for a list of command-line options.\n\n");
781  modeInteractive = true;
782  }
783  else
784  {
785  String mode = argv[1];
786  if (mode == "interactive") modeInteractive = true;
787  else if (mode == "benchmark") modeBenchmark = true;
788  else showHelp = true;
789  }
790 
791  // Parse options.
792 
793  String logFile;
794  Vec2i frameSize = Vec2i(1024, 768);
795  String stateFile;
796  String meshFile;
797  Array<String> cameras;
798  Array<String> kernels;
799  F32 sbvhAlpha = 1.0e-5f;
800  F32 aoRadius = 5.0f;
801  int numSamples = 32;
802  bool sortRays = true;
803  int warmupRepeats = 2;
804  int measureRepeats = 10;
805 
806  for (int i = 2; i < argc; i++)
807  {
808  const char* ptr = argv[i];
809 
810  if ((parseLiteral(ptr, "--help") || parseLiteral(ptr, "-h")) && !*ptr)
811  {
812  showHelp = true;
813  }
814  else if (parseLiteral(ptr, "--log="))
815  {
816  if (!*ptr)
817  setError("Invalid log file '%s'!", argv[i]);
818  logFile = ptr;
819  }
820  else if (parseLiteral(ptr, "--size="))
821  {
822  if (!parseInt(ptr, frameSize.x) || !parseLiteral(ptr, "x") || !parseInt(ptr, frameSize.y) || *ptr || min(frameSize) <= 0)
823  setError("Invalid frame size '%s'!", argv[i]);
824  }
825  else if (modeInteractive && parseLiteral(ptr, "--state="))
826  {
827  if (!*ptr)
828  setError("Invalid state file '%s'!", argv[i]);
829  stateFile = ptr;
830  }
831  else if (modeBenchmark && parseLiteral(ptr, "--mesh="))
832  {
833  if (!*ptr)
834  setError("Invalid mesh file '%s'!", argv[i]);
835  meshFile = ptr;
836  }
837  else if (modeBenchmark && parseLiteral(ptr, "--camera="))
838  {
839  if (!*ptr)
840  setError("Invalid camera signature '%s'!", argv[i]);
841  cameras.add(ptr);
842  }
843  else if (modeBenchmark && parseLiteral(ptr, "--kernel="))
844  {
845  if (!*ptr)
846  setError("Invalid kernel name '%s'!", argv[i]);
847  kernels.add(ptr);
848  }
849  else if (modeBenchmark && parseLiteral(ptr, "--sbvh-alpha="))
850  {
851  if (!parseFloat(ptr, sbvhAlpha) || *ptr || sbvhAlpha < 0.0f || sbvhAlpha > 1.0f)
852  setError("Invalid SBVH alpha '%s'!", argv[i]);
853  }
854  else if (modeBenchmark && parseLiteral(ptr, "--ao-radius="))
855  {
856  if (!parseFloat(ptr, aoRadius) || *ptr || aoRadius < 0.0f)
857  setError("Invalid AO radius '%s'!", argv[i]);
858  }
859  else if (modeBenchmark && parseLiteral(ptr, "--samples="))
860  {
861  if (!parseInt(ptr, numSamples) || *ptr || numSamples < 1)
862  setError("Invalid number of samples '%s'!", argv[i]);
863  }
864  else if (modeBenchmark && parseLiteral(ptr, "--sort="))
865  {
866  int value = 0;
867  if (!parseInt(ptr, value) || *ptr || value < 0 || value > 1)
868  setError("Invalid ray sorting enable/disable '%s'!", argv[i]);
869  sortRays = (value != 0);
870  }
871  else if (modeBenchmark && parseLiteral(ptr, "--warmup-repeats="))
872  {
873  if (!parseInt(ptr, warmupRepeats) || *ptr || warmupRepeats < 0)
874  setError("Invalid number of warmup repeats '%s'!", argv[i]);
875  }
876  else if (modeBenchmark && parseLiteral(ptr, "--measure-repeats="))
877  {
878  if (!parseInt(ptr, measureRepeats) || *ptr || measureRepeats < 1)
879  setError("Invalid number of measurement repeats '%s'!", argv[i]);
880  }
881  else
882  {
883  setError("Invalid option '%s'!", argv[i]);
884  }
885  }
886 
887  // Show help.
888 
889  if (showHelp)
890  {
891  printf("%s", s_commandHelpText);
892  exitCode = 1;
893  clearError();
894  return;
895  }
896 
897  // Log file specified => start logging.
898 
899  if (logFile.getLength())
900  pushLogFile(logFile);
901 
902  // Validate options.
903 
904  if (modeBenchmark)
905  {
906  if (!meshFile.getLength())
907  setError("Mesh file (--mesh) not specified!");
908  if (!cameras.getSize())
909  setError("No camera signatures (--camera) specified!");
910  if (!kernels.getSize())
911  listKernels(kernels);
912  }
913 
914  // Run.
915 
916  if (modeInteractive)
917  runInteractive(frameSize, stateFile);
918 
919  if (modeBenchmark)
920  runBenchmark(frameSize, meshFile, cameras, kernels, sbvhAlpha, aoRadius, numSamples, sortRays, warmupRepeats, measureRepeats);
921 
922  // Handle errors.
923 
924  if (hasError())
925  {
926  printf("Error: %s\n", getError().getPtr());
927  exitCode = 1;
928  clearError();
929  return;
930  }
931 }
932 
933 //------------------------------------------------------------------------
MeshBase * importMesh(const String &fileName)
Definition: Mesh.cpp:1185
App(void)
Definition: App.cpp:152
void addStateObject(StateObject *obj)
bool nextBatch(void)
Definition: Renderer.cpp:313
Stucture holding the BVH build parameters.
Definition: BVH.hpp:109
#define NULL
Definition: Defs.hpp:39
String substring(int start, int end) const
Definition: String.cpp:96
void runInteractive(const Vec2i &frameSize, const String &stateFile)
Definition: App.cpp:594
const char * getPtr(void) const
Definition: String.hpp:51
#define FW_KEY_NONE
Definition: Keys.hpp:37
#define FW_KEY_F3
Definition: Keys.hpp:83
String getFileName(void) const
Definition: String.cpp:284
Mat4f setVGXform(const Mat4f &m)
Definition: GLContext.hpp:171
bool GetStringValue(const char *name, char *value, const bool isFatal=false) const
void setDefaultFont(void)
Definition: GLContext.hpp:188
void setWindowSize(const Vec2i &size)
Definition: App.hpp:65
CudaAS * getCudaBVH(void)
Definition: Renderer.cpp:103
const char * name
Definition: DLLImports.cpp:42
void swapBuffers(void)
Definition: GLContext.cpp:276
void setError(const char *fmt,...)
Definition: Defs.cpp:253
void ** ptr
Definition: DLLImports.cpp:74
CUdevice int ordinal char int CUdevice dev CUdevprop CUdevice dev CUcontext ctx CUcontext ctx CUcontext pctx CUmodule const void image CUmodule const void fatCubin CUfunction CUmodule const char name void p CUfunction unsigned int bytes CUtexref pTexRef CUtexref CUarray unsigned int Flags CUtexref int CUaddress_mode am CUtexref unsigned int Flags CUaddress_mode CUtexref int dim CUarray_format int CUtexref hTexRef CUfunction unsigned int numbytes CUfunction int float value CUfunction int CUtexref hTexRef CUfunction int int grid_height CUevent unsigned int Flags CUevent hEvent CUevent hEvent CUstream unsigned int Flags CUstream hStream GLuint bufferobj unsigned int CUdevice dev CUdeviceptr unsigned int CUmodule const char name CUdeviceptr unsigned int bytesize CUdeviceptr dptr void unsigned int bytesize void CUdeviceptr unsigned int ByteCount CUarray unsigned int CUdeviceptr unsigned int ByteCount CUarray unsigned int const void unsigned int ByteCount CUarray unsigned int CUarray unsigned int unsigned int ByteCount void CUarray unsigned int unsigned int CUstream hStream const CUDA_MEMCPY2D pCopy CUdeviceptr const void unsigned int CUstream hStream const CUDA_MEMCPY2D CUstream hStream CUdeviceptr unsigned char unsigned int N CUdeviceptr unsigned int unsigned int N CUdeviceptr unsigned int unsigned short unsigned int unsigned int Height CUarray const CUDA_ARRAY_DESCRIPTOR pAllocateArray CUarray const CUDA_ARRAY3D_DESCRIPTOR pAllocateArray unsigned int CUtexref CUdeviceptr unsigned int bytes CUcontext unsigned int CUdevice device GLenum texture GLenum GLuint buffer GLenum GLuint renderbuffer GLenum GLsizeiptr const GLvoid GLenum usage GLuint shader GLenum type GLsizei const GLuint framebuffers GLsizei const GLuint renderbuffers GLuint v GLuint v GLenum GLenum GLenum GLuint GLint level GLsizei GLuint framebuffers GLuint const GLchar name GLenum GLintptr GLsizeiptr GLvoid data GLuint GLenum GLint param GLuint GLenum GLint param GLhandleARB programObj GLenum GLenum GLsizei GLsizei height GLenum GLint GLint GLsizei GLsizei GLsizei GLint GLenum GLenum const GLvoid pixels GLint GLsizei const GLfloat value GLint GLfloat GLfloat v1 GLint GLfloat GLfloat GLfloat v2 GLint GLsizei const GLfloat value GLint GLsizei GLboolean const GLfloat value GLuint program GLuint GLfloat GLfloat GLfloat z GLuint GLint GLenum GLboolean GLsizei const GLvoid pointer GLuint GLuint const GLchar name GLenum GLsizei GLenum GLsizei GLsizei height GLenum GLuint renderbuffer GLenum GLenum GLint * params
Definition: DLLImports.inl:373
Vec2i drawLabel(const String &str, const Vec4f &pos, const Vec2f &align, U32 fgABGR, U32 bgABGR)
Definition: GLContext.cpp:704
int argc
Definition: Main.cpp:43
virtual Buffer & getTriWoopBuffer(void)=0
Returns buffer of woopified triangles.
void addListener(Listener *listener)
Definition: Window.cpp:282
String clearError(void)
Definition: Defs.cpp:269
#define FW_KEY_F6
Definition: Keys.hpp:86
void addToggle(bool *target, const String &key, const String &title, bool *dirtyNotify=NULL)
void setStateFilePrefix(const String &prefix)
void beginSliderStack(void)
void addSlider(F32 *target, F32 minValue, F32 maxValue, bool isExponential, const String &increaseKey, const String &decreaseKey, const String &format, F32 speed=0.25f, bool *dirtyNotify=NULL)
virtual Buffer & getTriIndexBuffer(void)=0
Returns buffer of triangle indexes.
F32 traceBatch(void)
Definition: Renderer.cpp:364
#define FW_KEY_V
Definition: Keys.hpp:214
int exitCode
Definition: Main.cpp:45
S64 getSize(void) const
Definition: Buffer.hpp:69
void popOwner(void)
Definition: StateDump.hpp:52
int lastIndexOf(char chr) const
Definition: String.hpp:80
F32 splitAlpha
Spatial split area threshold.
Definition: BVH.hpp:113
bool restoreError(const String &old)
Definition: Defs.cpp:278
void setEnableRandom(bool enable)
Definition: Renderer.hpp:94
bool parseLiteral(const char *&ptr, const char *str)
Definition: String.cpp:365
static int getComputeCapability(void)
Definition: CudaModule.cpp:508
F32 renderFrame(GLContext *gl, const CameraControls &camera)
Definition: Renderer.cpp:248
virtual void readState(StateDump &d)
Definition: App.cpp:314
void repaint(void)
Definition: Window.cpp:216
void updateResult(void)
Definition: Renderer.cpp:373
void loadDefaultState(void)
Definition: App.hpp:67
float F32
Definition: Defs.hpp:89
#define FW_KEY_F5
Definition: Keys.hpp:85
#define FW_KEY_F1
Definition: Keys.hpp:81
void listKernels(Array< String > &kernelNames)
Definition: App.cpp:576
bool ReadEnvFile(const char *filename)
void init(void)
Definition: App.cpp:770
void setBuildParams(const BVH::BuildParams &params)
Definition: Renderer.hpp:89
CUdevice int ordinal char int CUdevice dev CUdevprop CUdevice dev CUcontext ctx CUcontext ctx CUcontext pctx CUmodule const void image CUmodule const void fatCubin CUfunction CUmodule const char name void p CUfunction unsigned int bytes CUtexref pTexRef CUtexref CUarray unsigned int Flags CUtexref int CUaddress_mode am CUtexref unsigned int Flags CUaddress_mode CUtexref int dim CUarray_format int CUtexref hTexRef CUfunction unsigned int numbytes CUfunction int float value CUfunction int CUtexref hTexRef CUfunction int int grid_height CUevent unsigned int Flags CUevent hEvent CUevent hEvent CUstream unsigned int Flags CUstream hStream GLuint bufferobj unsigned int CUdevice dev CUdeviceptr unsigned int CUmodule const char name CUdeviceptr unsigned int bytesize CUdeviceptr dptr void unsigned int bytesize void CUdeviceptr unsigned int ByteCount CUarray unsigned int CUdeviceptr unsigned int ByteCount CUarray unsigned int const void unsigned int ByteCount CUarray unsigned int CUarray unsigned int unsigned int ByteCount void CUarray unsigned int unsigned int CUstream hStream const CUDA_MEMCPY2D pCopy CUdeviceptr const void unsigned int CUstream hStream const CUDA_MEMCPY2D CUstream hStream CUdeviceptr unsigned char unsigned int N CUdeviceptr unsigned int unsigned int N CUdeviceptr unsigned int unsigned short unsigned int unsigned int Height CUarray const CUDA_ARRAY_DESCRIPTOR pAllocateArray CUarray const CUDA_ARRAY3D_DESCRIPTOR pAllocateArray unsigned int CUtexref CUdeviceptr unsigned int bytes CUcontext unsigned int CUdevice device GLenum texture GLenum GLuint buffer GLenum GLuint renderbuffer GLenum GLsizeiptr const GLvoid GLenum usage GLuint shader GLenum type GLsizei const GLuint framebuffers GLsizei const GLuint renderbuffers GLuint v
Definition: DLLImports.inl:329
const String & getError(void)
Definition: Defs.cpp:296
void set(const StateDump &other)
Definition: StateDump.hpp:49
void showModalMessage(const String &msg)
Definition: Window.cpp:487
FW_CUDA_FUNC T min(const VectorBase< T, L, S > &v)
Definition: Math.hpp:461
void setVisible(bool visible)
Definition: Window.cpp:138
virtual void writeState(StateDump &d) const
Definition: App.cpp:336
FW_CUDA_FUNC T max(const VectorBase< T, L, S > &v)
Definition: Math.hpp:462
void setFont(const String &name, int size, U32 style)
Definition: GLContext.cpp:645
void setControlVisibility(bool visible)
#define FW_KEY_F4
Definition: Keys.hpp:84
void setMesh(MeshBase *mesh)
Definition: Renderer.cpp:68
void realize(void)
Definition: Window.cpp:184
#define FW_ASSERT(X)
Definition: Defs.hpp:67
signed int S32
Definition: Defs.hpp:88
void pushLogFile(const String &name, bool append=true)
Definition: Defs.cpp:394
String getMeshImportFilter(void)
Definition: Mesh.cpp:1215
int getLength(void) const
Definition: String.hpp:49
String showFileLoadDialog(const String &title, const String &filters="", const String &initialDir="", bool forceInitialDir=false)
Definition: Window.hpp:135
void setSize(const Vec2i &size)
Definition: Window.cpp:106
Mat4f xformMatchPixels(void) const
Definition: GLContext.hpp:152
String encodeSignature(void) const
String sprintf(const char *fmt,...)
Definition: Defs.cpp:241
static bool isAvailable(void)
Definition: CudaModule.hpp:68
void toggleBVHVis(void)
Definition: Renderer.hpp:118
GLContext * getGL(void)
Definition: Window.cpp:203
bool parseInt(const char *&ptr, S32 &value)
Definition: String.cpp:384
#define FW_KEY_TAB
Definition: Keys.hpp:158
signed __int64 S64
Definition: Defs.hpp:98
F32 exp2(F32 a)
Definition: Math.hpp:87
void setParams(const Params &params)
Definition: Renderer.cpp:94
bool hasError(void)
Definition: Defs.cpp:289
void addButton(bool *target, const String &key, const String &title, bool *dirtyNotify=NULL)
String getStateFileName(int idx) const
int getTotalNumRays(void)
Definition: Renderer.cpp:429
void showMessageDialog(const String &title, const String &text)
Definition: Window.cpp:312
CUdevice int ordinal char int CUdevice dev CUdevprop CUdevice dev CUcontext ctx CUcontext ctx CUcontext pctx CUmodule const void image CUmodule const void fatCubin CUfunction CUmodule const char name void p CUfunction unsigned int bytes CUtexref pTexRef CUtexref CUarray unsigned int Flags CUtexref int CUaddress_mode am CUtexref unsigned int Flags CUaddress_mode CUtexref int dim CUarray_format int CUtexref hTexRef CUfunction unsigned int numbytes CUfunction int float value CUfunction int CUtexref hTexRef CUfunction f
Definition: DLLImports.inl:88
CUdevice int ordinal char int CUdevice dev CUdevprop CUdevice dev CUcontext ctx CUcontext ctx CUcontext pctx CUmodule const void image CUmodule const void fatCubin CUfunction CUmodule const char name void p CUfunction unsigned int bytes CUtexref pTexRef CUtexref CUarray unsigned int Flags CUtexref int CUaddress_mode am CUtexref unsigned int Flags CUaddress_mode CUtexref int dim CUarray_format int CUtexref hTexRef CUfunction unsigned int numbytes CUfunction int float value
Definition: DLLImports.inl:84
static void pollMessages(void)
Definition: Window.cpp:593
void initForMesh(const MeshBase *mesh)
void showFPS(bool show)
char ** argv
Definition: Main.cpp:44
void printf(const char *fmt,...)
Definition: Defs.cpp:225
void setMessageWindow(Window *window)
Definition: Renderer.hpp:93
bool parseFloat(const char *&ptr, F32 &value)
Definition: String.cpp:440
void pushOwner(const String &id)
Definition: StateDump.hpp:51
#define FW_ARRAY_SIZE(X)
Definition: Defs.hpp:79
bool loadState(const String &fileName)
Definition: App.hpp:66
int numTriangles(void) const
Definition: Mesh.hpp:153
#define FW_KEY_F2
Definition: Keys.hpp:82
void failIfError(void)
Definition: Defs.cpp:361
#define FW_KEY_M
Definition: Keys.hpp:205
EventType type
Definition: Window.hpp:69
void runBenchmark(const Vec2i &frameSize, const String &meshFile, const Array< String > &cameras, const Array< String > &kernels, F32 sbvhAlpha, F32 aoRadius, int numSamples, bool sortSecondary, int warmupRepeats, int measureRepeats)
Definition: App.cpp:622
const Array< U8 > * get(const String &id) const
Definition: StateDump.cpp:77
void decodeSignature(const String &sig)
const Vec2i & getViewSize(void) const
Definition: GLContext.hpp:148
virtual Buffer & getNodeBuffer(void)=0
Returns node buffer.
static void staticInit(void)
Definition: CudaModule.cpp:311
void fail(const char *fmt,...)
Definition: Defs.cpp:304
void setTitle(const String &title)
Definition: Window.cpp:95
void flashButtonTitles(void)
Definition: App.hpp:68
void displayResult(GLContext *gl)
Definition: Renderer.cpp:416
bool saveState(const String &fileName)
S32 getSize(void) const
Interface for acceleration structure.
Definition: CudaAS.hpp:19
void beginFrame(GLContext *gl, const CameraControls &camera)
Definition: Renderer.cpp:267
virtual ~App(void)
Definition: App.cpp:200
void message(const String &str, const String &volatileID="", U32 abgr=0xffffffffu)
virtual bool handleEvent(const Window::Event &ev)
Definition: App.cpp:207
void drawModalMessage(const String &msg)
Definition: GLContext.cpp:786
Definition: App.hpp:42