diff --git a/.gitignore b/.gitignore index 8eb2a3180e..f017c128a5 100644 --- a/.gitignore +++ b/.gitignore @@ -2,8 +2,7 @@ *# bin *.user* -build -build_release +build* *.sw? tags .ycm_extra_conf.pyc @@ -16,3 +15,4 @@ tbb embree ispc ospray-doc +modules diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f517ed379e..3b3e4e8c5a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -13,6 +13,18 @@ build-centos6-gcc: - gcc - build +build-centos6-icc: + type: build + script: + - module load intel + - export CC=icc + - export CXX=icpc + - scripts/build_gitlab/linux.sh + tags: + - centos6 + - icc + - build + build-centos7-gcc: type: build script: @@ -22,33 +34,42 @@ build-centos7-gcc: - gcc - build -build-fedora-gcc: +build-arch-gcc: type: build script: - scripts/build_gitlab/linux.sh tags: - - fedora + - arch - gcc - build -build-ubuntu-gcc: +build-ubuntu1604-gcc: type: build script: - scripts/build_gitlab/linux.sh tags: - - ubuntu + - ubuntu1604 - gcc - build -#build-ubuntu-clang: -# type: build -# script: -# - export CC=clang -# - export CXX=clang++ -# - scripts/build_gitlab/linux.sh -# tags: -# - ubuntu -# - clang +build-ubuntu1604-clang: + type: build + script: + - export CC=clang + - export CXX=clang++ + - scripts/build_gitlab/linux.sh + tags: + - ubuntu1604 + - clang + +build-ubuntu1404-gcc: + type: build + script: + - scripts/build_gitlab/linux.sh + tags: + - ubuntu1404 + - gcc + - build build-sles-gcc: type: build @@ -89,7 +110,7 @@ build-windows-msvc14: build-windows-icc: type: build script: - - call scripts\build_gitlab\win.bat "Visual Studio 12 2013 Win64" "Intel C++ Compiler 16.0" + - call scripts\build_gitlab\win.bat "Visual Studio 12 2013 Win64" "Intel C++ Compiler 17.0" tags: - icc - build @@ -133,7 +154,7 @@ release-linux-icc: only: - devel - master - - release-1.0 + - release-1.1.x artifacts: paths: - build_release/*.gz @@ -151,7 +172,7 @@ release-osx-clang: only: - devel - master - - release-1.0 + - release-1.1.x artifacts: paths: - build_release/*.gz @@ -168,7 +189,7 @@ release-windows: only: - devel - master - - release-1.0 + - release-1.1.x artifacts: paths: - build_release\ospray*.zip diff --git a/CHANGELOG.md b/CHANGELOG.md index 79ab98b953..08036dc659 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,53 @@ Version History --------------- +### Changes in v1.1.0: + +- New "scivis" renderer features + - Single sided lighting (enabled by default) + - Many new volume rendering specific features + - Adaptive sampling to help improve the correctness of + rendering high frequency volume data + - Pre-integration of transfer function for higher fidelity + images + - Ambient occlusion + - Volumes can cast shadows + - Smooth shading in volumes + - Single shading point option for accelerated shading +- Add preliminary support for adaptive accumulation in the MPI device +- Camera specific features + - Initial support for stereo rendering with the perspective camera + - Option `architectural` in perspective camera, rectifying + vertical edges to appear parallel + - Rendering a subsection of the full view with + `imageStart`/`imageEnd` supported by all cameras +- This will be our last release supporting the first generation Intel® + Xeon Phi™ coprocessor (codename Knights Corner) + - Future major and minor releases will be upgraded to the latest + version of Embree, which no longer supports Knights Corner + - Depending on user feedback, patch releases are still made to + fix bugs +- Enhanced output statistics in `ospBenchmark` application +- Many fixes to the OSPRay SDK + - Improved CMake detection of compile-time enabled features + - Now distribute OSPRay configuration and ISPC CMake macros + - Improved SDK support on Windows +- OSPRay library can now be compiled with `-Wall` and `-Wextra` enabled + - Tested with GCC v5.3.1 and Clang v3.8 + - Sample applications and modules have not been fixed yet, thus + applications which build OSPRay as a CMake subproject should + disable them with `-DOSPRAY_ENABLE_APPS=OFF` and + `-DOSPRAY_ENABLE_MODULES=OFF` +- Minor bug fixes, improvements, and cleanups + - Regard shading normal when bump mapping + - Fix internal CMake naming inconsistencies in macros + - Fix missing API calls in C++ wrapper classes + - Fix crashes on MIC + - Fix thread count initialization bug with TBB + - CMake optimizations for faster configuration times + - Enhanced support for scripting in both `ospGlutViewer` and + `ospBenchmark` applications + ### Changes in v1.0.0: - New OSPRay 'SDK' @@ -16,7 +63,7 @@ Version History where multiple wrappers will share the same underlying handle when assigned, copied, or moved - New OSPRay objects are only created when a class instance is - explicity constructed + explicitly constructed - C++ users are encouraged to use these over the `ospray.h` API - Complete rework of sample applications @@ -33,13 +80,13 @@ Version History Intel C++ compiler (icc)) - Enhanced support of sample applications on Windows - New minimum ISPC version is 1.9.0 -- Support of Intel® AVX-512 for second generation Intel® Xeon Phi™ +- Support of Intel® AVX-512 for second generation Intel Xeon Phi processor (codename Knights Landing) is now a part of the `OSPRAY_BUILD_ISA` CMake build configuration - Compiling AVX-512 requires icc to be enabled as a build option - Enhanced error messages when `ospLoadModule()` fails - Added `OSP_FB_RGBA32F` support in the `DistributedFrameBuffer` -- Updated Glass shader in the PathTracer +- Updated Glass shader in the path tracer - Many miscellaneous cleanups, bugfixes, and improvements ### Changes in v0.10.1: @@ -78,7 +125,7 @@ Version History - OSPRay can now use a newer, pre-installed Embree enabled by the new `OSPRAY_USE_EXTERNAL_EMBREE` CMake option - New `ospcommon` library used to separately provide math types and OS - abstractions for both OSPRay and sample apps + abstractions for both OSPRay and sample applications - Removes extra dependencies on internal Embree math types and utility functions - `ospray.h` header is now C99 compatible @@ -136,7 +183,7 @@ changes. standard library versions (GCC v4.8.0) - Optimization of volume sampling resulting in volume rendering speedups of up to 1.5x -- Updates to pathtracer +- Updates to path tracer - Reworked material system - Added texture transformations and colored transparency in OBJ material diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b37283a42..bb67c4613d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,141 +29,58 @@ IF(POLICY CMP0054) ENDIF() SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/cmake) -SET(OSPRAY_VERSION_MAJOR 1) -SET(OSPRAY_VERSION_MINOR 0) -SET(OSPRAY_VERSION_PATCH 0) -SET(OSPRAY_VERSION_GITHASH 0) -IF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git) - FIND_PACKAGE(Git) - IF(GIT_FOUND) - EXECUTE_PROCESS( - COMMAND ${GIT_EXECUTABLE} rev-parse HEAD - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" - OUTPUT_VARIABLE "OSPRAY_VERSION_GITHASH" - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE) - ENDIF() -ENDIF() - -SET(OSPRAY_VERSION - ${OSPRAY_VERSION_MAJOR}.${OSPRAY_VERSION_MINOR}.${OSPRAY_VERSION_PATCH} -) -SET(OSPRAY_SOVERSION 0) - - -SET(CONFIGURATION_TYPES "Debug;Release;RelWithDebInfo") -IF (WIN32) - IF (NOT OSPRAY_DEFAULT_CMAKE_CONFIGURATION_TYPES_SET) - SET(CMAKE_CONFIGURATION_TYPES "${CONFIGURATION_TYPES}" - CACHE STRING "List of generated configurations." FORCE) - SET(OSPRAY_DEFAULT_CMAKE_CONFIGURATION_TYPES_SET ON - CACHE INTERNAL "Default CMake configuration types set.") - ENDIF() -ELSE() - IF(NOT CMAKE_BUILD_TYPE) - SET(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the build type." FORCE) - SET_PROPERTY(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS ${CONFIGURATION_TYPES}) - ENDIF() -ENDIF() - -SET(OSPRAY_BINARY_DIR ${PROJECT_BINARY_DIR}) -SET(LIBRARY_OUTPUT_PATH ${OSPRAY_BINARY_DIR}) -SET(EXECUTABLE_OUTPUT_PATH ${OSPRAY_BINARY_DIR}) ############################################################## # CMake modules and macro files ############################################################## -INCLUDE(cmake/ospray.cmake) -INCLUDE(cmake/ispc.cmake) -INCLUDE(cmake/mpi.cmake) +INCLUDE(ospray_macros) +INCLUDE(ospray_options) +INCLUDE(ispc) +INCLUDE(mpi) IF(NOT WIN32) INCLUDE(cmake/doxygen.cmake) ENDIF() -############################################################## -# OSPRay specific build options and configuration selection -############################################################## - -OPTION(OSPRAY_USE_EXTERNAL_EMBREE - "Use a pre-built Embree instead of the internally built version" ON) - -OPTION(OSPRAY_VOLUME_VOXELRANGE_IN_APP "Move 'voxelrange' computations to app?") -MARK_AS_ADVANCED(OSPRAY_VOLUME_VOXELRANGE_IN_APP) - -IF (WIN32) - SET(OSPRAY_BUILD_MIC_SUPPORT OFF CACHE INTERNAL - "OSPRay with KNC not supported on Windows.") -ELSE() - OPTION(OSPRAY_BUILD_MIC_SUPPORT "Build OSPRay with KNC Support?") - IF (OSPRAY_BUILD_MIC_SUPPORT AND NOT OSPRAY_COMPILER_ICC) - MESSAGE(FATAL_ERROR "MIC support requires the Intel Compiler.") - ENDIF() -ENDIF() - -OPTION(OSPRAY_BUILD_MPI_DEVICE "Add MPI Remote/Distributed rendering support?") - -SET(OSPRAY_MIC ${OSPRAY_BUILD_MIC_SUPPORT}) -SET(OSPRAY_MPI ${OSPRAY_BUILD_MPI_DEVICE}) - -############################################################## -# create binary packages; before any INSTALL() invocation/definition -############################################################## - -OPTION(OSPRAY_ZIP_MODE "Use tarball/zip CPack generator instead of RPM" ON) -MARK_AS_ADVANCED(OSPRAY_ZIP_MODE) - -INCLUDE(package) - ############################################################## # the OSPRay 'common' library ############################################################## -CONFIGURE_OSPRAY() - -SET(OSPRAY_TARGET "intel64") -ADD_SUBDIRECTORY(ospcommon builddir/ospray_common/intel64) -IF (OSPRAY_MIC) - SET(OSPRAY_TARGET "mic") - ADD_SUBDIRECTORY(ospcommon builddir/ospray_common/mic) -ENDIF() +OSPRAY_ADD_SUBDIRECTORY(ospcommon) ############################################################## # the OSPRay library ############################################################## -SET(OSPRAY_TARGET "intel64") -ADD_SUBDIRECTORY(ospray builddir/ospray/intel64) -IF (OSPRAY_MIC) - SET(OSPRAY_TARGET "mic") - ADD_SUBDIRECTORY(ospray builddir/ospray/mic) -ENDIF() +OSPRAY_ADD_SUBDIRECTORY(ospray) ############################################################## # OSPRay modules ############################################################## -SET(OSPRAY_TARGET "intel64") -ADD_SUBDIRECTORY(modules builddir/modules/intel64) -IF (OSPRAY_MIC) - SET(OSPRAY_TARGET "mic") - ADD_SUBDIRECTORY(modules builddir/modules/mic) +OPTION(OSPRAY_ENABLE_MODULES "Enable the 'modules' subtree in the build." ON) +MARK_AS_ADVANCED(OSPRAY_ENABLE_MODULES) + +IF (OSPRAY_ENABLE_MODULES) + OSPRAY_ADD_SUBDIRECTORY(modules) ENDIF() ############################################################## # OSPRay sample apps; at the end: they may need modules ############################################################## -SET(OSPRAY_TARGET "intel64") -ADD_SUBDIRECTORY(apps builddir/apps/intel64) -IF (OSPRAY_MIC) - SET(OSPRAY_TARGET "mic") - ADD_SUBDIRECTORY(apps builddir/apps/mic) +OPTION(OSPRAY_ENABLE_APPS "Enable the 'apps' subtree in the build." ON) +MARK_AS_ADVANCED(OSPRAY_ENABLE_APPS) + +IF (OSPRAY_ENABLE_APPS) + # NOTE(jda) - Don't use OSPRAY_ADD_SUBDIRECTORY() macro as we don't have any + # KNC code in the apps subdirectory to compile. + ADD_SUBDIRECTORY(apps) ENDIF() -# create a configure file that both ospray and ispc can read the cmake config from -# needs to be at the end, after all cache variables have been set +# create a configure file that both ospray and ispc can read the cmake config +# from needs to be at the end, after all cache variables have been set CONFIGURE_FILE(ospray/common/OSPConfig.h.in OSPConfig.h) INSTALL(FILES ${CMAKE_BINARY_DIR}/OSPConfig.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/ospray diff --git a/README.md b/README.md index 5268985a61..eb2a93deb2 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ OSPRay ====== -This is release v1.0.0 of OSPRay. For changes and new features see the +This is release v1.1.0 of OSPRay. For changes and new features see the [changelog](CHANGELOG.md). Also visit http://www.ospray.org for more information. @@ -216,6 +216,3 @@ at the [OSPRay Demos and Examples] page. [imgTutorial2]: https://ospray.github.io/images/tutorial_accumulatedframe.png [imgQtViewer]: https://ospray.github.io/images/QtViewer.jpg [imgVolumeViewer]: https://ospray.github.io/images/VolumeViewer.png -[imgSpotLight]: https://ospray.github.io/images/spot_light.png -[imgQuadLight]: https://ospray.github.io/images/quad_light.png -[imgHDRILight]: https://ospray.github.io/images/hdri_light.png diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index f95371d59b..532725fcb3 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -14,71 +14,68 @@ ## limitations under the License. ## ## ======================================================================== ## -IF(NOT THIS_IS_MIC) +INCLUDE_DIRECTORIES( + ${CMAKE_SOURCE_DIR}/ospray/include + ${CMAKE_SOURCE_DIR} + ${CMAKE_CURRENT_LIST_DIR} + common +) - INCLUDE_DIRECTORIES( - ${CMAKE_SOURCE_DIR}/ospray/include - ${CMAKE_SOURCE_DIR} - ${CMAKE_CURRENT_LIST_DIR} - common - ) +# common utilities +ADD_SUBDIRECTORY(common/commandline) +ADD_SUBDIRECTORY(common/importer) +ADD_SUBDIRECTORY(common/ospray_cpp) +ADD_SUBDIRECTORY(common/tfn_lib) +ADD_SUBDIRECTORY(common/miniSG) +ADD_SUBDIRECTORY(common/xml) - # common utilities - ADD_SUBDIRECTORY(common/commandline) - ADD_SUBDIRECTORY(common/importer) - ADD_SUBDIRECTORY(common/ospray_cpp) - ADD_SUBDIRECTORY(common/tfn_lib) - ADD_SUBDIRECTORY(common/miniSG) - ADD_SUBDIRECTORY(common/xml) +# benchmark application which has no windowing framework dependencies +OPTION(OSPRAY_APPS_BENCHMARK "Build ospBenchmark application." ON) - # benchmark application which has no windowing framework dependencies - OPTION(OSPRAY_APPS_BENCHMARK "Build ospBenchmark application." ON) - - IF(OSPRAY_APPS_BENCHMARK) - ADD_SUBDIRECTORY(bench) - ENDIF() +IF(OSPRAY_APPS_BENCHMARK) + ADD_SUBDIRECTORY(bench) +ENDIF() - # determine if we can enable scripting features (can't with icc) - IF(NOT OSPRAY_COMPILER_ICC) - OPTION(OSPRAY_APPS_ENABLE_SCRIPTING - "Enable scripting features in viewer apps." - ON) - MARK_AS_ADVANCED(OSPRAY_APPS_ENABLE_SCRIPTING) - ELSE() - SET(OSPRAY_APPS_ENABLE_SCRIPTING OFF) - ENDIF() +# determine if we can enable scripting features (can't with icc) +IF(NOT OSPRAY_COMPILER_ICC) + OPTION(OSPRAY_APPS_ENABLE_SCRIPTING + "Enable scripting features in viewer apps." + ON) + MARK_AS_ADVANCED(OSPRAY_APPS_ENABLE_SCRIPTING) +ELSE() + SET(OSPRAY_APPS_ENABLE_SCRIPTING OFF) +ENDIF() - IF(OSPRAY_APPS_ENABLE_SCRIPTING) - ADD_DEFINITIONS(-DOSPRAY_APPS_ENABLE_SCRIPTING) - INCLUDE_DIRECTORIES(common/script/chaiscript) - ADD_SUBDIRECTORY(common/script) - ENDIF() +IF(OSPRAY_APPS_ENABLE_SCRIPTING) + ADD_DEFINITIONS(-DOSPRAY_APPS_ENABLE_SCRIPTING) + INCLUDE_DIRECTORIES(common/script/chaiscript) + ADD_SUBDIRECTORY(common/script) +ENDIF() - # mini-scene graph viewer implemented with GLUT - OPTION(OSPRAY_APPS_GLUTVIEWER "Build ospGlutViewer application." ON) +# mini-scene graph viewer implemented with GLUT +OPTION(OSPRAY_APPS_GLUTVIEWER "Build ospGlutViewer application." ON) - IF(OSPRAY_APPS_GLUTVIEWER) - INCLUDE(${PROJECT_SOURCE_DIR}/cmake/glut.cmake) - # common utility classes for GLUT-based 3D viewer widget - ADD_SUBDIRECTORY(common/widgets) - ADD_SUBDIRECTORY(glutViewer) - ENDIF() +IF(OSPRAY_APPS_GLUTVIEWER) + INCLUDE(${PROJECT_SOURCE_DIR}/cmake/glut.cmake) + # common utility classes for GLUT-based 3D viewer widget + ADD_SUBDIRECTORY(common/widgets) + ADD_SUBDIRECTORY(glutViewer) +ENDIF() - # NOTE(jda) - Disable Qt based viewers when on OS X using ICC due to - # unresolved issues - # qt-based viewer for geometry (and soon volumes) - IF(NOT (APPLE AND OSPRAY_COMPILER_ICC)) - OPTION(OSPRAY_APPS_QTVIEWER "Build ospQtViewer (Qt-based model viewer)" ON) - IF (OSPRAY_APPS_QTVIEWER) - ADD_SUBDIRECTORY(qtViewer) - ENDIF() +# NOTE(jda) - Disable Qt based viewers when on OS X using ICC due to +# unresolved issues +# qt-based viewer for geometry (and soon volumes) +IF(NOT (APPLE AND OSPRAY_COMPILER_ICC)) + OPTION(OSPRAY_APPS_QTVIEWER "Build ospQtViewer (Qt-based model viewer)" ON) + IF (OSPRAY_APPS_QTVIEWER) + ADD_SUBDIRECTORY(qtViewer) ENDIF() +ENDIF() - # volume viewer application - IF(NOT (APPLE AND (${CMAKE_CXX_COMPILER_ID} STREQUAL "Intel"))) - OPTION(OSPRAY_APPS_VOLUMEVIEWER "Build ospVolumeViewer application." ON) - IF(OSPRAY_APPS_VOLUMEVIEWER) - ADD_SUBDIRECTORY(volumeViewer) - ENDIF() +# volume viewer application +IF(NOT (APPLE AND OSPRAY_COMPILER_ICC)) + OPTION(OSPRAY_APPS_VOLUMEVIEWER "Build ospVolumeViewer application." ON) + IF(OSPRAY_APPS_VOLUMEVIEWER) + ADD_SUBDIRECTORY(volumeViewer) ENDIF() ENDIF() diff --git a/apps/bench/BenchScriptHandler.cpp b/apps/bench/BenchScriptHandler.cpp new file mode 100644 index 0000000000..04c97d3afa --- /dev/null +++ b/apps/bench/BenchScriptHandler.cpp @@ -0,0 +1,133 @@ +// ======================================================================== // +// Copyright 2009-2016 Intel Corporation // +// // +// Licensed under the Apache License, Version 2.0 (the "License"); // +// you may not use this file except in compliance with the License. // +// You may obtain a copy of the License at // +// // +// http://www.apache.org/licenses/LICENSE-2.0 // +// // +// Unless required by applicable law or agreed to in writing, software // +// distributed under the License is distributed on an "AS IS" BASIS, // +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // +// See the License for the specific language governing permissions and // +// limitations under the License. // +// ======================================================================== // + +#ifdef OSPRAY_APPS_ENABLE_SCRIPTING + +#include +#include + +#include +#include + +#include "pico_bench/pico_bench.h" +#include "chaiscript/utility/utility.hpp" + +#include "tfn_lib/tfn_lib.h" +#include "common/importer/Importer.h" + +#include "BenchScriptHandler.h" + +BenchScriptHandler::BenchScriptHandler(std::shared_ptr &fixture) + : OSPRayScriptHandler(fixture->model.handle(), fixture->renderer.handle(), fixture->camera.handle()) +{ + scriptEngine().add_global(chaiscript::var(fixture), "defaultFixture"); + registerScriptTypes(); + registerScriptFunctions(); +} +void BenchScriptHandler::registerScriptFunctions() { + auto &chai = this->scriptEngine(); + + // load the first volume in the file. This isn't really a great solution for + // final support of loading data from scripts but will work ok. + auto loadVolume = [&](const std::string &fname) { + ospray::importer::Group *imported = ospray::importer::import(fname); + if (imported->volume.empty()) { + throw std::runtime_error("Volume file " + fname + " contains no volumes"); + } + return ospray::cpp::Volume(imported->volume[0]->handle); + }; + + chai.add(chaiscript::fun(loadVolume), "loadVolume"); +} +void BenchScriptHandler::registerScriptTypes() { + using Millis = OSPRayFixture::Millis; + auto &chai = this->scriptEngine(); + chaiscript::ModulePtr m = chaiscript::ModulePtr(new chaiscript::Module()); + + auto millisToString = [](const Millis &m) { + return std::to_string(m.count()) + "ms"; + }; + chaiscript::utility::add_class(*m, "Millis", + {}, + { + {chaiscript::fun(&Millis::count), "count"}, + {chaiscript::fun(millisToString), "to_string"} + } + ); + + auto statsToString = [](const BenchStats &stats) { + std::stringstream ss; + ss << "Frame Time " << stats + << "\nFPS Statistics:\n" + << "\tmax: " << 1000.0 / stats.min().count() << " fps\n" + << "\tmin: " << 1000.0 / stats.max().count() << " fps\n" + << "\tmedian: " << 1000.0 / stats.median().count() << " fps\n" + << "\tmean: " << 1000.0 / stats.mean().count() << " fps\n"; + return ss.str(); + }; + chaiscript::utility::add_class(*m, "Statistics", + {}, + { + // Are these casts even needed?? the functons aren't overloaded. + {chaiscript::fun(static_cast(&BenchStats::percentile)), "percentile"}, + {chaiscript::fun(static_cast(&BenchStats::winsorize)), "winsorize"}, + {chaiscript::fun(&BenchStats::median), "median"}, + {chaiscript::fun(&BenchStats::median_abs_dev), "median_abs_dev"}, + {chaiscript::fun(&BenchStats::mean), "mean"}, + {chaiscript::fun(&BenchStats::std_dev), "std_dev"}, + {chaiscript::fun(&BenchStats::min), "min"}, + {chaiscript::fun(&BenchStats::max), "max"}, + {chaiscript::fun(&BenchStats::size), "size"}, + {chaiscript::fun(&BenchStats::operator[]), "[]"}, + {chaiscript::fun(static_cast(&BenchStats::operator=)), "="}, + {chaiscript::fun(statsToString), "to_string"} + } + ); + + auto setRenderer = [&](OSPRayFixture &fix, ospray::cpp::Renderer &r) { + fix.renderer = r; + }; + auto setCamera = [&](OSPRayFixture &fix, ospray::cpp::Camera &c) { + fix.camera = c; + }; + auto setModel = [&](OSPRayFixture &fix, ospray::cpp::Model &m) { + fix.model = m; + }; + auto benchDefault = [&](OSPRayFixture &fix) { + return fix.benchmark(); + }; + + chaiscript::utility::add_class(*m, "Fixture", + { + chaiscript::constructor(), + }, + { + {chaiscript::fun(&OSPRayFixture::benchmark), "benchmark"}, + {chaiscript::fun(benchDefault), "benchmark"}, + {chaiscript::fun(&OSPRayFixture::saveImage), "saveImage"}, + {chaiscript::fun(&OSPRayFixture::setFrameBuffer), "setFrameBuffer"}, + {chaiscript::fun(setRenderer), "setRenderer"}, + {chaiscript::fun(setCamera), "setCamera"}, + {chaiscript::fun(setModel), "setModel"} + } + ); + + chai.add(m); +} + +#endif + + diff --git a/ospray/fb/DisplayWall.h b/apps/bench/BenchScriptHandler.h similarity index 52% rename from ospray/fb/DisplayWall.h rename to apps/bench/BenchScriptHandler.h index 3f09e4c8f7..5432f641f4 100644 --- a/ospray/fb/DisplayWall.h +++ b/apps/bench/BenchScriptHandler.h @@ -16,45 +16,22 @@ #pragma once -/*! \file ospray/fb/DisplayWall.h +#ifdef OSPRAY_APPS_ENABLE_SCRIPTING - \brief EXPERIMENTAL initial steps to support for a "DisplayCluster" based display wall - */ +#include +#include "common/script/OSPRayScriptHandler.h" +#include "OSPRayFixture.h" -// ospray -#include "fb/PixelOp.h" +class BenchScriptHandler : public ospray::OSPRayScriptHandler { + public: + BenchScriptHandler(std::shared_ptr &fixture); -// DisplayCluster -class DcSocket; + private: + void registerScriptFunctions(); + void registerScriptTypes(); -namespace ospray { + using BenchStats = pico_bench::Statistics; +}; - /*! \brief a 'display wall' pixel op, that will send ready tiles to - a display wall software such as displayCluster */ - struct DisplayWallPO : public PixelOp { - struct Instance : public PixelOp::Instance { - FrameBuffer *fb; - int frameIndex; +#endif - //! DisplayCluster socket. - DcSocket *dcSocket; - - //! DisplayCluster stream name. - std::string streamName; - - Instance(DisplayWallPO *po, FrameBuffer *fb); - virtual ~Instance() {} - - virtual void beginFrame(); - - virtual void postAccum(Tile &tile); - }; - - virtual PixelOp::Instance *createInstance(FrameBuffer *fb, PixelOp::Instance *prev) { PING; return new Instance(this, fb); }; - - //! \brief common function to help printf-debugging - /*! Every derived class should overrride this! */ - virtual std::string toString() const { return "ospray::DisplayWallPO"; } - }; - -} diff --git a/apps/bench/CMakeLists.txt b/apps/bench/CMakeLists.txt index fbb5f8c32f..5ab6a90c5e 100644 --- a/apps/bench/CMakeLists.txt +++ b/apps/bench/CMakeLists.txt @@ -14,17 +14,23 @@ ## limitations under the License. ## ## ======================================================================== ## +ADD_DEFINITIONS(-DPICO_BENCH_NO_DECLVAL) +SET(LIBS ospray ospray_commandline ospray_common ospray_minisg + ospray_importer ospray_tfn) + +IF (OSPRAY_APPS_ENABLE_SCRIPTING) + ADD_DEFINITIONS(-DOSPRAY_APPS_ENABLE_SCRIPTING) + INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/apps/common/script) + LIST(APPEND LIBS ospray_script) +ENDIF() + +INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/apps/common) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_LIST_DIR}) -OSPRAY_CREATE_APPLICATION(Benchmark +OSPRAY_CREATE_APPLICATION(ospBenchmark bench.cpp OSPRayFixture.cpp - OSPRayFixture.h - simple_outputter.hpp + BenchScriptHandler.cpp LINK - ospray - ospray_commandline - ospray_common - ospray_minisg - ospray_importer + ${LIBS} ) diff --git a/apps/bench/OSPRayFixture.cpp b/apps/bench/OSPRayFixture.cpp index 8aba6c9afe..fa5f356494 100644 --- a/apps/bench/OSPRayFixture.cpp +++ b/apps/bench/OSPRayFixture.cpp @@ -16,29 +16,20 @@ #include "OSPRayFixture.h" -using std::string; - using namespace ospcommon; +using namespace ospray; -std::unique_ptr OSPRayFixture::renderer; -std::unique_ptr OSPRayFixture::camera; -std::unique_ptr OSPRayFixture::model; -std::unique_ptr OSPRayFixture::fb; - -string OSPRayFixture::imageOutputFile; - -std::vector OSPRayFixture::benchmarkModelFiles; - -int OSPRayFixture::width = 1024; -int OSPRayFixture::height = 1024; +const static int DEFAULT_WIDTH = 1024; +const static int DEFAULT_HEIGHT = 1024; +const static size_t DEFAULT_BENCH_FRAMES = 100; +const static size_t DEFAULT_WARMUP_FRAMES = 10; -int OSPRayFixture::numWarmupFrames = 10; - -vec3f OSPRayFixture::bg_color = {1.f, 1.f, 1.f}; +const static vec3f DEFAULT_BG_COLOR = {1.f, 1.f, 1.f}; +namespace bench { // helper function to write the rendered image as PPM file -static void writePPM(const string &fileName, const int sizeX, const int sizeY, - const uint32_t *pixel) +void writePPM(const std::string &fileName, const int sizeX, const int sizeY, + const uint32_t *pixel) { FILE *file = fopen(fileName.c_str(), "wb"); fprintf(file, "P6\n%i %i\n255\n", sizeX, sizeY); @@ -55,36 +46,48 @@ static void writePPM(const string &fileName, const int sizeX, const int sizeY, fprintf(file, "\n"); fclose(file); } - -static void createFramebuffer(OSPRayFixture *f) -{ - *f->fb = ospray::cpp::FrameBuffer(osp::vec2i{f->width, f->height}, - OSP_FB_SRGBA, - OSP_FB_COLOR|OSP_FB_ACCUM); - f->fb->clear(OSP_FB_ACCUM | OSP_FB_COLOR); } -void OSPRayFixture::SetUp() +OSPRayFixture::OSPRayFixture(cpp::Renderer r, cpp::Camera c, cpp::Model m) + : renderer(r), camera(c), model(m), width(DEFAULT_WIDTH), height(DEFAULT_HEIGHT), + defaultBenchFrames(DEFAULT_BENCH_FRAMES), defaultWarmupFrames(DEFAULT_WARMUP_FRAMES) { - createFramebuffer(this); - - renderer->set("world", *model); - renderer->set("model", *model); - renderer->set("camera", *camera); - renderer->set("spp", 1); - - renderer->commit(); - - for (int i = 0; i < numWarmupFrames; ++i) { - renderer->renderFrame(*fb, OSP_FB_COLOR | OSP_FB_ACCUM); + setFrameBuffer(width, height); + renderer.set("world", model); + renderer.set("model", model); + renderer.set("camera", camera); + renderer.commit(); +} +pico_bench::Statistics +OSPRayFixture::benchmark(const size_t warmUpFrames, const size_t benchFrames) { + const size_t warmup = warmUpFrames == 0 ? defaultWarmupFrames : warmUpFrames; + const size_t bench = benchFrames == 0 ? defaultBenchFrames : benchFrames; + for (size_t i = 0; i < warmup; ++i) { + renderer.renderFrame(fb, framebufferFlags); } + fb.clear(framebufferFlags); + + auto benchmarker = pico_bench::Benchmarker(bench); + auto stats = benchmarker([&]() { + renderer.renderFrame(fb, framebufferFlags); + }); + stats.time_suffix = " ms"; + return stats; +} +void OSPRayFixture::saveImage(const std::string &fname) { + auto *lfb = (uint32_t*)fb.map(OSP_FB_COLOR); + bench::writePPM(fname + ".ppm", width, height, lfb); + fb.unmap(lfb); } +void OSPRayFixture::setFrameBuffer(const int w, const int h, const int fbFlags) { + width = w > 0 ? w : width; + height = h > 0 ? h : height; -void OSPRayFixture::TearDown() -{ - if (!imageOutputFile.empty()) { - auto *lfb = (uint32_t*)fb->map(OSP_FB_COLOR); - writePPM(imageOutputFile + ".ppm", width, height, lfb); - fb->unmap(lfb); - } + fb = cpp::FrameBuffer(osp::vec2i{width, height}, OSP_FB_SRGBA, fbFlags); + fb.clear(fbFlags); + framebufferFlags = fbFlags; + + camera.set("aspect", static_cast(width) / height); + camera.commit(); } + diff --git a/apps/bench/OSPRayFixture.h b/apps/bench/OSPRayFixture.h index 9723537182..bfbaabd239 100644 --- a/apps/bench/OSPRayFixture.h +++ b/apps/bench/OSPRayFixture.h @@ -14,37 +14,55 @@ // limitations under the License. // // ======================================================================== // +#pragma once -#include "hayai/hayai.hpp" +#include +#include "pico_bench/pico_bench.h" #include #include #include -struct OSPRayFixture : public hayai::Fixture -{ - // Fixture hayai interface // +namespace bench { +void writePPM(const std::string &fileName, const int sizeX, const int sizeY, + const uint32_t *pixel); +} - void SetUp() override; - void TearDown() override; +struct OSPRayFixture { + using Millis = std::chrono::duration>; - // Fixture data // + // Create a benchmarker with default image dims and bench frame count, + // image dims = 1024x1024 + // warm up frames = 10 + // benchmark frames = 100 + OSPRayFixture(ospray::cpp::Renderer renderer, ospray::cpp::Camera camera, + ospray::cpp::Model model); + // Benchmark the scene, passing no params (or 0 for warmUpFrames or benchFrames) will + // use the default configuration stored in the fixture, e.g. what was parsed from + // the command line. + pico_bench::Statistics benchmark(const size_t warmUpFrames = 0, const size_t benchFrames = 0); + // Save the rendered image. The name should not be suffixed by .ppm, it will be appended + // for you. + void saveImage(const std::string &fname); + // Change the framebuffer dimensions for the benchmark. If either is 0, the previously + // set width or height will be used accordingly. Can also change the framebuffer flags used + // to enable/disable accumulation. + void setFrameBuffer(const int w = 0, const int h = 0, const int fbFlags = OSP_FB_COLOR | OSP_FB_ACCUM); - static std::unique_ptr renderer; - static std::unique_ptr camera; - static std::unique_ptr model; - static std::unique_ptr fb; + ospray::cpp::Renderer renderer; + ospray::cpp::Camera camera; + ospray::cpp::Model model; - // Command-line configuration data // + size_t defaultWarmupFrames; + size_t defaultBenchFrames; - static std::string imageOutputFile; +private: + ospray::cpp::FrameBuffer fb; - static std::vector benchmarkModelFiles; + // Configuration data // - static int width; - static int height; - - static int numWarmupFrames; - - static ospcommon::vec3f bg_color; + int width; + int height; + int framebufferFlags; }; + diff --git a/apps/bench/bench.cpp b/apps/bench/bench.cpp index 0d5dce458a..9ef4ee8d20 100644 --- a/apps/bench/bench.cpp +++ b/apps/bench/bench.cpp @@ -14,29 +14,18 @@ // limitations under the License. // // ======================================================================== // -#include "hayai/hayai.hpp" -#include "simple_outputter.hpp" +#include #include "OSPRayFixture.h" +#include "BenchScriptHandler.h" #include "commandline/Utility.h" +#include "pico_bench/pico_bench.h" using std::cout; using std::endl; using std::string; -BENCHMARK_F(OSPRayFixture, test1, 1, 100) -{ - renderer->renderFrame(*fb, OSP_FB_COLOR | OSP_FB_ACCUM); -} - -// NOTE(jda) - Implement make_unique() as it didn't show up until C++14... -template -std::unique_ptr make_unique(Args&& ...args) -{ - return std::unique_ptr(new T( std::forward(args)... )); -} - void printUsageAndExit() { cout << "Usage: ospBenchmark [options] model_file" << endl; @@ -77,15 +66,27 @@ void printUsageAndExit() cout << " Ex: -r pathtracer" << endl; cout << " default: ao1" << endl; + /* + * TODO: This was never used anyway? cout << endl; cout << " -bg | --background --> Specify the background color: R G B" << endl; + */ cout << endl; cout << " -wf | --warmup --> Specify the number of warmup frames: N" << endl; cout << " default: 10" << endl; + cout << endl; + cout << " -bf | --bench --> Specify the number of benchmark frames: N" + << endl; + cout << " default: 100" << endl; + + cout << endl; + cout << " -lft | --log-frame-times --> Log frame time in ms for every frame rendered" + << endl; + cout << endl; cout << "**camera rendering options**" << endl; @@ -132,73 +133,114 @@ void printUsageAndExit() cout << " -is | --surface --> Specify an isosurface at value: val " << endl; + cout << endl; + cout << " --help --> Print this help text" << endl; +#ifdef OSPRAY_APPS_ENABLE_SCRIPTING + cout << endl; + cout << " --script --> Specify a script file to drive the benchmarker.\n" + << " In a script you can access the parsed world and command\n" + << " line benchmark configuration via the following variables:\n" + << " defaultFixture -> benchmark settings from the commandline\n" + << " m -> world model parsed from command line scene args\n" + << " c -> camera set from command line args\n" + << " r -> renderer set from command line args\n"; +#endif + exit(0); } +std::string imageOutputFile = ""; +std::string scriptFile = ""; +size_t numWarmupFrames = 0; +size_t numBenchFrames = 0; +bool logFrameTimes = false; +// This is the fixture setup by the command line arguments +std::shared_ptr cmdlineFixture; + void parseCommandLine(int argc, const char *argv[]) { + using namespace ospcommon; + using namespace ospray::cpp; if (argc <= 1) { printUsageAndExit(); } + int width = 0; + int height = 0; for (int i = 1; i < argc; ++i) { string arg = argv[i]; - if (arg == "-i" || arg == "--image") { - OSPRayFixture::imageOutputFile = argv[++i]; + if (arg == "--help") { + printUsageAndExit(); + } else if (arg == "-i" || arg == "--image") { + imageOutputFile = argv[++i]; } else if (arg == "-w" || arg == "--width") { - OSPRayFixture::width = atoi(argv[++i]); + width = atoi(argv[++i]); } else if (arg == "-h" || arg == "--height") { - OSPRayFixture::height = atoi(argv[++i]); + height = atoi(argv[++i]); } else if (arg == "-wf" || arg == "--warmup") { - OSPRayFixture::numWarmupFrames = atoi(argv[++i]); - } else if (arg == "-bg" || arg == "--background") { - ospcommon::vec3f &color = OSPRayFixture::bg_color; - color.x = atof(argv[++i]); - color.y = atof(argv[++i]); - color.z = atof(argv[++i]); + numWarmupFrames = atoi(argv[++i]); + } else if (arg == "-bf" || arg == "--bench") { + numBenchFrames = atoi(argv[++i]); + } else if (arg == "-lft" || arg == "--log-frame-times") { + logFrameTimes = true; + } else if (arg == "--script") { + scriptFile = argv[++i]; } } auto ospObjs = parseWithDefaultParsers(argc, argv); - ospcommon::box3f bbox; - std::tie(bbox, - *OSPRayFixture::model, - *OSPRayFixture::renderer, - *OSPRayFixture::camera) = ospObjs; - - float width = OSPRayFixture::width; - float height = OSPRayFixture::height; - auto &camera = *OSPRayFixture::camera; - camera.set("aspect", width/height); - camera.commit(); -} - -void allocateFixtureObjects() -{ - // NOTE(jda) - Have to allocate objects here, because we can't allocate them - // statically (before ospInit) and can't in the fixture's - // constructor because they need to exist during parseCommandLine. - OSPRayFixture::renderer = make_unique(); - OSPRayFixture::camera = make_unique(); - OSPRayFixture::model = make_unique(); - OSPRayFixture::fb = make_unique(); + Model model; + Renderer renderer; + Camera camera; + std::tie(std::ignore, model, renderer, camera) = ospObjs; + cmdlineFixture = std::make_shared(renderer, camera, model); + if (width > 0 || height > 0) { + cmdlineFixture->setFrameBuffer(width, height); + } + // Set the default warm up and bench frames + if (numWarmupFrames > 0) { + cmdlineFixture->defaultWarmupFrames = numWarmupFrames; + } + if (numBenchFrames > 0){ + cmdlineFixture->defaultBenchFrames = numBenchFrames; + } } -int main(int argc, const char *argv[]) -{ +int main(int argc, const char *argv[]) { ospInit(&argc, argv); - allocateFixtureObjects(); parseCommandLine(argc, argv); -# if 0 - hayai::ConsoleOutputter outputter; + if (scriptFile.empty()) { + // If we don't have a script do this, otherwise run the script + // and let it setup bench scenes and benchmrk them and so on + auto stats = cmdlineFixture->benchmark(); + if (logFrameTimes) { + for (size_t i = 0; i < stats.size(); ++i) { + std::cout << stats[i].count() << stats.time_suffix << "\n"; + } + } + std::cout << "Frame Time " << stats << "\n" + << "FPS Statistics:\n" + << "\tmax: " << 1000.0 / stats.min().count() << " fps\n" + << "\tmin: " << 1000.0 / stats.max().count() << " fps\n" + << "\tmedian: " << 1000.0 / stats.median().count() << " fps\n" + << "\tmean: " << 1000.0 / stats.mean().count() << " fps\n"; + } else { +#ifdef OSPRAY_APPS_ENABLE_SCRIPTING + // The script will be responsible for setting up the benchmark config + // and calling `benchmark(N)` to benchmark the scene + BenchScriptHandler scriptHandler(cmdlineFixture); + scriptHandler.runScriptFromFile(scriptFile); #else - hayai::SimpleOutputter outputter; + throw std::runtime_error("You must build with OSPRAY_APPS_ENABLE_SCRIPTING=ON " + "to use scripting"); #endif + } - hayai::Benchmarker::AddOutputter(outputter); - - hayai::Benchmarker::RunAllTests(); + if (!imageOutputFile.empty()) { + cmdlineFixture->saveImage(imageOutputFile); + } return 0; } + diff --git a/apps/bench/hayai/hayai.hpp b/apps/bench/hayai/hayai.hpp deleted file mode 100644 index 0396751064..0000000000 --- a/apps/bench/hayai/hayai.hpp +++ /dev/null @@ -1,136 +0,0 @@ -#ifndef __HAYAI -#define __HAYAI - -#include "hayai_benchmarker.hpp" -#include "hayai_test.hpp" -#include "hayai_default_test_factory.hpp" -#include "hayai_fixture.hpp" -#include "hayai_console_outputter.hpp" -#include "hayai_json_outputter.hpp" -#include "hayai_junit_xml_outputter.hpp" - - -#define HAYAI_VERSION "1.0.1" - - -#define BENCHMARK_CLASS_NAME_(fixture_name, benchmark_name) \ - fixture_name ## _ ## benchmark_name ## _Benchmark - -#define BENCHMARK_(fixture_name, \ - benchmark_name, \ - fixture_class_name, \ - runs, \ - iterations) \ - class BENCHMARK_CLASS_NAME_(fixture_name, benchmark_name) \ - : public fixture_class_name \ - { \ - public: \ - BENCHMARK_CLASS_NAME_(fixture_name, benchmark_name)() \ - { \ - \ - } \ - protected: \ - virtual void TestBody(); \ - private: \ - static const ::hayai::TestDescriptor* _descriptor; \ - }; \ - \ - const ::hayai::TestDescriptor* \ - BENCHMARK_CLASS_NAME_(fixture_name, benchmark_name)::_descriptor = \ - ::hayai::Benchmarker::Instance().RegisterTest( \ - #fixture_name, \ - #benchmark_name, \ - runs, \ - iterations, \ - new ::hayai::TestFactoryDefault< \ - BENCHMARK_CLASS_NAME_(fixture_name, benchmark_name) \ - >(), \ - ::hayai::TestParametersDescriptor()); \ - \ - void BENCHMARK_CLASS_NAME_(fixture_name, benchmark_name)::TestBody() - -#define BENCHMARK_F(fixture_name, \ - benchmark_name, \ - runs, \ - iterations) \ - BENCHMARK_(fixture_name, \ - benchmark_name, \ - fixture_name, \ - runs, \ - iterations) - -#define BENCHMARK(fixture_name, \ - benchmark_name, \ - runs, \ - iterations) \ - BENCHMARK_(fixture_name, \ - benchmark_name, \ - ::hayai::Test, \ - runs, \ - iterations) - -// Parametrized benchmarks. -#define BENCHMARK_P_(fixture_name, \ - benchmark_name, \ - fixture_class_name, \ - runs, \ - iterations, \ - arguments) \ - class BENCHMARK_CLASS_NAME_(fixture_name, benchmark_name) \ - : public fixture_class_name { \ - public: \ - BENCHMARK_CLASS_NAME_(fixture_name, benchmark_name) () {} \ - virtual ~ BENCHMARK_CLASS_NAME_(fixture_name, benchmark_name) () {} \ - static const std::size_t _runs = runs; \ - static const std::size_t _iterations = iterations; \ - static const char* _argumentsDeclaration() { return #arguments; } \ - protected: \ - inline void TestPayload arguments; \ - }; \ - void BENCHMARK_CLASS_NAME_(fixture_name, benchmark_name)::TestPayload arguments - -#define BENCHMARK_P(fixture_name, \ - benchmark_name, \ - runs, \ - iterations, \ - arguments) \ - BENCHMARK_P_(fixture_name, \ - benchmark_name, \ - hayai::Fixture, \ - runs, \ - iterations, \ - arguments) - -#define BENCHMARK_P_F(fixture_name, benchmark_name, runs, iterations, arguments) \ - BENCHMARK_P_(fixture_name, benchmark_name, fixture_name, runs, iterations, arguments) - -#define BENCHMARK_P_CLASS_NAME_(fixture_name, benchmark_name, id) \ - fixture_name ## _ ## benchmark_name ## _Benchmark_ ## id - -#define BENCHMARK_P_INSTANCE1(fixture_name, benchmark_name, arguments, id) \ - class BENCHMARK_P_CLASS_NAME_(fixture_name, benchmark_name, id): \ - public BENCHMARK_CLASS_NAME_(fixture_name, benchmark_name) { \ - protected: \ - virtual void TestBody() { this->TestPayload arguments; } \ - private: \ - static const ::hayai::TestDescriptor* _descriptor; \ - }; \ - const ::hayai::TestDescriptor* BENCHMARK_P_CLASS_NAME_(fixture_name, benchmark_name, id)::_descriptor = \ - ::hayai::Benchmarker::Instance().RegisterTest( \ - #fixture_name, #benchmark_name, \ - BENCHMARK_CLASS_NAME_(fixture_name, benchmark_name)::_runs, \ - BENCHMARK_CLASS_NAME_(fixture_name, benchmark_name)::_iterations, \ - new ::hayai::TestFactoryDefault< BENCHMARK_P_CLASS_NAME_(fixture_name, benchmark_name, id) >(), \ - ::hayai::TestParametersDescriptor(BENCHMARK_CLASS_NAME_(fixture_name, benchmark_name)::_argumentsDeclaration(), #arguments)) - -#if defined(__COUNTER__) -# define BENCHMARK_P_ID_ __COUNTER__ -#else -# define BENCHMARK_P_ID_ __LINE__ -#endif - -#define BENCHMARK_P_INSTANCE(fixture_name, benchmark_name, arguments) \ - BENCHMARK_P_INSTANCE1(fixture_name, benchmark_name, arguments, BENCHMARK_P_ID_) - - -#endif diff --git a/apps/bench/hayai/hayai_benchmarker.hpp b/apps/bench/hayai/hayai_benchmarker.hpp deleted file mode 100644 index 3250f02aa7..0000000000 --- a/apps/bench/hayai/hayai_benchmarker.hpp +++ /dev/null @@ -1,541 +0,0 @@ -#ifndef __HAYAI_BENCHMARKER -#define __HAYAI_BENCHMARKER -#include -#include -#include -#include -#include -#include - -#include "hayai_test_factory.hpp" -#include "hayai_test_descriptor.hpp" -#include "hayai_test_result.hpp" -#include "hayai_console_outputter.hpp" - - -namespace hayai -{ - /// Benchmarking execution controller singleton. - class Benchmarker - { - public: - /// Get the singleton instance of @ref Benchmarker. - - /// @returns a reference to the singleton instance of the - /// benchmarker execution controller. - static Benchmarker& Instance() - { - static Benchmarker singleton; - return singleton; - } - - - /// Register a test with the benchmarker instance. - - /// @param fixtureName Name of the fixture. - /// @param testName Name of the test. - /// @param runs Number of runs for the test. - /// @param iterations Number of iterations per run. - /// @param testFactory Test factory implementation for the test. - /// @returns a pointer to a @ref TestDescriptor instance - /// representing the given test. - static TestDescriptor* RegisterTest( - const char* fixtureName, - const char* testName, - std::size_t runs, - std::size_t iterations, - TestFactory* testFactory, - TestParametersDescriptor parameters - ) - { - // Determine if the test has been disabled. - static const char* disabledPrefix = "DISABLED_"; - bool isDisabled = ((::strlen(testName) >= 9) && - (!::memcmp(testName, disabledPrefix, 9))); - - if (isDisabled) - testName += 9; - - // Add the descriptor. - TestDescriptor* descriptor = new TestDescriptor(fixtureName, - testName, - runs, - iterations, - testFactory, - parameters, - isDisabled); - - Instance()._tests.push_back(descriptor); - - return descriptor; - } - - - /// Add an outputter. - - /// @param outputter Outputter. The caller must ensure that the - /// outputter remains in existence for the entire benchmark run. - static void AddOutputter(Outputter& outputter) - { - Instance()._outputters.push_back(&outputter); - } - - - /// Apply a pattern filter to the tests. - - /// --gtest_filter-compatible pattern: - /// - /// https://code.google.com/p/googletest/wiki/AdvancedGuide - /// - /// @param pattern Filter pattern compatible with gtest. - static void ApplyPatternFilter(const char* pattern) - { - Benchmarker& instance = Instance(); - - // Split the filter at '-' if it exists. - const char* const dash = strchr(pattern, '-'); - - std::string positive; - std::string negative; - - if (dash == NULL) - positive = pattern; - else - { - positive = std::string(pattern, dash); - negative = std::string(dash + 1); - if (positive.empty()) - positive = "*"; - } - - // Iterate across all tests and test them against the patterns. - std::size_t index = 0; - while (index < instance._tests.size()) - { - TestDescriptor* desc = instance._tests[index]; - - if ((!FilterMatchesString(positive.c_str(), - desc->CanonicalName)) || - (FilterMatchesString(negative.c_str(), - desc->CanonicalName))) - { - instance._tests.erase( - instance._tests.begin() + - std::vector::difference_type(index) - ); - delete desc; - } - else - ++index; - } - } - - - /// Run all benchmarking tests. - static void RunAllTests() - { - ConsoleOutputter defaultOutputter; - std::vector defaultOutputters; - defaultOutputters.push_back(&defaultOutputter); - - Benchmarker& instance = Instance(); - std::vector& outputters = - (instance._outputters.empty() ? - defaultOutputters : - instance._outputters); - - // Get the tests for execution. - std::vector tests = instance.GetTests(); - - const std::size_t totalCount = tests.size(); - std::size_t disabledCount = 0; - - std::vector::const_iterator testsIt = - tests.begin(); - - while (testsIt != tests.end()) - { - if ((*testsIt)->IsDisabled) - ++disabledCount; - ++testsIt; - } - - const std::size_t enabledCount = totalCount - disabledCount; - - // Calibrate the tests. - const CalibrationModel calibrationModel = GetCalibrationModel(); - - // Begin output. - for (std::size_t outputterIndex = 0; - outputterIndex < outputters.size(); - outputterIndex++) - outputters[outputterIndex]->Begin(enabledCount, disabledCount); - - // Run through all the tests in ascending order. - std::size_t index = 0; - - while (index < tests.size()) - { - // Get the test descriptor. - TestDescriptor* descriptor = tests[index++]; - - // Check if test matches include filters - if (instance._include.size() > 0) - { - bool included = false; - std::string name = - descriptor->FixtureName + "." + - descriptor->TestName; - - for (std::size_t i = 0; i < instance._include.size(); i++) - { - if (name.find(instance._include[i]) != - std::string::npos) - { - included = true; - break; - } - } - - if (!included) - continue; - } - - // Check if test is not disabled. - if (descriptor->IsDisabled) - { - for (std::size_t outputterIndex = 0; - outputterIndex < outputters.size(); - outputterIndex++) - outputters[outputterIndex]->SkipDisabledTest( - descriptor->FixtureName, - descriptor->TestName, - descriptor->Parameters, - descriptor->Runs, - descriptor->Iterations - ); - - continue; - } - - // Describe the beginning of the run. - for (std::size_t outputterIndex = 0; - outputterIndex < outputters.size(); - outputterIndex++) - outputters[outputterIndex]->BeginTest( - descriptor->FixtureName, - descriptor->TestName, - descriptor->Parameters, - descriptor->Runs, - descriptor->Iterations - ); - - // Execute each individual run. - std::vector runTimes(descriptor->Runs); - uint64_t overheadCalibration = - calibrationModel.GetCalibration(descriptor->Iterations); - - std::size_t run = 0; - while (run < descriptor->Runs) - { - // Construct a test instance. - Test* test = descriptor->Factory->CreateTest(); - - // Run the test. - uint64_t time = test->Run(descriptor->Iterations); - - // Store the test time. - runTimes[run] = (time > overheadCalibration ? - time - overheadCalibration : - 0); - - // Dispose of the test instance. - delete test; - - ++run; - } - - // Calculate the test result. - TestResult testResult(runTimes, descriptor->Iterations); - - // Describe the end of the run. - for (std::size_t outputterIndex = 0; - outputterIndex < outputters.size(); - outputterIndex++) - outputters[outputterIndex]->EndTest( - descriptor->FixtureName, - descriptor->TestName, - descriptor->Parameters, - testResult - ); - - } - - // End output. - for (std::size_t outputterIndex = 0; - outputterIndex < outputters.size(); - outputterIndex++) - outputters[outputterIndex]->End(enabledCount, - disabledCount); - } - - - /// List tests. - static std::vector ListTests() - { - std::vector tests; - Benchmarker& instance = Instance(); - - std::size_t index = 0; - while (index < instance._tests.size()) - tests.push_back(instance._tests[index++]); - - return tests; - } - - - /// Shuffle tests. - - /// Randomly shuffles the order of tests. - static void ShuffleTests() - { - Benchmarker& instance = Instance(); - std::random_shuffle(instance._tests.begin(), - instance._tests.end()); - } - private: - /// Calibration model. - - /// Describes a linear calibration model for test runs. - struct CalibrationModel - { - public: - CalibrationModel(std::size_t scale, - uint64_t slope, - uint64_t yIntercept) - : Scale(scale), - Slope(slope), - YIntercept(yIntercept) - { - - } - - - /// Scale. - - /// Number of iterations per slope unit. - const std::size_t Scale; - - - /// Slope. - const uint64_t Slope; - - - /// Y-intercept; - const uint64_t YIntercept; - - - /// Get calibration value for a run. - int64_t GetCalibration(std::size_t iterations) const - { - return YIntercept + (iterations * Slope) / Scale; - } - }; - - - /// Private constructor. - Benchmarker() - { - - } - - - /// Private destructor. - ~Benchmarker() - { - // Release all test descriptors. - std::size_t index = _tests.size(); - while (index--) - delete _tests[index]; - } - - - /// Get the tests to be executed. - std::vector GetTests() const - { - std::vector tests; - - std::size_t index = 0; - while (index < _tests.size()) - tests.push_back(_tests[index++]); - - return tests; - } - - - /// Test if a filter matches a string. - - /// Adapted from gtest. All rights reserved by original authors. - static bool FilterMatchesString(const char* filter, - const std::string& str) - { - const char *patternStart = filter; - - while (true) - { - if (PatternMatchesString(patternStart, str.c_str())) - return true; - - // Finds the next pattern in the filter. - patternStart = strchr(patternStart, ':'); - - // Returns if no more pattern can be found. - if (!patternStart) - return false; - - // Skips the pattern separater (the ':' character). - patternStart++; - } - } - - - /// Test if pattern matches a string. - - /// Adapted from gtest. All rights reserved by original authors. - static bool PatternMatchesString(const char* pattern, const char *str) - { - switch (*pattern) - { - case '\0': - case ':': - return (*str == '\0'); - case '?': // Matches any single character. - return ((*str != '\0') && - (PatternMatchesString(pattern + 1, str + 1))); - case '*': // Matches any string (possibly empty) of characters. - return (((*str != '\0') && - (PatternMatchesString(pattern, str + 1))) || - (PatternMatchesString(pattern + 1, str))); - default: - return ((*pattern == *str) && - (PatternMatchesString(pattern + 1, str + 1))); - } - } - - - /// Get calibration model. - - /// Returns an average linear calibration model. - static CalibrationModel GetCalibrationModel() - { - // We perform a number of runs of varying iterations with an empty - // test body. The assumption here is, that the time taken for the - // test run is linear with regards to the number of iterations, ie. - // some constant overhead with a per-iteration overhead. This - // hypothesis has been manually validated by linear regression over - // sample data. - // - // In order to avoid losing too much precision, we are going to - // calibrate in terms of the overhead of some x n iterations, - // where n must be a sufficiently large number to produce some - // significant runtime. On a high-end 2012 Retina MacBook Pro with - // -O3 on clang-602.0.53 (LLVM 6.1.0) n = 1,000,000 produces - // run times of ~1.9 ms, which should be sufficiently precise. - // - // However, as the constant overhead is mostly related to - // retrieving the system clock, which under the same conditions - // clocks in at around 17 ms, we run the risk of winding up with - // a negative y-intercept if we do not fix the y-intercept. This - // intercept is therefore fixed by a large number of runs of 0 - // iterations. - ::hayai::Test* test = new Test(); - -#define HAYAI_CALIBRATION_INTERESECT_RUNS 10000 - -#define HAYAI_CALIBRATION_RUNS 10 -#define HAYAI_CALIBRATION_SCALE 1000000 -#define HAYAI_CALIBRATION_PPR 6 - - // Determine the intercept. - uint64_t - interceptSum = 0, - interceptMin = std::numeric_limits::min(), - interceptMax = 0; - - for (std::size_t run = 0; - run < HAYAI_CALIBRATION_INTERESECT_RUNS; - ++run) - { - uint64_t intercept = test->Run(0); - interceptSum += intercept; - if (intercept < interceptMin) - interceptMin = intercept; - if (intercept > interceptMax) - interceptMax = intercept; - } - - uint64_t interceptAvg = - interceptSum / HAYAI_CALIBRATION_INTERESECT_RUNS; - - // Produce a series of sample points. - std::vector x(HAYAI_CALIBRATION_RUNS * - HAYAI_CALIBRATION_PPR); - std::vector t(HAYAI_CALIBRATION_RUNS * - HAYAI_CALIBRATION_PPR); - - std::size_t point = 0; - - for (std::size_t run = 0; run < HAYAI_CALIBRATION_RUNS; ++run) - { -#define HAYAI_CALIBRATION_POINT(_x) \ - x[point] = _x; \ - t[point++] = \ - test->Run(_x * std::size_t(HAYAI_CALIBRATION_SCALE)) - - HAYAI_CALIBRATION_POINT(1); - HAYAI_CALIBRATION_POINT(2); - HAYAI_CALIBRATION_POINT(5); - HAYAI_CALIBRATION_POINT(10); - HAYAI_CALIBRATION_POINT(15); - HAYAI_CALIBRATION_POINT(20); - -#undef HAYAI_CALIBRATION_POINT - } - - // As we have a fixed y-intercept, b, the optimal slope for a line - // fitting the sample points will be - // $\frac {\sum_{i=1}^{n} x_n \cdot (y_n - b)} - // {\sum_{i=1}^{n} {x_n}^2}$. - uint64_t - sumProducts = 0, - sumXSquared = 0; - - std::size_t p = x.size(); - while (p--) - { - sumXSquared += x[p] * x[p]; - sumProducts += x[p] * (t[p] - interceptAvg); - } - - uint64_t slope = sumProducts / sumXSquared; - - delete test; - - return CalibrationModel(HAYAI_CALIBRATION_SCALE, - slope, - interceptAvg); - -#undef HAYAI_CALIBRATION_INTERESECT_RUNS - -#undef HAYAI_CALIBRATION_RUNS -#undef HAYAI_CALIBRATION_SCALE -#undef HAYAI_CALIBRATION_PPR - } - - - std::vector _outputters; ///< Registered outputters. - std::vector _tests; ///< Registered tests. - std::vector _include; ///< Test filters. - }; -} -#endif diff --git a/apps/bench/hayai/hayai_clock.hpp b/apps/bench/hayai/hayai_clock.hpp deleted file mode 100644 index 33702c5a1a..0000000000 --- a/apps/bench/hayai/hayai_clock.hpp +++ /dev/null @@ -1,362 +0,0 @@ -// -// System-specific implementation of the clock functions. -// -// Copyright (C) 2011 Nick Bruun -// Copyright (C) 2013 Vlad Lazarenko -// Copyright (C) 2014 Nicolas Pauss -// -// Implementation notes: -// -// On Windows, QueryPerformanceCounter() is used. It gets -// real-time clock with up to nanosecond precision. -// -// On Apple (OS X, iOS), mach_absolute_time() is used. It gets -// CPU/bus dependent real-time clock with up to nanosecond precision. -// -// On Unix, gethrtime() is used with HP-UX and Solaris. Otherwise, -// clock_gettime() is used to access monotonic real-time clock -// with up to nanosecond precision. On kernels 2.6.28 and newer, the ticks -// are also raw and are not subject to NTP and/or adjtime(3) adjustments. -// -// Other POSIX compliant platforms resort to using gettimeofday(). It is -// subject to clock adjustments, does not allow for higher than microsecond -// resolution and is also declared obsolete by POSIX.1-2008. -// -// Note on C++11: -// -// Starting with C++11, we could use std::chrono. However, the details of -// what clock is really being used is implementation-specific. For example, -// Visual Studio 2012 defines "high_resolution_clock" as system clock with -// ~1 millisecond precision that is not acceptable for performance -// measurements. Therefore, we are much better off having full control of what -// mechanism we use to obtain the system clock. -// -// Note on durations: it is assumed that end times passed to the clock methods -// are all after the start time. Wrap-around of clocks is not tested, as -// nanosecond precision of unsigned 64-bit integers would require an uptime of -// almost 585 years for this to happen. Let's call ourselves safe on that one. -// -#ifndef __HAYAI_CLOCK -#define __HAYAI_CLOCK - -#include "hayai_compatibility.hpp" - - -// Win32 -#if defined(_WIN32) -#ifndef NOMINMAX -#define NOMINMAX -#endif -#include - -// Apple -#elif defined(__APPLE__) && defined(__MACH__) -#include - -// Unix -#elif defined(__unix__) || defined(__unix) || defined(unix) - -// gethrtime -# if (defined(__hpux) || defined(hpux)) || ((defined(__sun__) || defined(__sun) || defined(sun)) && (defined(__SVR4) || defined(__svr4__))) -# include - -// clock_gettime -# elif defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) -# include - -// gettimeofday -# else -# include - -# endif -#else -#error "Unable to define high resolution timer for an unknown OS." -#endif - -#include -#include - - -namespace hayai -{ -// Win32 -#if defined(_WIN32) - class Clock - { - public: - /// Time point. - - /// Opaque representation of a point in time. - typedef LARGE_INTEGER TimePoint; - - - /// Get the current time as a time point. - - /// @returns the current time point. - static TimePoint Now() - { - TimePoint result; - QueryPerformanceCounter(&result); - return result; - } - - - /// Get the duration between two time points. - - /// @param startTime Start time point. - /// @param endTime End time point. - /// @returns the number of nanoseconds elapsed between the two time - /// points. - static uint64_t Duration(const TimePoint& startTime, - const TimePoint& endTime) - { - const static double performanceFrequencyNs = - PerformanceFrequencyNs(); - - return static_cast( - (endTime.QuadPart - startTime.QuadPart) - * performanceFrequencyNs - ); - } - - - /// Clock implementation description. - - /// @returns a description of the clock implementation used. - static const char* Description() - { - return "QueryPerformanceCounter"; - } - private: - static double PerformanceFrequencyNs() - { - TimePoint result; - QueryPerformanceFrequency(&result); - return 1e9 / static_cast(result.QuadPart); - } - }; - -// Mach kernel. -#elif defined(__APPLE__) && defined(__MACH__) - class Clock - { - public: - /// Time point. - - /// Opaque representation of a point in time. - typedef uint64_t TimePoint; - - - /// Get the current time as a time point. - - /// @returns the current time point. - static TimePoint Now() __hayai_noexcept - { - return mach_absolute_time(); - } - - - /// Get the duration between two time points. - - /// @param startTime Start time point. - /// @param endTime End time point. - /// @returns the number of nanoseconds elapsed between the two time - /// points. - static uint64_t Duration(const TimePoint& startTime, - const TimePoint& endTime) __hayai_noexcept - { - mach_timebase_info_data_t time_info; - mach_timebase_info(&time_info); - - return (endTime - startTime) * time_info.numer / time_info.denom; - } - - - /// Clock implementation description. - - /// @returns a description of the clock implementation used. - static const char* Description() - { - return "mach_absolute_time"; - } - }; - -// Unix -#elif defined(__unix__) || defined(__unix) || defined(unix) - -// gethrtime -# if (defined(__hpux) || defined(hpux)) || ((defined(__sun__) || defined(__sun) || defined(sun)) && (defined(__SVR4) || defined(__svr4__))) - class Clock - { - public: - /// Time point. - - /// Opaque representation of a point in time. - typedef hrtime_t TimePoint; - - - /// Get the current time as a time point. - - /// @returns the current time point. - static TimePoint Now() __hayai_noexcept - { - return gethrtime(); - } - - - /// Get the duration between two time points. - - /// @param startTime Start time point. - /// @param endTime End time point. - /// @returns the number of nanoseconds elapsed between the two time - /// points. - static uint64_t Duration(const TimePoint& startTime, - const TimePoint& endTime) __hayai_noexcept - { - return static_cast(endTime - startTime); - } - - - /// Clock implementation description. - - /// @returns a description of the clock implementation used. - static const char* Description() - { - return "gethrtime"; - } - }; - - -// clock_gettime -# elif defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) - class Clock - { - public: - /// Time point. - - /// Opaque representation of a point in time. - typedef struct timespec TimePoint; - - - /// Get the current time as a time point. - - /// @returns the current time point. - static TimePoint Now() __hayai_noexcept - { - TimePoint result; -# if defined(CLOCK_MONOTONIC_RAW) - clock_gettime(CLOCK_MONOTONIC_RAW, &result); -# elif defined(CLOCK_MONOTONIC) - clock_gettime(CLOCK_MONOTONIC, &result); -# elif defined(CLOCK_REALTIME) - clock_gettime(CLOCK_REALTIME, &result); -# else - clock_gettime((clockid_t)-1, &result); -# endif - return result; - } - - - /// Get the duration between two time points. - - /// @param startTime Start time point. - /// @param endTime End time point. - /// @returns the number of nanoseconds elapsed between the two time - /// points. - static uint64_t Duration(const TimePoint& startTime, - const TimePoint& endTime) __hayai_noexcept - { - TimePoint timeDiff; - - timeDiff.tv_sec = endTime.tv_sec - startTime.tv_sec; - if (endTime.tv_nsec < startTime.tv_nsec) - { - timeDiff.tv_nsec = endTime.tv_nsec + 1000000000LL - - startTime.tv_nsec; - timeDiff.tv_sec--; - } - else - timeDiff.tv_nsec = endTime.tv_nsec - startTime.tv_nsec; - - return static_cast(timeDiff.tv_sec * 1000000000L + - timeDiff.tv_nsec); - } - - - /// Clock implementation description. - - /// @returns a description of the clock implementation used. - static const char* Description() - { -# if defined(CLOCK_MONOTONIC_RAW) - return "clock_gettime(CLOCK_MONOTONIC_RAW)"; -# elif defined(CLOCK_MONOTONIC) - return "clock_gettime(CLOCK_MONOTONIC)"; -# elif defined(CLOCK_REALTIME) - return "clock_gettime(CLOCK_REALTIME)"; -# else - return "clock_gettime(-1)"; -# endif - } - }; - -// gettimeofday -# else - class Clock - { - public: - /// Time point. - - /// Opaque representation of a point in time. - typedef struct timeval TimePoint; - - - /// Get the current time as a time point. - - /// @returns the current time point. - static TimePoint Now() __hayai_noexcept - { - TimePoint result; - gettimeofday(&result, NULL); - return result; - } - - - /// Get the duration between two time points. - - /// @param startTime Start time point. - /// @param endTime End time point. - /// @returns the number of nanoseconds elapsed between the two time - /// points. - static uint64_t Duration(const TimePoint& startTime, - const TimePoint& endTime) __hayai_noexcept - { - TimePoint timeDiff; - - timeDiff.tv_sec = endTime.tv_sec - startTime.tv_sec; - if (endTime.tv_usec < startTime.tv_usec) - { - timeDiff.tv_usec = endTime.tv_usec + 1000000L - - startTime.tv_usec; - timeDiff.tv_sec--; - } - else - timeDiff.tv_usec = endTime.tv_usec - startTime.tv_usec; - - return static_cast(timeDiff.tv_sec * 1000000000LL + - timeDiff.tv_usec * 1000); - } - - - /// Clock implementation description. - - /// @returns a description of the clock implementation used. - static const char* Description() - { - return "gettimeofday"; - } - }; -# endif -#endif -} -#endif diff --git a/apps/bench/hayai/hayai_compatibility.hpp b/apps/bench/hayai/hayai_compatibility.hpp deleted file mode 100644 index 8cb53072cf..0000000000 --- a/apps/bench/hayai/hayai_compatibility.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef __HAYAI_COMPATIBILITY -#define __HAYAI_COMPATIBILITY - -# if __cplusplus > 201100L -# define __hayai_noexcept noexcept -# else -# define __hayai_noexcept -# endif - -#endif diff --git a/apps/bench/hayai/hayai_console.hpp b/apps/bench/hayai/hayai_console.hpp deleted file mode 100644 index 6639890b0c..0000000000 --- a/apps/bench/hayai/hayai_console.hpp +++ /dev/null @@ -1,199 +0,0 @@ -#ifndef __HAYAI_CONSOLE -#define __HAYAI_CONSOLE - -#include - -#if !defined(HAYAI_NO_COLOR) -# if defined(_WIN32) -# ifndef NOMINMAX -# define NOMINMAX -# endif -# include -# else -# include -# include -# endif -#endif - - -namespace hayai -{ - /// Static helper class for outputting to a terminal/console. - class Console - { - public: - /// Console text colors. - enum TextColor - { - /// Default console color. Used for resets. - TextDefault, - - /// Black. - /// - /// @warning Avoid using black unless it is absolutely necesssary. - TextBlack, - - /// Blue. - TextBlue, - - /// Green. - TextGreen, - - /// Cyan. - TextCyan, - - /// Red. - TextRed, - - /// Purple. - TextPurple, - - /// Yellow. - TextYellow, - - /// White. - /// - /// @warning Avoid using white unless it is absolutely necessary. - TextWhite - }; - - - /// Get the singleton instance of @ref Console. - - /// @returns a reference to the singleton instance of the - /// benchmarker execution controller. - inline static Console& Instance() - { - static Console singleton; - return singleton; - } - - - /// Test if formatting is enabled. - inline static bool IsFormattingEnabled() - { - return Instance()._formattingEnabled; - } - - - /// Set whether formatting is enabled. - inline static void SetFormattingEnabled(bool enabled) - { - Instance()._formattingEnabled = enabled; - } - private: - inline Console() - : _formattingEnabled(true) - { - - } - - - bool _formattingEnabled; - }; - -#if defined(_WIN32) && !defined(HAYAI_NO_COLOR) // Windows - static inline WORD GetConsoleAttributes() - { - CONSOLE_SCREEN_BUFFER_INFO consoleInfo; - GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), - &consoleInfo); - return consoleInfo.wAttributes; - } - - inline std::ostream& operator <<(std::ostream& stream, - const Console::TextColor& color) - { - static const WORD defaultConsoleAttributes = - GetConsoleAttributes(); - WORD newColor; - - if ((!Console::IsFormattingEnabled()) || - ((stream.rdbuf() != std::cout.rdbuf()) && - (stream.rdbuf() != std::cerr.rdbuf()))) - return stream; - - switch(color) - { - case Console::TextDefault: - newColor = defaultConsoleAttributes; - break; - case Console::TextBlack: - newColor = 0; - break; - case Console::TextBlue: - newColor = FOREGROUND_BLUE; - break; - case Console::TextGreen: - newColor = FOREGROUND_GREEN; - break; - case Console::TextCyan: - newColor = FOREGROUND_GREEN | FOREGROUND_BLUE; - break; - case Console::TextRed: - newColor = FOREGROUND_RED; - break; - case Console::TextPurple: - newColor = FOREGROUND_RED | FOREGROUND_BLUE; - break; - case Console::TextYellow: - newColor = - FOREGROUND_RED | - FOREGROUND_GREEN | - FOREGROUND_INTENSITY; - break; - case Console::TextWhite: - newColor = - FOREGROUND_RED | - FOREGROUND_GREEN | - FOREGROUND_BLUE | - FOREGROUND_INTENSITY; - break; - } - SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), newColor); - return stream; - } -#elif !defined(HAYAI_NO_COLOR) // Linux or others - inline std::ostream& operator <<(std::ostream& stream, - const Console::TextColor& color) - { - static const bool outputNoColor = isatty(fileno(stdout)) != 1; - - if ((!Console::IsFormattingEnabled()) || - (outputNoColor) || - ((stream.rdbuf() != std::cout.rdbuf()) && - (stream.rdbuf() != std::cerr.rdbuf()))) - return stream; - - const char* value = ""; - switch(color) { - case Console::TextDefault: - value = "\033[m"; break; - case Console::TextBlack: - value = "\033[0;30m"; break; - case Console::TextBlue: - value = "\033[0;34m"; break; - case Console::TextGreen: - value = "\033[0;32m"; break; - case Console::TextCyan: - value = "\033[0;36m"; break; - case Console::TextRed: - value = "\033[0;31m"; break; - case Console::TextPurple: - value = "\033[0;35m"; break; - case Console::TextYellow: - value = "\033[0;33m"; break; - case Console::TextWhite: - value = "\033[0;37m"; break; - } - return stream << value; - } -#else // No color - inline std::ostream& operator <<(std::ostream& stream, - const Console::TextColor&) - { - return stream; - } -#endif -} -#endif diff --git a/apps/bench/hayai/hayai_console_outputter.hpp b/apps/bench/hayai/hayai_console_outputter.hpp deleted file mode 100644 index 3f904f578f..0000000000 --- a/apps/bench/hayai/hayai_console_outputter.hpp +++ /dev/null @@ -1,251 +0,0 @@ -#ifndef __HAYAI_CONSOLEOUTPUTTER -#define __HAYAI_CONSOLEOUTPUTTER -#include "hayai_outputter.hpp" -#include "hayai_console.hpp" - - -namespace hayai -{ - /// Console outputter. - - /// Prints the result to standard output. - class ConsoleOutputter - : public Outputter - { - public: - /// Initialize console outputter. - - /// @param stream Output stream. Must exist for the entire duration of - /// the outputter's use. - ConsoleOutputter(std::ostream& stream = std::cout) - : _stream(stream) - { - - } - - - virtual void Begin(const std::size_t& enabledCount, - const std::size_t& disabledCount) - { - _stream << std::fixed; - _stream << Console::TextGreen << "[==========]" - << Console::TextDefault << " Running " - << enabledCount - << (enabledCount == 1 ? " benchmark." : " benchmarks"); - - if (disabledCount) - _stream << ", skipping " - << disabledCount - << (disabledCount == 1 ? - " benchmark." : - " benchmarks"); - else - _stream << "."; - - _stream << std::endl; - } - - - virtual void End(const std::size_t& executedCount, - const std::size_t& disabledCount) - { - _stream << Console::TextGreen << "[==========]" - << Console::TextDefault << " Ran " << executedCount - << (executedCount == 1 ? - " benchmark." : - " benchmarks"); - - if (disabledCount) - _stream << ", skipped " - << disabledCount - << (disabledCount == 1 ? - " benchmark." : - " benchmarks"); - else - _stream << "."; - - _stream << std::endl; - } - - - inline void BeginOrSkipTest(const std::string& fixtureName, - const std::string& testName, - const TestParametersDescriptor& parameters, - const std::size_t& runsCount, - const std::size_t& iterationsCount, - const bool skip) - { - if (skip) - _stream << Console::TextCyan << "[ DISABLED ]"; - else - _stream << Console::TextGreen << "[ RUN ]"; - - _stream << Console::TextYellow << " "; - WriteTestNameToStream(_stream, fixtureName, testName, parameters); - _stream << Console::TextDefault - << " (" << runsCount - << (runsCount == 1 ? " run, " : " runs, ") - << iterationsCount - << (iterationsCount == 1 ? - " iteration per run)" : - " iterations per run)") - << std::endl; - } - - - virtual void BeginTest(const std::string& fixtureName, - const std::string& testName, - const TestParametersDescriptor& parameters, - const std::size_t& runsCount, - const std::size_t& iterationsCount) - { - BeginOrSkipTest(fixtureName, - testName, - parameters, - runsCount, - iterationsCount, - false); - } - - - virtual void SkipDisabledTest( - const std::string& fixtureName, - const std::string& testName, - const TestParametersDescriptor& parameters, - const std::size_t& runsCount, - const std::size_t& iterationsCount - ) - { - BeginOrSkipTest(fixtureName, - testName, - parameters, - runsCount, - iterationsCount, - true); - } - - - virtual void EndTest(const std::string& fixtureName, - const std::string& testName, - const TestParametersDescriptor& parameters, - const TestResult& result) - { -#define PAD(x) _stream << std::setw(34) << x << std::endl; -#define PAD_DEVIATION(description, \ - deviated, \ - average, \ - unit) \ - { \ - double _d_ = \ - double(deviated) - double(average); \ - \ - PAD(description << \ - deviated << " " << unit << " (" << \ - (deviated < average ? \ - Console::TextRed : \ - Console::TextGreen) << \ - (deviated > average ? "+" : "") << \ - _d_ << " " << unit << " / " << \ - (deviated > average ? "+" : "") << \ - (_d_ * 100.0 / average) << " %" << \ - Console::TextDefault << ")"); \ - } -#define PAD_DEVIATION_INVERSE(description, \ - deviated, \ - average, \ - unit) \ - { \ - double _d_ = \ - double(deviated) - double(average); \ - \ - PAD(description << \ - deviated << " " << unit << " (" << \ - (deviated > average ? \ - Console::TextRed : \ - Console::TextGreen) << \ - (deviated > average ? "+" : "") << \ - _d_ << " " << unit << " / " << \ - (deviated > average ? "+" : "") << \ - (_d_ * 100.0 / average) << " %" << \ - Console::TextDefault << ")"); \ - } - - _stream << Console::TextGreen << "[ DONE ]" - << Console::TextYellow << " "; - WriteTestNameToStream(_stream, fixtureName, testName, parameters); - _stream << Console::TextDefault << " (" - << std::setprecision(6) - << (result.TimeTotal() / 1000000.0) << " ms)" - << std::endl; - - _stream << Console::TextBlue << "[ RUNS ] " - << Console::TextDefault - << " Average time: " - << std::setprecision(3) - << result.RunTimeAverage() / 1000.0 << " us" - << std::endl; - - PAD_DEVIATION_INVERSE("Fastest: ", - (result.RunTimeMinimum() / 1000.0), - (result.RunTimeAverage() / 1000.0), - "us"); - PAD_DEVIATION_INVERSE("Slowest: ", - (result.RunTimeMaximum() / 1000.0), - (result.RunTimeAverage() / 1000.0), - "us"); - - _stream << std::setprecision(5); - - PAD(""); - PAD("Average performance: " << - result.RunsPerSecondAverage() << " runs/s"); - PAD_DEVIATION("Best performance: ", - result.RunsPerSecondMaximum(), - result.RunsPerSecondAverage(), - "runs/s"); - PAD_DEVIATION("Worst performance: ", - result.RunsPerSecondMinimum(), - result.RunsPerSecondAverage(), - "runs/s"); - - _stream << Console::TextBlue << "[ITERATIONS] " - << Console::TextDefault - << std::setprecision(3) - << " Average time: " - << result.IterationTimeAverage() / 1000.0 << " us" - << std::endl; - - PAD_DEVIATION_INVERSE("Fastest: ", - (result.IterationTimeMinimum() / 1000.0), - (result.IterationTimeAverage() / 1000.0), - "us"); - PAD_DEVIATION_INVERSE("Slowest: ", - (result.IterationTimeMaximum() / 1000.0), - (result.IterationTimeAverage() / 1000.0), - "us"); - - _stream << std::setprecision(5); - - PAD(""); - PAD("Average performance: " << - result.IterationsPerSecondAverage() << - " iterations/s"); - PAD_DEVIATION("Best performance: ", - (result.IterationsPerSecondMaximum()), - (result.IterationsPerSecondAverage()), - "iterations/s"); - PAD_DEVIATION("Worst performance: ", - (result.IterationsPerSecondMinimum()), - (result.IterationsPerSecondAverage()), - "iterations/s"); - -#undef PAD_DEVIATION_INVERSE -#undef PAD_DEVIATION -#undef PAD - } - - - std::ostream& _stream; - }; -} -#endif diff --git a/apps/bench/hayai/hayai_default_test_factory.hpp b/apps/bench/hayai/hayai_default_test_factory.hpp deleted file mode 100644 index 34f66ac108..0000000000 --- a/apps/bench/hayai/hayai_default_test_factory.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef __HAYAI_DEFAULTTESTFACTORY -#define __HAYAI_DEFAULTTESTFACTORY -#include "hayai_test_factory.hpp" - -namespace hayai -{ - /// Default test factory implementation. - - /// Simply constructs an instance of a the test of class @ref T with no - /// constructor parameters. - /// - /// @tparam T Test class. - template - class TestFactoryDefault - : public TestFactory - { - public: - /// Create a test instance with no constructor parameters. - - /// @returns a pointer to an initialized test. - virtual Test* CreateTest() - { - return new T(); - } - }; -} -#endif diff --git a/apps/bench/hayai/hayai_fixture.hpp b/apps/bench/hayai/hayai_fixture.hpp deleted file mode 100644 index 315c234d56..0000000000 --- a/apps/bench/hayai/hayai_fixture.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef __HAYAI_FIXTURE -#define __HAYAI_FIXTURE -#include "hayai_test.hpp" - -namespace hayai -{ - typedef Test Fixture; -} -#endif diff --git a/apps/bench/hayai/hayai_json_outputter.hpp b/apps/bench/hayai/hayai_json_outputter.hpp deleted file mode 100644 index 6637564966..0000000000 --- a/apps/bench/hayai/hayai_json_outputter.hpp +++ /dev/null @@ -1,333 +0,0 @@ -#ifndef __HAYAI_JSONOUTPUTTER -#define __HAYAI_JSONOUTPUTTER -#include -#include - -#include "hayai_outputter.hpp" - - -#define JSON_OBJECT_BEGIN "{" -#define JSON_OBJECT_END "}" -#define JSON_ARRAY_BEGIN "[" -#define JSON_ARRAY_END "]" -#define JSON_STRING_BEGIN "\"" -#define JSON_STRING_END "\"" -#define JSON_NAME_SEPARATOR ":" -#define JSON_VALUE_SEPARATOR "," -#define JSON_TRUE "true" -#define JSON_FALSE "false" - -namespace hayai -{ - /// JSON outputter. - - /// Outputs the result of benchmarks in JSON format with the following - /// structure: - /// - /// { - /// "format_version": 1, - /// "benchmarks": [{ - /// "fixture": "DeliveryMan", - /// "name": "DeliverPackage", - /// "parameters": { - /// "declaration": "std::size_t distance", - /// "value": "1" - /// }, - /// "iterations_per_run": 10, - /// "disabled": false, - /// "runs": [{ - /// "duration": 3801.889831 - /// }, ..] - /// }, { - /// "fixture": "DeliveryMan", - /// "name": "DisabledTest", - /// "iterations_per_run": 10, - /// "disabled": true - /// }, ..] - /// } - /// - /// All durations are represented as milliseconds. - class JsonOutputter - : public Outputter - { - public: - /// Initialize JSON outputter. - - /// @param stream Output stream. Must exist for the entire duration of - /// the outputter's use. - JsonOutputter(std::ostream& stream) - : _stream(stream), - _firstTest(true) - { - - } - - - virtual void Begin(const std::size_t& enabledCount, - const std::size_t& disabledCount) - { - (void)enabledCount; - (void)disabledCount; - - _stream << - JSON_OBJECT_BEGIN - - JSON_STRING_BEGIN "format_version" JSON_STRING_END - JSON_NAME_SEPARATOR - "1" - - JSON_VALUE_SEPARATOR - - JSON_STRING_BEGIN "benchmarks" JSON_STRING_END - JSON_NAME_SEPARATOR - JSON_ARRAY_BEGIN; - } - - - virtual void End(const std::size_t& executedCount, - const std::size_t& disabledCount) - { - (void)executedCount; - (void)disabledCount; - - _stream << - JSON_ARRAY_END - JSON_OBJECT_END; - } - - - virtual void BeginTest(const std::string& fixtureName, - const std::string& testName, - const TestParametersDescriptor& parameters, - const std::size_t& runsCount, - const std::size_t& iterationsCount) - { - BeginTestObject(fixtureName, - testName, - parameters, - runsCount, - iterationsCount, - false); - } - - - virtual void SkipDisabledTest(const std::string& fixtureName, - const std::string& testName, - const TestParametersDescriptor& parameters, - const std::size_t& runsCount, - const std::size_t& iterationsCount) - { - BeginTestObject(fixtureName, - testName, - parameters, - runsCount, - iterationsCount, - true); - EndTestObject(); - } - - - virtual void EndTest(const std::string& fixtureName, - const std::string& testName, - const TestParametersDescriptor& parameters, - const TestResult& result) - { - (void)fixtureName; - (void)testName; - (void)parameters; - - _stream << - JSON_VALUE_SEPARATOR - - JSON_STRING_BEGIN "runs" JSON_STRING_END - JSON_NAME_SEPARATOR - JSON_ARRAY_BEGIN; - - const std::vector& runTimes = result.RunTimes(); - - for (std::vector::const_iterator it = runTimes.begin(); - it != runTimes.end(); - ++it) - { - if (it != runTimes.begin()) - _stream << JSON_VALUE_SEPARATOR; - - _stream << JSON_OBJECT_BEGIN - - JSON_STRING_BEGIN "duration" JSON_STRING_END - JSON_NAME_SEPARATOR - << std::fixed - << std::setprecision(6) - << (double(*it) / 1000000.0) - << JSON_OBJECT_END; - } - - _stream << - JSON_ARRAY_END; - - EndTestObject(); - } - private: - void BeginTestObject(const std::string& fixtureName, - const std::string& testName, - const TestParametersDescriptor& parameters, - const std::size_t& runsCount, - const std::size_t& iterationsCount, - bool disabled) - { - (void)runsCount; - - if (_firstTest) - _firstTest = false; - else - _stream << JSON_VALUE_SEPARATOR; - - _stream << - JSON_OBJECT_BEGIN - - JSON_STRING_BEGIN "fixture" JSON_STRING_END - JSON_NAME_SEPARATOR; - - WriteString(fixtureName); - - _stream << - JSON_VALUE_SEPARATOR - - JSON_STRING_BEGIN "name" JSON_STRING_END - JSON_NAME_SEPARATOR; - - WriteString(testName); - - _stream << - JSON_VALUE_SEPARATOR; - - const std::vector& descs = - parameters.Parameters(); - - if (!descs.empty()) - { - _stream << - JSON_STRING_BEGIN "parameters" JSON_STRING_END - JSON_NAME_SEPARATOR - JSON_ARRAY_BEGIN; - - for (std::size_t i = 0; i < descs.size(); ++i) - { - if (i) - _stream << JSON_VALUE_SEPARATOR; - - const TestParameterDescriptor& desc = descs[i]; - - _stream << - JSON_OBJECT_BEGIN - - JSON_STRING_BEGIN "declaration" JSON_STRING_END - JSON_NAME_SEPARATOR; - - WriteString(desc.Declaration); - - _stream << - JSON_VALUE_SEPARATOR - - JSON_STRING_BEGIN "value" JSON_STRING_END - JSON_NAME_SEPARATOR; - - WriteString(desc.Value); - - _stream << - JSON_OBJECT_END; - } - - _stream << - JSON_ARRAY_END - JSON_VALUE_SEPARATOR; - } - - _stream << - JSON_STRING_BEGIN "iterations_per_run" JSON_STRING_END - JSON_NAME_SEPARATOR << iterationsCount << - - JSON_VALUE_SEPARATOR - - JSON_STRING_BEGIN "disabled" JSON_STRING_END - JSON_NAME_SEPARATOR << (disabled ? JSON_TRUE : JSON_FALSE); - } - - - inline void EndTestObject() - { - _stream << - JSON_OBJECT_END; - } - - - /// Write an escaped string. - - /// The escaping is currently very rudimentary and assumes that names, - /// parameters etc. are ASCII. - /// - /// @param str String to write. - void WriteString(const std::string& str) - { - _stream << JSON_STRING_BEGIN; - - std::string::const_iterator it = str.begin(); - while (it != str.end()) - { - char c = *it++; - - switch (c) - { - case '\\': - case '"': - case '/': - _stream << "\\" << c; - break; - - case '\b': - _stream << "\\b"; - break; - - case '\f': - _stream << "\\f"; - break; - - case '\n': - _stream << "\\n"; - break; - - case '\r': - _stream << "\\r"; - break; - - case '\t': - _stream << "\\t"; - break; - - default: - _stream << c; - break; - } - } - - _stream << JSON_STRING_END; - } - - - std::ostream& _stream; - bool _firstTest; - }; -} - -#undef JSON_OBJECT_BEGIN -#undef JSON_OBJECT_END -#undef JSON_ARRAY_BEGIN -#undef JSON_ARRAY_END -#undef JSON_STRING_BEGIN -#undef JSON_STRING_END -#undef JSON_NAME_SEPARATOR -#undef JSON_VALUE_SEPARATOR -#undef JSON_TRUE -#undef JSON_FALSE - -#endif diff --git a/apps/bench/hayai/hayai_junit_xml_outputter.hpp b/apps/bench/hayai/hayai_junit_xml_outputter.hpp deleted file mode 100644 index e7e116483c..0000000000 --- a/apps/bench/hayai/hayai_junit_xml_outputter.hpp +++ /dev/null @@ -1,260 +0,0 @@ -#ifndef __HAYAI_JUNITXMLOUTPUTTER -#define __HAYAI_JUNITXMLOUTPUTTER -#include -#include -#include -#include -#include - -#include "hayai_outputter.hpp" - - -namespace hayai -{ - /// JUnit-compatible XML outputter. - class JUnitXmlOutputter - : public Outputter - { - private: - /// Test case. - class TestCase - { - public: - TestCase(const std::string& fixtureName, - const std::string& testName, - const TestParametersDescriptor& parameters, - const TestResult* result) - { - // Derive a pretty name. - std::stringstream nameStream; - WriteTestNameToStream(nameStream, - fixtureName, - testName, - parameters); - Name = nameStream.str(); - - // Derive the result. - Skipped = !result; - - if (result) - { - std::stringstream timeStream; - timeStream << std::fixed - << std::setprecision(9) - << (result->IterationTimeAverage() / 1e9); - Time = timeStream.str(); - } - } - - - std::string Name; - std::string Time; - bool Skipped; - }; - - - /// Test suite map. - typedef std::map > TestSuiteMap; - public: - /// Initialize outputter. - - /// @param stream Output stream. Must exist for the entire duration of - /// the outputter's use. - JUnitXmlOutputter(std::ostream& stream) - : _stream(stream) - { - - } - - - virtual void Begin(const std::size_t& enabledCount, - const std::size_t& disabledCount) - { - (void)enabledCount; - (void)disabledCount; - } - - - virtual void End(const std::size_t& executedCount, - const std::size_t& disabledCount) - { - (void)executedCount; - (void)disabledCount; - - // Write the header. - _stream << "" - << std::endl - << "" << std::endl; - - // Write out each test suite (fixture.) - for (TestSuiteMap::iterator testSuiteIt = _testSuites.begin(); - testSuiteIt != _testSuites.end(); - ++testSuiteIt) - { - _stream << " first - << "\" tests=\"" << testSuiteIt->second.size() << "\">" - << std::endl; - - // Write out each test case. - for (std::vector::iterator testCaseIt = - testSuiteIt->second.begin(); - testCaseIt != testSuiteIt->second.end(); - ++testCaseIt) - { - _stream << " Name); - _stream << "\""; - - if (!testCaseIt->Skipped) - _stream << " time=\"" << testCaseIt->Time << "\" />" - << std::endl; - else - { - _stream << ">" << std::endl - << " " << std::endl - << " " << std::endl; - } - } - - _stream << " " << std::endl; - } - - _stream << "" << std::endl; - } - - - virtual void BeginTest(const std::string& fixtureName, - const std::string& testName, - const TestParametersDescriptor& parameters, - const std::size_t& runsCount, - const std::size_t& iterationsCount) - { - (void)fixtureName; - (void)testName; - (void)parameters; - (void)runsCount; - (void)iterationsCount; - } - - - virtual void SkipDisabledTest(const std::string& fixtureName, - const std::string& testName, - const TestParametersDescriptor& parameters, - const std::size_t& runsCount, - const std::size_t& iterationsCount) - { - (void)fixtureName; - (void)testName; - (void)parameters; - (void)runsCount; - (void)iterationsCount; - } - - - virtual void EndTest(const std::string& fixtureName, - const std::string& testName, - const TestParametersDescriptor& parameters, - const TestResult& result) - { - (void)fixtureName; - (void)testName; - (void)parameters; - - TestSuiteMap::iterator fixtureIt = - _testSuites.find(fixtureName); - if (fixtureIt == _testSuites.end()) - { - _testSuites[fixtureName] = std::vector(); - fixtureIt = _testSuites.find(fixtureName); - } - - std::vector& testCases = fixtureIt->second; - - testCases.push_back(TestCase(fixtureName, - testName, - parameters, - &result)); - - /* - _stream << - JSON_VALUE_SEPARATOR - - JSON_STRING_BEGIN "runs" JSON_STRING_END - JSON_NAME_SEPARATOR - JSON_ARRAY_BEGIN; - - const std::vector& runTimes = result.RunTimes(); - - for (std::vector::const_iterator it = runTimes.begin(); - it != runTimes.end(); - ++it) - { - if (it != runTimes.begin()) - _stream << JSON_VALUE_SEPARATOR; - - _stream << JSON_OBJECT_BEGIN - - JSON_STRING_BEGIN "duration" JSON_STRING_END - JSON_NAME_SEPARATOR - << std::fixed - << std::setprecision(6) - << (double(*it) / 1000000.0) - << JSON_OBJECT_END; - } - - _stream << - JSON_ARRAY_END; - - EndTestObject(); - */ - } - private: - /// Write an escaped string. - - /// The escaping is currently very rudimentary and assumes that names, - /// parameters etc. are ASCII. - /// - /// @param str String to write. - void WriteEscapedString(const std::string& str) - { - std::string::const_iterator it = str.begin(); - while (it != str.end()) - { - char c = *it++; - - switch (c) - { - case '"': - _stream << """; - break; - - case '\'': - _stream << "'"; - break; - - case '<': - _stream << "<"; - break; - - case '>': - _stream << ">"; - break; - - case '&': - _stream << "&"; - break; - - default: - _stream << c; - break; - } - } - } - - - std::ostream& _stream; - TestSuiteMap _testSuites; - }; -} - -#endif diff --git a/apps/bench/hayai/hayai_outputter.hpp b/apps/bench/hayai/hayai_outputter.hpp deleted file mode 100644 index 94055b2b1b..0000000000 --- a/apps/bench/hayai/hayai_outputter.hpp +++ /dev/null @@ -1,113 +0,0 @@ -#ifndef __HAYAI_OUTPUTTER -#define __HAYAI_OUTPUTTER -#include -#include - -#include "hayai_test_result.hpp" - - -namespace hayai -{ - /// Outputter. - - /// Abstract base class for outputters. - class Outputter - { - public: - /// Begin benchmarking. - - /// The total number of benchmarks registred is the sum of the two - /// counts passed to the outputter. - /// - /// @param enabledCount Number of benchmarks to be executed. - /// @param disabledCount Number of disabled benchmarks to be skipped. - virtual void Begin(const std::size_t& enabledCount, - const std::size_t& disabledCount) = 0; - - - /// End benchmarking. - - /// @param executedCount Number of benchmarks that have been executed. - /// @param disabledCount Number of benchmarks that have been skipped - /// because they are disabled. - virtual void End(const std::size_t& executedCount, - const std::size_t& disabledCount) = 0; - - - /// Begin benchmark test run. - - /// @param fixtureName Fixture name. - /// @param testName Test name. - /// @param parameters Test parameter description. - /// @param runsCount Number of runs to be executed. - /// @param iterationsCount Number of iterations per run. - virtual void BeginTest(const std::string& fixtureName, - const std::string& testName, - const TestParametersDescriptor& parameters, - const std::size_t& runsCount, - const std::size_t& iterationsCount) = 0; - - - /// End benchmark test run. - - /// @param fixtureName Fixture name. - /// @param testName Test name. - /// @param parameters Test parameter description. - /// @param result Test result. - virtual void EndTest(const std::string& fixtureName, - const std::string& testName, - const TestParametersDescriptor& parameters, - const TestResult& result) = 0; - - - /// Skip disabled benchmark test run. - - /// @param fixtureName Fixture name. - /// @param testName Test name. - /// @param parameters Test parameter description. - /// @param runsCount Number of runs to be executed. - /// @param iterationsCount Number of iterations per run. - virtual void SkipDisabledTest(const std::string& fixtureName, - const std::string& testName, - const TestParametersDescriptor& - parameters, - const std::size_t& runsCount, - const std::size_t& iterationsCount) = 0; - - - virtual ~Outputter() - { - - } - protected: - /// Write a nicely formatted test name to a stream. - static void WriteTestNameToStream(std::ostream& stream, - const std::string& fixtureName, - const std::string& testName, - const TestParametersDescriptor& - parameters) - { - stream << fixtureName << "." << testName; - - const std::vector& descs = - parameters.Parameters(); - - if (descs.empty()) - return; - - stream << "("; - - for (std::size_t i = 0; i < descs.size(); ++i) - { - if (i) - stream << ", "; - - const TestParameterDescriptor& desc = descs[i]; - stream << desc.Declaration << " = " << desc.Value; - } - - stream << ")"; - } - }; -} -#endif diff --git a/apps/bench/hayai/hayai_test.hpp b/apps/bench/hayai/hayai_test.hpp deleted file mode 100644 index 36d25fdbc2..0000000000 --- a/apps/bench/hayai/hayai_test.hpp +++ /dev/null @@ -1,83 +0,0 @@ -#ifndef __HAYAI_TEST -#define __HAYAI_TEST -#include - -#include "hayai_clock.hpp" -#include "hayai_test_result.hpp" - - -namespace hayai -{ - /// Base test class. - - /// @ref SetUp is invoked before each run, and @ref TearDown is invoked - /// once the run is finished. Iterations rely on the same fixture - /// for every run. - /// - /// The default test class does not contain any actual code in the - /// SetUp and TearDown methods, which means that tests can inherit - /// this class directly for non-fixture based benchmarking tests. - class Test - { - public: - /// Set up the testing fixture for execution of a run. - virtual void SetUp() - { - - } - - - /// Tear down the previously set up testing fixture after the - /// execution run. - virtual void TearDown() - { - - } - - - /// Run the test. - - /// @param iterations Number of iterations to gather data for. - /// @returns the number of nanoseconds the run took. - uint64_t Run(std::size_t iterations) - { - std::size_t iteration = iterations; - - // Set up the testing fixture. - SetUp(); - - // Get the starting time. - Clock::TimePoint startTime, endTime; - - startTime = Clock::Now(); - - // Run the test body for each iteration. - while (iteration--) - TestBody(); - - // Get the ending time. - endTime = Clock::Now(); - - // Tear down the testing fixture. - TearDown(); - - // Return the duration in nanoseconds. - return Clock::Duration(startTime, endTime); - } - - - virtual ~Test() - { - - } - protected: - /// Test body. - - /// Executed for each iteration the benchmarking test is run. - virtual void TestBody() - { - - } - }; -} -#endif diff --git a/apps/bench/hayai/hayai_test_descriptor.hpp b/apps/bench/hayai/hayai_test_descriptor.hpp deleted file mode 100644 index 529744e847..0000000000 --- a/apps/bench/hayai/hayai_test_descriptor.hpp +++ /dev/null @@ -1,365 +0,0 @@ -#ifndef __HAYAI_TESTDESCRIPTOR -#define __HAYAI_TESTDESCRIPTOR -#include -#include -#include -#include - -#include "hayai_test.hpp" -#include "hayai_test_factory.hpp" - - -namespace hayai -{ - /// Parameter declaration. - - /// Describes parameter type and name. - class TestParameterDescriptor - { - public: - TestParameterDescriptor(std::string declaration, - std::string value) - : Declaration(declaration), - Value(value) - { - - } - - - /// Declaration. - std::string Declaration; - - - /// Value. - std::string Value; - }; - - - /// Test parameters descriptor. - class TestParametersDescriptor - { - private: - /// Quoting state. - enum QuotingState - { - /// Unquoted. - Unquoted, - - - /// Single quoted. - SingleQuoted, - - - /// Double quoted. - DoubleQuoted - }; - - - /// Trimmed string. - - /// @param start Start character. - /// @param end Character one position beyond end. - inline static std::string TrimmedString(const char* start, - const char* end) - { - while (start < end) - { - if ((*start == ' ') || - (*start == '\r') || - (*start == '\n') || - (*start == '\t')) - ++start; - else - break; - } - - while (end > start) - { - const char c = *(end - 1); - - if ((c != ' ') && - (c != '\r') && - (c != '\n') && - (c != '\t')) - break; - - --end; - } - - return std::string(start, std::string::size_type(end - start)); - } - - - /// Parse comma separated parentherized value. - - /// @param separated Separated values as "(..[, ..])". - /// @returns the individual values with white space trimmed. - static std::vector - ParseCommaSeparated(const char* separated) - { - std::vector result; - - if (*separated) - ++separated; - - while ((*separated) && (*separated != ')')) - { - std::size_t escapeCounter = 0; - const char* start = separated; - QuotingState state = Unquoted; - bool escaped = false; - - while (*separated) - { - const char c = *separated++; - - if (state == Unquoted) - { - if ((c == '"') || (c == '\'')) - { - state = (c == '"' ? DoubleQuoted : SingleQuoted); - escaped = false; - } - else if ((c == '<') || - (c == '(') || - (c == '[') || - (c == '{')) - ++escapeCounter; - else if ((escapeCounter) && - ((c == '>') || - (c == ')') || - (c == ']') || - (c == '}'))) - --escapeCounter; - else if ((!escapeCounter) && - ((c == ',') || (c == ')'))) - { - result.push_back(TrimmedString(start, - separated - 1)); - break; - } - } - else - { - if (escaped) - escaped = false; - else if (c == '\\') - escaped = true; - else if (c == (state == DoubleQuoted ? '"' : '\'')) - state = Unquoted; - } - } - } - - return result; - } - - - /// Parse parameter declaration. - - /// @param raw Raw declaration. - TestParameterDescriptor ParseDescriptor(const std::string& raw) - { - const char* position = raw.c_str(); - - // Split the declaration into its declaration and its default - // type. - const char* equalPosition = NULL; - std::size_t escapeCounter = 0; - QuotingState state = Unquoted; - bool escaped = false; - - while (*position) - { - const char c = *position++; - - if (state == Unquoted) - { - if ((c == '"') || (c == '\'')) - { - state = (c == '"' ? DoubleQuoted : SingleQuoted); - escaped = false; - } - else if ((c == '<') || - (c == '(') || - (c == '[') || - (c == '{')) - ++escapeCounter; - else if ((escapeCounter) && - ((c == '>') || - (c == ')') || - (c == ']') || - (c == '}'))) - --escapeCounter; - else if ((!escapeCounter) && - (c == '=')) - { - equalPosition = position; - break; - } - } - else - { - if (escaped) - escaped = false; - else if (c == '\\') - escaped = true; - else if (c == (state == DoubleQuoted ? '"' : '\'')) - state = Unquoted; - } - } - - // Construct the parameter descriptor. - if (equalPosition) - { - const char* start = raw.c_str(); - const char* end = start + raw.length(); - - return TestParameterDescriptor( - std::string(TrimmedString(start, - equalPosition - 1)), - std::string(TrimmedString(equalPosition, - end)) - ); - } - else - return TestParameterDescriptor(raw, std::string()); - } - public: - TestParametersDescriptor() - { - - } - - - TestParametersDescriptor(const char* rawDeclarations, - const char* rawValues) - { - // Parse the declarations. - std::vector declarations = - ParseCommaSeparated(rawDeclarations); - - for (std::vector::const_iterator it = - declarations.begin(); - it != declarations.end(); - ++it) - _parameters.push_back(ParseDescriptor(*it)); - - // Parse the values. - std::vector values = ParseCommaSeparated(rawValues); - - std::size_t - straightValues = (_parameters.size() > values.size() ? - values.size() : - _parameters.size()), - variadicValues = 0; - - if (values.size() > _parameters.size()) - { - if (straightValues > 0) - --straightValues; - variadicValues = values.size() - _parameters.size() + 1; - } - - for (std::size_t i = 0; i < straightValues; ++i) - _parameters[i].Value = values[i]; - - if (variadicValues) - { - std::stringstream variadic; - - for (std::size_t i = 0; i < variadicValues; ++i) - { - if (i) - variadic << ", "; - variadic << values[straightValues + i]; - } - - _parameters[_parameters.size() - 1].Value = variadic.str(); - } - } - - - inline const std::vector& Parameters() const - { - return _parameters; - } - private: - std::vector _parameters; - }; - - - /// Test descriptor. - class TestDescriptor - { - public: - /// Initialize a new test descriptor. - - /// @param fixtureName Name of the fixture. - /// @param testName Name of the test. - /// @param runs Number of runs for the test. - /// @param iterations Number of iterations per run. - /// @param testFactory Test factory implementation for the test. - /// @param parameters Parametrized test parameters. - TestDescriptor(const char* fixtureName, - const char* testName, - std::size_t runs, - std::size_t iterations, - TestFactory* testFactory, - TestParametersDescriptor parameters, - bool isDisabled = false) - : FixtureName(fixtureName), - TestName(testName), - CanonicalName(std::string(fixtureName) + "." + testName), - Runs(runs), - Iterations(iterations), - Factory(testFactory), - Parameters(parameters), - IsDisabled(isDisabled) - { - - } - - - /// Dispose of a test descriptor. - ~TestDescriptor() - { - delete this->Factory; - } - - - /// Fixture name. - std::string FixtureName; - - - /// Test name. - std::string TestName; - - - /// Canonical name. - - /// As: .. - std::string CanonicalName; - - - /// Test runs. - std::size_t Runs; - - - /// Iterations per test run. - std::size_t Iterations; - - - /// Test factory. - TestFactory* Factory; - - - /// Parameters for parametrized tests - TestParametersDescriptor Parameters; - - - /// Disabled. - bool IsDisabled; - }; -} -#endif diff --git a/apps/bench/hayai/hayai_test_factory.hpp b/apps/bench/hayai/hayai_test_factory.hpp deleted file mode 100644 index 1c5f469e0c..0000000000 --- a/apps/bench/hayai/hayai_test_factory.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef __HAYAI_TESTFACTORY -#define __HAYAI_TESTFACTORY -#include "hayai_test.hpp" - -namespace hayai -{ - /// Base class for test factory implementations. - class TestFactory - { - public: - /// Virtual destructor - - /// Has no function in the base class. - virtual ~TestFactory() - { - - } - - - /// Creates a test instance to run. - - /// @returns a pointer to an initialized test. - virtual Test* CreateTest() = 0; - }; -} -#endif diff --git a/apps/bench/hayai/hayai_test_result.hpp b/apps/bench/hayai/hayai_test_result.hpp deleted file mode 100644 index 6d8288bc1f..0000000000 --- a/apps/bench/hayai/hayai_test_result.hpp +++ /dev/null @@ -1,153 +0,0 @@ -#ifndef __HAYAI_TESTRESULT -#define __HAYAI_TESTRESULT -#include -#include -#include - -#include "hayai_clock.hpp" - - -namespace hayai -{ - /// Test result descriptor. - - /// All durations are expressed in nanoseconds. - struct TestResult - { - public: - /// Initialize test result descriptor. - - /// @param runTimes Timing for the individual runs. - /// @param iterations Number of iterations per run. - TestResult(const std::vector& runTimes, - std::size_t iterations) - : _runTimes(runTimes), - _iterations(iterations), - _timeTotal(0), - _timeRunMin(std::numeric_limits::max()), - _timeRunMax(std::numeric_limits::min()) - { - // Summarize under the assumption of values being accessed more - // than once. - std::vector::iterator runIt = _runTimes.begin(); - - while (runIt != _runTimes.end()) - { - const uint64_t run = *runIt; - - _timeTotal += run; - if ((runIt == _runTimes.begin()) || (run > _timeRunMax)) - _timeRunMax = run; - if ((runIt == _runTimes.begin()) || (run < _timeRunMin)) - _timeRunMin = run; - - ++runIt; - } - } - - - /// Total time. - inline double TimeTotal() const - { - return _timeTotal; - } - - - /// Run times. - inline const std::vector& RunTimes() const - { - return _runTimes; - } - - - /// Average time per run. - inline double RunTimeAverage() const - { - return double(_timeTotal) / double(_runTimes.size()); - } - - - /// Maximum time per run. - inline double RunTimeMaximum() const - { - return _timeRunMax; - } - - - /// Minimum time per run. - inline double RunTimeMinimum() const - { - return _timeRunMin; - } - - - /// Average runs per second. - inline double RunsPerSecondAverage() const - { - return 1000000000.0 / RunTimeAverage(); - } - - - /// Maximum runs per second. - inline double RunsPerSecondMaximum() const - { - return 1000000000.0 / _timeRunMin; - } - - - /// Minimum runs per second. - inline double RunsPerSecondMinimum() const - { - return 1000000000.0 / _timeRunMax; - } - - - /// Average time per iteration. - inline double IterationTimeAverage() const - { - return RunTimeAverage() / double(_iterations); - } - - - /// Minimum time per iteration. - inline double IterationTimeMinimum() const - { - return _timeRunMin / double(_iterations); - } - - - /// Maximum time per iteration. - inline double IterationTimeMaximum() const - { - return _timeRunMax / double(_iterations); - } - - - /// Average iterations per second. - inline double IterationsPerSecondAverage() const - { - return 1000000000.0 / IterationTimeAverage(); - } - - - /// Minimum iterations per second. - inline double IterationsPerSecondMinimum() const - { - return 1000000000.0 / IterationTimeMaximum(); - } - - - /// Maximum iterations per second. - inline double IterationsPerSecondMaximum() const - { - return 1000000000.0 / IterationTimeMinimum(); - } - private: - std::vector _runTimes; - std::size_t _iterations; - uint64_t _timeTotal; - uint64_t _timeRunMin; - uint64_t _timeRunMax; - }; -} -#endif diff --git a/apps/bench/pico_bench/pico_bench.h b/apps/bench/pico_bench/pico_bench.h new file mode 100644 index 0000000000..3f0cad2612 --- /dev/null +++ b/apps/bench/pico_bench/pico_bench.h @@ -0,0 +1,203 @@ +#ifndef PICO_BENCH_H +#define PICO_BENCH_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace pico_bench { + +/* Statistics on some time measurement value T, e.g. T = std::chrono::milliseconds + * T must be some std::chrono::duration type + */ +template +class Statistics { + using rep = typename T::rep; + std::vector samples; + +public: + std::string time_suffix; + + Statistics(std::vector s) : samples(s) { + std::sort(samples.begin(), samples.end()); + } + T percentile(const float p) const { + return percentile(p, samples); + } + // Winsorize the data, sets all entries above 100 - limit percentile and below limit percentile + // to the value of that percentile + void winsorize(const float limit){ + winsorize(limit, samples); + } + T median() const { + return percentile(50.0, samples); + } + T median_abs_dev() const { + const auto m = median(); + std::vector deviations; + deviations.reserve(samples.size()); + std::transform(samples.begin(), samples.end(), std::back_inserter(deviations), + [&m](const T &t){ + return T{std::abs((t - m).count())}; + }); + std::sort(deviations.begin(), deviations.end()); + return percentile(50.0, deviations); + } + T mean() const { + const auto m = std::accumulate(samples.begin(), samples.end(), T{0}); + return m / samples.size(); + } + T std_dev() const { + const auto m = mean(); + auto val = std::accumulate(samples.begin(), samples.end(), T{0}, + [&m](const T &p, const T &t){ + return T{static_cast(p.count() + std::pow((t - m).count(), 2))}; + }); + return T{static_cast(std::sqrt(1.0 / static_cast(samples.size()) + * static_cast(val.count())))}; + } + T min() const { + return samples.front(); + } + T max() const { + return samples.back(); + } + size_t size() const { + return samples.size(); + } + const T& operator[](size_t i) const { + return samples[i]; + } + +private: + // Winsorize the data, sets all entries above 100 - limit percentile and below limit percentile + // to the value of that percentile + static void winsorize(const float limit, std::vector &samples){ + const auto low = percentile(limit, samples); + const auto high = percentile(100.0 - limit, samples); + for (auto &t : samples){ + if (t < low){ + t = low; + } + else if (t > high){ + t = high; + } + } + } + static T percentile(const float p, const std::vector &samples){ + assert(!samples.empty()); + assert(p <= 100.0); + assert(p >= 0.0); + if (samples.size() == 1){ + return samples.front(); + } + if (p == 100.0){ + return samples.back(); + } + const double rank = p / 100.0 * (static_cast(samples.size()) - 1.0); + const double low_r = std::floor(rank); + const double dist = rank - low_r; + const size_t k = static_cast(low_r); + const auto low = samples[k]; + const auto high = samples[k + 1]; + return T{static_cast(low.count() + (high - low).count() * dist)}; + } +}; + +/* Benchmarking measurment using some desired unit of time measurement, + * e.g. T = std::chrono::milliseconds. T must be some std::chrono::duration + */ +template +class Benchmarker { + const size_t MAX_ITER; + const T MAX_RUNTIME; + + template + struct BenchWrapper { + Fn fn; + + BenchWrapper(Fn fn) : fn(fn){} + T operator()(){ + auto start = std::chrono::high_resolution_clock::now(); + fn(); + auto end = std::chrono::high_resolution_clock::now(); + return std::chrono::duration_cast(end - start); + } + }; + +public: + using stats_type = Statistics; + + // Benchmark the functions either max_iter times or until max_runtime seconds have elapsed + // max_runtime should be > 0 + Benchmarker(const size_t max_iter, const std::chrono::seconds max_runtime) + : MAX_ITER(max_iter), MAX_RUNTIME(std::chrono::duration_cast(max_runtime)) + {} + // Create a benchmarker that will run the function for the desired number of iterations, + // regardless of how long it takes + Benchmarker(const size_t max_iter) : MAX_ITER(max_iter), MAX_RUNTIME(0) + {} + +#ifndef PICO_BENCH_NO_DECLVAL + template + typename std::enable_if()())>::value, stats_type>::type + operator()(Fn fn) const { + return (*this)(BenchWrapper{fn}); + } + + template + typename std::enable_if()()), T>::value, + stats_type>::type + operator()(Fn fn) const { + // Do a single un-timed warm up run + fn(); + T elapsed{0}; + std::vector samples; + for (size_t i = 0; i < MAX_ITER && (MAX_RUNTIME.count() == 0 || elapsed < MAX_RUNTIME); + ++i, elapsed += samples.back()) + { + samples.push_back(fn()); + } + return stats_type{samples}; + } +#else + template + stats_type operator()(Fn _fn) const { + BenchWrapper fn{_fn}; + // Do a single un-timed warm up run + fn(); + T elapsed{0}; + std::vector samples; + for (size_t i = 0; i < MAX_ITER && (MAX_RUNTIME.count() == 0 || elapsed < MAX_RUNTIME); + ++i, elapsed += samples.back()) + { + samples.push_back(fn()); + } + return stats_type{samples}; + } +#endif +}; +} + +template +std::ostream& operator<<(std::ostream &os, const pico_bench::Statistics &stats){ + os << "Statistics:\n" + << "\tmax: " << stats.max().count() << stats.time_suffix << "\n" + << "\tmin: " << stats.min().count() << stats.time_suffix << "\n" + << "\tmedian: " << stats.median().count() << stats.time_suffix << "\n" + << "\tmedian abs dev: " << stats.median_abs_dev().count() << stats.time_suffix << "\n" + << "\tmean: " << stats.mean().count() << stats.time_suffix << "\n" + << "\tstd dev: " << stats.std_dev().count() << stats.time_suffix << "\n" + << "\t# of samples: " << stats.size(); + return os; +} + +#endif + diff --git a/apps/bench/simple_outputter.hpp b/apps/bench/simple_outputter.hpp index 6e19d3fefe..0ba78a2653 100644 --- a/apps/bench/simple_outputter.hpp +++ b/apps/bench/simple_outputter.hpp @@ -3,70 +3,70 @@ #include "hayai/hayai_outputter.hpp" #include "hayai/hayai_console.hpp" - namespace hayai { - /// Console outputter. + /// Console outputter. - /// Prints the result to standard output. - class SimpleOutputter - : public Outputter - { - public: - /// Initialize console outputter. + /// Prints the result to standard output. + class SimpleOutputter + : public Outputter + { + int numBenchmarkFrames {100}; - /// @param stream Output stream. Must exist for the entire duration of - /// the outputter's use. - SimpleOutputter(std::ostream& stream = std::cout) - : _stream(stream) - { + public: + /// Initialize console outputter. - } + /// @param stream Output stream. Must exist for the entire duration of + /// the outputter's use. + SimpleOutputter(int numFrames, std::ostream& stream = std::cout) + : numBenchmarkFrames(numFrames), _stream(stream) + { + } - void Begin(const std::size_t&, const std::size_t&) override - { - } + void Begin(const std::size_t&, const std::size_t&) override + { + } - void End(const std::size_t&, const std::size_t&) override - { - } + void End(const std::size_t&, const std::size_t&) override + { + } - void BeginTest(const std::string&, - const std::string&, - const TestParametersDescriptor&, - const std::size_t&, - const std::size_t&) override - { - } + void BeginTest(const std::string&, + const std::string&, + const TestParametersDescriptor&, + const std::size_t&, + const std::size_t&) override + { + } - void SkipDisabledTest(const std::string&, - const std::string&, - const TestParametersDescriptor&, - const std::size_t&, - const std::size_t&) override - { - } + void SkipDisabledTest(const std::string&, + const std::string&, + const TestParametersDescriptor&, + const std::size_t&, + const std::size_t&) override + { + } - void EndTest(const std::string&, - const std::string&, - const TestParametersDescriptor&, - const TestResult& result) override - { - _stream << Console::TextBlue - << Console::TextDefault - << std::setprecision(5) - << std::setw(9) - << result.IterationsPerSecondAverage() - << " fps"; - } + void EndTest(const std::string&, + const std::string&, + const TestParametersDescriptor&, + const TestResult& result) override + { + _stream << Console::TextBlue + << Console::TextDefault + << std::setprecision(5) + << std::setw(9) + << result.IterationsPerSecondAverage() * numBenchmarkFrames + << " fps\n"; + } - std::ostream& _stream; - }; + std::ostream& _stream; + }; } #endif diff --git a/apps/common/commandline/CMakeLists.txt b/apps/common/commandline/CMakeLists.txt index 1f86bafb3c..1abc38ad48 100644 --- a/apps/common/commandline/CMakeLists.txt +++ b/apps/common/commandline/CMakeLists.txt @@ -95,7 +95,7 @@ IF(OSPRAY_COMMANDLINE_TACHYON_SUPPORT) ) ENDIF() -OSPRAY_CREATE_LIBRARY(commandline +OSPRAY_CREATE_LIBRARY(ospray_commandline ${SOURCE_FILES} LINK ospray_common diff --git a/apps/common/commandline/CameraParser.cpp b/apps/common/commandline/CameraParser.cpp index fac5366b9f..3ab80bf12c 100644 --- a/apps/common/commandline/CameraParser.cpp +++ b/apps/common/commandline/CameraParser.cpp @@ -1,4 +1,5 @@ // ======================================================================== // +// Copyright 2016 SURVICE Engineering Company // // Copyright 2016 Intel Corporation // // // // Licensed under the Apache License, Version 2.0 (the "License"); // @@ -14,29 +15,56 @@ // limitations under the License. // // ======================================================================== // +#include +#include +#include + #include "CameraParser.h" + bool DefaultCameraParser::parse(int ac, const char **&av) { for (int i = 1; i < ac; i++) { const std::string arg = av[i]; if (arg == "--camera" || arg == "-c") { - m_cameraType = av[++i]; + cameraType = av[++i]; + } else if (arg == "-v" || arg == "--view") { + std::ifstream fin(av[++i]); + if (!fin.is_open()) + { + throw std::runtime_error("Failed to open \"" + std::string(av[i]) + + "\" for reading"); + } + + auto token = std::string(""); + while (fin >> token) + { + if (token == "-vp") + fin >> eye.x >> eye.y >> eye.z; + else if (token == "-vu") + fin >> up.x >> up.y >> up.z; + else if (token == "-vi") + fin >> gaze.x >> gaze.y >> gaze.z; + else if (token == "-fv") + fin >> fovy; + else + throw std::runtime_error("Unrecognized token: \"" + token + '\"'); + } + } else if (arg == "-vp" || arg == "--eye") { - auto &pos = m_eye; - pos.x = atof(av[++i]); - pos.y = atof(av[++i]); - pos.z = atof(av[++i]); + eye.x = atof(av[++i]); + eye.y = atof(av[++i]); + eye.z = atof(av[++i]); } else if (arg == "-vu" || arg == "--up") { - auto &up = m_up; up.x = atof(av[++i]); up.y = atof(av[++i]); up.z = atof(av[++i]); } else if (arg == "-vi" || arg == "--gaze") { - auto &at = m_gaze; - at.x = atof(av[++i]); - at.y = atof(av[++i]); - at.z = atof(av[++i]); + gaze.x = atof(av[++i]); + gaze.y = atof(av[++i]); + gaze.z = atof(av[++i]); + } else if (arg == "-fv" || arg == "--fovy") { + fovy = atof(av[++i]); } } @@ -47,17 +75,18 @@ bool DefaultCameraParser::parse(int ac, const char **&av) ospray::cpp::Camera DefaultCameraParser::camera() { - return m_camera; + return parsedCamera; } void DefaultCameraParser::finalize() { - if (m_cameraType.empty()) - m_cameraType = "perspective"; - - m_camera = ospray::cpp::Camera(m_cameraType.c_str()); - m_camera.set("pos", m_eye); - m_camera.set("up", m_up); - m_camera.set("dir", m_gaze - m_eye); - m_camera.commit(); + if (cameraType.empty()) + cameraType = "perspective"; + + parsedCamera = ospray::cpp::Camera(cameraType.c_str()); + parsedCamera.set("pos", eye); + parsedCamera.set("up", up); + parsedCamera.set("dir", gaze - eye); + parsedCamera.set("fovy", fovy); + parsedCamera.commit(); } diff --git a/apps/common/commandline/CameraParser.h b/apps/common/commandline/CameraParser.h index fea3adc2a0..92bcfe74f8 100644 --- a/apps/common/commandline/CameraParser.h +++ b/apps/common/commandline/CameraParser.h @@ -1,4 +1,5 @@ // ======================================================================== // +// Copyright 2016 SURVICE Engineering Company // // Copyright 2009-2016 Intel Corporation // // // // Licensed under the Apache License, Version 2.0 (the "License"); // @@ -38,12 +39,13 @@ class OSPRAY_COMMANDLINE_INTERFACE DefaultCameraParser : public CameraParser protected: - std::string m_cameraType; - ospray::cpp::Camera m_camera; + std::string cameraType; + ospray::cpp::Camera parsedCamera; - ospcommon::vec3f m_eye {-1, 1, -1}; - ospcommon::vec3f m_up { 1, -1, 1}; - ospcommon::vec3f m_gaze{ 0, 1, 0}; + ospcommon::vec3f eye {.5, .5, 1}; + ospcommon::vec3f up { 0, 1, 0}; + ospcommon::vec3f gaze{ 0, -.1, -1}; + float fovy{ 60.f }; private: diff --git a/apps/common/commandline/LightsParser.cpp b/apps/common/commandline/LightsParser.cpp index 8b78850cc4..45cb3750c5 100644 --- a/apps/common/commandline/LightsParser.cpp +++ b/apps/common/commandline/LightsParser.cpp @@ -25,51 +25,41 @@ using namespace ospcommon; DefaultLightsParser::DefaultLightsParser(ospray::cpp::Renderer renderer) : - m_renderer(renderer), - m_defaultDirLight_direction(.3, -1, -.2) + renderer(renderer), + defaultDirLight_direction(.3, -1, -.2), defaultDirLight_intensity(3.14f) { } bool DefaultLightsParser::parse(int ac, const char **&av) { std::vector lights; + + bool hasHDRI = false; + int HDRI_up = 1;//y + float HDRI_intensity = 1; + const char * HDRI_file_name; for (int i = 1; i < ac; i++) { const std::string arg = av[i]; if (arg == "--sun-dir") { if (!strcmp(av[i+1],"none")) { ++i; - m_defaultDirLight_direction = vec3f(0.f); + defaultDirLight_direction = vec3f(0.f); } else { - m_defaultDirLight_direction.x = atof(av[++i]); - m_defaultDirLight_direction.y = atof(av[++i]); - m_defaultDirLight_direction.z = atof(av[++i]); + defaultDirLight_direction.x = atof(av[++i]); + defaultDirLight_direction.y = atof(av[++i]); + defaultDirLight_direction.z = atof(av[++i]); } + } else if (arg == "--sun-int") { + defaultDirLight_intensity = atof(av[++i]); } else if (arg == "--hdri-light") { + hasHDRI = true; if (i+2 >= ac) throw std::runtime_error("Not enough arguments! Usage:\n\t" "--hdri-light .(pfm|ppm)"); - auto ospHdri = m_renderer.newLight("hdri"); - ospHdri.set("name", "hdri light"); - if (1) {//TODO: add commandline option for up direction. - ospHdri.set("up", 0.f, 1.f, 0.f); - ospHdri.set("dir", 1.f, 0.f, 0.0f); - } else {// up = z - ospHdri.set("up", 0.f, 0.f, 1.f); - ospHdri.set("dir", 0.f, 1.f, 0.0f); - } - ospHdri.set( "intensity", atof(av[++i])); - FileName imageFile(av[++i]); - ospray::miniSG::Texture2D *lightMap = ospray::miniSG::loadTexture(imageFile.path(), imageFile.base()); - if (lightMap == NULL){ - std::cout << "Failed to load hdri-light texture '" << imageFile << "'" << std::endl; - } else { - std::cout << "Successfully loaded hdri-light texture '" << imageFile << "'" << std::endl; - } - OSPTexture2D ospLightMap = ospray::miniSG::createTexture2D(lightMap); - ospHdri.set( "map", ospLightMap); - ospHdri.commit(); - lights.push_back(ospHdri.handle()); + + HDRI_intensity = atof(av[++i]); + HDRI_file_name = av[++i]; } else if (arg == "--backplate") { FileName imageFile(av[++i]); ospray::miniSG::Texture2D *backplate = ospray::miniSG::loadTexture(imageFile.path(), imageFile.base()); @@ -77,20 +67,59 @@ bool DefaultLightsParser::parse(int ac, const char **&av) std::cout << "Failed to load backplate texture '" << imageFile << "'" << std::endl; } OSPTexture2D ospBackplate = ospray::miniSG::createTexture2D(backplate); - m_renderer.set("backplate", ospBackplate); + renderer.set("backplate", ospBackplate); + } else if (arg == "--hdri-up") { + if (!strcmp(av[i+1],"x") || !strcmp(av[i+1],"X")) { + HDRI_up = 0; + } else if (!strcmp(av[i+1],"y") || !strcmp(av[i+1],"Y")) { + HDRI_up = 1; + } else if (!strcmp(av[i+1],"z") || !strcmp(av[i+1],"Z")) { + HDRI_up = 2; + } else { + printf("--hdri-up must be x, y, or z.\n"); + } + } + }// Done reading commandline args. + + // HDRI environment light. + if (hasHDRI) { + auto ospHdri = renderer.newLight("hdri"); + ospHdri.set("name", "hdri light"); + if (HDRI_up == 0) {// up = x + ospHdri.set("up", 1.f, 0.f, 0.f); + ospHdri.set("dir", 0.f, 0.f, 1.0f); + } else if (HDRI_up == 1) {// up = y + ospHdri.set("up", 0.f, 1.f, 0.f); + ospHdri.set("dir", 1.f, 0.f, 0.0f); + } else if (HDRI_up == 2) {// up = z + ospHdri.set("up", 0.f, 0.f, 1.f); + ospHdri.set("dir", 0.f, 1.f, 0.0f); + } + ospHdri.set( "intensity", HDRI_intensity); + FileName imageFile(HDRI_file_name); + ospray::miniSG::Texture2D *lightMap = ospray::miniSG::loadTexture(imageFile.path(), imageFile.base()); + if (lightMap == NULL){ + std::cout << "Failed to load hdri-light texture '" << imageFile << "'" << std::endl; + } else { + std::cout << "Successfully loaded hdri-light texture '" << imageFile << "'" << std::endl; } + OSPTexture2D ospLightMap = ospray::miniSG::createTexture2D(lightMap); + ospHdri.set( "map", ospLightMap); + ospHdri.commit(); + lights.push_back(ospHdri.handle()); } //TODO: Need to figure out where we're going to read lighting data from - if (m_defaultDirLight_direction != vec3f(0.f)) { - auto ospLight = m_renderer.newLight("directional"); + if (defaultDirLight_direction != vec3f(0.f)) { + auto ospLight = renderer.newLight("directional"); if (ospLight.handle() == nullptr) { throw std::runtime_error("Failed to create a 'DirectionalLight'!"); } ospLight.set("name", "sun"); - ospLight.set("color", 1.f, 1.f, 1.f); - ospLight.set("direction", m_defaultDirLight_direction); + ospLight.set("color", 1.f, .94f, .88f); + ospLight.set("direction", defaultDirLight_direction); + ospLight.set("intensity", defaultDirLight_intensity); ospLight.set("angularDiameter", 0.53f); ospLight.commit(); lights.push_back(ospLight.handle()); @@ -98,7 +127,7 @@ bool DefaultLightsParser::parse(int ac, const char **&av) auto lightArray = ospray::cpp::Data(lights.size(), OSP_OBJECT, lights.data()); //lightArray.commit(); - m_renderer.set("lights", lightArray); + renderer.set("lights", lightArray); finalize(); diff --git a/apps/common/commandline/LightsParser.h b/apps/common/commandline/LightsParser.h index 49397573d3..59f3e91484 100644 --- a/apps/common/commandline/LightsParser.h +++ b/apps/common/commandline/LightsParser.h @@ -36,11 +36,12 @@ class OSPRAY_COMMANDLINE_INTERFACE DefaultLightsParser : public LightsParser protected: - ospray::cpp::Renderer m_renderer; + ospray::cpp::Renderer renderer; /*! when using the OBJ renderer, we create a automatic dirlight with this * direction; use ''--sun-dir x y z' to change */ - ospcommon::vec3f m_defaultDirLight_direction; + ospcommon::vec3f defaultDirLight_direction; + float defaultDirLight_intensity; private: void finalize(); diff --git a/apps/common/commandline/RendererParser.cpp b/apps/common/commandline/RendererParser.cpp index 34846aad82..95293f8568 100644 --- a/apps/common/commandline/RendererParser.cpp +++ b/apps/common/commandline/RendererParser.cpp @@ -22,9 +22,13 @@ bool DefaultRendererParser::parse(int ac, const char **&av) const std::string arg = av[i]; if (arg == "--renderer" || arg == "-r") { assert(i+1 < ac); - m_rendererType = av[++i]; + rendererType = av[++i]; } else if (arg == "--spp" || arg == "-spp") { - m_spp = atoi(av[++i]); + spp = atoi(av[++i]); + } else if (arg == "--noshadows" || arg == "-ns") { + shadows = 0; + } else if (arg == "--ao-samples" || arg == "-ao") { + aoSamples = atoi(av[++i]); } else if (arg == "--max-depth") { maxDepth = atoi(av[++i]); } @@ -37,25 +41,25 @@ bool DefaultRendererParser::parse(int ac, const char **&av) ospray::cpp::Renderer DefaultRendererParser::renderer() { - return m_renderer; + return parsedRenderer; } void DefaultRendererParser::finalize() { - if (m_rendererType.empty()) - m_rendererType = "scivis"; + if (rendererType.empty()) + rendererType = "scivis"; - m_renderer = ospray::cpp::Renderer(m_rendererType.c_str()); + parsedRenderer = ospray::cpp::Renderer(rendererType.c_str()); // Set renderer defaults (if not using 'aoX' renderers) - if (m_rendererType[0] != 'a' && m_rendererType[1] != 'o') + if (rendererType[0] != 'a' && rendererType[1] != 'o') { - m_renderer.set("aoSamples", 1); - m_renderer.set("shadowsEnabled", 1); + parsedRenderer.set("aoSamples", aoSamples); + parsedRenderer.set("shadowsEnabled", shadows); } - m_renderer.set("spp", m_spp); - m_renderer.set("maxDepth", maxDepth); + parsedRenderer.set("spp", spp); + parsedRenderer.set("maxDepth", maxDepth); - m_renderer.commit(); + parsedRenderer.commit(); } diff --git a/apps/common/commandline/RendererParser.h b/apps/common/commandline/RendererParser.h index 007107db83..48a944df87 100644 --- a/apps/common/commandline/RendererParser.h +++ b/apps/common/commandline/RendererParser.h @@ -38,11 +38,13 @@ class OSPRAY_COMMANDLINE_INTERFACE DefaultRendererParser : public RendererParser protected: - std::string m_rendererType; - ospray::cpp::Renderer m_renderer; + std::string rendererType; + ospray::cpp::Renderer parsedRenderer; - int m_spp{1}; + int spp{1}; int maxDepth{5}; + int shadows{1}; + int aoSamples{1}; private: diff --git a/apps/common/commandline/SceneParser/MultiSceneParser.cpp b/apps/common/commandline/SceneParser/MultiSceneParser.cpp index dc196e4dee..5cab269022 100644 --- a/apps/common/commandline/SceneParser/MultiSceneParser.cpp +++ b/apps/common/commandline/SceneParser/MultiSceneParser.cpp @@ -30,27 +30,27 @@ using namespace ospray; using namespace ospcommon; MultiSceneParser::MultiSceneParser(cpp::Renderer renderer) : - m_renderer(renderer) + renderer(renderer) { } bool MultiSceneParser::parse(int ac, const char **&av) { - TriangleMeshSceneParser triangleMeshParser(m_renderer); + TriangleMeshSceneParser triangleMeshParser(renderer); #ifdef OSPRAY_TACHYON_SUPPORT - TachyonSceneParser tachyonParser(m_renderer); + TachyonSceneParser tachyonParser(renderer); #endif - ParticleSceneParser particleParser(m_renderer); - StreamLineSceneParser streamlineParser(m_renderer); + ParticleSceneParser particleParser(renderer); + StreamLineSceneParser streamlineParser(renderer); #ifndef _WIN32 - VolumeSceneParser volumeParser(m_renderer); + VolumeSceneParser volumeParser(renderer); #endif bool gotTriangleMeshScene = triangleMeshParser.parse(ac, av); #ifdef OSPRAY_TACHYON_SUPPORT bool gotTachyonScene = tachyonParser.parse(ac, av); #endif - bool gotPartileScene = particleParser.parse(ac, av); + bool gotParticleScene = particleParser.parse(ac, av); bool gotStreamLineScene = streamlineParser.parse(ac, av); #ifndef _WIN32 bool gotVolumeScene = volumeParser.parse(ac, av); @@ -64,7 +64,7 @@ bool MultiSceneParser::parse(int ac, const char **&av) else if (gotTachyonScene) parser = &tachyonParser; #endif - else if (gotPartileScene) + else if (gotParticleScene) parser = &particleParser; else if (gotStreamLineScene) parser = &streamlineParser; @@ -74,8 +74,11 @@ bool MultiSceneParser::parse(int ac, const char **&av) #endif if (parser) { - m_model = parser->model(); - m_bbox = parser->bbox(); + sceneModel = parser->model(); + sceneBbox = parser->bbox(); + } else { + sceneModel = cpp::Model(); + sceneModel.commit(); } return parser != nullptr; @@ -83,10 +86,10 @@ bool MultiSceneParser::parse(int ac, const char **&av) cpp::Model MultiSceneParser::model() const { - return m_model; + return sceneModel; } box3f MultiSceneParser::bbox() const { - return m_bbox; + return sceneBbox; } diff --git a/apps/common/commandline/SceneParser/MultiSceneParser.h b/apps/common/commandline/SceneParser/MultiSceneParser.h index ea37a8ebfd..f66dc9689d 100644 --- a/apps/common/commandline/SceneParser/MultiSceneParser.h +++ b/apps/common/commandline/SceneParser/MultiSceneParser.h @@ -32,9 +32,9 @@ class OSPRAY_COMMANDLINE_INTERFACE MultiSceneParser : public SceneParser protected: - ospray::cpp::Renderer m_renderer; - ospray::cpp::Model m_model; - ospcommon::box3f m_bbox; + ospray::cpp::Renderer renderer; + ospray::cpp::Model sceneModel; + ospcommon::box3f sceneBbox; private: diff --git a/apps/common/commandline/SceneParser/particle/Model.cpp b/apps/common/commandline/SceneParser/particle/Model.cpp index cb9dbf5891..d673fd8395 100644 --- a/apps/common/commandline/SceneParser/particle/Model.cpp +++ b/apps/common/commandline/SceneParser/particle/Model.cpp @@ -120,7 +120,8 @@ namespace ospray { throw std::runtime_error("could not parse .dat.xyz header in input file "+fileName); char line[10000]; - fgets(line,10000,file); // description line + if (!fgets(line,10000,file)) + throw std::runtime_error("could not fgets"); std::cout << "#" << fileName << " (.dat.xyz format): expecting " << numAtoms << " atoms" << std::endl; for (int i=0;i; attribute[name]->push_back(value); } - void savePositions(const std::string &fileName) + void savePositions(const std::string &/*fileName*/) { - FILE *file = fopen(fileName.c_str(),"wb"); + NOT_IMPLEMENTED } - void saveAttribute(const std::string &fileName, const std::vector &attr) + + void saveAttribute(const std::string &fileName, + const std::vector &attr) { FILE *file = fopen(fileName.c_str(),"wb"); - for (int i=0;i *>::const_iterator it=attribute.begin(); - it != attribute.end();it++) { + for (auto it = attribute.begin(); it != attribute.end(); it++) { fprintf(txt,"attribute offset %li name %s\n", ftell(bin),it->first.c_str()); fwrite(&*it->second->begin(),sizeof(float),it->second->size(),bin); @@ -109,18 +106,18 @@ namespace ospray { void cullPartialData() { size_t largestCompleteSize = atom.size(); - for (std::map *>::const_iterator it=attribute.begin(); - it != attribute.end();it++) + for (auto it = attribute.begin(); it != attribute.end(); it++) largestCompleteSize = std::min(largestCompleteSize,it->second->size()); if (atom.size() > largestCompleteSize) { - std::cout << "#osp:uintah: atoms w missing attribute(s): discarding" << std::endl; + std::cout << "#osp:uintah: atoms w missing attribute(s): discarding" + << std::endl; atom.resize(largestCompleteSize); } - for (std::map *>::const_iterator it=attribute.begin(); - it != attribute.end();it++) { + for (auto it = attribute.begin(); it != attribute.end(); it++) { if (it->second->size() > largestCompleteSize) { - std::cout << "#osp:uintah: attribute(s) w/o atom(s): discarding" << std::endl; + std::cout << "#osp:uintah: attribute(s) w/o atom(s): discarding" + << std::endl; it->second->resize(largestCompleteSize); } } diff --git a/apps/common/commandline/SceneParser/particle/ParticleSceneParser.cpp b/apps/common/commandline/SceneParser/particle/ParticleSceneParser.cpp index 8d7390c5aa..0b7e69d0e0 100644 --- a/apps/common/commandline/SceneParser/particle/ParticleSceneParser.cpp +++ b/apps/common/commandline/SceneParser/particle/ParticleSceneParser.cpp @@ -83,7 +83,7 @@ struct DeferredLoadJob { // Class definitions ////////////////////////////////////////////////////////// ParticleSceneParser::ParticleSceneParser(cpp::Renderer renderer) : - m_renderer(renderer) + renderer(renderer) { } @@ -136,8 +136,12 @@ bool ParticleSceneParser::parse(int ac, const char **&av) } if (loadedScene) { + sceneModel = make_unique(); + + auto &model = *sceneModel; + //TODO: this needs parallelized as it was in ospParticleViewer... - for (int i = 0; i < deferredLoadingListXYZ.size(); ++i) { + for (uint32_t i = 0; i < deferredLoadingListXYZ.size(); ++i) { FileName defFileName = deferredLoadingListXYZ[i]->defFileName; FileName xyzFileName = deferredLoadingListXYZ[i]->xyzFileName; particle::Model *model = deferredLoadingListXYZ[i]->model; @@ -147,9 +151,9 @@ bool ParticleSceneParser::parse(int ac, const char **&av) model->loadXYZ(xyzFileName); } - for (int i = 0; i < particleModel.size(); i++) { + for (uint32_t i = 0; i < particleModel.size(); i++) { OSPModel model = ospNewModel(); - OSPData materialData = makeMaterials(m_renderer.handle(), particleModel[i]); + OSPData materialData = makeMaterials(renderer.handle(), particleModel[i]); OSPData data = ospNewData(particleModel[i]->atom.size()*5,OSP_FLOAT, &particleModel[i]->atom[0],OSP_DATA_SHARED_BUFFER); @@ -170,8 +174,8 @@ bool ParticleSceneParser::parse(int ac, const char **&av) modelTimeStep.push_back(model); } - m_model = modelTimeStep[timeStep]; - m_bbox = particleModel[0]->getBBox(); + model = modelTimeStep[timeStep]; + sceneBbox = particleModel[0]->getBBox(); } return loadedScene; @@ -179,11 +183,11 @@ bool ParticleSceneParser::parse(int ac, const char **&av) ospray::cpp::Model ParticleSceneParser::model() const { - return m_model; + return sceneModel.get() == nullptr ? cpp::Model() : *sceneModel; } ospcommon::box3f ParticleSceneParser::bbox() const { - return m_bbox; + return sceneBbox; } diff --git a/apps/common/commandline/SceneParser/particle/ParticleSceneParser.h b/apps/common/commandline/SceneParser/particle/ParticleSceneParser.h index 4277af7f5b..243f0afc8c 100644 --- a/apps/common/commandline/SceneParser/particle/ParticleSceneParser.h +++ b/apps/common/commandline/SceneParser/particle/ParticleSceneParser.h @@ -32,7 +32,8 @@ class OSPRAY_COMMANDLINE_INTERFACE ParticleSceneParser : public SceneParser private: - ospray::cpp::Renderer m_renderer; - ospray::cpp::Model m_model; - ospcommon::box3f m_bbox; + ospray::cpp::Renderer renderer; + ospcommon::box3f sceneBbox; + + std::unique_ptr sceneModel; }; diff --git a/apps/common/commandline/SceneParser/particle/uintah.cpp b/apps/common/commandline/SceneParser/particle/uintah.cpp index 0d4a80f4b2..e6532ec6fe 100644 --- a/apps/common/commandline/SceneParser/particle/uintah.cpp +++ b/apps/common/commandline/SceneParser/particle/uintah.cpp @@ -77,7 +77,7 @@ namespace ospray { } // PRINT(len); - for (int i=0;i *>::const_iterator it=model->attribute.begin(); - it != model->attribute.end();it++) { + for (auto it = model->attribute.begin(); + it != model->attribute.end(); + it++) { attrs << "," << it->first; } @@ -178,7 +179,7 @@ namespace ospray { } // PRINT(len); - for (int i=0;igetProp("type"); - for (int i=0;ichild.size();i++) { + for (uint32_t i = 0; i < var->child.size(); i++) { xml::Node *n = var->child[i]; if (n->name == "index") { index = atoi(n->content.c_str()); @@ -237,6 +238,9 @@ namespace ospray { } } + (void)index; + (void)patch; + if (numParticles > 0 && variable == "p.x" /* && index == .... */ @@ -278,7 +282,7 @@ namespace ospray { assert(doc->child.size() == 1); xml::Node *node = doc->child[0]; assert(node->name == "Uintah_Output"); - for (int i=0;ichild.size();i++) { + for (uint32_t i = 0; i < node->child.size(); i++) { xml::Node *c = node->child[i]; assert(c->name == "Variable"); parse__Variable(model,basePath,c); @@ -289,10 +293,10 @@ namespace ospray { const std::string &basePath, xml::Node *node) { assert(node->name == "Data"); - for (int i=0;ichild.size();i++) { + for (uint32_t i = 0; i < node->child.size(); i++) { xml::Node *c = node->child[i]; assert(c->name == "Datafile"); - for (int j=0;jprop.size();j++) { + for (uint32_t j = 0; j < c->prop.size(); j++) { xml::Prop *p = c->prop[j]; if (p->name == "href") { try { @@ -310,11 +314,12 @@ namespace ospray { } } } - void parse__Uintah_TimeStep_Meta(Model *model, - const std::string &basePath, xml::Node *node) + void parse__Uintah_TimeStep_Meta(Model */*model*/, + const std::string &/*basePath*/, + xml::Node *node) { assert(node->name == "Meta"); - for (int i=0;ichild.size();i++) { + for (uint32_t i = 0; i < node->child.size(); i++) { xml::Node *c = node->child[i]; if (c->name == "endianness") { if (c->content == "big_endian") { @@ -328,7 +333,7 @@ namespace ospray { const std::string &basePath, xml::Node *node) { assert(node->name == "Uintah_timestep"); - for (int i=0;ichild.size();i++) { + for (uint32_t i = 0; i < node->child.size(); i++) { xml::Node *c = node->child[i]; if (c->name == "Meta") { parse__Uintah_TimeStep_Meta(model,basePath,c); @@ -363,8 +368,8 @@ namespace ospray { << model->atom.size() << " particles (" << attrs.str() << ")" << std::endl; box3f bounds = empty; - for (int i=0;iatom.size();i++) { - bounds.extend(model->atom[i].position); + for (const auto & atom : model->atom) { + bounds.extend(atom.position); } std::cout << "#osp:mpm: bounds of particle centers: " << bounds << std::endl; delete doc; diff --git a/apps/common/commandline/SceneParser/streamlines/StreamLineSceneParser.cpp b/apps/common/commandline/SceneParser/streamlines/StreamLineSceneParser.cpp index 53e5473e63..1c1113cd0d 100644 --- a/apps/common/commandline/SceneParser/streamlines/StreamLineSceneParser.cpp +++ b/apps/common/commandline/SceneParser/streamlines/StreamLineSceneParser.cpp @@ -73,8 +73,8 @@ struct Triangles { box3f getBounds() const { box3f bounds = empty; - for (int i=0;i vertex; std::vector index; - float radius; - - StreamLines() : radius(0.001f) {} + float radius {0.001f}; void parsePNT(const FileName &fn) { @@ -132,6 +130,7 @@ struct StreamLines { int numStreamlines; int rc = fread(&numStreamlines, sizeof(int), 1, file); + (void)rc; Assert(rc == 1); for(int s=0; schild.size() != 1 || doc->child[0]->name != "OSPRay") throw std::runtime_error("could not parse osx file: Not in OSPRay format!?"); xml::Node *root_element = doc->child[0]; - for (int childID=0;childIDchild.size();childID++) { + for (uint32_t childID = 0; childID < root_element->child.size(); childID++) { xml::Node *node = root_element->child[childID]; if (node->name == "Info") { // ignore @@ -335,13 +334,13 @@ void parseOSX(StreamLines *streamLines, if (node->name == "Model") { xml::Node *model_node = node; - for (int childID=0;childIDchild.size();childID++) { + for (uint32_t childID = 0; childID < model_node->child.size(); childID++) { xml::Node *node = model_node->child[childID]; if (node->name == "StreamLines") { xml::Node *sl_node = node; - for (int childID=0;childIDchild.size();childID++) { + for (uint32_t childID = 0; childID < sl_node->child.size(); childID++) { xml::Node *node = sl_node->child[childID]; if (node->name == "vertex") { osxParseVec3fas(streamLines->vertex,node->content); @@ -357,7 +356,7 @@ void parseOSX(StreamLines *streamLines, if (node->name == "TriangleMesh") { xml::Node *tris_node = node; - for (int childID=0;childIDchild.size();childID++) { + for (uint32_t childID = 0; childID < tris_node->child.size(); childID++) { xml::Node *node = tris_node->child[childID]; if (node->name == "vertex") { osxParseVec3fas(triangles->vertex,node->content); @@ -390,16 +389,13 @@ void exportOSX(const char *fn,StreamLines *streamLines, Triangles *triangles) fprintf(file,"\n"); { fprintf(file,"\n"); - for (int i=0;ivertex.size();i++) - fprintf(file,"%f %f %f\n", - streamLines->vertex[i].x, - streamLines->vertex[i].y, - streamLines->vertex[i].z); + for (const auto &v : streamLines->vertex) + fprintf(file,"%f %f %f\n", v.x, v.y, v.z); fprintf(file,"\n"); fprintf(file,"\n"); - for (int i=0;iindex.size();i++) - fprintf(file,"%i ",streamLines->index[i]); + for (const auto & i : streamLines->index) + fprintf(file,"%i ",i); fprintf(file,"\n\n"); } fprintf(file,"\n"); @@ -408,27 +404,18 @@ void exportOSX(const char *fn,StreamLines *streamLines, Triangles *triangles) fprintf(file,"\n"); { fprintf(file,"\n"); - for (int i=0;ivertex.size();i++) - fprintf(file,"%f %f %f\n", - triangles->vertex[i].x, - triangles->vertex[i].y, - triangles->vertex[i].z); + for (const auto &v : triangles->vertex) + fprintf(file,"%f %f %f\n", v.x, v.y, v.z); fprintf(file,"\n"); fprintf(file,"\n"); - for (int i=0;icolor.size();i++) - fprintf(file,"%f %f %f\n", - triangles->color[i].x, - triangles->color[i].y, - triangles->color[i].z); + for (const auto &c : triangles->color) + fprintf(file,"%f %f %f\n", c.x, c.y, c.z); fprintf(file,"\n"); fprintf(file,"\n"); - for (int i=0;iindex.size();i++) - fprintf(file,"%i %i %i\n", - triangles->index[i].x, - triangles->index[i].y, - triangles->index[i].z); + for (const auto &i : triangles->index) + fprintf(file,"%i %i %i\n", i.x, i.y, i.z); fprintf(file,"\n"); } @@ -443,7 +430,7 @@ void exportOSX(const char *fn,StreamLines *streamLines, Triangles *triangles) // Class definitions ////////////////////////////////////////////////////////// StreamLineSceneParser::StreamLineSceneParser(cpp::Renderer renderer) : - m_renderer(renderer) + renderer(renderer) { } @@ -502,9 +489,11 @@ bool StreamLineSceneParser::parse(int ac, const char **&av) } if (loadedScene) { - m_model = ospNewModel(); + sceneModel = make_unique(); + + auto &model = *sceneModel; - OSPMaterial mat = ospNewMaterial(m_renderer.handle(), "default"); + OSPMaterial mat = ospNewMaterial(renderer.handle(), "default"); if (mat) { ospSet3f(mat, "kd", .7, .7, .7); ospCommit(mat); @@ -525,7 +514,7 @@ bool StreamLineSceneParser::parse(int ac, const char **&av) if (mat) ospSetMaterial(geom,mat); ospCommit(geom); - ospAddGeometry(m_model.handle(), geom); + ospAddGeometry(model.handle(), geom); bounds.extend(streamLines->getBounds()); } @@ -543,19 +532,19 @@ bool StreamLineSceneParser::parse(int ac, const char **&av) ospSetObject(geom, "vertex.color", color); ospSetMaterial(geom, mat); ospCommit(geom); - ospAddGeometry(m_model.handle(), geom); + ospAddGeometry(model.handle(), geom); bounds.extend(triangles->getBounds()); } if (swc && !swc->bounds.empty()) { OSPMaterial material[3]; material[0] = mat; - material[1] = ospNewMaterial(m_renderer.handle(), "default"); + material[1] = ospNewMaterial(renderer.handle(), "default"); if (material[1]) { ospSet3f(material[1], "kd", .0, .7, .0); // OBJ renderer, green ospCommit(material[1]); } - material[2] = ospNewMaterial(m_renderer.handle(), "default"); + material[2] = ospNewMaterial(renderer.handle(), "default"); if (material[2]) { ospSet3f(material[2], "kd", .7, .0, .7); // OBJ renderer, magenta ospCommit(material[2]); @@ -575,8 +564,7 @@ bool StreamLineSceneParser::parse(int ac, const char **&av) ospSetMaterial(spheres[i], material[i]); ospCommit(spheres[i]); - ospAddGeometry(m_model.handle(), spheres[i]); - + ospAddGeometry(model.handle(), spheres[i]); cylinders[i] = ospNewGeometry("cylinders"); Assert(cylinders[i]); @@ -589,14 +577,14 @@ bool StreamLineSceneParser::parse(int ac, const char **&av) ospSetMaterial(cylinders[i], material[i]); ospCommit(cylinders[i]); - ospAddGeometry(m_model.handle(), cylinders[i]); + ospAddGeometry(model.handle(), cylinders[i]); } bounds.extend(swc->getBounds()); } - m_model.commit(); - m_bbox = bounds; + model.commit(); + sceneBbox = bounds; } if (streamLines) delete streamLines; @@ -608,10 +596,10 @@ bool StreamLineSceneParser::parse(int ac, const char **&av) cpp::Model StreamLineSceneParser::model() const { - return m_model; + return sceneModel.get() == nullptr ? cpp::Model() : *sceneModel; } box3f StreamLineSceneParser::bbox() const { - return m_bbox; + return sceneBbox; } diff --git a/apps/common/commandline/SceneParser/streamlines/StreamLineSceneParser.h b/apps/common/commandline/SceneParser/streamlines/StreamLineSceneParser.h index eb8fd67ee0..43c9dc9708 100644 --- a/apps/common/commandline/SceneParser/streamlines/StreamLineSceneParser.h +++ b/apps/common/commandline/SceneParser/streamlines/StreamLineSceneParser.h @@ -32,9 +32,9 @@ class OSPRAY_COMMANDLINE_INTERFACE StreamLineSceneParser : public SceneParser private: - ospray::cpp::Model m_model; - ospray::cpp::Renderer m_renderer; - ospcommon::box3f m_bbox; + std::unique_ptr sceneModel; + ospray::cpp::Renderer renderer; + ospcommon::box3f sceneBbox; void finalize(); }; diff --git a/apps/common/commandline/SceneParser/tachyon/Model.cpp b/apps/common/commandline/SceneParser/tachyon/Model.cpp index 94d76484fc..97562c624f 100644 --- a/apps/common/commandline/SceneParser/tachyon/Model.cpp +++ b/apps/common/commandline/SceneParser/tachyon/Model.cpp @@ -17,7 +17,7 @@ #undef NDEBUG // ospray -#include "common/AffineSpace.h" +#include "ospcommon/AffineSpace.h" // tachyon module #include "Model.h" #include "Loc.h" diff --git a/apps/common/commandline/SceneParser/tachyon/Model.h b/apps/common/commandline/SceneParser/tachyon/Model.h index 7c8b242762..a0272babb3 100644 --- a/apps/common/commandline/SceneParser/tachyon/Model.h +++ b/apps/common/commandline/SceneParser/tachyon/Model.h @@ -17,8 +17,8 @@ #pragma once // ospray -#include "common/vec.h" -#include "common/box.h" +#include "ospcommon/vec.h" +#include "ospcommon/box.h" // std #include #include diff --git a/apps/common/commandline/SceneParser/tachyon/TachyonSceneParser.cpp b/apps/common/commandline/SceneParser/tachyon/TachyonSceneParser.cpp index fb8d0d3b0b..5f974fdd53 100644 --- a/apps/common/commandline/SceneParser/tachyon/TachyonSceneParser.cpp +++ b/apps/common/commandline/SceneParser/tachyon/TachyonSceneParser.cpp @@ -16,7 +16,7 @@ #include "TachyonSceneParser.h" #include "Model.h" -#include "common/FileName.h" +#include "ospcommon/FileName.h" #include using std::cout; @@ -159,7 +159,7 @@ OSPModel specifyModel(tachyon::Model &tm) // Class definitions ////////////////////////////////////////////////////////// TachyonSceneParser::TachyonSceneParser(cpp::Renderer renderer) : - m_renderer(renderer) + renderer(renderer) { } @@ -176,8 +176,8 @@ bool TachyonSceneParser::parse(int ac, const char **&av) TimeStep ts(arg); importFile(ts.tm, arg); ts.om = specifyModel(ts.tm); - m_model = ts.om; - m_bbox = ts.tm.getBounds(); + sceneModel = ts.om; + sceneBbox = ts.tm.getBounds(); break; } } @@ -188,10 +188,10 @@ bool TachyonSceneParser::parse(int ac, const char **&av) cpp::Model TachyonSceneParser::model() const { - return m_model; + return sceneModel; } box3f TachyonSceneParser::bbox() const { - return m_bbox; + return sceneBbox; } diff --git a/apps/common/commandline/SceneParser/tachyon/TachyonSceneParser.h b/apps/common/commandline/SceneParser/tachyon/TachyonSceneParser.h index bd18c482e5..866f7ecb35 100644 --- a/apps/common/commandline/SceneParser/tachyon/TachyonSceneParser.h +++ b/apps/common/commandline/SceneParser/tachyon/TachyonSceneParser.h @@ -31,7 +31,7 @@ class TachyonSceneParser : public SceneParser private: - ospray::cpp::Renderer m_renderer; - ospray::cpp::Model m_model; - ospcommon::box3f m_bbox; + ospray::cpp::Renderer renderer; + ospray::cpp::Model sceneModel; + ospcommon::box3f sceneBbox; }; diff --git a/apps/common/commandline/SceneParser/tachyon/parser.yy b/apps/common/commandline/SceneParser/tachyon/parser.yy index 7fff5b5b46..a3f63e3cb2 100644 --- a/apps/common/commandline/SceneParser/tachyon/parser.yy +++ b/apps/common/commandline/SceneParser/tachyon/parser.yy @@ -21,7 +21,7 @@ #include "SceneParser/tachyon/Model.h" #include "SceneParser/tachyon/Loc.h" -#include "common/vec.h" +#include "ospcommon/vec.h" extern int yydebug; diff --git a/apps/common/commandline/SceneParser/trianglemesh/TriangleMeshSceneParser.cpp b/apps/common/commandline/SceneParser/trianglemesh/TriangleMeshSceneParser.cpp index 422c9c3d3d..6270cb3c0e 100644 --- a/apps/common/commandline/SceneParser/trianglemesh/TriangleMeshSceneParser.cpp +++ b/apps/common/commandline/SceneParser/trianglemesh/TriangleMeshSceneParser.cpp @@ -44,13 +44,13 @@ static void warnMaterial(const std::string &type) TriangleMeshSceneParser::TriangleMeshSceneParser(cpp::Renderer renderer, std::string geometryType) : - m_renderer(renderer), - m_geometryType(geometryType), - m_alpha(false), - m_createDefaultMaterial(true), - m_maxObjectsToConsider((uint32_t)-1), - m_forceInstancing(false), - m_msgModel(new miniSG::Model) + renderer(renderer), + geometryType(geometryType), + alpha(false), + shouldCreateDefaultMaterial(true), + maxObjectsToConsider((uint32_t)-1), + forceInstancing(false), + msgModel(new miniSG::Model) { } @@ -61,77 +61,83 @@ bool TriangleMeshSceneParser::parse(int ac, const char **&av) for (int i = 1; i < ac; i++) { const std::string arg = av[i]; if (arg == "--max-objects") { - m_maxObjectsToConsider = atoi(av[++i]); + maxObjectsToConsider = atoi(av[++i]); } else if (arg == "--force-instancing") { - m_forceInstancing = true; + forceInstancing = true; } else if (arg == "--alpha") { - m_alpha = true; + alpha = true; } else if (arg == "--no-default-material") { - m_createDefaultMaterial = false; + shouldCreateDefaultMaterial = false; + } else if (arg == "--trianglemesh-type") { + geometryType = av[++i]; } else { FileName fn = arg; if (fn.ext() == "stl") { - miniSG::importSTL(*m_msgModel,fn); + miniSG::importSTL(*msgModel,fn); loadedScene = true; } else if (fn.ext() == "msg") { - miniSG::importMSG(*m_msgModel,fn); + miniSG::importMSG(*msgModel,fn); loadedScene = true; } else if (fn.ext() == "tri") { - miniSG::importTRI(*m_msgModel,fn); + miniSG::importTRI(*msgModel,fn); loadedScene = true; } else if (fn.ext() == "xml") { - miniSG::importRIVL(*m_msgModel,fn); + miniSG::importRIVL(*msgModel,fn); loadedScene = true; } else if (fn.ext() == "obj") { - miniSG::importOBJ(*m_msgModel,fn); + miniSG::importOBJ(*msgModel,fn); loadedScene = true; } else if (fn.ext() == "hbp") { - miniSG::importHBP(*m_msgModel,fn); + miniSG::importHBP(*msgModel,fn); loadedScene = true; } else if (fn.ext() == "x3d") { - miniSG::importX3D(*m_msgModel,fn); + miniSG::importX3D(*msgModel,fn); loadedScene = true; } else if (fn.ext() == "astl") { - miniSG::importSTL(m_msgAnimation,fn); + miniSG::importSTL(msgAnimation,fn); loadedScene = true; } } } - if (loadedScene) finalize(); + if (loadedScene) { + sceneModel = make_unique(); + finalize(); + } + return loadedScene; } cpp::Model TriangleMeshSceneParser::model() const { - return m_model; + return sceneModel.get() == nullptr ? cpp::Model() : *sceneModel; } ospcommon::box3f TriangleMeshSceneParser::bbox() const { - return m_msgModel.ptr->getBBox(); + return msgModel.ptr->getBBox(); } cpp::Material -TriangleMeshSceneParser::createDefaultMaterial(cpp::Renderer renderer) +TriangleMeshSceneParser::createDefaultMaterial(cpp::Renderer ren) { - if(!m_createDefaultMaterial) return nullptr; + if(!shouldCreateDefaultMaterial) return nullptr; static auto ospMat = cpp::Material(nullptr); if (ospMat.handle()) return ospMat; - ospMat = renderer.newMaterial("OBJMaterial"); + ospMat = ren.newMaterial("OBJMaterial"); ospMat.set("Kd", .8f, 0.f, 0.f); ospMat.commit(); return ospMat; } -cpp::Material TriangleMeshSceneParser::createMaterial(cpp::Renderer renderer, +cpp::Material TriangleMeshSceneParser::createMaterial(cpp::Renderer ren, miniSG::Material *mat) { - if (mat == nullptr) return createDefaultMaterial(renderer); + if (mat == nullptr) return createDefaultMaterial(ren); static std::map alreadyCreatedMaterials; @@ -144,10 +150,10 @@ cpp::Material TriangleMeshSceneParser::createMaterial(cpp::Renderer renderer, cpp::Material ospMat; try { - ospMat = alreadyCreatedMaterials[mat] = renderer.newMaterial(type); + ospMat = alreadyCreatedMaterials[mat] = ren.newMaterial(type); } catch (const std::runtime_error &/*e*/) { warnMaterial(type); - return createDefaultMaterial(renderer); + return createDefaultMaterial(ren); } const bool isOBJMaterial = !strcmp(type, "OBJMaterial"); @@ -204,36 +210,36 @@ void TriangleMeshSceneParser::finalize() // contain instances bool doesInstancing = 0; - if (m_forceInstancing) { + if (forceInstancing) { doesInstancing = true; - } else if (m_msgModel->instance.size() > m_msgModel->mesh.size()) { + } else if (msgModel->instance.size() > msgModel->mesh.size()) { doesInstancing = true; } else { doesInstancing = false; } - if (m_msgModel->instance.size() > m_maxObjectsToConsider) { - m_msgModel->instance.resize(m_maxObjectsToConsider); + if (msgModel->instance.size() > maxObjectsToConsider) { + msgModel->instance.resize(maxObjectsToConsider); if (!doesInstancing) { - m_msgModel->mesh.resize(m_maxObjectsToConsider); + msgModel->mesh.resize(maxObjectsToConsider); } } std::vector instanceModels; - for (size_t i=0;imesh.size();i++) { - Ref msgMesh = m_msgModel->mesh[i]; + for (size_t i=0;imesh.size();i++) { + Ref msgMesh = msgModel->mesh[i]; // create ospray mesh - auto ospMesh = m_alpha ? cpp::Geometry("alpha_aware_triangle_mesh") : - cpp::Geometry(m_geometryType); + auto ospMesh = alpha ? cpp::Geometry("alpha_aware_triangle_mesh") : + cpp::Geometry(geometryType); // check if we have to transform the vertices: if (doesInstancing == false && - m_msgModel->instance[i] != miniSG::Instance(i)) { + msgModel->instance[i] != miniSG::Instance(i)) { for (size_t vID = 0; vID < msgMesh->position.size(); vID++) { - msgMesh->position[vID] = xfmPoint(m_msgModel->instance[i].xfm, + msgMesh->position[vID] = xfmPoint(msgModel->instance[i].xfm, msgMesh->position[vID]); } } @@ -291,7 +297,7 @@ void TriangleMeshSceneParser::finalize() // add triangle material id array to mesh if (msgMesh->materialList.empty()) { // we have a single material for this mesh... - auto singleMaterial = createMaterial(m_renderer, msgMesh->material.ptr); + auto singleMaterial = createMaterial(renderer, msgMesh->material.ptr); ospMesh.setMaterial(singleMaterial); } else { // we have an entire material list, assign that list @@ -299,7 +305,7 @@ void TriangleMeshSceneParser::finalize() std::vector alphaMaps; std::vector alphas; for (size_t i = 0; i < msgMesh->materialList.size(); i++) { - auto m = createMaterial(m_renderer, msgMesh->materialList[i].ptr); + auto m = createMaterial(renderer, msgMesh->materialList[i].ptr); auto handle = m.handle(); materialList.push_back(handle); @@ -334,7 +340,7 @@ void TriangleMeshSceneParser::finalize() // only set these if alpha aware mode enabled // this currently doesn't work on the MICs! - if(m_alpha) { + if(alpha) { auto ospAlphaMapList = cpp::Data(alphaMaps.size(), OSP_OBJECT, &alphaMaps[0]); @@ -355,18 +361,18 @@ void TriangleMeshSceneParser::finalize() model_i.commit(); instanceModels.push_back(model_i.handle()); } else { - m_model.addGeometry(ospMesh); + sceneModel->addGeometry(ospMesh); } } if (doesInstancing) { - for (size_t i = 0; i < m_msgModel->instance.size(); i++) { + for (size_t i = 0; i < msgModel->instance.size(); i++) { OSPGeometry inst = - ospNewInstance(instanceModels[m_msgModel->instance[i].meshID], - reinterpret_cast(m_msgModel->instance[i].xfm)); - m_model.addGeometry(inst); + ospNewInstance(instanceModels[msgModel->instance[i].meshID], + reinterpret_cast(msgModel->instance[i].xfm)); + sceneModel->addGeometry(inst); } } - m_model.commit(); + sceneModel->commit(); } diff --git a/apps/common/commandline/SceneParser/trianglemesh/TriangleMeshSceneParser.h b/apps/common/commandline/SceneParser/trianglemesh/TriangleMeshSceneParser.h index f1f907c369..794a1ed884 100644 --- a/apps/common/commandline/SceneParser/trianglemesh/TriangleMeshSceneParser.h +++ b/apps/common/commandline/SceneParser/trianglemesh/TriangleMeshSceneParser.h @@ -38,21 +38,22 @@ class OSPRAY_COMMANDLINE_INTERFACE TriangleMeshSceneParser : public SceneParser ospray::cpp::Material createMaterial(ospray::cpp::Renderer renderer, ospray::miniSG::Material *mat); - ospray::cpp::Model m_model; - ospray::cpp::Renderer m_renderer; + ospray::cpp::Renderer renderer; - std::string m_geometryType; + std::unique_ptr sceneModel; - bool m_alpha; - bool m_createDefaultMaterial; - unsigned int m_maxObjectsToConsider; + std::string geometryType; + + bool alpha; + bool shouldCreateDefaultMaterial; + unsigned int maxObjectsToConsider; // if turned on, we'll put each triangle mesh into its own instance, // no matter what - bool m_forceInstancing; + bool forceInstancing; - ospcommon::Ref m_msgModel; - std::vector m_msgAnimation; + ospcommon::Ref msgModel; + std::vector msgAnimation; void finalize(); }; diff --git a/apps/common/commandline/SceneParser/volume/VolumeSceneParser.cpp b/apps/common/commandline/SceneParser/volume/VolumeSceneParser.cpp index 3714ed018b..f44b5b3292 100644 --- a/apps/common/commandline/SceneParser/volume/VolumeSceneParser.cpp +++ b/apps/common/commandline/SceneParser/volume/VolumeSceneParser.cpp @@ -33,7 +33,7 @@ using std::endl; // SceneParser definitions //////////////////////////////////////////////////// VolumeSceneParser::VolumeSceneParser(cpp::Renderer renderer) : - m_renderer(renderer) + renderer(renderer) { } @@ -47,21 +47,21 @@ bool VolumeSceneParser::parse(int ac, const char **&av) for (int i = 1; i < ac; i++) { const std::string arg = av[i]; if (arg == "-s" || arg == "--sampling-rate") { - m_samplingRate = atof(av[++i]); + samplingRate = atof(av[++i]); } else if (arg == "-tfc" || arg == "--tf-color") { ospcommon::vec4f color; color.x = atof(av[++i]); color.y = atof(av[++i]); color.z = atof(av[++i]); color.w = atof(av[++i]); - m_tf_colors.push_back(color); + tf_colors.push_back(color); } else if (arg == "-tfs" || arg == "--tf-scale") { - m_tf_scale = atof(av[++i]); + tf_scale = atof(av[++i]); } else if (arg == "-tff" || arg == "--tf-file") { importTransferFunction(std::string(av[++i])); loadedTransferFunction = true; } else if (arg == "-is" || arg == "--surface") { - m_isosurfaces.push_back(atof(av[++i])); + isosurfaces.push_back(atof(av[++i])); } else { FileName fn = arg; if (fn.ext() == "osp") { @@ -72,6 +72,7 @@ bool VolumeSceneParser::parse(int ac, const char **&av) } if (loadedScene) { + sceneModel = make_unique(); if (!loadedTransferFunction) { createDefaultTransferFunction(); } @@ -83,18 +84,18 @@ bool VolumeSceneParser::parse(int ac, const char **&av) cpp::Model VolumeSceneParser::model() const { - return m_model; + return sceneModel.get() == nullptr ? cpp::Model() : *sceneModel; } ospcommon::box3f VolumeSceneParser::bbox() const { - return m_bbox; + return sceneBbox; } void VolumeSceneParser::importObjectsFromFile(const std::string &filename, bool loadedTransferFunction) { - auto &model = m_model; + auto &model = *sceneModel; // Load OSPRay objects from a file. ospray::importer::Group *imported = ospray::importer::import(filename); @@ -112,8 +113,8 @@ void VolumeSceneParser::importObjectsFromFile(const std::string &filename, auto volume = ospray::cpp::Volume(vol->handle); // For now we set the same transfer function on all volumes. - volume.set("transferFunction", m_tf); - volume.set("samplingRate", m_samplingRate); + volume.set("transferFunction", transferFunction); + volume.set("samplingRate", samplingRate); volume.commit(); // Add the loaded volume(s) to the model. @@ -123,17 +124,17 @@ void VolumeSceneParser::importObjectsFromFile(const std::string &filename, // opacity components of the transfer function if we didn't load a transfer // function for a file (in that case this is already set) if (!loadedTransferFunction) { - m_tf.set("valueRange", vol->voxelRange.x, vol->voxelRange.y); - m_tf.commit(); + transferFunction.set("valueRange", vol->voxelRange.x, vol->voxelRange.y); + transferFunction.commit(); } - //m_bbox.extend(vol->bounds); - m_bbox = vol->bounds; + //sceneBbox.extend(vol->bounds); + sceneBbox = vol->bounds; // Create any specified isosurfaces - if (!m_isosurfaces.empty()) { - auto isoValueData = ospray::cpp::Data(m_isosurfaces.size(), OSP_FLOAT, - m_isosurfaces.data()); + if (!isosurfaces.empty()) { + auto isoValueData = ospray::cpp::Data(isosurfaces.size(), OSP_FLOAT, + isosurfaces.data()); auto isoGeometry = ospray::cpp::Geometry("isosurfaces"); isoGeometry.set("isovalues", isoValueData); @@ -152,9 +153,10 @@ void VolumeSceneParser::importTransferFunction(const std::string &filename) tfn::TransferFunction fcn(filename); auto colorsData = ospray::cpp::Data(fcn.rgbValues.size(), OSP_FLOAT3, fcn.rgbValues.data()); - m_tf.set("colors", colorsData); + transferFunction = cpp::TransferFunction("piecewise_linear"); + transferFunction.set("colors", colorsData); - m_tf_scale = fcn.opacityScaling; + tf_scale = fcn.opacityScaling; // Sample the opacity values, taking 256 samples to match the volume viewer // the volume viewer does the sampling a bit differently so we match that // instead of what's done in createDefault @@ -189,33 +191,35 @@ void VolumeSceneParser::importTransferFunction(const std::string &filename) * (fcn.opacityValues[hi].y - fcn.opacityValues[lo].y); } } - opacityValues.push_back(m_tf_scale * opacity); + opacityValues.push_back(tf_scale * opacity); } auto opacityValuesData = ospray::cpp::Data(opacityValues.size(), OSP_FLOAT, opacityValues.data()); - m_tf.set("opacities", opacityValuesData); - m_tf.set("valueRange", vec2f(fcn.dataValueMin, fcn.dataValueMax)); + transferFunction.set("opacities", opacityValuesData); + transferFunction.set("valueRange", vec2f(fcn.dataValueMin, fcn.dataValueMax)); // Commit transfer function - m_tf.commit(); + transferFunction.commit(); } void VolumeSceneParser::createDefaultTransferFunction() { + transferFunction = cpp::TransferFunction("piecewise_linear"); + // Add colors std::vector colors; - if (m_tf_colors.empty()) { + if (tf_colors.empty()) { colors.emplace_back(0.f, 0.f, 0.f, 0.f); colors.emplace_back(0.9f, 0.9f, 0.9f, 1.f); } else { - colors = m_tf_colors; + colors = tf_colors; } std::vector colorsAsVec3; for (auto &c : colors) colorsAsVec3.emplace_back(c.x, c.y, c.z); auto colorsData = ospray::cpp::Data(colors.size(), OSP_FLOAT3, colorsAsVec3.data()); - m_tf.set("colors", colorsData); + transferFunction.set("colors", colorsData); // Add opacities std::vector opacityValues; @@ -234,13 +238,13 @@ void VolumeSceneParser::createDefaultTransferFunction() float opacity = (1-t)*v0 + t*v1; if (opacity > 1.f) opacity = 1.f; - opacityValues.push_back(m_tf_scale*opacity); + opacityValues.push_back(tf_scale*opacity); } auto opacityValuesData = ospray::cpp::Data(opacityValues.size(), OSP_FLOAT, opacityValues.data()); - m_tf.set("opacities", opacityValuesData); + transferFunction.set("opacities", opacityValuesData); // Commit transfer function - m_tf.commit(); + transferFunction.commit(); } diff --git a/apps/common/commandline/SceneParser/volume/VolumeSceneParser.h b/apps/common/commandline/SceneParser/volume/VolumeSceneParser.h index aaca3ba36c..1f0d3546e0 100644 --- a/apps/common/commandline/SceneParser/volume/VolumeSceneParser.h +++ b/apps/common/commandline/SceneParser/volume/VolumeSceneParser.h @@ -47,15 +47,16 @@ class OSPRAY_COMMANDLINE_INTERFACE VolumeSceneParser : public SceneParser // Data // - ospray::cpp::Renderer m_renderer; - ospray::cpp::Model m_model; - ospcommon::box3f m_bbox; + ospray::cpp::Renderer renderer; + ospcommon::box3f sceneBbox; - float m_samplingRate{0.125f}; + std::unique_ptr sceneModel; - float m_tf_scale{1.f}; - std::vector m_tf_colors; - std::vector m_isosurfaces; + float samplingRate{0.125f}; - ospray::cpp::TransferFunction m_tf{"piecewise_linear"}; + float tf_scale{1.f}; + std::vector tf_colors; + std::vector isosurfaces; + + ospray::cpp::TransferFunction transferFunction; }; diff --git a/apps/common/importer/CMakeLists.txt b/apps/common/importer/CMakeLists.txt index 834a688018..c0f3728bde 100644 --- a/apps/common/importer/CMakeLists.txt +++ b/apps/common/importer/CMakeLists.txt @@ -14,7 +14,7 @@ ## limitations under the License. ## ## ======================================================================== ## -OSPRAY_CREATE_LIBRARY(importer +OSPRAY_CREATE_LIBRARY(ospray_importer importOSP.cpp importRAW.cpp importRM.cpp diff --git a/apps/common/importer/Importer.h b/apps/common/importer/Importer.h index 7b9c5b9988..cceeabacd9 100644 --- a/apps/common/importer/Importer.h +++ b/apps/common/importer/Importer.h @@ -33,6 +33,8 @@ # define OSPIMPORTER_INTERFACE #endif +#define OSPRAY_APPS_IMPORTER_ENABLE_PRINTS 0 + namespace ospray { namespace importer { using namespace ospcommon; diff --git a/apps/common/importer/importRAW.cpp b/apps/common/importer/importRAW.cpp index ce4aa49d20..5cccd70e7e 100644 --- a/apps/common/importer/importRAW.cpp +++ b/apps/common/importer/importRAW.cpp @@ -47,13 +47,13 @@ namespace ospray { // Offset into the volume data file if any. if (volume->fileOffset > 0) fseek(file, volume->fileOffset, SEEK_SET); - + // Volume dimensions. - ospcommon::vec3i volumeDimensions = volume->dimensions; + ospcommon::vec3i volumeDimensions = volume->dimensions; assert(volumeDimensions != vec3i(0) && volumeDimensions != vec3i(-1)); - + // Voxel type string. - const char *voxelType = volume->voxelType.c_str(); + const char *voxelType = volume->voxelType.c_str(); // Voxel size in bytes. size_t voxelSize; @@ -75,8 +75,8 @@ namespace ospray { exitOnCondition(reduce_min(subvolumeOffsets) < 0 || reduce_max(subvolumeOffsets - volumeDimensions) >= 0, "invalid subvolume offsets"); - - ospcommon::vec3i subvolumeDimensions = volumeDimensions - subvolumeOffsets; + + ospcommon::vec3i subvolumeDimensions = volumeDimensions - subvolumeOffsets; if (volume->subVolumeDimensions != vec3i(-1)) subvolumeDimensions = volume->subVolumeDimensions; @@ -84,15 +84,15 @@ namespace ospray { reduce_max(subvolumeDimensions - (volumeDimensions - subvolumeOffsets)) > 0, "invalid subvolume dimension(s) specified"); - - ospcommon::vec3i subvolumeSteps = ospcommon::vec3i(1); + + ospcommon::vec3i subvolumeSteps = ospcommon::vec3i(1); if (volume->subVolumeSteps != vec3i(-1)) subvolumeSteps = volume->subVolumeSteps; exitOnCondition(reduce_min(subvolumeSteps) < 1 || reduce_max(subvolumeSteps - (volumeDimensions - subvolumeOffsets)) >= 0, "invalid subvolume steps"); - + bool useSubvolume = false; // Check for volume scale factor from the environment @@ -104,17 +104,19 @@ namespace ospray { throw std::runtime_error("Could not parse OSPRAY_RM_SCALE_FACTOR env-var. Must be of format" "xx (e.g '1.5x2x0.5')"); } +#if OSPRAY_APPS_IMPORTER_ENABLE_PRINTS std::cout << "#importRAW: got OSPRAY_VOLUME_SCALE_FACTOR env-var = {" << scaleFactor.x << ", " << scaleFactor.y << ", " << scaleFactor.z << "}\n"; +#endif volume->scaleFactor = scaleFactor; ospSetVec3f(volume->handle, "scaleFactor", (osp::vec3f&)volume->scaleFactor); } - + // The dimensions of the volume to be imported; this will be changed if a // subvolume is specified. ospcommon::vec3i importVolumeDimensions = volumeDimensions; - + if (reduce_max(subvolumeOffsets) > 0 || subvolumeDimensions != volumeDimensions || reduce_max(subvolumeSteps) > 1) { @@ -145,7 +147,9 @@ namespace ospray { } ospSetVec3i(volume->handle, "dimensions", (osp::vec3i&)dims); } +#if OSPRAY_APPS_IMPORTER_ENABLE_PRINTS PRINT(volumeDimensions); +#endif // To avoid hitting memory limits or exceeding the 2GB limit in MPIDevice::ospSetRegion we // set the volume data in at 1.5GB chunks @@ -170,13 +174,14 @@ namespace ospray { } } +#if OSPRAY_APPS_IMPORTER_ENABLE_PRINTS std::cout << "#importRAW: Reading volume in chunks of size {" << chunkDimensions.x << ", " << chunkDimensions.y << ", " << chunkDimensions.z << "}" << std::endl; +#endif if (!useSubvolume) { // Log out some progress stats after we've read LOG_PROGRESS_SIZE bytes (25GB) const size_t LOG_PROGRESS_SIZE = 25e9; - const size_t VOLUME_TOTAL_SIZE = voxelSize * volumeDimensions.x * volumeDimensions.y * volumeDimensions.z; size_t totalDataRead = 0; size_t dataSizeRead = 0; @@ -191,10 +196,12 @@ namespace ospray { remainderVoxels.x = volumeDimensions.x % chunkDimensions.x; remainderVoxels.y = volumeDimensions.y % chunkDimensions.y; remainderVoxels.z = volumeDimensions.z % chunkDimensions.z; +#if OSPRAY_APPS_IMPORTER_ENABLE_PRINTS std::cout << "#importRAW: Number of chunks on each axis = {" << numChunks.x << ", " << numChunks.y << ", " << numChunks.z << "}, remainderVoxels {" << remainderVoxels.x << ", " << remainderVoxels.y << ", " << remainderVoxels.z << "}, each chunk is " << chunkVoxels << " voxels " << std::endl; +#endif // Load and copy in each chunk of the volume data into the OSPRay volume for (int chunkz = 0; chunkz < numChunks.z; ++chunkz) { for (int chunky = 0; chunky < numChunks.y; ++chunky) { @@ -205,9 +212,15 @@ namespace ospray { if (dataSizeRead >= LOG_PROGRESS_SIZE){ totalDataRead += dataSizeRead; dataSizeRead = 0; - float percent = 100.0 * totalDataRead / static_cast(VOLUME_TOTAL_SIZE); +#if OSPRAY_APPS_IMPORTER_ENABLE_PRINTS + const size_t VOLUME_TOTAL_SIZE = + voxelSize * volumeDimensions.x * volumeDimensions.y * + volumeDimensions.z; + float percent = 100.0 * totalDataRead / + static_cast(VOLUME_TOTAL_SIZE); std::cout << "#importRAW: Have read " << totalDataRead * 1e-9 << "GB of " << VOLUME_TOTAL_SIZE * 1e-9 << "GB (" << percent << "%)" << std::endl; +#endif } // The end of the file may have been reached unexpectedly. @@ -308,8 +321,8 @@ namespace ospray { // } // // Copy subvolume row into the volume. - // ospcommon::vec3i region_lo(0, - // (i2 - subvolumeOffsets.y) / subvolumeSteps.y, + // ospcommon::vec3i region_lo(0, + // (i2 - subvolumeOffsets.y) / subvolumeSteps.y, // (i3 - subvolumeOffsets.z) / subvolumeSteps.z); // ospcommon::vec3i region_sz(importVolumeDimensions.x, 1, 1); // ospSetRegion(volume, @@ -326,12 +339,14 @@ namespace ospray { if (volume->scaleFactor != vec3f(1.f)) { volume->dimensions = vec3i(vec3f(volume->dimensions) * volume->scaleFactor); +#if OSPRAY_APPS_IMPORTER_ENABLE_PRINTS std::cout << "#importRAW: scaled volume to " << volume->dimensions << std::endl; +#endif } volume->bounds = ospcommon::empty; volume->bounds.extend(volume->gridOrigin); volume->bounds.extend(volume->gridOrigin+ vec3f(volume->dimensions) * volume->gridSpacing); - + #ifndef _WIN32 if (gzipped) pclose(file); @@ -339,8 +354,8 @@ namespace ospray { #endif fclose(file); // Return the volume. - + } - + } // ::ospray::vv } // ::ospray diff --git a/apps/common/importer/importRM.cpp b/apps/common/importer/importRM.cpp index 7e65450b28..8f8ea83f79 100644 --- a/apps/common/importer/importRM.cpp +++ b/apps/common/importer/importRM.cpp @@ -50,7 +50,7 @@ namespace ospray { uint8_t voxel[256*256*128]; }; - RMLoaderThreads(Volume *volume, const std::string &fileName, int numThreads=10) + RMLoaderThreads(Volume *volume, const std::string &fileName, int numThreads=10) : volume(volume), nextBlockID(0), nextPinID(0), numThreads(numThreads) { inFilesDir = fileName.substr(0, fileName.rfind('.')); @@ -119,7 +119,7 @@ namespace ospray { } } - void run() + void run() { int threadID = nextPinID.fetch_add(1); @@ -134,7 +134,9 @@ namespace ospray { int K = (blockID / 64); +#if OSPRAY_APPS_IMPORTER_ENABLE_PRINTS printf("[b%i:%i,%i,%i,(%i)]",blockID,I,J,K,threadID); +#endif loadBlock(*block,inFilesDir,blockID); ospcommon::vec2f blockRange(block->voxel[0]); @@ -185,7 +187,7 @@ namespace ospray { RMLoaderThreads(volume,fileName,numThreads); double t1 = ospcommon::getSysTime(); - std::cout << "done loading " << fileName + std::cout << "done loading " << fileName << ", needed " << (t1-t0) << " seconds" << std::endl; ospSet2f(volume->handle,"voxelRange",volume->voxelRange.x,volume->voxelRange.y); diff --git a/apps/common/loaders/CMakeLists.txt b/apps/common/loaders/CMakeLists.txt index 17029cf56d..e5ce066d42 100644 --- a/apps/common/loaders/CMakeLists.txt +++ b/apps/common/loaders/CMakeLists.txt @@ -16,7 +16,7 @@ CONFIGURE_OSPRAY() -OSPRAY_CREATE_LIBRARY(loaders +OSPRAY_CREATE_LIBRARY(ospray_loaders ObjectFile.cpp OSPObjectFile.cpp PLYTriangleMeshFile.cpp diff --git a/apps/common/miniSG/importOBJ.cpp b/apps/common/miniSG/importOBJ.cpp index fcdf3b3776..0e61dd9ca5 100644 --- a/apps/common/miniSG/importOBJ.cpp +++ b/apps/common/miniSG/importOBJ.cpp @@ -304,7 +304,7 @@ namespace ospray { if (!strncmp(token, "map_Ks" , 6)) { parseSepOpt(token += 6); cur->setParam("map_Ks", loadTexture(path, std::string(token)),Material::Param::TEXTURE); continue; } /*! the following are extensions to the standard */ if (!strncmp(token, "map_Refl" , 8)) { parseSepOpt(token += 8); cur->setParam("map_Refl", loadTexture(path, std::string(token)),Material::Param::TEXTURE); continue; } - if (!strncmp(token, "map_Bump" , 8)) { parseSepOpt(token += 8); cur->setParam("map_Bump", loadTexture(path, std::string(token), true),Material::Param::TEXTURE); continue; } + if (!strncmp(token, "map_Bump" , 8) || !strncmp(token, "map_bump" , 8)) { parseSepOpt(token += 8); cur->setParam("map_Bump", loadTexture(path, std::string(token), true),Material::Param::TEXTURE); continue; } if (!strncmp(token, "bumpMap" , 7)) { parseSepOpt(token += 7); cur->setParam("map_Bump", loadTexture(path, std::string(token), true),Material::Param::TEXTURE); continue; } if (!strncmp(token, "colorMap" , 8)) { parseSepOpt(token += 8); cur->setParam("map_Kd", loadTexture(path, std::string(token)),Material::Param::TEXTURE); continue; } diff --git a/apps/common/miniSG/importRIVL.cpp b/apps/common/miniSG/importRIVL.cpp index ee5ca52e6e..013d6ec18a 100644 --- a/apps/common/miniSG/importRIVL.cpp +++ b/apps/common/miniSG/importRIVL.cpp @@ -662,7 +662,6 @@ namespace ospray { t.v0 = tm->triangle[i].x; t.v1 = tm->triangle[i].y; t.v2 = tm->triangle[i].z; - mesh->triangle[i] = t; assert(mesh->triangle[i].v0 >= 0 @@ -700,7 +699,6 @@ namespace ospray { } } model.mesh.push_back(mesh); - if (tm->material.size() == 1) { mesh->material = tm->material[0].ptr->general; } else { diff --git a/apps/common/miniSG/importX3D.cpp b/apps/common/miniSG/importX3D.cpp index 14a0967597..6fdfb13fe4 100644 --- a/apps/common/miniSG/importX3D.cpp +++ b/apps/common/miniSG/importX3D.cpp @@ -118,8 +118,8 @@ namespace ospray { continue; } - throw std::runtime_error("importX3D: unknown child type '" - + node->name + "' to 'IndexedFaceSet' node"); + std::cout << "importX3D: unknown child type '" << node->name + << "' to 'IndexedFaceSet' node\n"; } model.mesh.push_back(mesh); diff --git a/apps/common/miniSG/miniSG.cpp b/apps/common/miniSG/miniSG.cpp index 9a304402ab..a2c2c2ff8f 100644 --- a/apps/common/miniSG/miniSG.cpp +++ b/apps/common/miniSG/miniSG.cpp @@ -27,477 +27,489 @@ using namespace Magick; #endif namespace ospray { -namespace miniSG { - -Texture2D::Texture2D() - : channels(0) - , depth(0) - , width(0) - , height(0) - , data(nullptr) -{} - -Material::Material() -{ - // setParam( "Kd", vec3f(.7f) ); - // setParam( "Ks", vec3f(0.f) ); - // setParam( "Ka", vec3f(0.f) ); -} - -Texture2D *loadTexture(const std::string &_path, const std::string &fileNameBase, const bool prefereLinear) -{ - std::string path = _path; - FileName fileName = path+"/"+fileNameBase; - - if (fileNameBase.size() > 0) { + namespace miniSG { + + Texture2D::Texture2D() + : channels(0) + , depth(0) + , width(0) + , height(0) + , data(nullptr) + {} + + Material::Material() + { + // setParam( "Kd", vec3f(.7f) ); + // setParam( "Ks", vec3f(0.f) ); + // setParam( "Ka", vec3f(0.f) ); + } + + Texture2D *loadTexture(const std::string &_path, const std::string &fileNameBase, const bool prefereLinear) + { + std::string path = _path; + FileName fileName = path+"/"+fileNameBase; + + if (fileNameBase.size() > 0) { if (fileNameBase.substr(0,1) == "/") {// Absolute path. - fileName = fileNameBase; - path = ""; + fileName = fileNameBase; + path = ""; } - } + } - static std::map textureCache; - if (textureCache.find(fileName.str()) != textureCache.end()) + static std::map textureCache; + if (textureCache.find(fileName.str()) != textureCache.end()) return textureCache[fileName.str()]; - Texture2D *tex = nullptr; - const std::string ext = fileName.ext(); - if (ext == "ppm") { + Texture2D *tex = nullptr; + const std::string ext = fileName.ext(); + if (ext == "ppm") { try { - int rc, peekchar; - - // open file - FILE *file = fopen(fileName.str().c_str(),"rb"); - const int LINESZ=10000; - char lineBuf[LINESZ+1]; - - if (!file) - throw std::runtime_error("#osp:miniSG: could not open texture file '"+fileName.str()+"'."); - - // read format specifier: - int format=0; - rc = fscanf(file,"P%i\n",&format); - if (format != 6) - throw std::runtime_error("#osp:miniSG: can currently load only binary P6 subformats for PPM texture files. " - "Please report this bug at ospray.github.io."); - - // skip all comment lines - peekchar = getc(file); - while (peekchar == '#') { - auto tmp = fgets(lineBuf,LINESZ,file); - (void)tmp; - peekchar = getc(file); - } ungetc(peekchar,file); - - // read width and height from first non-comment line - int width=-1,height=-1; - rc = fscanf(file,"%i %i\n",&width,&height); - if (rc != 2) - throw std::runtime_error("#osp:miniSG: could not parse width and height in P6 PPM file '"+fileName.str()+"'. " - "Please report this bug at ospray.github.io, and include named file to reproduce the error."); - - // skip all comment lines + int rc, peekchar; + + // open file + FILE *file = fopen(fileName.str().c_str(),"rb"); + const int LINESZ=10000; + char lineBuf[LINESZ+1]; + + if (!file) + throw std::runtime_error("#osp:miniSG: could not open texture file '"+fileName.str()+"'."); + + // read format specifier: + int format=0; + rc = fscanf(file,"P%i\n",&format); + if (format != 6) + throw std::runtime_error("#osp:miniSG: can currently load only binary P6 subformats for PPM texture files. " + "Please report this bug at ospray.github.io."); + + // skip all comment lines + peekchar = getc(file); + while (peekchar == '#') { + auto tmp = fgets(lineBuf,LINESZ,file); + (void)tmp; peekchar = getc(file); - while (peekchar == '#') { - auto tmp = fgets(lineBuf,LINESZ,file); - (void)tmp; - peekchar = getc(file); - } ungetc(peekchar,file); - - // read maxval - int maxVal=-1; - rc = fscanf(file,"%i",&maxVal); + } ungetc(peekchar,file); + + // read width and height from first non-comment line + int width=-1,height=-1; + rc = fscanf(file,"%i %i\n",&width,&height); + if (rc != 2) + throw std::runtime_error("#osp:miniSG: could not parse width and height in P6 PPM file '"+fileName.str()+"'. " + "Please report this bug at ospray.github.io, and include named file to reproduce the error."); + + // skip all comment lines + peekchar = getc(file); + while (peekchar == '#') { + auto tmp = fgets(lineBuf,LINESZ,file); + (void)tmp; peekchar = getc(file); - - if (rc != 1) - throw std::runtime_error("#osp:miniSG: could not parse maxval in P6 PPM file '"+fileName.str()+"'. " - "Please report this bug at ospray.github.io, and include named file to reproduce the error."); - if (maxVal != 255) - throw std::runtime_error("#osp:miniSG: could not parse P6 PPM file '"+fileName.str()+"': currently supporting only maxVal=255 formats." - "Please report this bug at ospray.github.io, and include named file to reproduce the error."); - - tex = new Texture2D; - tex->width = width; - tex->height = height; - tex->channels = 3; - tex->depth = 1; - tex->prefereLinear = prefereLinear; - tex->data = new unsigned char[width*height*3]; - rc = fread(tex->data,width*height*3,1,file); - // flip in y, because OSPRay's textures have the origin at the lower left corner - unsigned char *texels = (unsigned char *)tex->data; - for (int y = 0; y < height/2; y++) - for (int x = 0; x < width*3; x++) - std::swap(texels[y*width*3+x], texels[(height-1-y)*width*3+x]); + } ungetc(peekchar,file); + + // read maxval + int maxVal=-1; + rc = fscanf(file,"%i",&maxVal); + peekchar = getc(file); + + if (rc != 1) + throw std::runtime_error("#osp:miniSG: could not parse maxval in P6 PPM file '"+fileName.str()+"'. " + "Please report this bug at ospray.github.io, and include named file to reproduce the error."); + if (maxVal != 255) + throw std::runtime_error("#osp:miniSG: could not parse P6 PPM file '"+fileName.str()+"': currently supporting only maxVal=255 formats." + "Please report this bug at ospray.github.io, and include named file to reproduce the error."); + + tex = new Texture2D; + tex->width = width; + tex->height = height; + tex->channels = 3; + tex->depth = 1; + tex->prefereLinear = prefereLinear; + tex->data = new unsigned char[width*height*3]; + rc = fread(tex->data,width*height*3,1,file); + // flip in y, because OSPRay's textures have the origin at the lower left corner + unsigned char *texels = (unsigned char *)tex->data; + for (int y = 0; y < height/2; y++) + for (int x = 0; x < width*3; x++) + std::swap(texels[y*width*3+x], texels[(height-1-y)*width*3+x]); } catch(std::runtime_error e) { - std::cerr << e.what() << std::endl; + std::cerr << e.what() << std::endl; } - } else if (ext == "pfm") { + } else if (ext == "pfm") { try { - // Note: the PFM file specification does not support comments thus we don't skip any - // http://netpbm.sourceforge.net/doc/pfm.html - int rc = 0; - FILE *file = fopen(fileName.str().c_str(), "rb"); - const int LINESZ = 10000; - char lineBuf[LINESZ + 1]; - if (!file) { - throw std::runtime_error("#osp:miniSG: could not open texture file '"+fileName.str()+"'."); - } - // read format specifier: - // PF: color floating point image - // Pf: grayscae floating point image - char format[2] = {0}; - fscanf(file, "%c%c\n", &format[0], &format[1]); - if (format[0] != 'P' || (format[1] != 'F' && format[1] != 'f')){ - throw std::runtime_error("#osp:miniSG: invalid pfm texture file, header is not PF or Pf"); - } - int numChannels = 3; - if (format[1] == 'f') { - numChannels = 1; - } - - // read width and height - int width = -1; - int height = -1; - rc = fscanf(file, "%i %i\n", &width, &height); - if (rc != 2) { - throw std::runtime_error("#osp:miniSG: could not parse width and height in PF PFM file '"+fileName.str()+"'. " - "Please report this bug at ospray.github.io, and include named file to reproduce the error."); - } - - // read scale factor/endiannes - float scaleEndian = 0.0; - rc = fscanf(file, "%f\n", &scaleEndian); - - if (rc != 1) { - throw std::runtime_error("#osp:miniSG: could not parse scale factor/endianness in PF PFM file '"+fileName.str()+"'. " - "Please report this bug at ospray.github.io, and include named file to reproduce the error."); - } - if (scaleEndian == 0.0) { - throw std::runtime_error("#osp:miniSG: scale factor/endianness in PF PFM file can not be 0"); - } - if (scaleEndian > 0.0) { - throw std::runtime_error("#osp:miniSG: could not parse PF PFM file '"+fileName.str()+"': currently supporting only little endian formats" - "Please report this bug at ospray.github.io, and include named file to reproduce the error."); - } - float scaleFactor = std::abs(scaleEndian); - - tex = new Texture2D; - tex->width = width; - tex->height = height; - tex->channels = numChannels; - tex->depth = sizeof(float); - tex->prefereLinear = prefereLinear; - tex->data = new unsigned char[width * height * numChannels * sizeof(float)]; - fread(tex->data, sizeof(float), width * height * numChannels, file); - // flip in y, because OSPRay's textures have the origin at the lower left corner - float *texels = (float *)tex->data; - for (size_t y = 0; y < height / 2; ++y) { - for (size_t x = 0; x < width * numChannels; ++x) { - // Scale the pixels by the scale factor - texels[y * width * numChannels + x] = texels[y * width * numChannels + x] * scaleFactor; - texels[(height - 1 - y) * width * numChannels + x] = texels[(height - 1 - y) * width * numChannels + x] * scaleFactor; - std::swap(texels[y * width * numChannels + x], texels[(height - 1 - y) * width * numChannels + x]); - } + // Note: the PFM file specification does not support comments thus we don't skip any + // http://netpbm.sourceforge.net/doc/pfm.html + int rc = 0; + FILE *file = fopen(fileName.str().c_str(), "rb"); + if (!file) { + throw std::runtime_error("#osp:miniSG: could not open texture file '"+fileName.str()+"'."); + } + // read format specifier: + // PF: color floating point image + // Pf: grayscae floating point image + char format[2] = {0}; + if (fscanf(file, "%c%c\n", &format[0], &format[1]) != 2) + throw std::runtime_error("could not fscanf"); + + if (format[0] != 'P' || (format[1] != 'F' && format[1] != 'f')){ + throw std::runtime_error("#osp:miniSG: invalid pfm texture file, header is not PF or Pf"); + } + int numChannels = 3; + if (format[1] == 'f') { + numChannels = 1; + } + + // read width and height + int width = -1; + int height = -1; + rc = fscanf(file, "%i %i\n", &width, &height); + if (rc != 2) { + throw std::runtime_error("#osp:miniSG: could not parse width and height in PF PFM file '"+fileName.str()+"'. " + "Please report this bug at ospray.github.io, and include named file to reproduce the error."); + } + + // read scale factor/endiannes + float scaleEndian = 0.0; + rc = fscanf(file, "%f\n", &scaleEndian); + + if (rc != 1) { + throw std::runtime_error("#osp:miniSG: could not parse scale factor/endianness in PF PFM file '"+fileName.str()+"'. " + "Please report this bug at ospray.github.io, and include named file to reproduce the error."); + } + if (scaleEndian == 0.0) { + throw std::runtime_error("#osp:miniSG: scale factor/endianness in PF PFM file can not be 0"); + } + if (scaleEndian > 0.0) { + throw std::runtime_error("#osp:miniSG: could not parse PF PFM file '"+fileName.str()+"': currently supporting only little endian formats" + "Please report this bug at ospray.github.io, and include named file to reproduce the error."); + } + float scaleFactor = std::abs(scaleEndian); + + tex = new Texture2D; + tex->width = width; + tex->height = height; + tex->channels = numChannels; + tex->depth = sizeof(float); + tex->prefereLinear = prefereLinear; + tex->data = new float[width * height * numChannels]; + if (fread(tex->data, sizeof(float), width * height * numChannels, file) + != width * height * numChannels) + throw std::runtime_error("could not fread"); + // flip in y, because OSPRay's textures have the origin at the lower left corner + float *texels = (float *)tex->data; + for (int y = 0; y < height / 2; ++y) { + for (int x = 0; x < width * numChannels; ++x) { + // Scale the pixels by the scale factor + texels[y * width * numChannels + x] = texels[y * width * numChannels + x] * scaleFactor; + texels[(height - 1 - y) * width * numChannels + x] = texels[(height - 1 - y) * width * numChannels + x] * scaleFactor; + std::swap(texels[y * width * numChannels + x], texels[(height - 1 - y) * width * numChannels + x]); } + } } catch(std::runtime_error e) { - std::cerr << e.what() << std::endl; + std::cerr << e.what() << std::endl; } - } - else { + } + else { #ifdef USE_IMAGEMAGICK Magick::Image image(fileName.str().c_str()); tex = new Texture2D; tex->width = image.columns(); tex->height = image.rows(); tex->channels = image.matte() ? 4 : 3; - tex->depth = 4; + const bool hdr = image.depth() > 8; + tex->depth = hdr ? 4 : 1; tex->prefereLinear = prefereLinear; float rcpMaxRGB = 1.0f/float(MaxRGB); const Magick::PixelPacket* pixels = image.getConstPixels(0,0,tex->width,tex->height); if (!pixels) { - std::cerr << "#osp:minisg: failed to load texture '"+fileName.str()+"'" << std::endl; - delete tex; - tex = nullptr; + std::cerr << "#osp:minisg: failed to load texture '"+fileName.str()+"'" << std::endl; + delete tex; + tex = nullptr; } else { - tex->data = new float[tex->width*tex->height*tex->channels]; - // convert pixels and flip image (because OSPRay's textures have the origin at the lower left corner) - for (size_t y=0; yheight; y++) { - for (size_t x=0; xwidth; x++) { - const Magick::PixelPacket &pixel = pixels[y*tex->width+x]; - float *dst = &((float*)tex->data)[(x+(tex->height-1-y)*tex->width)*tex->channels]; - *dst++ = pixel.red * rcpMaxRGB; - *dst++ = pixel.green * rcpMaxRGB; - *dst++ = pixel.blue * rcpMaxRGB; - if (tex->channels == 4) - *dst++ = pixel.opacity * rcpMaxRGB; - } + tex->data = new unsigned char[tex->width*tex->height*tex->channels*tex->depth]; + // convert pixels and flip image (because OSPRay's textures have the origin at the lower left corner) + for (size_t y=0; yheight; y++) { + for (size_t x=0; xwidth; x++) { + const Magick::PixelPacket &pixel = pixels[y*tex->width+x]; + if (hdr) { + float *dst = &((float*)tex->data)[(x+(tex->height-1-y)*tex->width)*tex->channels]; + *dst++ = pixel.red * rcpMaxRGB; + *dst++ = pixel.green * rcpMaxRGB; + *dst++ = pixel.blue * rcpMaxRGB; + if (tex->channels == 4) + *dst++ = pixel.opacity * rcpMaxRGB; + } else { + unsigned char *dst = &((unsigned char*)tex->data)[(x+(tex->height-1-y)*tex->width)*tex->channels]; + *dst++ = pixel.red; + *dst++ = pixel.green; + *dst++ = pixel.blue; + if (tex->channels == 4) + *dst++ = pixel.opacity; + } } + } } #endif + } + textureCache[fileName.str()] = tex; + return tex; } - textureCache[fileName.str()] = tex; - return tex; -} -float Material::getParam(const char *name, float defaultVal) -{ - ParamMap::iterator it = params.find(name); - if (it != params.end()) { + float Material::getParam(const char *name, float defaultVal) + { + ParamMap::iterator it = params.find(name); + if (it != params.end()) { assert( it->second->type == Param::FLOAT && "Param type mismatch" ); return it->second->f[0]; - } + } - return defaultVal; -} + return defaultVal; + } -vec2f Material::getParam(const char *name, vec2f defaultVal) -{ - ParamMap::iterator it = params.find(name); - if (it != params.end()) { + vec2f Material::getParam(const char *name, vec2f defaultVal) + { + ParamMap::iterator it = params.find(name); + if (it != params.end()) { assert( it->second->type == Param::FLOAT_2 && "Param type mismatch" ); return vec2f(it->second->f[0], it->second->f[1]); - } + } - return defaultVal; -} + return defaultVal; + } -vec3f Material::getParam(const char *name, vec3f defaultVal) -{ - ParamMap::iterator it = params.find(name); - if (it != params.end()) { + vec3f Material::getParam(const char *name, vec3f defaultVal) + { + ParamMap::iterator it = params.find(name); + if (it != params.end()) { assert( it->second->type == Param::FLOAT_3 && "Param type mismatch" ); return vec3f( it->second->f[0], it->second->f[1], it->second->f[2] ); - } + } - return defaultVal; -} + return defaultVal; + } -vec4f Material::getParam(const char *name, vec4f defaultVal) -{ - ParamMap::iterator it = params.find(name); - if (it != params.end()) { + vec4f Material::getParam(const char *name, vec4f defaultVal) + { + ParamMap::iterator it = params.find(name); + if (it != params.end()) { assert( it->second->type == Param::FLOAT_4 && "Param type mismatch" ); return vec4f( it->second->f[0], it->second->f[1], it->second->f[2], it->second->f[3] ); - } + } - return defaultVal; -} + return defaultVal; + } -int32_t Material::getParam(const char *name, int32_t defaultVal) -{ - ParamMap::iterator it = params.find(name); - if (it != params.end()) { + int32_t Material::getParam(const char *name, int32_t defaultVal) + { + ParamMap::iterator it = params.find(name); + if (it != params.end()) { assert( it->second->type == Param::INT && "Param type mismatch" ); return it->second->i[0]; - } + } - return defaultVal; -} + return defaultVal; + } -vec2i Material::getParam(const char *name, vec2i defaultVal) -{ - ParamMap::iterator it = params.find(name); - if (it != params.end()) { + vec2i Material::getParam(const char *name, vec2i defaultVal) + { + ParamMap::iterator it = params.find(name); + if (it != params.end()) { assert( it->second->type == Param::INT_2 && "Param type mismatch" ); return vec2i(it->second->i[0], it->second->i[1]); - } + } - return defaultVal; -} + return defaultVal; + } -vec3i Material::getParam(const char *name, vec3i defaultVal) -{ - ParamMap::iterator it = params.find(name); - if (it != params.end()) { + vec3i Material::getParam(const char *name, vec3i defaultVal) + { + ParamMap::iterator it = params.find(name); + if (it != params.end()) { assert( it->second->type == Param::INT_3 && "Param type mismatch" ); return vec3i(it->second->i[0], it->second->i[1], it->second->i[2]); - } + } - return defaultVal; -} + return defaultVal; + } -vec4i Material::getParam(const char *name, vec4i defaultVal) -{ - ParamMap::iterator it = params.find(name); - if (it != params.end()) { + vec4i Material::getParam(const char *name, vec4i defaultVal) + { + ParamMap::iterator it = params.find(name); + if (it != params.end()) { assert( it->second->type == Param::INT_4 && "Param type mismatch" ); return vec4i(it->second->i[0], it->second->i[1], it->second->i[2], it->second->i[3]); - } + } - return defaultVal; -} + return defaultVal; + } -uint32_t Material::getParam(const char *name, uint32_t defaultVal) -{ - ParamMap::iterator it = params.find(name); - if (it != params.end()) { + uint32_t Material::getParam(const char *name, uint32_t defaultVal) + { + ParamMap::iterator it = params.find(name); + if (it != params.end()) { assert( it->second->type == Param::UINT && "Param type mismatch" ); return it->second->ui[0]; - } + } - return defaultVal; -} + return defaultVal; + } -vec2ui Material::getParam(const char *name, vec2ui defaultVal) -{ - ParamMap::iterator it = params.find(name); - if (it != params.end()) { + vec2ui Material::getParam(const char *name, vec2ui defaultVal) + { + ParamMap::iterator it = params.find(name); + if (it != params.end()) { assert( it->second->type == Param::UINT_2 && "Param type mismatch" ); return vec2ui(it->second->ui[0], it->second->ui[1]); - } + } - return defaultVal; -} + return defaultVal; + } -vec3ui Material::getParam(const char *name, vec3ui defaultVal) -{ - ParamMap::iterator it = params.find(name); - if (it != params.end()) { + vec3ui Material::getParam(const char *name, vec3ui defaultVal) + { + ParamMap::iterator it = params.find(name); + if (it != params.end()) { assert( it->second->type == Param::UINT_3 && "Param type mismatch" ); return vec3ui(it->second->ui[0], it->second->ui[1], it->second->ui[2]); - } + } - return defaultVal; -} + return defaultVal; + } -vec4ui Material::getParam(const char *name, vec4ui defaultVal) -{ - ParamMap::iterator it = params.find(name); - if (it != params.end()) { + vec4ui Material::getParam(const char *name, vec4ui defaultVal) + { + ParamMap::iterator it = params.find(name); + if (it != params.end()) { assert( it->second->type == Param::UINT_4 && "Param type mismatch" ); return vec4ui(it->second->ui[0], it->second->ui[1], it->second->ui[2], it->second->ui[3]); - } + } - return defaultVal; -} + return defaultVal; + } -const char *Material::getParam(const char *name, const char *defaultVal) -{ - ParamMap::iterator it = params.find(name); - if (it != params.end()) { + const char *Material::getParam(const char *name, const char *defaultVal) + { + ParamMap::iterator it = params.find(name); + if (it != params.end()) { assert( it->second->type == Param::STRING && "Param type mismatch" ); return it->second->s; - } + } - return defaultVal; -} + return defaultVal; + } -void *Material::getParam(const char *name, void *defaultVal) -{ - ParamMap::iterator it = params.find(name); - if (it != params.end()) { + void *Material::getParam(const char *name, void *defaultVal) + { + ParamMap::iterator it = params.find(name); + if (it != params.end()) { assert( it->second->type == Param::TEXTURE /*|| other 'data' types*/&& "Param type mismatch" ); return it->second->ptr; - } + } - return defaultVal; -} + return defaultVal; + } -void error(const std::string &err) -{ - throw std::runtime_error("ospray::miniSG fatal error : "+err); -} + void error(const std::string &err) + { + throw std::runtime_error("ospray::miniSG fatal error : "+err); + } -bool operator==(const Instance &a, const Instance &b) -{ return a.meshID == b.meshID && a.xfm == b.xfm; } + bool operator==(const Instance &a, const Instance &b) + { return a.meshID == b.meshID && a.xfm == b.xfm; } -bool operator!=(const Instance &a, const Instance &b) -{ return !(a==b); } + bool operator!=(const Instance &a, const Instance &b) + { return !(a==b); } -/*! computes and returns the world-space bounding box of given mesh */ -box3f Mesh::getBBox() -{ - if (bounds.empty()) { + /*! computes and returns the world-space bounding box of given mesh */ + box3f Mesh::getBBox() + { + if (bounds.empty()) { for (size_t i = 0; i < position.size(); i++) - bounds.extend(position[i]); + bounds.extend(position[i]); + } + return bounds; } - return bounds; -} - -/*! computes and returns the world-space bounding box of the entire model */ -box3f Model::getBBox() -{ - // this does not yet properly support instancing with transforms! - box3f bBox = ospcommon::empty; - if (!instance.empty()) { + + /*! computes and returns the world-space bounding box of the entire model */ + box3f Model::getBBox() + { + // this does not yet properly support instancing with transforms! + box3f bBox = ospcommon::empty; + if (!instance.empty()) { std::vector meshBounds; for (size_t i = 0; i < mesh.size(); i++) - meshBounds.push_back(mesh[i]->getBBox()); + meshBounds.push_back(mesh[i]->getBBox()); for (size_t i = 0;i < instance.size(); i++) { - box3f b_i = meshBounds[instance[i].meshID]; - vec3f corner; - for (int iz=0;iz<2;iz++) { - corner.z = iz?b_i.upper.z:b_i.lower.z; - for (int iy=0;iy<2;iy++) { - corner.y = iy?b_i.upper.y:b_i.lower.y; - for (int ix=0;ix<2;ix++) { - corner.x = ix?b_i.upper.x:b_i.lower.x; - bBox.extend(xfmPoint(instance[i].xfm,corner)); - } - } + box3f b_i = meshBounds[instance[i].meshID]; + vec3f corner; + for (int iz=0;iz<2;iz++) { + corner.z = iz?b_i.upper.z:b_i.lower.z; + for (int iy=0;iy<2;iy++) { + corner.y = iy?b_i.upper.y:b_i.lower.y; + for (int ix=0;ix<2;ix++) { + corner.x = ix?b_i.upper.x:b_i.lower.x; + bBox.extend(xfmPoint(instance[i].xfm,corner)); + } } + } } - } else { + } else { for (size_t i = 0; i < mesh.size(); i++) - bBox.extend(mesh[i]->getBBox()); + bBox.extend(mesh[i]->getBBox()); + } + return bBox; } - return bBox; -} -size_t Model::numUniqueTriangles() const -{ - size_t sum = 0; - for (size_t i = 0; i < mesh.size(); i++) + size_t Model::numUniqueTriangles() const + { + size_t sum = 0; + for (size_t i = 0; i < mesh.size(); i++) sum += mesh[i]->triangle.size(); - return sum; -} + return sum; + } -OSPTexture2D createTexture2D(Texture2D *msgTex) -{ - if(msgTex == NULL) { + OSPTexture2D createTexture2D(Texture2D *msgTex) + { + if(msgTex == NULL) { static int numWarnings = 0; if (++numWarnings < 10) - std::cout << "WARNING: material does not have Textures (only warning for the first 10 times)!" << std::endl; + std::cout << "WARNING: material does not have Textures (only warning for the first 10 times)!" << std::endl; return NULL; - } + } - static std::map alreadyCreatedTextures; - if (alreadyCreatedTextures.find(msgTex) != alreadyCreatedTextures.end()) + static std::map alreadyCreatedTextures; + if (alreadyCreatedTextures.find(msgTex) != alreadyCreatedTextures.end()) return alreadyCreatedTextures[msgTex]; - //TODO: We need to come up with a better way to handle different possible pixel layouts - OSPTextureFormat type = OSP_TEXTURE_R8; + //TODO: We need to come up with a better way to handle different possible pixel layouts + OSPTextureFormat type = OSP_TEXTURE_R8; - if (msgTex->depth == 1) { + if (msgTex->depth == 1) { if( msgTex->channels == 1 ) type = OSP_TEXTURE_R8; if( msgTex->channels == 3 ) - type = msgTex->prefereLinear ? OSP_TEXTURE_RGB8 : OSP_TEXTURE_SRGB; + type = msgTex->prefereLinear ? OSP_TEXTURE_RGB8 : OSP_TEXTURE_SRGB; if( msgTex->channels == 4 ) - type = msgTex->prefereLinear ? OSP_TEXTURE_RGBA8 : OSP_TEXTURE_SRGBA; - } else if (msgTex->depth == 4) { + type = msgTex->prefereLinear ? OSP_TEXTURE_RGBA8 : OSP_TEXTURE_SRGBA; + } else if (msgTex->depth == 4) { if( msgTex->channels == 1 ) type = OSP_TEXTURE_R32F; if( msgTex->channels == 3 ) type = OSP_TEXTURE_RGB32F; if( msgTex->channels == 4 ) type = OSP_TEXTURE_RGBA32F; - } + } - vec2i texSize(msgTex->width, msgTex->height); - OSPTexture2D ospTex = ospNewTexture2D( (osp::vec2i&)texSize, - type, - msgTex->data, - 0); + vec2i texSize(msgTex->width, msgTex->height); + OSPTexture2D ospTex = ospNewTexture2D( (osp::vec2i&)texSize, + type, + msgTex->data, + 0); - alreadyCreatedTextures[msgTex] = ospTex; + alreadyCreatedTextures[msgTex] = ospTex; - ospCommit(ospTex); - //g_tex = ospTex; // remember last texture for debugging + ospCommit(ospTex); + //g_tex = ospTex; // remember last texture for debugging - return ospTex; -} + return ospTex; + } -} // ::ospray::minisg + } // ::ospray::minisg } // ::ospray diff --git a/apps/common/ospray_cpp/Camera.h b/apps/common/ospray_cpp/Camera.h index 9f1d384ee0..d0bf649ff2 100644 --- a/apps/common/ospray_cpp/Camera.h +++ b/apps/common/ospray_cpp/Camera.h @@ -36,7 +36,7 @@ inline Camera::Camera(const std::string &type) { OSPCamera c = ospNewCamera(type.c_str()); if (c) { - m_object = c; + ospObject = c; } else { throw std::runtime_error("Failed to create OSPCamera!"); } diff --git a/apps/common/ospray_cpp/Data.h b/apps/common/ospray_cpp/Data.h index b7171a7004..c55b468d73 100644 --- a/apps/common/ospray_cpp/Data.h +++ b/apps/common/ospray_cpp/Data.h @@ -36,7 +36,7 @@ class Data : public ManagedObject_T inline Data::Data(size_t numItems, OSPDataType format, const void *init, int flags) { - m_object = ospNewData(numItems, format, init, flags); + ospObject = ospNewData(numItems, format, init, flags); } inline Data::Data(const Data ©) : diff --git a/apps/common/ospray_cpp/FrameBuffer.h b/apps/common/ospray_cpp/FrameBuffer.h index e93c565a9d..21123ccc00 100644 --- a/apps/common/ospray_cpp/FrameBuffer.h +++ b/apps/common/ospray_cpp/FrameBuffer.h @@ -51,7 +51,7 @@ class FrameBuffer : public ManagedObject_T void free(); - bool m_owner = true; + bool owner = true; }; // Inlined function definitions /////////////////////////////////////////////// @@ -60,19 +60,19 @@ inline FrameBuffer::FrameBuffer(const osp::vec2i &size, OSPFrameBufferFormat format, int channels) { - m_object = ospNewFrameBuffer(size, format, channels); + ospObject = ospNewFrameBuffer(size, format, channels); } inline FrameBuffer::FrameBuffer(const FrameBuffer ©) : ManagedObject_T(copy.handle()), - m_owner(false) + owner(false) { } inline FrameBuffer::FrameBuffer(FrameBuffer &&move) : ManagedObject_T(move.handle()) { - move.m_object = nullptr; + move.ospObject = nullptr; } inline FrameBuffer::FrameBuffer(OSPFrameBuffer existing) : @@ -83,15 +83,15 @@ inline FrameBuffer::FrameBuffer(OSPFrameBuffer existing) : inline FrameBuffer& FrameBuffer::operator=(const FrameBuffer ©) { free(); - m_object = copy.m_object; + ospObject = copy.ospObject; return *this; } inline FrameBuffer& FrameBuffer::operator=(FrameBuffer &&move) { free(); - m_object = move.m_object; - move.m_object = nullptr; + ospObject = move.ospObject; + move.ospObject = nullptr; return *this; } @@ -127,7 +127,7 @@ inline void FrameBuffer::clear(uint32_t channel) inline void FrameBuffer::free() { - if (m_owner && handle()) { + if (owner && handle()) { ospFreeFrameBuffer(handle()); } } diff --git a/apps/common/ospray_cpp/Geometry.h b/apps/common/ospray_cpp/Geometry.h index fdd74f562a..cca66dfc55 100644 --- a/apps/common/ospray_cpp/Geometry.h +++ b/apps/common/ospray_cpp/Geometry.h @@ -40,7 +40,7 @@ inline Geometry::Geometry(const std::string &type) { OSPGeometry c = ospNewGeometry(type.c_str()); if (c) { - m_object = c; + ospObject = c; } else { throw std::runtime_error("Failed to create OSPGeometry!"); } diff --git a/apps/common/ospray_cpp/ManagedObject.h b/apps/common/ospray_cpp/ManagedObject.h index cbc4312904..1ea4f768a4 100644 --- a/apps/common/ospray_cpp/ManagedObject.h +++ b/apps/common/ospray_cpp/ManagedObject.h @@ -64,6 +64,9 @@ namespace ospray { // OSPObject* virtual void set(const std::string &name, OSPObject v) = 0; + + // ManagedObject& + virtual void set(const std::string &name, const ManagedObject &v) = 0; //! Commit to ospray virtual void commit() const = 0; @@ -110,8 +113,7 @@ namespace ospray { void set(const std::string &name, OSPObject v) override; - template - void set(const std::string &name, const ManagedObject_T &v); + void set(const std::string &name, const ManagedObject &v) override; void commit() const override; @@ -122,14 +124,14 @@ namespace ospray { protected: - OSP_TYPE m_object; + OSP_TYPE ospObject; }; - // Inlined function definitions /////////////////////////////////////////////// + // Inlined function definitions /////////////////////////////////////////// template inline ManagedObject_T::ManagedObject_T(OSP_TYPE object) : - m_object(object) + ospObject(object) { using OSPObject_T = typename std::remove_pointer::type; using OtherOSP_T = typename std::remove_pointer::type; @@ -149,141 +151,139 @@ namespace ospray { inline void ManagedObject_T::set(const std::string &name, const std::string &v) { - ospSetString(m_object, name.c_str(), v.c_str()); + ospSetString(ospObject, name.c_str(), v.c_str()); } template inline void ManagedObject_T::set(const std::string &name, int v) { - ospSet1i(m_object, name.c_str(), v); + ospSet1i(ospObject, name.c_str(), v); } template inline void ManagedObject_T::set(const std::string &name, int v1, int v2) { - ospSet2i(m_object, name.c_str(), v1, v2); + ospSet2i(ospObject, name.c_str(), v1, v2); } template inline void ManagedObject_T::set(const std::string &name, int v1, int v2, int v3) { - ospSet3i(m_object, name.c_str(), v1, v2, v3); + ospSet3i(ospObject, name.c_str(), v1, v2, v3); } template inline void ManagedObject_T::set(const std::string &name, float v) { - ospSet1f(m_object, name.c_str(), v); + ospSet1f(ospObject, name.c_str(), v); } template inline void ManagedObject_T::set(const std::string &name, float v1, float v2) { - ospSet2f(m_object, name.c_str(), v1, v2); + ospSet2f(ospObject, name.c_str(), v1, v2); } template inline void ManagedObject_T::set(const std::string &name, float v1, float v2, float v3) { - ospSet3f(m_object, name.c_str(), v1, v2, v3); + ospSet3f(ospObject, name.c_str(), v1, v2, v3); } template inline void ManagedObject_T::set(const std::string &name, double v) { - ospSet1f(m_object, name.c_str(), v); + ospSet1f(ospObject, name.c_str(), v); } template inline void ManagedObject_T::set(const std::string &name, double v1, double v2) { - ospSet2f(m_object, name.c_str(), v1, v2); + ospSet2f(ospObject, name.c_str(), v1, v2); } template inline void ManagedObject_T::set(const std::string &name, double v1, double v2, double v3) { - ospSet3f(m_object, name.c_str(), v1, v2, v3); + ospSet3f(ospObject, name.c_str(), v1, v2, v3); } template inline void ManagedObject_T::set(const std::string &name, const ospcommon::vec2i &v) { - ospSetVec2i(m_object, name.c_str(), (const osp::vec2i&)v); + ospSetVec2i(ospObject, name.c_str(), (const osp::vec2i&)v); } template inline void ManagedObject_T::set(const std::string &name, const ospcommon::vec2f &v) { - ospSetVec2f(m_object, name.c_str(), (const osp::vec2f&)v); + ospSetVec2f(ospObject, name.c_str(), (const osp::vec2f&)v); } template inline void ManagedObject_T::set(const std::string &name, const ospcommon::vec3i &v) { - ospSetVec3i(m_object, name.c_str(), (const osp::vec3i&)v); + ospSetVec3i(ospObject, name.c_str(), (const osp::vec3i&)v); } template inline void ManagedObject_T::set(const std::string &name, const ospcommon::vec3f &v) { - ospSetVec3f(m_object, name.c_str(), (const osp::vec3f&)v); + ospSetVec3f(ospObject, name.c_str(), (const osp::vec3f&)v); } template inline void ManagedObject_T::set(const std::string &name, const ospcommon::vec4f &v) { - ospSetVec4f(m_object, name.c_str(), (const osp::vec4f&)v); + ospSetVec4f(ospObject, name.c_str(), (const osp::vec4f&)v); } template inline void ManagedObject_T::set(const std::string &name, void *v) { - ospSetVoidPtr(m_object, name.c_str(), v); + ospSetVoidPtr(ospObject, name.c_str(), v); } template inline void ManagedObject_T::set(const std::string &name, OSPObject v) { - ospSetObject(m_object, name.c_str(), v); + ospSetObject(ospObject, name.c_str(), v); } template - template inline void - ManagedObject_T::set(const std::string &name, - const ManagedObject_T &v) + ManagedObject_T::set(const std::string &name, const ManagedObject &v) { - ospSetObject(m_object, name.c_str(), v.handle()); + ospSetObject(ospObject, name.c_str(), v.object()); } template inline void ManagedObject_T::commit() const { - ospCommit(m_object); + ospCommit(ospObject); } template OSPObject ManagedObject_T::object() const { - return (OSPObject)m_object; + return (OSPObject)ospObject; } template inline OSP_TYPE ManagedObject_T::handle() const { - return m_object; + return ospObject; } }// namespace cpp diff --git a/apps/common/ospray_cpp/Model.h b/apps/common/ospray_cpp/Model.h index 0635611067..c4c2861ca9 100644 --- a/apps/common/ospray_cpp/Model.h +++ b/apps/common/ospray_cpp/Model.h @@ -39,6 +39,9 @@ class Model : public ManagedObject_T void addVolume(Volume &v); void addVolume(OSPVolume v); + + void removeVolume(Volume &v); + void removeVolume(OSPVolume v); }; // Inlined function definitions /////////////////////////////////////////////// @@ -47,7 +50,7 @@ inline Model::Model() { OSPModel c = ospNewModel(); if (c) { - m_object = c; + ospObject = c; } else { throw std::runtime_error("Failed to create OSPModel!"); } @@ -93,5 +96,15 @@ inline void Model::addVolume(OSPVolume v) ospAddVolume(handle(), v); } +inline void Model::removeVolume(Volume &v) +{ + removeVolume(v.handle()); +} + +inline void Model::removeVolume(OSPVolume v) +{ + ospRemoveVolume(handle(), v); +} + }// namespace cpp }// namespace ospray diff --git a/apps/common/ospray_cpp/PixelOp.h b/apps/common/ospray_cpp/PixelOp.h index 64e66defae..32389f4987 100644 --- a/apps/common/ospray_cpp/PixelOp.h +++ b/apps/common/ospray_cpp/PixelOp.h @@ -37,7 +37,7 @@ inline PixelOp::PixelOp(const std::string &type) { OSPPixelOp c = ospNewPixelOp(type.c_str()); if (c) { - m_object = c; + ospObject = c; } else { throw std::runtime_error("Failed to create OSPPixelOp!"); } diff --git a/apps/common/ospray_cpp/Renderer.h b/apps/common/ospray_cpp/Renderer.h index 9ca3240aa8..d832297cc3 100644 --- a/apps/common/ospray_cpp/Renderer.h +++ b/apps/common/ospray_cpp/Renderer.h @@ -36,6 +36,8 @@ class Renderer : public ManagedObject_T Light newLight(const std::string &type); float renderFrame(const FrameBuffer &fb, uint32_t channels); + + OSPPickResult pick(const ospcommon::vec2f &screenPos); }; // Inlined function definitions /////////////////////////////////////////////// @@ -44,7 +46,7 @@ inline Renderer::Renderer(const std::string &type) { OSPRenderer c = ospNewRenderer(type.c_str()); if (c) { - m_object = c; + ospObject = c; } else { throw std::runtime_error("Failed to create OSPRenderer!"); } @@ -81,6 +83,13 @@ inline float Renderer::renderFrame(const FrameBuffer &fb, uint32_t channels) return ospRenderFrame(fb.handle(), handle(), channels); } +inline OSPPickResult Renderer::pick(const ospcommon::vec2f &screenPos) +{ + OSPPickResult result; + ospPick(&result, handle(), (const osp::vec2f&)screenPos); + return result; +} + }// namespace cpp }// namespace ospray diff --git a/apps/common/ospray_cpp/TransferFunction.h b/apps/common/ospray_cpp/TransferFunction.h index ddc5837294..371d21fe10 100644 --- a/apps/common/ospray_cpp/TransferFunction.h +++ b/apps/common/ospray_cpp/TransferFunction.h @@ -25,6 +25,7 @@ class TransferFunction : public ManagedObject_T { public: + TransferFunction(); TransferFunction(const std::string &type); TransferFunction(const TransferFunction ©); TransferFunction(OSPTransferFunction existing); @@ -32,11 +33,13 @@ class TransferFunction : public ManagedObject_T // Inlined function definitions /////////////////////////////////////////////// +inline TransferFunction::TransferFunction() {} + inline TransferFunction::TransferFunction(const std::string &type) { OSPTransferFunction c = ospNewTransferFunction(type.c_str()); if (c) { - m_object = c; + ospObject = c; } else { throw std::runtime_error("Failed to create OSPTransferFunction!"); } diff --git a/apps/common/ospray_cpp/Volume.h b/apps/common/ospray_cpp/Volume.h index 41305906da..a58c9dd706 100644 --- a/apps/common/ospray_cpp/Volume.h +++ b/apps/common/ospray_cpp/Volume.h @@ -16,6 +16,8 @@ #pragma once +#include + #include namespace ospray { @@ -28,6 +30,15 @@ class Volume : public ManagedObject_T Volume(const std::string &type); Volume(const Volume ©); Volume(OSPVolume existing); + + void setRegion(void *source, + const ospcommon::vec3i ®ionCoords, + const ospcommon::vec3i ®ionSize); + + void sampleVolume(float **results, + const ospcommon::vec3f *worldCoordinates, + size_t count); + std::vector sampleVolume(const std::vector &points); }; // Inlined function definitions /////////////////////////////////////////////// @@ -36,7 +47,7 @@ inline Volume::Volume(const std::string &type) { OSPVolume c = ospNewVolume(type.c_str()); if (c) { - m_object = c; + ospObject = c; } else { throw std::runtime_error("Failed to create OSPVolume!"); } @@ -52,5 +63,40 @@ inline Volume::Volume(OSPVolume existing) : { } +inline void Volume::setRegion(void *source, + const ospcommon::vec3i ®ionCoords, + const ospcommon::vec3i ®ionSize) +{ + ospSetRegion(handle(), + source, + (const osp::vec3i&)regionCoords, + (const osp::vec3i&)regionSize); +} + +inline void Volume::sampleVolume(float **results, + const ospcommon::vec3f *worldCoordinates, + size_t count) +{ + ospSampleVolume(results, + handle(), + (const osp::vec3f&)*worldCoordinates, + count); +} + +inline std::vector +Volume::sampleVolume(const std::vector &points) +{ + float *results = nullptr; + auto numPoints = points.size(); + sampleVolume(&results, points.data(), numPoints); + + if (!results) + throw std::runtime_error("Failed to sample volume!"); + + std::vector retval(points.size()); + memcpy(retval.data(), results, numPoints*sizeof(float)); + return retval; +} + }// namespace cpp }// namespace ospray diff --git a/apps/common/script/CMakeLists.txt b/apps/common/script/CMakeLists.txt index cf572fc655..704e9d1b3f 100644 --- a/apps/common/script/CMakeLists.txt +++ b/apps/common/script/CMakeLists.txt @@ -14,14 +14,23 @@ ## limitations under the License. ## ## ======================================================================== ## -ADD_LIBRARY(ospray_script +FIND_PACKAGE(Readline) + +SET(LIBS ospray_common ospray_tfn ospray ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS}) +INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/apps/common) + +IF(READLINE_FOUND) + ADD_DEFINITIONS(-DUSE_SYSTEM_READLINE) + INCLUDE_DIRECTORIES(${Readline_INCLUDE_DIR}) + SET(LIBS ${LIBS} ${Readline_LIBRARY}) +ELSE() + MESSAGE(STATUS "Readline NOT found, command history feature NOT enabled.") +ENDIF() + +OSPRAY_CREATE_LIBRARY(ospray_script OSPRayScriptHandler.cpp OSPRayScriptHandler.h +LINK + ${LIBS} ) -TARGET_LINK_LIBRARIES(ospray_script - ospray_common - ospray - ${CMAKE_THREAD_LIBS_INIT} - ${CMAKE_DL_LIBS} -) diff --git a/apps/common/script/OSPRayScriptHandler.cpp b/apps/common/script/OSPRayScriptHandler.cpp index e01001d693..890c07d18e 100644 --- a/apps/common/script/OSPRayScriptHandler.cpp +++ b/apps/common/script/OSPRayScriptHandler.cpp @@ -14,10 +14,13 @@ // limitations under the License. // // ======================================================================== // +#include "ospray/common/OSPCommon.h" #include "OSPRayScriptHandler.h" - +#include "ospcommon/vec.h" +#include "ospcommon/box.h" #include "chaiscript/chaiscript_stdlib.hpp" #include "chaiscript/utility/utility.hpp" +#include "tfn_lib/tfn_lib.h" using std::runtime_error; @@ -67,27 +70,23 @@ static void using_history(){} static std::string get_next_command() { std::string retval("quit"); - if ( ! std::cin.eof() ) { - char *input_raw = readline("% "); - if ( input_raw ) { - add_history(input_raw); - - std::string val(input_raw); - size_t pos = val.find_first_not_of("\t \n"); - if (pos != std::string::npos) - { - val.erase(0, pos); - } - pos = val.find_last_not_of("\t \n"); - if (pos != std::string::npos) - { - val.erase(pos+1, std::string::npos); - } + char *input_raw = readline("% "); + if (input_raw) { + add_history(input_raw); + + std::string val(input_raw); + size_t pos = val.find_first_not_of("\t \n"); + if (pos != std::string::npos) { + val.erase(0, pos); + } + pos = val.find_last_not_of("\t \n"); + if (pos != std::string::npos) { + val.erase(pos+1, std::string::npos); + } - retval = val; + retval = val; - ::free(input_raw); - } + ::free(input_raw); } return retval; } @@ -151,23 +150,104 @@ void ospCommit(OSPObject object) ::ospCommit(object); } +ospray::cpp::TransferFunction loadTransferFunction(const std::string &fname) { + using namespace ospcommon; + tfn::TransferFunction fcn(fname); + ospray::cpp::TransferFunction transferFunction("piecewise_linear"); + auto colorsData = ospray::cpp::Data(fcn.rgbValues.size(), OSP_FLOAT3, + fcn.rgbValues.data()); + transferFunction.set("colors", colorsData); + + const float tf_scale = fcn.opacityScaling; + // Sample the opacity values, taking 256 samples to match the volume viewer + // the volume viewer does the sampling a bit differently so we match that + // instead of what's done in createDefault + std::vector opacityValues; + const int N_OPACITIES = 256; + size_t lo = 0; + size_t hi = 1; + for (int i = 0; i < N_OPACITIES; ++i) { + const float x = float(i) / float(N_OPACITIES - 1); + float opacity = 0; + if (i == 0) { + opacity = fcn.opacityValues[0].y; + } else if (i == N_OPACITIES - 1) { + opacity = fcn.opacityValues.back().y; + } else { + // If we're over this val, find the next segment + if (x > fcn.opacityValues[lo].x) { + for (size_t j = lo; j < fcn.opacityValues.size() - 1; ++j) { + if (x <= fcn.opacityValues[j + 1].x) { + lo = j; + hi = j + 1; + break; + } + } + } + const float delta = x - fcn.opacityValues[lo].x; + const float interval = fcn.opacityValues[hi].x - fcn.opacityValues[lo].x; + if (delta == 0 || interval == 0) { + opacity = fcn.opacityValues[lo].y; + } else { + opacity = fcn.opacityValues[lo].y + delta / interval + * (fcn.opacityValues[hi].y - fcn.opacityValues[lo].y); + } + } + opacityValues.push_back(tf_scale * opacity); + } + + auto opacityValuesData = ospray::cpp::Data(opacityValues.size(), + OSP_FLOAT, + opacityValues.data()); + transferFunction.set("opacities", opacityValuesData); + transferFunction.set("valueRange", vec2f(fcn.dataValueMin, fcn.dataValueMax)); + transferFunction.commit(); + return transferFunction; +} + +// Get an string environment variable +std::string getEnvString(const std::string &var) { + return ospray::getEnvVar(var).second; +} + } // OSPRayScriptHandler definitions //////////////////////////////////////////// namespace ospray { +namespace script { + Module::Module(RegisterModuleFn registerMod, GetHelpFn getHelp) + : registerMod(registerMod), getHelp(getHelp) + {} + void Module::registerModule(chaiscript::ChaiScript &engine) { + registerMod(engine); + } + void Module::help() const { + if (getHelp) { + getHelp(); + } + } + + static std::vector SCRIPT_MODULES; + void register_module(RegisterModuleFn registerModule, GetHelpFn getHelp) { + SCRIPT_MODULES.push_back(Module(registerModule, getHelp)); + } +} + OSPRayScriptHandler::OSPRayScriptHandler(OSPModel model, OSPRenderer renderer, OSPCamera camera) : - m_model(model), - m_renderer(renderer), - m_camera(camera), - m_chai(chaiscript::Std_Lib::library()), - m_running(false) + model(model), + renderer(renderer), + camera(camera), + chai(chaiscript::Std_Lib::library()), + scriptRunning(false), + lock(scriptMutex, std::defer_lock_t()) { registerScriptTypes(); registerScriptFunctions(); + registerScriptObjects(); std::stringstream ss; ss << "Commands available:" << endl << endl; @@ -193,9 +273,11 @@ OSPRayScriptHandler::OSPRayScriptHandler(OSPModel model, ss << "ospSet3i(object, id, int, int, int)" << endl; ss << "ospSetVoidPtr(object, id, ptr)" << endl; ss << "ospCommit(object)" << endl; + ss << "TransferFunction loadTransferFunction(file)" << endl; + ss << "string getEnvString(env_var)" << endl; ss << endl; - m_helpText = ss.str(); + helpText = ss.str(); } OSPRayScriptHandler::~OSPRayScriptHandler() @@ -205,15 +287,13 @@ OSPRayScriptHandler::~OSPRayScriptHandler() void OSPRayScriptHandler::runScriptFromFile(const std::string &file) { - if (m_running) { + if (scriptRunning) { throw runtime_error("Cannot execute a script file when" " running interactively!"); } - registerScriptObjects(); - try { - m_chai.eval_file(file); + chai.eval_file(file); } catch (const chaiscript::exception::eval_error &e) { cerr << "ERROR: script '" << file << "' executed with error(s):" << endl; cerr << " " << e.what() << endl; @@ -222,8 +302,6 @@ void OSPRayScriptHandler::runScriptFromFile(const std::string &file) void OSPRayScriptHandler::consoleLoop() { - registerScriptObjects(); - using_history(); do { @@ -232,7 +310,10 @@ void OSPRayScriptHandler::consoleLoop() if (input == "done" || input == "exit" || input == "quit") { break; } else if (input == "help") { - cout << m_helpText << endl; + cout << helpText << endl; + for (const auto &m : script::SCRIPT_MODULES) { + m.help(); + } continue; } else { stringstream ss(input); @@ -246,27 +327,32 @@ void OSPRayScriptHandler::consoleLoop() runChaiLine(input); - } while (m_running); + } while (scriptRunning); + scriptRunning = false; cout << "**** EXIT COMMAND MODE *****" << endl; } void OSPRayScriptHandler::runChaiLine(const std::string &line) { + lock.lock(); try { - m_chai.eval(line); + chai.eval(line); } catch (const chaiscript::exception::eval_error &e) { cerr << e.what() << endl; } + lock.unlock(); } void OSPRayScriptHandler::runChaiFile(const std::string &file) { + lock.lock(); try { - m_chai.eval_file(file); + chai.eval_file(file); } catch (const std::runtime_error &e) { cerr << e.what() << endl; } + lock.unlock(); } void OSPRayScriptHandler::start() @@ -275,35 +361,43 @@ void OSPRayScriptHandler::start() cout << "**** START COMMAND MODE ****" << endl << endl; cout << "Type 'help' to see available objects and functions." << endl; cout << endl; - m_running = true; - m_thread = std::thread(&OSPRayScriptHandler::consoleLoop, this); + scriptRunning = true; + thread = std::thread(&OSPRayScriptHandler::consoleLoop, this); } void OSPRayScriptHandler::stop() { - m_running = false; - if (m_thread.joinable()) - m_thread.join(); + scriptRunning = false; + if (thread.joinable()){ + thread.join(); + } } bool OSPRayScriptHandler::running() { - return m_running; + return scriptRunning; } chaiscript::ChaiScript &OSPRayScriptHandler::scriptEngine() { - if (m_running) + if (scriptRunning) throw runtime_error("Cannot modify the script env while running!"); - return m_chai; + return chai; } void OSPRayScriptHandler::registerScriptObjects() { - m_chai.add(chaiscript::var(m_model), "m"); - m_chai.add(chaiscript::var(m_renderer), "r"); - m_chai.add(chaiscript::var(m_camera), "c"); + chai.add_global(chaiscript::var(model), "m"); + chai.add_global(chaiscript::var(renderer), "r"); + chai.add_global(chaiscript::var(camera), "c"); + chai.add_global_const(chaiscript::const_var(static_cast(OSP_FB_COLOR)), "OSP_FB_COLOR"); + chai.add_global_const(chaiscript::const_var(static_cast(OSP_FB_ACCUM)), "OSP_FB_ACCUM"); + chai.add_global_const(chaiscript::const_var(static_cast(OSP_FB_DEPTH)), "OSP_FB_DEPTH"); + chai.add_global_const(chaiscript::const_var(static_cast(OSP_FB_VARIANCE)), "OSP_FB_VARIANCE"); + for (auto &m : script::SCRIPT_MODULES) { + m.registerModule(chai); + } } void OSPRayScriptHandler::registerScriptTypes() @@ -330,7 +424,12 @@ void OSPRayScriptHandler::registerScriptTypes() {chaiscript::fun(static_cast(&ospray::cpp::ManagedObject::set)), "set"}, {chaiscript::fun(static_cast(&ospray::cpp::ManagedObject::set)), "set"}, {chaiscript::fun(static_cast(&ospray::cpp::ManagedObject::set)), "set"}, - //{chaiscript::fun(static_cast(&ospray::cpp::ManagedObject::set)), "set"}, + {chaiscript::fun(static_cast(&ospray::cpp::ManagedObject::set)), "set"}, + {chaiscript::fun(static_cast(&ospray::cpp::ManagedObject::set)), "set"}, + {chaiscript::fun(static_cast(&ospray::cpp::ManagedObject::set)), "set"}, + {chaiscript::fun(static_cast(&ospray::cpp::ManagedObject::set)), "set"}, + {chaiscript::fun(static_cast(&ospray::cpp::ManagedObject::set)), "set"}, + {chaiscript::fun(static_cast(&ospray::cpp::ManagedObject::set)), "set"}, {chaiscript::fun(&ospray::cpp::ManagedObject::commit), "commit"}, {chaiscript::fun(&ospray::cpp::ManagedObject::object), "handle"} } @@ -463,65 +562,137 @@ void OSPRayScriptHandler::registerScriptTypes() } ); - m_chai.add(m); + using namespace ospcommon; + chaiscript::utility::add_class(*m, "vec2i", + { + chaiscript::constructor(), + }, + { + {chaiscript::fun(static_cast(operator+)), "+"}, + {chaiscript::fun(static_cast(operator*)), "*"}, + {chaiscript::fun(static_cast(operator-)), "-"}, + {chaiscript::fun(static_cast(&vec2i::operator=)), "="}, + } + ); + + chaiscript::utility::add_class(*m, "vec2f", + { + chaiscript::constructor(), + }, + { + {chaiscript::fun(static_cast(operator+)), "+"}, + {chaiscript::fun(static_cast(operator*)), "*"}, + {chaiscript::fun(static_cast(operator-)), "-"}, + {chaiscript::fun(static_cast(&vec2f::operator=)), "="}, + } + ); + + chaiscript::utility::add_class(*m, "vec3i", + { + chaiscript::constructor(), + }, + { + {chaiscript::fun(static_cast(operator+)), "+"}, + {chaiscript::fun(static_cast(operator*)), "*"}, + {chaiscript::fun(static_cast(operator-)), "-"}, + {chaiscript::fun(static_cast(&vec3i::operator=)), "="}, + } + ); + + chaiscript::utility::add_class(*m, "vec3f", + { + chaiscript::constructor(), + }, + { + {chaiscript::fun(static_cast(operator+)), "+"}, + {chaiscript::fun(static_cast(operator*)), "*"}, + {chaiscript::fun(static_cast(operator-)), "-"}, + {chaiscript::fun(static_cast(&vec3f::operator=)), "="}, + } + ); + + chaiscript::utility::add_class(*m, "vec4f", + { + chaiscript::constructor(), + }, + { + {chaiscript::fun(static_cast(operator+)), "+"}, + {chaiscript::fun(static_cast(operator*)), "*"}, + {chaiscript::fun(static_cast(operator-)), "-"}, + {chaiscript::fun(static_cast(&vec4f::operator=)), "="}, + } + ); + + chaiscript::utility::add_class(*m, "box3f", + { + chaiscript::constructor(), + chaiscript::constructor(), + }, + { + } + ); + + chai.add(m); // Inheritance relationships // // osp objects - m_chai.add(chaiscript::base_class()); - m_chai.add(chaiscript::base_class()); - m_chai.add(chaiscript::base_class()); - m_chai.add(chaiscript::base_class()); - m_chai.add(chaiscript::base_class()); - m_chai.add(chaiscript::base_class()); - m_chai.add(chaiscript::base_class()); - m_chai.add(chaiscript::base_class()); - m_chai.add(chaiscript::base_class()); - m_chai.add(chaiscript::base_class()); + chai.add(chaiscript::base_class()); + chai.add(chaiscript::base_class()); + chai.add(chaiscript::base_class()); + chai.add(chaiscript::base_class()); + chai.add(chaiscript::base_class()); + chai.add(chaiscript::base_class()); + chai.add(chaiscript::base_class()); + chai.add(chaiscript::base_class()); + chai.add(chaiscript::base_class()); - m_chai.add(chaiscript::base_class()); - m_chai.add(chaiscript::base_class()); + chai.add(chaiscript::base_class()); + chai.add(chaiscript::base_class()); // ospray::cpp objects - m_chai.add(chaiscript::base_class()); - m_chai.add(chaiscript::base_class()); - m_chai.add(chaiscript::base_class()); - m_chai.add(chaiscript::base_class()); - m_chai.add(chaiscript::base_class()); - m_chai.add(chaiscript::base_class()); - m_chai.add(chaiscript::base_class()); - m_chai.add(chaiscript::base_class()); - m_chai.add(chaiscript::base_class()); - m_chai.add(chaiscript::base_class()); - m_chai.add(chaiscript::base_class()); - m_chai.add(chaiscript::base_class()); } void OSPRayScriptHandler::registerScriptFunctions() { - m_chai.add(chaiscript::fun(&chaiospray::ospLoadModule), "ospLoadModule"); - m_chai.add(chaiscript::fun(&chaiospray::ospSetString), "ospSetString" ); - m_chai.add(chaiscript::fun(&chaiospray::ospSetObject), "ospSetObject" ); - m_chai.add(chaiscript::fun(&chaiospray::ospSet1f), "ospSet1f" ); - m_chai.add(chaiscript::fun(&chaiospray::ospSet1i), "ospSet1i" ); - m_chai.add(chaiscript::fun(&chaiospray::ospSet2f), "ospSet2f" ); - m_chai.add(chaiscript::fun(&chaiospray::ospSet2i), "ospSet2i" ); - m_chai.add(chaiscript::fun(&chaiospray::ospSet3f), "ospSet3f" ); - m_chai.add(chaiscript::fun(&chaiospray::ospSet3i), "ospSet3i" ); - m_chai.add(chaiscript::fun(&chaiospray::ospSetVoidPtr), "ospSetVoidPtr"); - m_chai.add(chaiscript::fun(&chaiospray::ospCommit), "ospCommit" ); + chai.add(chaiscript::fun(&chaiospray::ospLoadModule), "ospLoadModule"); + chai.add(chaiscript::fun(&chaiospray::ospSetString), "ospSetString" ); + chai.add(chaiscript::fun(&chaiospray::ospSetObject), "ospSetObject" ); + chai.add(chaiscript::fun(&chaiospray::ospSet1f), "ospSet1f" ); + chai.add(chaiscript::fun(&chaiospray::ospSet1i), "ospSet1i" ); + chai.add(chaiscript::fun(&chaiospray::ospSet2f), "ospSet2f" ); + chai.add(chaiscript::fun(&chaiospray::ospSet2i), "ospSet2i" ); + chai.add(chaiscript::fun(&chaiospray::ospSet3f), "ospSet3f" ); + chai.add(chaiscript::fun(&chaiospray::ospSet3i), "ospSet3i" ); + chai.add(chaiscript::fun(&chaiospray::ospSetVoidPtr), "ospSetVoidPtr"); + chai.add(chaiscript::fun(&chaiospray::ospCommit), "ospCommit" ); + chai.add(chaiscript::fun(&chaiospray::loadTransferFunction), "loadTransferFunction"); + chai.add(chaiscript::fun(&chaiospray::getEnvString), "getEnvString"); } }// namespace ospray diff --git a/apps/common/script/OSPRayScriptHandler.h b/apps/common/script/OSPRayScriptHandler.h index e40e474dfd..75fffc3eb7 100644 --- a/apps/common/script/OSPRayScriptHandler.h +++ b/apps/common/script/OSPRayScriptHandler.h @@ -17,6 +17,7 @@ #pragma once #include +#include #include #include @@ -34,14 +35,50 @@ // ChaiScript #include "chaiscript/chaiscript.hpp" +#ifdef _WIN32 + #ifdef ospray_script_EXPORTS + #define OSPSCRIPT_INTERFACE __declspec(dllexport) + #else + #define OSPSCRIPT_INTERFACE __declspec(dllimport) + #endif +#else + #define OSPSCRIPT_INTERFACE +#endif + namespace ospray { -class OSPRayScriptHandler +// Protect some of the script module functionality under an additional namespace +namespace script { + using RegisterModuleFn = void (*)(chaiscript::ChaiScript&); + using GetHelpFn = void (*)(); + + class OSPSCRIPT_INTERFACE Module { + RegisterModuleFn registerMod; + GetHelpFn getHelp; + + public: + Module(RegisterModuleFn registerMod, GetHelpFn getHelp); + // Register the types, functions and objects exported by this module. + void registerModule(chaiscript::ChaiScript &engine); + // Print the modules help string via getHelp if a help callback was registered. + void help() const; + }; + + //! \brief Setup a modules scripting registration callbacks to be called when a script + //! thread begins or requests help. + //! + //! registerModule Register types, functions and global variables exported by the module + //! getHelp Print the modules help string to cout, detailing functions/types/objects. getHelp + // can be null if no help text will be provided. + OSPSCRIPT_INTERFACE void register_module(RegisterModuleFn registerModule, GetHelpFn getHelp); +} + +class OSPSCRIPT_INTERFACE OSPRayScriptHandler { public: OSPRayScriptHandler(OSPModel model, OSPRenderer renderer, OSPCamera camera); - ~OSPRayScriptHandler(); + virtual ~OSPRayScriptHandler(); void runScriptFromFile(const std::string &file); @@ -50,6 +87,11 @@ class OSPRayScriptHandler bool running(); + //! \brief Mutex that can be used to protect against scripts trampling + //! scene data that is actively being used for rendering. Acquiring + //! this mutex will block scripts from running until it's released. + std::mutex scriptMutex; + protected: //! \brief ChaiScript engine, only accessable if the interactive thread isn't @@ -61,7 +103,10 @@ class OSPRayScriptHandler //! \note Child classes should append this string with any additional help //! text that is desired when 'help' is invoked in the script engine. - std::string m_helpText; + std::string helpText; + + //! \brief This scripts unique lock managing locking/unlocking of the scriptMutex + std::unique_lock lock; private: @@ -76,16 +121,16 @@ class OSPRayScriptHandler // Data // - cpp::Model m_model; - cpp::Renderer m_renderer; - cpp::Camera m_camera; + cpp::Model model; + cpp::Renderer renderer; + cpp::Camera camera; - chaiscript::ChaiScript m_chai; + chaiscript::ChaiScript chai; - bool m_running; + bool scriptRunning; //! \brief background thread to handle the scripting commands from the console - std::thread m_thread; + std::thread thread; }; }// namespace ospray diff --git a/apps/common/tfn_lib/CMakeLists.txt b/apps/common/tfn_lib/CMakeLists.txt index d0b8466bb1..6e1f6ef5cc 100644 --- a/apps/common/tfn_lib/CMakeLists.txt +++ b/apps/common/tfn_lib/CMakeLists.txt @@ -14,12 +14,18 @@ ## limitations under the License. ## ## ======================================================================== ## -OSPRAY_CREATE_LIBRARY(tfn tfn_lib.cpp LINK ospray_common) +OSPRAY_CREATE_LIBRARY(ospray_tfn tfn_lib.cpp LINK ospray_common) -OSPRAY_CREATE_APPLICATION(CvtParaViewTfcn - convertParaViewTfcn.cpp - jsoncpp.cpp -LINK - ospray_common - ospray_tfn +OPTION(OSPRAY_APPS_PARAVIEW_TFN_CVT + "Build ParaView to OSPRay viewer transfer function converter" + ON ) + +IF (OSPRAY_APPS_PARAVIEW_TFN_CVT) + OSPRAY_CREATE_APPLICATION(ospCvtParaViewTfcn + convertParaViewTfcn.cpp + jsoncpp.cpp + LINK + ospray_tfn + ) +ENDIF() diff --git a/apps/common/widgets/CMakeLists.txt b/apps/common/widgets/CMakeLists.txt index 725e9dd6b1..6fe25b2355 100644 --- a/apps/common/widgets/CMakeLists.txt +++ b/apps/common/widgets/CMakeLists.txt @@ -15,22 +15,17 @@ ## ======================================================================== ## IF (OSPRAY_MODULE_DISPLAY_WALD) - INCLUDE_DIRECTORIES(${DISPLAY_WALD_INCLUDE_DIR}) - ADD_DEFINITIONS(-DOSPRAY_DISPLAY_WALD=1) + INCLUDE_DIRECTORIES(${DISPLAY_WALD_INCLUDE_DIR}) + ADD_DEFINITIONS(-DOSPRAY_DISPLAY_WALD=1) ENDIF() - -SET(LIBS - ospray - ospray_common - ${OPENGL_LIBRARIES} - ${GLUT_LIBRARIES} - ) - -OSPRAY_CREATE_LIBRARY(glut3d +OSPRAY_CREATE_LIBRARY(ospray_glut3d Glut3dExport.h glut3D.cpp OSPGlutViewer.cpp - LINK - ${LIBS} +LINK + ospray + ospray_common + ${OPENGL_LIBRARIES} + ${GLUT_LIBRARIES} ) diff --git a/apps/common/widgets/OSPGlutViewer.cpp b/apps/common/widgets/OSPGlutViewer.cpp index e72219cf5e..7a1920fb58 100644 --- a/apps/common/widgets/OSPGlutViewer.cpp +++ b/apps/common/widgets/OSPGlutViewer.cpp @@ -1,4 +1,5 @@ // ======================================================================== // +// Copyright 2016 SURVICE Engineering Company // // Copyright 2016 Intel Corporation // // // // Licensed under the Apache License, Version 2.0 (the "License"); // @@ -55,47 +56,45 @@ namespace ospray { OSPGlutViewer::OSPGlutViewer(const box3f &worldBounds, cpp::Model model, cpp::Renderer renderer, cpp::Camera camera) : Glut3DWidget(Glut3DWidget::FRAMEBUFFER_NONE), - m_model(model), - m_fb(nullptr), - m_renderer(renderer), - m_camera(camera), - m_queuedRenderer(nullptr), - m_alwaysRedraw(true), - m_accumID(-1), - m_fullScreen(false), - m_useDisplayWall(false) + sceneModel(model), + frameBuffer(nullptr), + renderer(renderer), + camera(camera), + queuedRenderer(nullptr), + alwaysRedraw(true), + fullScreen(false) { setWorldBounds(worldBounds); - m_renderer.set("world", m_model); - m_renderer.set("model", m_model); - m_renderer.set("camera", m_camera); - m_renderer.commit(); + renderer.set("world", sceneModel); + renderer.set("model", sceneModel); + renderer.set("camera", camera); + renderer.commit(); #if 0 cout << "#ospGlutViewer: set world bounds " << worldBounds << ", motion speed " << motionSpeed << endl; #endif - m_resetAccum = false; + resetAccum = false; } void OSPGlutViewer::setRenderer(OSPRenderer renderer) { - lock_guard lock{m_rendererMutex}; - m_queuedRenderer = renderer; + lock_guard lock{rendererMutex}; + queuedRenderer = renderer; } void OSPGlutViewer::resetAccumulation() { - m_resetAccum = true; + resetAccum = true; } void OSPGlutViewer::toggleFullscreen() { - m_fullScreen = !m_fullScreen; + fullScreen = !fullScreen; - if(m_fullScreen) { + if(fullScreen) { glutFullScreen(); } else { glutPositionWindow(0,10); @@ -104,7 +103,7 @@ void OSPGlutViewer::toggleFullscreen() void OSPGlutViewer::resetView() { - viewPort = m_viewPort; + viewPort = glutViewPort; } void OSPGlutViewer::printViewport() @@ -118,56 +117,24 @@ void OSPGlutViewer::printViewport() void OSPGlutViewer::saveScreenshot(const std::string &basename) { - const uint32_t *p = (uint32_t*)m_fb.map(OSP_FB_COLOR); - writePPM(basename + ".ppm", m_windowSize.x, m_windowSize.y, p); + const uint32_t *p = (uint32_t*)frameBuffer.map(OSP_FB_COLOR); + writePPM(basename + ".ppm", windowSize.x, windowSize.y, p); cout << "#ospGlutViewer: saved current frame to '" << basename << ".ppm'" << endl; } -void OSPGlutViewer::setDisplayWall(const OSPGlutViewer::DisplayWall &dw) -{ - displayWall = dw; - m_useDisplayWall = true; -} - void OSPGlutViewer::reshape(const vec2i &newSize) { Glut3DWidget::reshape(newSize); - m_windowSize = newSize; - m_fb = cpp::FrameBuffer(osp::vec2i{newSize.x, newSize.y}, OSP_FB_SRGBA, - OSP_FB_COLOR | OSP_FB_DEPTH | OSP_FB_ACCUM); - - m_fb.clear(OSP_FB_ACCUM); - - /*! for now, let's just attach the pixel op to the _main_ frame - buffer - eventually we need to have a _second_ frame buffer - of the proper (much higher) size, but for now let's just use - the existing one... */ - if (m_useDisplayWall && displayWall.fb.handle() != m_fb.handle()) { - PRINT(displayWall.size); - displayWall.fb = - ospray::cpp::FrameBuffer((const osp::vec2i&)displayWall.size, - OSP_FB_NONE, + windowSize = newSize; + frameBuffer = cpp::FrameBuffer(osp::vec2i{newSize.x, newSize.y}, + OSP_FB_SRGBA, OSP_FB_COLOR | OSP_FB_DEPTH | OSP_FB_ACCUM); - displayWall.fb.clear(OSP_FB_ACCUM); - - if (displayWall.po.handle() == nullptr) { -#if OSPRAY_DISPLAY_WALD - displayWall.po = ospray::cpp::PixelOp("display_wald"); -#else - displayWall.po = ospray::cpp::PixelOp("display_wall"); -#endif - displayWall.po.set("hostname", displayWall.hostname); - displayWall.po.set("streamName", displayWall.streamName); - displayWall.po.commit(); - } - - displayWall.fb.setPixelOp(displayWall.po); - } + frameBuffer.clear(OSP_FB_ACCUM); - m_camera.set("aspect", viewPort.aspect); - m_camera.commit(); + camera.set("aspect", viewPort.aspect); + camera.commit(); viewPort.modified = true; forceRedraw(); } @@ -176,7 +143,7 @@ void OSPGlutViewer::keypress(char key, const vec2i &where) { switch (key) { case 'R': - m_alwaysRedraw = !m_alwaysRedraw; + alwaysRedraw = !alwaysRedraw; forceRedraw(); break; case '!': @@ -209,6 +176,9 @@ void OSPGlutViewer::keypress(char key, const vec2i &where) viewPort.modified = true; forceRedraw(); break; + case 'c': + viewPort.modified = true;//Reset accumulation + break; case 'f': toggleFullscreen(); break; @@ -234,7 +204,7 @@ void OSPGlutViewer::mouseButton(int32_t whichButton, vec2f normpos = vec2f(pos.x / (float)windowSize.x, 1.0f - pos.y / (float)windowSize.y); OSPPickResult pick; - ospPick(&pick, m_renderer.handle(), + ospPick(&pick, renderer.handle(), osp::vec2f{normpos.x, normpos.y}); if(pick.hit) { viewPort.at = ospcommon::vec3f{pick.position.x, @@ -249,7 +219,7 @@ void OSPGlutViewer::mouseButton(int32_t whichButton, void OSPGlutViewer::display() { - if (!m_fb.handle() || !m_renderer.handle()) return; + if (!frameBuffer.handle() || !renderer.handle()) return; static int frameID = 0; @@ -260,17 +230,17 @@ void OSPGlutViewer::display() // call (which in itself will not do a lot other than triggering // work), but the average time between the two calls is roughly the // frame rate (including display overhead, of course) - if (frameID > 0) m_fps.doneRender(); + if (frameID > 0) fps.doneRender(); // NOTE: consume a new renderer if one has been queued by another thread switchRenderers(); - if (m_resetAccum) { - m_fb.clear(OSP_FB_ACCUM); - m_resetAccum = false; + if (resetAccum) { + frameBuffer.clear(OSP_FB_ACCUM); + resetAccum = false; } - m_fps.startRender(); + fps.startRender(); //} ++frameID; @@ -278,45 +248,39 @@ void OSPGlutViewer::display() if (viewPort.modified) { static bool once = true; if(once) { - m_viewPort = viewPort; + glutViewPort = viewPort; once = false; } - Assert2(m_camera.handle(),"ospray camera is null"); - m_camera.set("pos", viewPort.from); + Assert2(camera.handle(),"ospray camera is null"); + camera.set("pos", viewPort.from); auto dir = viewPort.at - viewPort.from; - m_camera.set("dir", dir); - m_camera.set("up", viewPort.up); - m_camera.set("aspect", viewPort.aspect); - m_camera.commit(); - viewPort.modified = false; - m_accumID=0; - m_fb.clear(OSP_FB_ACCUM); + camera.set("dir", dir); + camera.set("up", viewPort.up); + camera.set("aspect", viewPort.aspect); + camera.set("fovy", viewPort.openingAngle); + camera.commit(); - if (m_useDisplayWall) - displayWall.fb.clear(OSP_FB_ACCUM); + viewPort.modified = false; + frameBuffer.clear(OSP_FB_ACCUM); } - m_renderer.renderFrame(m_fb, OSP_FB_COLOR | OSP_FB_ACCUM); - if (m_useDisplayWall) { - m_renderer.renderFrame(displayWall.fb, OSP_FB_COLOR | OSP_FB_ACCUM); - } - ++m_accumID; + renderer.renderFrame(frameBuffer, OSP_FB_COLOR | OSP_FB_ACCUM); // set the glut3d widget's frame buffer to the opsray frame buffer, // then display - ucharFB = (uint32_t *)m_fb.map(OSP_FB_COLOR); + ucharFB = (uint32_t *)frameBuffer.map(OSP_FB_COLOR); frameBufferMode = Glut3DWidget::FRAMEBUFFER_UCHAR; Glut3DWidget::display(); - m_fb.unmap(ucharFB); + frameBuffer.unmap(ucharFB); // that pointer is no longer valid, so set it to null ucharFB = nullptr; std::string title("OSPRay GLUT Viewer"); - if (m_alwaysRedraw) { - title += " (" + std::to_string((long double)m_fps.getFPS()) + " fps)"; + if (alwaysRedraw) { + title += " (" + std::to_string((long double)fps.getFPS()) + " fps)"; setTitle(title); forceRedraw(); } else { @@ -326,12 +290,12 @@ void OSPGlutViewer::display() void OSPGlutViewer::switchRenderers() { - lock_guard lock{m_rendererMutex}; + lock_guard lock{rendererMutex}; - if (m_queuedRenderer.handle()) { - m_renderer = m_queuedRenderer; - m_queuedRenderer = nullptr; - m_fb.clear(OSP_FB_ACCUM); + if (queuedRenderer.handle()) { + renderer = queuedRenderer; + queuedRenderer = nullptr; + frameBuffer.clear(OSP_FB_ACCUM); } } diff --git a/apps/common/widgets/OSPGlutViewer.h b/apps/common/widgets/OSPGlutViewer.h index 342c4b4047..116ec8fd81 100644 --- a/apps/common/widgets/OSPGlutViewer.h +++ b/apps/common/widgets/OSPGlutViewer.h @@ -52,19 +52,6 @@ namespace ospray { void printViewport(); void saveScreenshot(const std::string &basename); - // Helper types // - - struct DisplayWall - { - std::string hostname; - std::string streamName; - ospcommon::vec2i size{-1}; - ospray::cpp::FrameBuffer fb; - ospray::cpp::PixelOp po; - } displayWall; - - void setDisplayWall(const DisplayWall &dw); - protected: virtual void reshape(const ospcommon::vec2i &newSize) override; @@ -72,36 +59,29 @@ namespace ospray { virtual void mouseButton(int32_t whichButton, bool released, const ospcommon::vec2i &pos) override; - private: - - // Private functions // - void display() override; void switchRenderers(); // Data // - cpp::Model m_model; - cpp::FrameBuffer m_fb; - cpp::Renderer m_renderer; - cpp::Camera m_camera; - - ospray::glut3D::FPSCounter m_fps; + cpp::Model sceneModel; + cpp::FrameBuffer frameBuffer; + cpp::Renderer renderer; + cpp::Camera camera; - std::mutex m_rendererMutex; - cpp::Renderer m_queuedRenderer; + ospray::glut3D::FPSCounter fps; - bool m_alwaysRedraw; + std::mutex rendererMutex; + cpp::Renderer queuedRenderer; - ospcommon::vec2i m_windowSize; - int m_accumID; - bool m_fullScreen; - glut3D::Glut3DWidget::ViewPort m_viewPort; + bool alwaysRedraw; - std::atomic m_resetAccum; + ospcommon::vec2i windowSize; + bool fullScreen; + glut3D::Glut3DWidget::ViewPort glutViewPort; - bool m_useDisplayWall; + std::atomic resetAccum; }; }// namespace ospray diff --git a/apps/common/widgets/glut3D.cpp b/apps/common/widgets/glut3D.cpp index 1bdf0af2cc..411905966e 100644 --- a/apps/common/widgets/glut3D.cpp +++ b/apps/common/widgets/glut3D.cpp @@ -1,4 +1,5 @@ // ======================================================================== // +// Copyright 2016 SURVICE Engineering Company // // Copyright 2009-2016 Intel Corporation // // // // Licensed under the Apache License, Version 2.0 (the "License"); // @@ -32,7 +33,10 @@ # include # include // for usleep #endif +#include #include +#include +#include namespace ospray { @@ -156,7 +160,7 @@ namespace ospray { from(0,0,-1), at(0,0,0), up(upVectorFromCmdLine), - openingAngle(60.f*M_PI/360.f), + openingAngle(60.f), aspect(1.f) { frame = AffineSpace3fa::translate(from) * AffineSpace3fa(ospcommon::one); @@ -464,6 +468,54 @@ namespace ospray { removeArgs(*ac,(char **&)av,i,3); --i; continue; } + if (arg == "-v" || arg == "--view") { + std::ifstream fin(av[i+1]); + if (!fin.is_open()) + { + throw std::runtime_error("Failed to open \"" + + std::string(av[i+1]) + + "\" for reading"); + } + + if (!viewPortFromCmdLine) + viewPortFromCmdLine = new Glut3DWidget::ViewPort; + + auto& fx = viewPortFromCmdLine->from.x; + auto& fy = viewPortFromCmdLine->from.y; + auto& fz = viewPortFromCmdLine->from.z; + + auto& ax = viewPortFromCmdLine->at.x; + auto& ay = viewPortFromCmdLine->at.y; + auto& az = viewPortFromCmdLine->at.z; + + auto& ux = upVectorFromCmdLine.x; + auto& uy = upVectorFromCmdLine.y; + auto& uz = upVectorFromCmdLine.z; + + auto& fov = viewPortFromCmdLine->openingAngle; + + auto token = std::string(""); + while (fin >> token) + { + if (token == "-vp") + fin >> fx >> fy >> fz; + else if (token == "-vu") + fin >> ux >> uy >> uz; + else if (token == "-vi") + fin >> ax >> ay >> az; + else if (token == "-fv") + fin >> fov; + else + { + throw std::runtime_error("Unrecognized token: \"" + token + + '\"'); + } + } + + assert(i+1 < *ac); + removeArgs(*ac,(char **&)av, i, 2); --i; + continue; + } if (arg == "-vu") { upVectorFromCmdLine.x = atof(av[i+1]); upVectorFromCmdLine.y = atof(av[i+2]); diff --git a/apps/common/widgets/glut3D.h b/apps/common/widgets/glut3D.h index 296775a99d..fefd77871b 100644 --- a/apps/common/widgets/glut3D.h +++ b/apps/common/widgets/glut3D.h @@ -168,7 +168,7 @@ namespace ospray { vec3f from; vec3f at; vec3f up; - float openingAngle; //!< in radians, along Y direction + float openingAngle; //!< in degrees, along Y direction float aspect; //!< aspect ratio X:Y // float focalDistance; diff --git a/apps/common/xml/CMakeLists.txt b/apps/common/xml/CMakeLists.txt index e0478e133c..d09106c98b 100644 --- a/apps/common/xml/CMakeLists.txt +++ b/apps/common/xml/CMakeLists.txt @@ -14,4 +14,4 @@ ## limitations under the License. ## ## ======================================================================== ## -OSPRAY_CREATE_LIBRARY(xml XML.cpp LINK ospray_common) +OSPRAY_CREATE_LIBRARY(ospray_xml XML.cpp LINK ospray_common) diff --git a/apps/common/xml/XML.h b/apps/common/xml/XML.h index 46bd61dfeb..5a510a268c 100644 --- a/apps/common/xml/XML.h +++ b/apps/common/xml/XML.h @@ -62,10 +62,12 @@ namespace ospray { if (prop[i]->name == name) return true; return false; } - inline std::string getProp(const std::string &name) const { + + /*! return value of property with given name if present, else return 'fallbackValue' */ + inline std::string getProp(const std::string &name, const std::string &fallbackValue="") const { for (size_t i = 0; i < prop.size(); i++) if (prop[i]->name == name) return prop[i]->value; - return ""; + return fallbackValue; } /*! find properly with given name, and return as long ('l') diff --git a/apps/glutViewer/CMakeLists.txt b/apps/glutViewer/CMakeLists.txt index 147a987fc7..47de838cba 100644 --- a/apps/glutViewer/CMakeLists.txt +++ b/apps/glutViewer/CMakeLists.txt @@ -14,26 +14,9 @@ ## limitations under the License. ## ## ======================================================================== ## -FIND_PACKAGE(Readline) - -IF(READLINE_FOUND) - ADD_DEFINITIONS(-DUSE_SYSTEM_READLINE) - SET(Readline_INC ${Readline_INCLUDE_DIR}) - SET(Readline_LIB ${Readline_LIBRARY}) -ELSE() - MESSAGE(STATUS "Readline NOT found, command history feature NOT enabled.") -ENDIF() - -IF (OSPRAY_MODULE_DISPLAY_WALD) - INCLUDE_DIRECTORIES(${DISPLAY_WALD_DIR}) - ADD_DEFINITIONS(-DOSPRAY_DISPLAY_WALD=1) - CONFIGURE_MPI() -ENDIF() - INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_LIST_DIR} ${CMAKE_CURRENT_LIST_DIR}/script - ${Readline_INC} ) # -------------------------------------------- @@ -62,15 +45,10 @@ SET(LIBS ospray_importer ${OPENGL_LIBRARIES} ${GLUT_LIBRARIES} - ${Readline_LIB} ) IF (OSPRAY_APPS_ENABLE_SCRIPTING) LIST(APPEND LIBS ospray_script) ENDIF() -IF (OSPRAY_MODULE_DISPLAY_WALD) - LIST(APPEND LIBS ospray_displayWald_client) -ENDIF() - -OSPRAY_CREATE_APPLICATION(GlutViewer ${APP_SRCS} LINK ${LIBS}) +OSPRAY_CREATE_APPLICATION(ospGlutViewer ${APP_SRCS} LINK ${LIBS}) diff --git a/apps/glutViewer/GlutViewerScriptHandler.cpp b/apps/glutViewer/GlutViewerScriptHandler.cpp index 23ae6a3346..44c8dc56f1 100644 --- a/apps/glutViewer/GlutViewerScriptHandler.cpp +++ b/apps/glutViewer/GlutViewerScriptHandler.cpp @@ -25,9 +25,9 @@ namespace ospray { GlutViewerScriptHandler::GlutViewerScriptHandler(OSPModel model, OSPRenderer renderer, OSPCamera camera, - ScriptedOSPGlutViewer *viewer) + ScriptedOSPGlutViewer *viewer) : OSPRayScriptHandler(model, renderer, camera), - m_viewer(viewer) + viewer(viewer) { registerScriptFunctions(); @@ -39,9 +39,13 @@ namespace ospray { ss << "toggleFullScreen() --> toggle fullscreen mode" << endl; ss << "resetView() --> reset camera view" << endl; ss << "printViewport() --> print view params in the console" << endl; + ss << "renderFrame(n_frames) --> release the script lock and render 'n_frames' frames,\n" + << " then return to running the script." << endl; + ss << "setWorldBounds(bbox) --> set the world bounds to the specified box3f,\n" + << " repositioning the camera." << endl; ss << "screenshot(filename) --> save a screenshot (adds '.ppm')" << endl; - m_helpText += ss.str(); + helpText += ss.str(); } void GlutViewerScriptHandler::registerScriptFunctions() @@ -50,32 +54,57 @@ namespace ospray { // setRenderer() auto setRenderer = [&](ospray::cpp::Renderer &r) { - m_viewer->setRenderer((OSPRenderer)r.handle()); + viewer->setRenderer((OSPRenderer)r.handle()); }; // refresh() auto refresh = [&]() { - m_viewer->resetAccumulation(); + viewer->resetAccumulation(); }; // toggleFullscreen() auto toggleFullscreen = [&]() { - m_viewer->toggleFullscreen(); + viewer->toggleFullscreen(); }; // resetView() auto resetView = [&]() { - m_viewer->resetView(); + viewer->resetView(); }; // printViewport() auto printViewport = [&]() { - m_viewer->printViewport(); + viewer->printViewport(); + }; + + // renderFrame() + auto renderFrame = [&](const int n_frames) { + // Temporarily unlock the mutex and wait for the display + // loop to acquire it and render and wait til a n frames have finished + const int startFrame = viewer->getFrameID(); + lock.unlock(); + // Wait for n_frames to be rendered + while (startFrame + n_frames > viewer->getFrameID()); + lock.lock(); + }; + auto renderOneFrame = [&]() { + // Temporarily unlock the mutex and wait for the display + // loop to acquire it and render and wait til a n frames have finished + const int startFrame = viewer->getFrameID(); + lock.unlock(); + // Wait for n_frames to be rendered + while (startFrame + 1 > viewer->getFrameID()); + lock.lock(); + }; + + // setWorldBounds + auto setWorldBounds = [&](const ospcommon::box3f &box) { + viewer->setWorldBounds(box); }; // screenshot() auto screenshot = [&](const std::string &name) { - m_viewer->saveScreenshot(name); + viewer->saveScreenshot(name); }; chai.add(chaiscript::fun(setRenderer), "setRenderer" ); @@ -83,6 +112,9 @@ namespace ospray { chai.add(chaiscript::fun(toggleFullscreen), "toggleFullscreen"); chai.add(chaiscript::fun(resetView), "resetView" ); chai.add(chaiscript::fun(printViewport), "printViewport" ); + chai.add(chaiscript::fun(renderFrame), "renderFrame" ); + chai.add(chaiscript::fun(renderOneFrame), "renderFrame" ); + chai.add(chaiscript::fun(setWorldBounds), "setWorldBounds" ); chai.add(chaiscript::fun(screenshot), "screenshot" ); } diff --git a/apps/glutViewer/GlutViewerScriptHandler.h b/apps/glutViewer/GlutViewerScriptHandler.h index fc0dac36ce..c91e741c99 100644 --- a/apps/glutViewer/GlutViewerScriptHandler.h +++ b/apps/glutViewer/GlutViewerScriptHandler.h @@ -37,7 +37,7 @@ namespace ospray { // Data // - ScriptedOSPGlutViewer *m_viewer; + ScriptedOSPGlutViewer *viewer; }; }// namespace ospray diff --git a/apps/glutViewer/ScriptedOSPGlutViewer.cpp b/apps/glutViewer/ScriptedOSPGlutViewer.cpp index 063810684f..e0890a6ab1 100644 --- a/apps/glutViewer/ScriptedOSPGlutViewer.cpp +++ b/apps/glutViewer/ScriptedOSPGlutViewer.cpp @@ -22,12 +22,9 @@ namespace ospray { using std::cout; using std::endl; - using std::string; - using std::lock_guard; using std::mutex; - using namespace ospcommon; ScriptedOSPGlutViewer::ScriptedOSPGlutViewer(const box3f &worldBounds, @@ -36,20 +33,106 @@ namespace ospray { cpp::Camera camera, std::string scriptFileName) : OSPGlutViewer(worldBounds, model, renderer, camera), - m_scriptHandler(model.handle(), renderer.handle(), camera.handle(), this) + scriptHandler(model.handle(), renderer.handle(), camera.handle(), this), + frameID(0) { if (!scriptFileName.empty()) - m_scriptHandler.runScriptFromFile(scriptFileName); + scriptHandler.runScriptFromFile(scriptFileName); + } + + int ScriptedOSPGlutViewer::getFrameID() const { + return frameID.load(); + } + + void ScriptedOSPGlutViewer::display() { + if (!frameBuffer.handle() || !renderer.handle()) return; + + // We need to synchronize with the scripting engine so we don't + // get our scene data trampled on if scripting is running. + std::lock_guard lock(scriptHandler.scriptMutex); + + //{ + // note that the order of 'start' and 'end' here is + // (intentionally) reversed: due to our asynchrounous rendering + // you cannot place start() and end() _around_ the renderframe + // call (which in itself will not do a lot other than triggering + // work), but the average time between the two calls is roughly the + // frame rate (including display overhead, of course) + if (frameID.load() > 0) fps.doneRender(); + + // NOTE: consume a new renderer if one has been queued by another thread + switchRenderers(); + + if (resetAccum) { + frameBuffer.clear(OSP_FB_ACCUM); + resetAccum = false; + } + + fps.startRender(); + //} + + ++frameID; + + if (viewPort.modified) { + static bool once = true; + if(once) { + glutViewPort = viewPort; + once = false; + } + Assert2(camera.handle(),"ospray camera is null"); + camera.set("pos", viewPort.from); + auto dir = viewPort.at - viewPort.from; + camera.set("dir", dir); + camera.set("up", viewPort.up); + camera.set("aspect", viewPort.aspect); + camera.set("fovy", viewPort.openingAngle); + camera.commit(); + viewPort.modified = false; + frameBuffer.clear(OSP_FB_ACCUM); + } + + renderer.renderFrame(frameBuffer, OSP_FB_COLOR | OSP_FB_ACCUM); + + // set the glut3d widget's frame buffer to the opsray frame buffer, + // then display + ucharFB = (uint32_t *)frameBuffer.map(OSP_FB_COLOR); + frameBufferMode = Glut3DWidget::FRAMEBUFFER_UCHAR; + Glut3DWidget::display(); + + frameBuffer.unmap(ucharFB); + + // that pointer is no longer valid, so set it to null + ucharFB = nullptr; + + std::string title("OSPRay GLUT Viewer"); + + if (alwaysRedraw) { + title += " (" + std::to_string((long double)fps.getFPS()) + " fps)"; + setTitle(title); + forceRedraw(); + } else { + setTitle(title); + } } void ScriptedOSPGlutViewer::keypress(char key, const vec2i &where) { switch (key) { case ':': - if (!m_scriptHandler.running()) { - m_scriptHandler.start(); + if (!scriptHandler.running()) { + scriptHandler.start(); } break; + case 27 /*ESC*/: + case 'q': + case 'Q': + if (scriptHandler.running()) { + std::cout << "Please exit command mode before quitting" + << " to avoid messing up your terminal\n"; + break; + } else { + std::exit(0); + } default: OSPGlutViewer::keypress(key,where); } diff --git a/apps/glutViewer/ScriptedOSPGlutViewer.h b/apps/glutViewer/ScriptedOSPGlutViewer.h index f360d8766e..27044aab07 100644 --- a/apps/glutViewer/ScriptedOSPGlutViewer.h +++ b/apps/glutViewer/ScriptedOSPGlutViewer.h @@ -16,6 +16,8 @@ #pragma once +#include + #include "common/widgets/OSPGlutViewer.h" #include "GlutViewerScriptHandler.h" @@ -29,11 +31,16 @@ namespace ospray { cpp::Model model, cpp::Renderer renderer, cpp::Camera camera, std::string scriptFileName = ""); + int getFrameID() const; + private: + void display() override; void keypress(char key, const ospcommon::vec2i &where) override; - GlutViewerScriptHandler m_scriptHandler; + GlutViewerScriptHandler scriptHandler; + + std::atomic frameID; }; }// namespace ospray diff --git a/apps/glutViewer/glutViewer.cpp b/apps/glutViewer/glutViewer.cpp index d29f91bf92..7d66baa202 100644 --- a/apps/glutViewer/glutViewer.cpp +++ b/apps/glutViewer/glutViewer.cpp @@ -22,10 +22,6 @@ # include "common/widgets/OSPGlutViewer.h" #endif -#if OSPRAY_DISPLAY_WALD -# include "client/Client.h" -#endif - std::string scriptFileFromCommandLine(int ac, const char **&av) { std::string scriptFileName; @@ -40,41 +36,6 @@ std::string scriptFileFromCommandLine(int ac, const char **&av) return scriptFileName; } -void parseForDisplayWall(int ac, const char **&av, ospray::OSPGlutViewer &v) -{ - for (int i = 1; i < ac; i++) { - const std::string arg = av[i]; - if (arg == "--display-wall") { - ospray::OSPGlutViewer::DisplayWall displayWall; -#if OSPRAY_DISPLAY_WALD - std::cout << "#osp.glutViewer: using displayWald-style display wall module" - << std::endl; - const std::string hostName = av[++i]; - const int portNo = 2903; /* todo: extract that from hostname if required */ - - std::cout << "#osp.glutViewer: trying to get display wall config from " - << hostName << ":" << portNo << std::endl; - ospray::dw::ServiceInfo service; - service.getFrom(hostName,portNo); - const ospcommon::vec2i size = service.totalPixelsInWall; - std::cout << "#osp.glutViewer: found display wald with " - << size.x << "x" << size.y << " pixels " - << "(" << ospcommon::prettyNumber(size.product()) << "pixels)" - << std::endl; - displayWall.hostname = service.mpiPortName; - displayWall.streamName = service.mpiPortName; - displayWall.size = size; -#else - displayWall.hostname = av[++i]; - displayWall.streamName = av[++i]; - displayWall.size.x = atof(av[++i]); - displayWall.size.y = atof(av[++i]); -#endif - v.setDisplayWall(displayWall); - } - } -} - int main(int ac, const char **av) { ospInit(&ac,av); @@ -99,7 +60,5 @@ int main(int ac, const char **av) #endif window.create("ospGlutViewer: OSPRay Mini-Scene Graph test viewer"); - parseForDisplayWall(ac, av, window); - ospray::glut3D::runGLUT(); } diff --git a/apps/qtViewer/CMakeLists.txt b/apps/qtViewer/CMakeLists.txt index d3f3ce12ac..fdcd59f5c4 100644 --- a/apps/qtViewer/CMakeLists.txt +++ b/apps/qtViewer/CMakeLists.txt @@ -52,7 +52,7 @@ SET(MOC_HEADERS QT4_WRAP_CPP(MOC_OUTFILES ${MOC_HEADERS}) -OSPRAY_CREATE_APPLICATION(QtViewer +OSPRAY_CREATE_APPLICATION(ospQtViewer ${SRCS} ${MOC_OUTFILES} LINK diff --git a/apps/qtViewer/ModelViewer.cpp b/apps/qtViewer/ModelViewer.cpp index 99cb2e5fc5..79170ace67 100644 --- a/apps/qtViewer/ModelViewer.cpp +++ b/apps/qtViewer/ModelViewer.cpp @@ -1,4 +1,5 @@ // ======================================================================== // +// Copyright 2016 SURVICE Engineering Company // // Copyright 2009-2016 Intel Corporation // // // // Licensed under the Apache License, Version 2.0 (the "License"); // @@ -433,10 +434,12 @@ namespace ospray { vec3f from = camera->getFrom(); vec3f up = camera->getUp(); vec3f at = camera->getAt(); + float fovy = camera->getFovy(); std::cout << "#osp:qtv: camera is" << " -vp " << from.x << " " << from.y << " " << from.z << " -vi " << at.x << " " << at.y << " " << at.z << " -vu " << up.x << " " << up.y << " " << up.z + << " -fv " << fovy << std::endl; } diff --git a/apps/qtViewer/main.cpp b/apps/qtViewer/main.cpp index 1507034cac..79c8868775 100644 --- a/apps/qtViewer/main.cpp +++ b/apps/qtViewer/main.cpp @@ -1,4 +1,5 @@ // ======================================================================== // +// Copyright 2016 SURVICE Engineering Company // // Copyright 2009-2016 Intel Corporation // // // // Licensed under the Apache License, Version 2.0 (the "License"); // @@ -26,6 +27,9 @@ #include "sg/module/Module.h" #include "sg/importer/Importer.h" +#include +#include + namespace ospray { namespace viewer { using std::cout; @@ -95,6 +99,51 @@ namespace ospray { sg::loadModule(argv[++argID]); } else if (arg == "--renderer") { integratorFromCommandLine = argv[++argID]; + } else if (arg == "-v") { + std::ifstream fin(argv[++argID]); + if (!fin.is_open()) + { + throw std::runtime_error("Failed to open \"" + + std::string(argv[argID]) + + "\" for reading"); + } + + if (!cameraFromCommandLine) cameraFromCommandLine = new sg::PerspectiveCamera; + + auto x = 0.f; + auto y = 0.f; + auto z = 0.f; + + auto token = std::string(""); + while (fin >> token) + { + if (token == "-vp") + { + fin >> x >> y >> z; + cameraFromCommandLine->setFrom(vec3f(x,y,z)); + } + else if (token == "-vu") + { + fin >> x >> y >> z; + cameraFromCommandLine->setUp(vec3f(x,y,z)); + } + else if (token == "-vi") + { + fin >> x >> y >> z; + upFromCommandLine = vec3f(x, y, z); + cameraFromCommandLine->setAt(upFromCommandLine); + } + else if (token == "-fv") + { + fin >> x; + cameraFromCommandLine->setFovy(x); + } + else + { + throw std::runtime_error("Unrecognized token: \"" + token + + '\"'); + } + } } else if (arg == "-vi") { if (!cameraFromCommandLine) cameraFromCommandLine = new sg::PerspectiveCamera; assert(argID+3render(ctx); @@ -87,7 +87,7 @@ namespace ospray { virtual box3f getBounds() { box3f bounds = empty; - for (int i=0;igetBounds()); } diff --git a/apps/qtViewer/sg/common/Common.cpp b/apps/qtViewer/sg/common/Common.cpp index dae763543c..cee59b74eb 100644 --- a/apps/qtViewer/sg/common/Common.cpp +++ b/apps/qtViewer/sg/common/Common.cpp @@ -35,29 +35,21 @@ namespace ospray { namespace sg { - //! parse vec3i from std::string (typically an xml-node's content string) - vec3i parseVec3i(const std::string &text) - { - vec3i ret; - int rc = sscanf(text.c_str(),"%i %i %i",&ret.x,&ret.y,&ret.z); - assert(rc == 3); - return ret; - } - - //! parse vec2i from std::string (typically an xml-node's content string) - vec2i parseVec2i(const std::string &text) - { - vec2i ret; - int rc = sscanf(text.c_str(),"%i %i",&ret.x,&ret.y); - assert(rc == 2); - return ret; - } - const unsigned char * mapFile(const std::string &fileName) { FILE *file = fopen(fileName.c_str(), "rb"); - if (!file) - THROW_SG_ERROR("could not open binary file"); + if (!file) { + std::cout << "========================================================" << std::endl; + std::cout << "WARNING: The ospray/sg .xml file you were trying to open" << std::endl; + std::cout << "does ***NOT*** come with an accompanying .xmlbin file." << std::endl; + std::cout << "Note this _may_ be OK in some cases, but if you do get" << std::endl; + std::cout << "undefined behavior or core dumps please make sure that" << std::endl; + std::cout << "you are not missing this file (ie, a common cause is to" << std::endl; + std::cout << "use a zipped .xmlbin file that we cannot directly use." << std::endl; + std::cout << "========================================================" << std::endl; + return NULL; + } + // THROW_SG_ERROR("could not open binary file"); fseek(file, 0, SEEK_END); ssize_t fileSize = #ifdef _WIN32 diff --git a/apps/qtViewer/sg/common/Common.h b/apps/qtViewer/sg/common/Common.h index 8037f95908..ef35b9ce32 100644 --- a/apps/qtViewer/sg/common/Common.h +++ b/apps/qtViewer/sg/common/Common.h @@ -63,16 +63,6 @@ namespace ospray { 'integrator' */ struct Integrator; - /*! @{ helper functions for parsing xml nodes */ - - //! parse vec3i from std::string (typically an xml-node's content string) - vec2i parseVec2i(const std::string &text); - - //! parse vec3i from std::string (typically an xml-node's content string) - vec3i parseVec3i(const std::string &text); - - /*! @} */ - //! map the given file to memory and return that pointer const unsigned char * mapFile(const std::string &fileName); diff --git a/apps/qtViewer/sg/common/Data.h b/apps/qtViewer/sg/common/Data.h index 8477f3ae3a..ff3ef45f8b 100644 --- a/apps/qtViewer/sg/common/Data.h +++ b/apps/qtViewer/sg/common/Data.h @@ -33,11 +33,11 @@ namespace ospray { struct DataBuffer : public Node { DataBuffer(OSPDataType type) - : type(type), data(NULL) + : type(type), data(nullptr) {} virtual ~DataBuffer() {} - virtual std::string toString() const { return "DataBuffer"; }; + virtual std::string toString() const { return "DataBuffer"; } virtual float get1f(index_t idx) const { INVALID_DATA_ERROR; } virtual vec2f get2f(index_t idx) const { INVALID_DATA_ERROR; } @@ -52,8 +52,8 @@ namespace ospray { virtual void *getBase() const = 0; virtual size_t getSize() const = 0; - virtual bool notEmpty() const { return getSize() != 0; }; - virtual OSPDataType getType() const { return type; }; + virtual bool notEmpty() const { return getSize() != 0; } + virtual OSPDataType getType() const { return type; } virtual OSPData getOSP() { if (notEmpty() && !data) { @@ -61,10 +61,10 @@ namespace ospray { ospCommit(data); } return data; - }; + } - OSPData data; OSPDataType type; + OSPData data; }; #undef INVALID_DATA_ERROR @@ -76,7 +76,7 @@ namespace ospray { template struct DataArrayT : public DataBuffer { DataArrayT(T *base, size_t size, bool mine=true) - : DataBuffer((OSPDataType)TID), base(base), mine(mine), size(size) + : DataBuffer((OSPDataType)TID), size(size), mine(mine), base(base) {} virtual void *getBase() const { return (void*)base; } virtual size_t getSize() const { return size; } diff --git a/apps/qtViewer/sg/common/Texture2D.cpp b/apps/qtViewer/sg/common/Texture2D.cpp index ce479e1e40..0d6266f44a 100644 --- a/apps/qtViewer/sg/common/Texture2D.cpp +++ b/apps/qtViewer/sg/common/Texture2D.cpp @@ -45,7 +45,8 @@ namespace ospray { // read format specifier: int format=0; - fscanf(file,"P%i\n",&format); + if (fscanf(file,"P%i\n",&format) != 1) + throw std::runtime_error("#osp:sg: could not parse PPM type"); if (format != 6) throw std::runtime_error("#osp:sg: can currently load only binary P6 subformats for PPM texture files. " "Please report this bug at ospray.github.io."); @@ -53,7 +54,8 @@ namespace ospray { // skip all comment lines peekchar = getc(file); while (peekchar == '#') { - fgets(lineBuf,LINESZ,file); + if (!fgets(lineBuf,LINESZ,file)) + throw std::runtime_error("could not fgets"); peekchar = getc(file); } ungetc(peekchar,file); @@ -67,7 +69,8 @@ namespace ospray { // skip all comment lines peekchar = getc(file); while (peekchar == '#') { - fgets(lineBuf,LINESZ,file); + if (!fgets(lineBuf,LINESZ,file)) + throw std::runtime_error("could not fgets"); peekchar = getc(file); } ungetc(peekchar,file); @@ -87,11 +90,12 @@ namespace ospray { tex->size = vec2i(width,height); tex->texelType = prefereLinear ? OSP_TEXTURE_RGB8 : OSP_TEXTURE_SRGB; tex->texel = new unsigned char[width*height*3]; - fread(tex->texel,width*height*3,1,file); + if (!fread(tex->texel,width*height*3,1,file)) + throw std::runtime_error("could not fread"); // flip in y, because OSPRay's textures have the origin at the lower left corner unsigned char *texels = (unsigned char *)tex->texel; - for (size_t y=0; y < height/2; y++) - for (size_t x=0; x < width*3; x++) + for (int y=0; y < height/2; y++) + for (int x=0; x < width*3; x++) std::swap(texels[y*width*3+x], texels[(height-1-y)*width*3+x]); } catch(std::runtime_error e) { std::cerr << e.what() << std::endl; diff --git a/apps/qtViewer/sg/common/TransferFunction.cpp b/apps/qtViewer/sg/common/TransferFunction.cpp index d1eaf791db..03a5411759 100644 --- a/apps/qtViewer/sg/common/TransferFunction.cpp +++ b/apps/qtViewer/sg/common/TransferFunction.cpp @@ -25,45 +25,47 @@ namespace ospray { //! constructor TransferFunction::TransferFunction() - : ospTransferFunction(NULL), - ospColorData(NULL), - ospAlphaData(NULL), - numSamples(128), - valueRange(0.f,1.f) - { + : ospTransferFunction(nullptr), + ospColorData(nullptr), + ospAlphaData(nullptr), + valueRange(0.f,1.f), + numSamples(128) + { setDefaultValues(); } // //! \brief Sets a new 'texture map' to be used for the color mapping void TransferFunction::setColorMap(const std::vector &colorArray) { - if (ospColorData) { ospRelease(ospColorData); ospColorData = NULL; } + if (ospColorData) { ospRelease(ospColorData); ospColorData = nullptr; } this->colorArray.clear(); - for (int i=0;icolorArray.push_back(std::pair(i,colorArray[i])); + for (uint32_t i = 0; i < colorArray.size(); ++i) + this->colorArray.push_back({i, colorArray[i]}); } //! \brief Sets a new 'texture map' to be used for the alpha mapping void TransferFunction::setAlphaMap(const std::vector &alphaArray) { - if (ospAlphaData) { ospRelease(ospAlphaData); ospAlphaData = NULL; } + if (ospAlphaData) { ospRelease(ospAlphaData); ospAlphaData = nullptr; } this->alphaArray.clear(); - for (int i=0;ialphaArray.push_back(std::pair(alphaArray[i].x,alphaArray[i].y)); + for (const auto &alpha : alphaArray) + this->alphaArray.push_back({alpha.x, alpha.y}); } float TransferFunction::getInterpolatedAlphaValue(float x) { if (x <= alphaArray.front().first) return alphaArray.front().second; - for (int i=1;ichild.size(); ii++) { + for (uint32_t ii = 0; ii != node->child.size(); ii++) { const xml::Node *child = node->child[ii]; // ------------------------------------------------------- // colors @@ -137,7 +139,7 @@ namespace ospray { while (c) { PRINT(c); colorArray.push_back(std::pair(colorArray.size(),toVec3f(c))); - c = strtok(NULL,",\n"); + c = strtok(nullptr,",\n"); } free(cont); @@ -155,7 +157,7 @@ namespace ospray { while (c) { vec2f cp = toVec2f(c); alphaArray.push_back(std::pair(cp.x,cp.y)); - c = strtok(NULL,",\n"); + c = strtok(nullptr,",\n"); } free(cont); @@ -185,6 +187,11 @@ namespace ospray { // alphaArray.push_back(std::pair(i,1.f)); //i/float(colorArray.size()-1)); } + std::string TransferFunction::toString() const + { + return "ospray::sg::TransferFunction"; + } + OSP_REGISTER_SG_NODE(TransferFunction) } // ::ospray::sg } // ::ospray diff --git a/apps/qtViewer/sg/common/TransferFunction.h b/apps/qtViewer/sg/common/TransferFunction.h index f484dcfcf1..b17adaf161 100644 --- a/apps/qtViewer/sg/common/TransferFunction.h +++ b/apps/qtViewer/sg/common/TransferFunction.h @@ -34,7 +34,7 @@ namespace ospray { void setDefaultValues(); /*! \brief returns a std::string with the c++ name of this class */ - virtual std::string toString() const { return "ospray::sg::TransferFunction"; } + virtual std::string toString() const; //! \brief creates ospray-side object(s) for this node virtual void render(RenderContext &ctx); @@ -59,7 +59,7 @@ namespace ospray { /*! return the ospray handle for this xfer fct, so we can assign it to ospray obejcts that need a reference to the ospray version of this xf */ - OSPTransferFunction getOSPHandle() const { return ospTransferFunction; }; + OSPTransferFunction getOSPHandle() const { return ospTransferFunction; } protected: OSPTransferFunction ospTransferFunction; OSPData ospColorData; diff --git a/apps/qtViewer/sg/common/World.cpp b/apps/qtViewer/sg/common/World.cpp index fd4d1626a7..eb27d2da96 100644 --- a/apps/qtViewer/sg/common/World.cpp +++ b/apps/qtViewer/sg/common/World.cpp @@ -22,8 +22,8 @@ namespace ospray { box3f World::getBounds() { box3f bounds = empty; - for (int i=0;igetBounds()); + for (auto &n : node) + bounds.extend(n->getBounds()); return bounds; } @@ -46,7 +46,6 @@ namespace ospray { if (ospModel) throw std::runtime_error("World::ospModel alrady exists!?"); ospModel = ospNewModel(); - affine3f xfm = one; for (size_t i=0;irender(ctx); } diff --git a/apps/qtViewer/sg/geometry/Spheres.cpp b/apps/qtViewer/sg/geometry/Spheres.cpp index 4cedfbc95a..b10ff7ac8d 100644 --- a/apps/qtViewer/sg/geometry/Spheres.cpp +++ b/apps/qtViewer/sg/geometry/Spheres.cpp @@ -30,7 +30,7 @@ namespace ospray { Spheres::Sphere::Sphere(vec3f position, float radius, - uint typeID) + uint32_t typeID) : position(position), radius(radius), typeID(typeID) @@ -60,7 +60,8 @@ namespace ospray { existant) that contains additional binary data that the xml node fields may point into */ - void Spheres::setFromXML(const xml::Node *const node, const unsigned char *binBasePtr) + void Spheres::setFromXML(const xml::Node *const node, + const unsigned char *binBasePtr) { size_t num = node->getPropl("num"); size_t ofs = node->getPropl("ofs"); @@ -70,8 +71,9 @@ namespace ospray { Spheres::Sphere s(vec3f(0.f),rad,0); if (ofs == (size_t)-1) { - cout << "#osp:qtv: 'Spheres' ofs is '-1', generating set of random spheres..." << endl; - for (int i=0;iradius); ospSet1i(ospGeometry,"bytes_per_sphere",sizeof(Spheres::Sphere)); ospSet1i(ospGeometry,"center_offset", 0*sizeof(float)); ospSet1i(ospGeometry,"offset_radius", 3*sizeof(float)); ospSet1i(ospGeometry,"offset_materialID", 4*sizeof(float)); - // ospSetData(geom,"materialList",materialData); - OSPMaterial mat = ospNewMaterial(ctx.integrator?ctx.integrator->getOSPHandle():NULL,"default"); + OSPMaterial mat = + ospNewMaterial(ctx.integrator?ctx.integrator->getOSPHandle():nullptr,"default"); if (mat) { vec3f kd = vec3f(.7f); ospSet3fv(mat,"kd",&kd.x); @@ -124,8 +125,8 @@ namespace ospray { void setFromXML(const xml::Node *const node, const unsigned char *binBasePtr) { - vec3i dimensions = parseVec3i(node->getProp("dimensions")); - int num = atoi(node->getProp("num").c_str()); + vec3i dimensions = toVec3i(node->getProp("dimensions").c_str()); + int num = toInt(node->getProp("num").c_str()); float max_r = atof(node->getProp("radius").c_str());//std::max(dimensions.x,std::max(dimensions.y,dimensions.z)) / powf(num,.33f); float f = 0.3f; // overhang around the dimensions diff --git a/apps/qtViewer/sg/geometry/Spheres.h b/apps/qtViewer/sg/geometry/Spheres.h index 61b88fbca6..30b40825ab 100644 --- a/apps/qtViewer/sg/geometry/Spheres.h +++ b/apps/qtViewer/sg/geometry/Spheres.h @@ -32,7 +32,7 @@ namespace ospray { uint32_t typeID; // constructor - Sphere(vec3f position, float radius, uint typeID=0); + Sphere(vec3f position, float radius, uint32_t typeID=0); // return the bounding box inline box3f getBounds() const diff --git a/apps/qtViewer/sg/geometry/TriangleMesh.cpp b/apps/qtViewer/sg/geometry/TriangleMesh.cpp index f2681e39b5..0019fc1539 100644 --- a/apps/qtViewer/sg/geometry/TriangleMesh.cpp +++ b/apps/qtViewer/sg/geometry/TriangleMesh.cpp @@ -25,7 +25,7 @@ namespace ospray { box3f TriangleMesh::getBounds() { box3f bounds = empty; - for (int i=0;igetSize();i++) + for (uint32_t i = 0; i < vertex->getSize(); i++) bounds.extend(vertex->get3f(i)); return bounds; } @@ -34,7 +34,7 @@ namespace ospray { box3f PTMTriangleMesh::getBounds() { box3f bounds = empty; - for (int i=0;igetSize();i++) + for (uint32_t i = 0; i < vertex->getSize(); i++) bounds.extend(vertex->get3f(i)); return bounds; } @@ -156,7 +156,7 @@ namespace ospray { std::vector ospMaterials; for (size_t i = 0; i < materialList.size(); i++) { - assert(materialList[i] != NULL); + assert(materialList[i].ptr != NULL); //If the material hasn't already been 'rendered' ensure that it is. materialList[i]->render(ctx); //Push the 'rendered' material onto the list diff --git a/apps/qtViewer/sg/importer/ImportOBJ.cpp b/apps/qtViewer/sg/importer/ImportOBJ.cpp index eae0a11c4e..8663c0bbc0 100644 --- a/apps/qtViewer/sg/importer/ImportOBJ.cpp +++ b/apps/qtViewer/sg/importer/ImportOBJ.cpp @@ -300,7 +300,7 @@ namespace ospray { if (!strncmp(token, "map_Ks" , 6)) { parseSepOpt(token += 6); cur->setParam("map_Ks", loadTexture(path, std::string(token))); continue; } /*! the following are extensions to the standard */ if (!strncmp(token, "map_Refl" , 8)) { parseSepOpt(token += 8); cur->setParam("map_Refl", loadTexture(path, std::string(token))); continue; } - if (!strncmp(token, "map_Bump" , 8)) { parseSepOpt(token += 8); cur->setParam("map_Bump", loadTexture(path, std::string(token), true)); continue; } + if (!strncmp(token, "map_Bump" , 8) || !strncmp(token, "map_bump", 8)) { parseSepOpt(token += 8); cur->setParam("map_Bump", loadTexture(path, std::string(token), true)); continue; } if (!strncmp(token, "bumpMap" , 7)) { parseSepOpt(token += 7); cur->setParam("map_Bump", loadTexture(path, std::string(token), true)); continue; } if (!strncmp(token, "colorMap" , 8)) { parseSepOpt(token += 8); cur->setParam("map_Kd", loadTexture(path, std::string(token))); continue; } diff --git a/apps/qtViewer/sg/importer/ImportOSP.cpp b/apps/qtViewer/sg/importer/ImportOSP.cpp index 7a770206ce..ac19eb6aaa 100644 --- a/apps/qtViewer/sg/importer/ImportOSP.cpp +++ b/apps/qtViewer/sg/importer/ImportOSP.cpp @@ -105,8 +105,7 @@ namespace ospray { { assert(node->name == "Info"); Info *info = new Info; - for (int i=0;ichild.size();i++) { - xml::Node *c = node->child[i]; + for (auto *c : node->child) { if (c->name == "acks") info->acks = c->content; else if (c->name == "description") @@ -138,8 +137,7 @@ namespace ospray { { assert(node->name == "Integrator"); Integrator *integrator = new Integrator(node->getProp("type")); - for (int i=0;ichild.size();i++) { - xml::Node *c = node->child[i]; + for (auto *c : node->child) { if (parseParam(integrator,c)) continue; throw std::runtime_error("unknown node type '"+c->name @@ -148,10 +146,11 @@ namespace ospray { return integrator; } - void parseWorldNode(sg::World *world, xml::Node *node, const unsigned char *binBasePtr) + void parseWorldNode(sg::World *world, + xml::Node *node, + const unsigned char *binBasePtr) { - for (int i=0;ichild.size();i++) { - xml::Node *c = node->child[i]; + for (auto *c : node->child) { Ref newNode = createNodeFrom(c,binBasePtr); world->node.push_back(newNode); } diff --git a/apps/qtViewer/sg/importer/ImportRIVL.cpp b/apps/qtViewer/sg/importer/ImportRIVL.cpp index 51e1754df2..1ed9d1ee1d 100644 --- a/apps/qtViewer/sg/importer/ImportRIVL.cpp +++ b/apps/qtViewer/sg/importer/ImportRIVL.cpp @@ -43,7 +43,7 @@ namespace ospray { throw std::runtime_error("emply RIVL model !?"); Ref lastNode; - for (int childID=0;childIDchild.size();childID++) {//xmlNode *node = root->children; node; node = node->next) { + for (uint32_t childID = 0; childID < root->child.size(); childID++) { xml::Node *node = root->child[childID]; std::string nodeName = node->name; if (nodeName == "text") { @@ -55,7 +55,7 @@ namespace ospray { nodeList.push_back(txt.ptr); int height = -1, width = -1, ofs = -1, channels = -1, depth = -1; - for (int pID=0;pIDprop.size();pID++) { + for (uint32_t pID = 0; pID < node->prop.size(); pID++) { xml::Prop *prop = node->prop[pID]; if (prop->name == "ofs") { ofs = atol(prop->value.c_str()); diff --git a/apps/qtViewer/sg/importer/ImportSpheres.cpp b/apps/qtViewer/sg/importer/ImportSpheres.cpp index 90095d887e..06ac34aa1b 100644 --- a/apps/qtViewer/sg/importer/ImportSpheres.cpp +++ b/apps/qtViewer/sg/importer/ImportSpheres.cpp @@ -59,9 +59,9 @@ namespace ospray { sg::Spheres *spheres = new sg::Spheres; float radius = 1.f/numPerSide; - for (int z=0;z"), volume(NULL), mappedPointer(NULL) + : dimensions(-1), voxelType(""), + mappedPointer(nullptr), volume(nullptr) {} /*! \brief returns a std::string with the c++ name of this class */ @@ -60,12 +61,12 @@ namespace ospray { const unsigned char *binBasePtr) { Assert2(binBasePtr, - "mapped binary file is NULL, in XML node that " + "mapped binary file is nullptr, in XML node that " "needs mapped binary data (sg::StructuredVolume)"); voxelType = node->getProp("voxelType"); if (node->hasProp("ofs")) mappedPointer = binBasePtr + node->getPropl("ofs"); - dimensions = parseVec3i(node->getProp("dimensions")); + dimensions = toVec3i(node->getProp("dimensions").c_str()); if (voxelType != "float" && voxelType != "uint8") throw std::runtime_error("unknown StructuredVolume.voxelType (currently only supporting 'float' and 'uint8')"); @@ -94,7 +95,7 @@ namespace ospray { ospSetString(volume,"voxelType",voxelType.c_str()); ospSetVec3i(volume,"dimensions",(const osp::vec3i&)dimensions); size_t nPerSlice = (size_t)dimensions.x*(size_t)dimensions.y; - assert(mappedPointer != NULL); + assert(mappedPointer != nullptr); for (int z=0;z"), volume(NULL) + : dimensions(-1), fileName(""), voxelType(""), volume(nullptr) {} /*! \brief returns a std::string with the c++ name of this class */ @@ -138,7 +139,7 @@ namespace ospray { { voxelType = node->getProp("voxelType"); if (voxelType == "uint8") voxelType = "uchar"; - dimensions = parseVec3i(node->getProp("dimensions")); + dimensions = toVec3i(node->getProp("dimensions").c_str()); fileName = node->getProp("fileName"); if (fileName == "") throw std::runtime_error("sg::StructuredVolumeFromFile: no 'fileName' specified"); @@ -179,8 +180,6 @@ namespace ospray { FileName realFileName = fileNameOfCorrespondingXmlDoc.path()+fileName; FILE *file = fopen(realFileName.c_str(),"rb"); - float minValue = +std::numeric_limits::infinity(); - float maxValue = -std::numeric_limits::infinity(); if (!file) throw std::runtime_error("StructuredVolumeFromFile::render(): could not open file '" +realFileName.str()+"' (expanded from xml file '" @@ -242,7 +241,7 @@ namespace ospray { //! constructor StackedRawSlices::StackedRawSlices() - : dimensions(-1), baseName(""), voxelType("uint8_t"), volume(NULL) + : baseName(""), voxelType("uint8_t"), dimensions(-1), volume(nullptr) {} /*! \brief returns a std::string with the c++ name of this class */ @@ -257,7 +256,7 @@ namespace ospray { void StackedRawSlices::setFromXML(const xml::Node *const node, const unsigned char *binBasePtr) { voxelType = node->getProp("voxelType"); - sliceResolution = parseVec2i(node->getProp("sliceResolution")); + sliceResolution = toVec2i(node->getProp("sliceResolution").c_str()); baseName = node->getProp("baseName"); firstSliceID = node->getPropl("firstSliceID"); numSlices = node->getPropl("numSlices"); diff --git a/apps/qtViewer/sg/volume/Volume.h b/apps/qtViewer/sg/volume/Volume.h index 98fb83c25b..6e2cc9d5a4 100644 --- a/apps/qtViewer/sg/volume/Volume.h +++ b/apps/qtViewer/sg/volume/Volume.h @@ -57,8 +57,8 @@ namespace ospray { /*! \brief 'render' the object to ospray */ virtual void render(RenderContext &ctx); - SG_NODE_DECLARE_MEMBER(vec3i,dimensions,Dimensions); - SG_NODE_DECLARE_MEMBER(std::string,voxelType,ScalarType); + SG_NODE_DECLARE_MEMBER(vec3i,dimensions,Dimensions) + SG_NODE_DECLARE_MEMBER(std::string,voxelType,ScalarType) const unsigned char *mappedPointer; diff --git a/apps/qtViewer/widgets/affineSpaceManipulator/QAffineSpaceManipulator.cpp b/apps/qtViewer/widgets/affineSpaceManipulator/QAffineSpaceManipulator.cpp index e2ee89c93d..8098452ecb 100644 --- a/apps/qtViewer/widgets/affineSpaceManipulator/QAffineSpaceManipulator.cpp +++ b/apps/qtViewer/widgets/affineSpaceManipulator/QAffineSpaceManipulator.cpp @@ -375,7 +375,9 @@ namespace ospray { for (int y=0;yaddWidget(formWidget); // Ambient light intensity. - ambientLightIntensitySpinBox.setRange(0.0, 1.0); + ambientLightIntensitySpinBox.setRange(0.0, 3.0); ambientLightIntensitySpinBox.setSingleStep(0.01); formLayout->addRow("Ambient light intensity", &ambientLightIntensitySpinBox); connect(&ambientLightIntensitySpinBox, SIGNAL(valueChanged(double)), this, SLOT(ambientLightChanged())); // Directional light intensity. - directionalLightIntensitySpinBox.setRange(0.0, 1.0); + directionalLightIntensitySpinBox.setRange(0.0, 3.0); directionalLightIntensitySpinBox.setSingleStep(0.01); formLayout->addRow("Directional light intensity", &directionalLightIntensitySpinBox); connect(&directionalLightIntensitySpinBox, SIGNAL(valueChanged(double)), this, SLOT(directionalLightChanged())); @@ -54,23 +54,24 @@ LightEditor::LightEditor(OSPLight ambientLight, OSPLight directionalLight) : amb connect(&directionalLightElevationSlider, SIGNAL(valueChanged(int)), this, SLOT(directionalLightChanged())); // Set default light parameters. - ambientLightIntensitySpinBox.setValue(0.05); + ambientLightIntensitySpinBox.setValue(0.1); //doesn't seem to fire if it's 0 first + ambientLightIntensitySpinBox.setValue(0.0); - directionalLightIntensitySpinBox.setValue(0.95); - directionalLightAzimuthSlider.setValue(0.125 * (directionalLightAzimuthSlider.minimum() + directionalLightAzimuthSlider.maximum())); // 45 degrees azimuth - directionalLightElevationSlider.setValue(0.75 * (directionalLightElevationSlider.minimum() + directionalLightElevationSlider.maximum())); // 45 degrees elevation + directionalLightIntensitySpinBox.setValue(1.0); + directionalLightAzimuthSlider.setValue(0.8 * (directionalLightAzimuthSlider.minimum() + directionalLightAzimuthSlider.maximum())); // 45 degrees azimuth + directionalLightElevationSlider.setValue(0.2 * (directionalLightElevationSlider.minimum() + directionalLightElevationSlider.maximum())); // 45 degrees elevation } void LightEditor::ambientLightChanged() { - ospSet1f(ambientLight, "intensity", float(ambientLightIntensitySpinBox.value())); + ospSet1f(ambientLight, "intensity", float(ambientLightIntensitySpinBox.value()*3.14)); ospCommit(ambientLight); emit lightsChanged(); } void LightEditor::directionalLightChanged() { - ospSet1f(directionalLight, "intensity", float(directionalLightIntensitySpinBox.value())); + ospSet1f(directionalLight, "intensity", float(directionalLightIntensitySpinBox.value()*3.14)); // Get alpha value in [-180, 180] degrees. float alpha = -180.0f + float(directionalLightAzimuthSlider.value() - directionalLightAzimuthSlider.minimum()) / float(directionalLightAzimuthSlider.maximum() - directionalLightAzimuthSlider.minimum()) * 360.0f; diff --git a/apps/volumeViewer/PreferencesDialog.cpp b/apps/volumeViewer/PreferencesDialog.cpp index b3dc2b1014..7086510268 100644 --- a/apps/volumeViewer/PreferencesDialog.cpp +++ b/apps/volumeViewer/PreferencesDialog.cpp @@ -39,14 +39,67 @@ PreferencesDialog::PreferencesDialog(VolumeViewer *volumeViewer, ospcommon::box3 connect(gradientShadingEnabledCheckBox, SIGNAL(toggled(bool)), volumeViewer, SLOT(setGradientShadingEnabled(bool))); formLayout->addRow("Volume gradient shading (lighting)", gradientShadingEnabledCheckBox); + QCheckBox *adaptiveSamplingCB = new QCheckBox(); + connect(adaptiveSamplingCB, SIGNAL(toggled(bool)), volumeViewer, SLOT(setAdaptiveSampling(bool))); + formLayout->addRow("Adaptive sampling", adaptiveSamplingCB); + + QCheckBox *preIntegrationCB = new QCheckBox(); + connect(preIntegrationCB, SIGNAL(toggled(bool)), volumeViewer, SLOT(setPreIntegration(bool))); + formLayout->addRow("PreIntegration", preIntegrationCB); + + QCheckBox *singleShadeCB = new QCheckBox(); + connect(singleShadeCB, SIGNAL(toggled(bool)), volumeViewer, SLOT(setSingleShade(bool))); + formLayout->addRow("Single Shading Calculation", singleShadeCB); + + QCheckBox *shadowsCB = new QCheckBox(); + connect(shadowsCB, SIGNAL(toggled(bool)), volumeViewer, SLOT(setShadows(bool))); + formLayout->addRow("Shadows", shadowsCB); + + QCheckBox *planeCB = new QCheckBox(); + connect(planeCB, SIGNAL(toggled(bool)), volumeViewer, SLOT(setPlane(bool))); + formLayout->addRow("Plane", planeCB); + + QDoubleSpinBox *adaptiveScalarSB = new QDoubleSpinBox(); + adaptiveScalarSB->setDecimals(4); + adaptiveScalarSB->setRange(1.0, 1000.0); + adaptiveScalarSB->setSingleStep(1.0); + connect(adaptiveScalarSB, SIGNAL(valueChanged(double)), volumeViewer, SLOT(setAdaptiveScalar(double))); + formLayout->addRow("Adaptive scalar", adaptiveScalarSB); + + QDoubleSpinBox *adaptiveMaxSamplingRateSB = new QDoubleSpinBox(); + adaptiveMaxSamplingRateSB->setDecimals(3); + adaptiveMaxSamplingRateSB->setRange(0.01, 2.0); + adaptiveMaxSamplingRateSB->setSingleStep(0.01); + connect(adaptiveMaxSamplingRateSB, SIGNAL(valueChanged(double)), volumeViewer, SLOT(setAdaptiveMaxSamplingRate(double))); + formLayout->addRow("Adaptive max sampling rate", adaptiveMaxSamplingRateSB); + + QDoubleSpinBox *adaptiveBacktrackSB = new QDoubleSpinBox(); + adaptiveBacktrackSB->setDecimals(4); + adaptiveBacktrackSB->setRange(0.0001, 2.0f); + adaptiveBacktrackSB->setSingleStep(0.0001); + connect(adaptiveBacktrackSB, SIGNAL(valueChanged(double)), volumeViewer, SLOT(setAdaptiveBacktrack(double))); + formLayout->addRow("Adaptive backtrack", adaptiveBacktrackSB); + // sampling rate selection QDoubleSpinBox *samplingRateSpinBox = new QDoubleSpinBox(); samplingRateSpinBox->setDecimals(3); - samplingRateSpinBox->setRange(0.01, 1.0); + samplingRateSpinBox->setRange(0.01, 2.0); samplingRateSpinBox->setSingleStep(0.01); connect(samplingRateSpinBox, SIGNAL(valueChanged(double)), volumeViewer, SLOT(setSamplingRate(double))); formLayout->addRow("Sampling rate", samplingRateSpinBox); + QDoubleSpinBox *aoWeightSB = new QDoubleSpinBox(); + aoWeightSB->setDecimals(3); + aoWeightSB->setRange(0.0, 4.0); + aoWeightSB->setSingleStep(0.1); + connect(aoWeightSB, SIGNAL(valueChanged(double)), volumeViewer, SLOT(setAOWeight(double))); + formLayout->addRow("AOWeight", aoWeightSB); + + QSpinBox *aoSamplesSB = new QSpinBox(); + aoSamplesSB->setRange(0, 64); + connect(aoSamplesSB, SIGNAL(valueChanged(int)), volumeViewer, SLOT(setAOSamples(int))); + formLayout->addRow("AOSamples", aoSamplesSB); + // volume clipping box for(size_t i=0; i<6; i++) { volumeClippingBoxSpinBoxes.push_back(new QDoubleSpinBox()); @@ -85,17 +138,27 @@ PreferencesDialog::PreferencesDialog(VolumeViewer *volumeViewer, ospcommon::box3 // set default values. this will trigger signal / slot executions. subsamplingInteractionEnabledCheckBox->setChecked(false); - gradientShadingEnabledCheckBox->setChecked(false); - samplingRateSpinBox->setValue(0.125); + gradientShadingEnabledCheckBox->setChecked(true); + singleShadeCB->setChecked(true); + adaptiveSamplingCB->setChecked(true); + preIntegrationCB->setChecked(true); + shadowsCB->setChecked(true); + planeCB->setChecked(true); + adaptiveScalarSB->setValue(15.f); + adaptiveMaxSamplingRateSB->setValue(0.7f); + adaptiveBacktrackSB->setValue(0.02f); + samplingRateSpinBox->setValue(0.07); + aoWeightSB->setValue(0.4f); + aoSamplesSB->setValue(1); } void PreferencesDialog::updateVolumeClippingBox() { - ospcommon::vec3f lower(volumeClippingBoxSpinBoxes[0]->value(), - volumeClippingBoxSpinBoxes[1]->value(), + ospcommon::vec3f lower(volumeClippingBoxSpinBoxes[0]->value(), + volumeClippingBoxSpinBoxes[1]->value(), volumeClippingBoxSpinBoxes[2]->value()); - ospcommon::vec3f upper(volumeClippingBoxSpinBoxes[3]->value(), - volumeClippingBoxSpinBoxes[4]->value(), + ospcommon::vec3f upper(volumeClippingBoxSpinBoxes[3]->value(), + volumeClippingBoxSpinBoxes[4]->value(), volumeClippingBoxSpinBoxes[5]->value()); volumeViewer->setVolumeClippingBox(ospcommon::box3f(lower, upper)); diff --git a/apps/volumeViewer/VolumeViewer.cpp b/apps/volumeViewer/VolumeViewer.cpp index 8e0e658906..246a06ce3b 100644 --- a/apps/volumeViewer/VolumeViewer.cpp +++ b/apps/volumeViewer/VolumeViewer.cpp @@ -53,7 +53,8 @@ VolumeViewer::VolumeViewer(const std::vector &objectFileFilenames, transferFunctionEditor(NULL), isosurfaceEditor(NULL), autoRotateAction(NULL), - autoRotationRate(0.025f) + autoRotationRate(0.025f), + usePlane(true) { // Default window size. resize(1024, 768); @@ -313,6 +314,124 @@ void VolumeViewer::setGradientShadingEnabled(bool value) render(); } +//! Set gradient shading flag on all volumes. +void VolumeViewer::setPreIntegration(bool value) +{ + for(size_t i=0; ihandle, "preIntegration", value); + ospCommit(modelStates[i].volumes[j]->handle); + } + + render(); +} + +//! Set gradient shading flag on all volumes. +void VolumeViewer::setSingleShade(bool value) +{ + for(size_t i=0; ihandle, "singleShade", value); + ospCommit(modelStates[i].volumes[j]->handle); + } + + render(); +} + +void VolumeViewer::setShadows(bool value) +{ + ospSet1i(renderer, "shadowsEnabled", value); + if(rendererInitialized) + ospCommit(renderer); + + render(); +} + +void VolumeViewer::setPlane(bool st) +{ + usePlane = st; + if (planeMesh) + { + for(size_t i=0; ihandle, "adaptiveScalar", value); + ospCommit(modelStates[i].volumes[j]->handle); + } + render(); +} + + +//! Set gradient shading flag on all volumes. +void VolumeViewer::setAdaptiveMaxSamplingRate(double value) +{ + for(size_t i=0; ihandle, "adaptiveMaxSamplingRate", value); + ospCommit(modelStates[i].volumes[j]->handle); + } + render(); +} + + +//! Set gradient shading flag on all volumes. +void VolumeViewer::setAdaptiveBacktrack(double value) +{ + for(size_t i=0; ihandle, "adaptiveBacktrack", value); + ospCommit(modelStates[i].volumes[j]->handle); + } + + render(); +} + +//! Set gradient shading flag on all volumes. +void VolumeViewer::setAdaptiveSampling(bool value) +{ + for(size_t i=0; ihandle, "adaptiveSampling", value); + ospCommit(modelStates[i].volumes[j]->handle); + } + + render(); +} + void VolumeViewer::setSamplingRate(double value) { for(size_t i=0; iboundingBox); } PRINT(boundingBox); - // // Get the bounding box of all volumes of the first model. - // if(modelStates.size() > 0 && modelStates[0].volumes.size() > 0) { - // ospGetVec3f(modelStates[0].volumes[0], "boundingBoxMin", (osp::vec3f*)&boundingBox.lower); - // ospGetVec3f(modelStates[0].volumes[0], "boundingBoxMax", (osp::vec3f*)&boundingBox.upper); - - // for (size_t i=1; i isovalues); + void setPlane(bool st); + + void setAOSamples(int value); + + void setAOWeight(double value); + protected: //! OSPRay object file filenames, one for each model / time step. @@ -220,4 +243,8 @@ public slots: //! Create and configure the user interface widgets and callbacks. void initUserInterfaceWidgets(); + bool usePlane; + + OSPGeometry planeMesh; + }; diff --git a/apps/volumeViewer/main.cpp b/apps/volumeViewer/main.cpp index e7664a7c18..bdb21d178d 100644 --- a/apps/volumeViewer/main.cpp +++ b/apps/volumeViewer/main.cpp @@ -82,8 +82,9 @@ int main(int argc, char *argv[]) bool showFrameRate = false; bool fullScreen = false; bool ownModelPerObject = false; - std::string renderer = "dvr"; + std::string renderer = "scivis";//"dvr"; std::string writeFramesFilename; + bool usePlane = false; std::vector inFileName; // Parse the optional command line arguments. @@ -109,6 +110,8 @@ int main(int argc, char *argv[]) rotationRate = atof(argv[++i]); std::cout << "got rotationRate = " << rotationRate << std::endl; + } else if (arg == "--plane") { + usePlane = true; } else if (arg == "--slice") { if (i + 1 >= argc) throw std::runtime_error("missing argument"); @@ -236,6 +239,8 @@ int main(int argc, char *argv[]) // Display the first model. volumeViewer->setModel(0); + volumeViewer->setPlane(usePlane); + // Load PLY geometries from file. for(unsigned int i=0; iaddGeometry(plyFilenames[i]); diff --git a/cmake/FindTBB.cmake b/cmake/FindTBB.cmake index 4c716ae743..f09673ea12 100644 --- a/cmake/FindTBB.cmake +++ b/cmake/FindTBB.cmake @@ -14,7 +14,7 @@ ## limitations under the License. ## ## ======================================================================== ## -SET(TBB_VERSION_REQUIRED "3.0") +SET(TBB_MAJOR_VERSION_REQUIRED "3.0") IF (NOT TBB_ROOT) SET(TBB_ROOT $ENV{TBB_ROOT}) @@ -118,7 +118,7 @@ ENDIF() SET(TBB_ROOT_LAST ${TBB_ROOT} CACHE INTERNAL "Last value of TBB_ROOT to detect changes") SET(TBB_ERROR_MESSAGE - "Threading Building Blocks (TBB) with minimum version ${TBB_VERSION_REQUIRED} not found. + "Threading Building Blocks (TBB) with minimum version ${TBB_MAJOR_VERSION_REQUIRED}.0 not found. OSPRay uses TBB as default tasking system. Please make sure you have the TBB headers installed as well (the package is typically named 'libtbb-dev' or 'tbb-devel') and/or hint the location of TBB in TBB_ROOT. Alternatively, you can try to use OpenMP as tasking system by setting OSPRAY_TASKING_SYSTEM=OpenMP") @@ -132,13 +132,13 @@ FIND_PACKAGE_HANDLE_STANDARD_ARGS(TBB IF (TBB_INCLUDE_DIR) FILE(READ ${TBB_INCLUDE_DIR}/tbb/tbb_stddef.h TBB_STDDEF_H) - STRING(REGEX MATCH "#define TBB_VERSION_MAJOR ([0-9])" DUMMY "${TBB_STDDEF_H}") + STRING(REGEX MATCH "#define TBB_VERSION_MAJOR ([0-9]+)" DUMMY "${TBB_STDDEF_H}") SET(TBB_VERSION_MAJOR ${CMAKE_MATCH_1}) - STRING(REGEX MATCH "#define TBB_VERSION_MINOR ([0-9])" DUMMY "${TBB_STDDEF_H}") + STRING(REGEX MATCH "#define TBB_VERSION_MINOR ([0-9]+)" DUMMY "${TBB_STDDEF_H}") SET(TBB_VERSION "${TBB_VERSION_MAJOR}.${CMAKE_MATCH_1}") - IF (TBB_VERSION VERSION_LESS TBB_VERSION_REQUIRED) + IF (TBB_VERSION_MAJOR VERSION_LESS TBB_VERSION_REQUIRED) MESSAGE(FATAL_ERROR ${TBB_ERROR_MESSAGE}) ENDIF() @@ -172,25 +172,3 @@ MARK_AS_ADVANCED(TBB_LIBRARY) MARK_AS_ADVANCED(TBB_LIBRARY_DEBUG) MARK_AS_ADVANCED(TBB_LIBRARY_MALLOC) MARK_AS_ADVANCED(TBB_LIBRARY_MALLOC_DEBUG) - - -############################################################## -# redistribute TBB -############################################################## - -IF (WIN32) - SET(TBB_DLL_HINTS - ${TBB_ROOT}/../redist/${TBB_ARCH}_win/tbb/${TBB_VCVER} - ${TBB_ROOT}/../redist/${TBB_ARCH}/tbb/${TBB_VCVER} - ) - FIND_FILE(TBB_DLL tbb.dll HINTS ${TBB_DLL_HINTS}) - FIND_FILE(TBB_DLL_MALLOC tbbmalloc.dll PATHS HINTS ${TBB_DLL_HINTS}) - MARK_AS_ADVANCED(TBB_DLL) - MARK_AS_ADVANCED(TBB_DLL_MALLOC) - INSTALL(PROGRAMS ${TBB_DLL} ${TBB_DLL_MALLOC} DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT apps) # 3rd party? -ELSEIF (OSPRAY_ZIP_MODE) - INSTALL(PROGRAMS ${TBB_LIBRARY} ${TBB_LIBRARY_MALLOC} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT lib) # /intel64? - IF(OSPRAY_MIC AND TBB_FOUND_MIC) - INSTALL(PROGRAMS ${TBB_LIBRARIES_MIC} DESTINATION ${CMAKE_INSTALL_LIBDIR}/mic COMPONENT lib_mic) - ENDIF() -ENDIF() diff --git a/cmake/configure_embree.cmake b/cmake/configure_embree.cmake new file mode 100644 index 0000000000..3f9b0f403c --- /dev/null +++ b/cmake/configure_embree.cmake @@ -0,0 +1,147 @@ +## ======================================================================== ## +## Copyright 2009-2016 Intel Corporation ## +## ## +## Licensed under the Apache License, Version 2.0 (the "License"); ## +## you may not use this file except in compliance with the License. ## +## You may obtain a copy of the License at ## +## ## +## http://www.apache.org/licenses/LICENSE-2.0 ## +## ## +## Unless required by applicable law or agreed to in writing, software ## +## distributed under the License is distributed on an "AS IS" BASIS, ## +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## +## See the License for the specific language governing permissions and ## +## limitations under the License. ## +## ======================================================================== ## + +# ------------------------------------------------------- +# Find or build Embree +# ------------------------------------------------------- + +SET(EMBREE_VERSION_REQUIRED 2.7.1) + +# Do a check to see if we can find the system Embree +IF(NOT DEFINED LAST_CONFIG_USED_EXTERNAL_EMBREE) + FIND_PACKAGE(embree ${EMBREE_VERSION_REQUIRED} QUIET) + IF(NOT DEFINED EMBREE_INCLUDE_DIRS) + MESSAGE(WARNING + "We did not find Embree installed on your system. If you would" + " like to use a newer version of Embree than the one in the" + " OSPRay source tree (v2.7.1), please download and extract or" + " compile Embree from source, set the 'embree_DIR' environment" + " variable to where it is installed, and re-enable the" + " OSPRAY_USE_EXTERNAL_EMBREE CMake option.") + SET(OSPRAY_USE_EXTERNAL_EMBREE OFF CACHE BOOL "" FORCE) + ENDIF() +ENDIF() + +IF(OSPRAY_USE_EXTERNAL_EMBREE) + + # Clear out embree directories if they were previously populated by an + # internal build + IF(NOT ${LAST_CONFIG_USED_EXTERNAL_EMBREE}) + UNSET(EMBREE_INCLUDE_DIRS) + UNSET(EMBREE_LIBRARIES) + UNSET(EMBREE_LIBRARY) + UNSET(EMBREE_LIBRARY_XEONPHI) + ENDIF() + + # Find existing Embree on the machine ####################################### + + FIND_PACKAGE(embree ${EMBREE_VERSION_REQUIRED} REQUIRED) + SET(LAST_CONFIG_USED_EXTERNAL_EMBREE ON CACHE INTERNAL "" FORCE) + + IF(OSPRAY_MIC AND NOT EMBREE_VERSION VERSION_LESS "2.10.0") + MESSAGE(FATAL_ERROR "The found Embree version ${EMBREE_VERSION} does not" + " support KNC anymore. Either disable the OSPRAY_BUILD_MIC_SUPPORT" + " option or use an Embree v2.9 or earlier.") + ENDIF() + + # NOTE(jda) - EMBREE_LIBRARIES is not defined until at lest v2.10.0, for now + # create a "faked" EMBREE_LIBRARIES until we set our min version + # to >= 2.10.0 of Embree + # also remove Embree's TBB libs if OSPRay uses TBB to avoid problems with + # cyclic rpath + IF(NOT DEFINED EMBREE_LIBRARIES OR OSPRAY_TASKING_TBB) + SET(EMBREE_LIBRARIES ${EMBREE_LIBRARY}) + ELSE() + # check if we need to add TBB to EMBREE_LIBRARIES + IF((EMBREE_TASKING_TBB OR (${EMBREE_TASKING_SYSTEM} STREQUAL "TBB")) + AND NOT EMBREE_USE_PACKAGED_TBB) + OSPRAY_WARN_ONCE(EMBREE_FORCE_TBB + "You *MUST* have TBB installed based on the Embree we found!") + FIND_PACKAGE(TBB REQUIRED) + SET(EMBREE_LIBRARIES ${EMBREE_LIBRARIES} ${TBB_LIBRARIES}) + ENDIF() + ENDIF() + + SET(EMBREE_ISA_SUPPORTS_AVX FALSE) + SET(EMBREE_ISA_SUPPORTS_AVX2 FALSE) + SET(EMBREE_ISA_SUPPORTS_AVX512 FALSE) + + # Workaround - name changed from EMBREE_ISA to EMBREE_MAX_ISA in 2.10 -> 2.11 + IF (DEFINED EMBREE_ISA) + SET(EMBREE_ISA_NAME EMBREE_ISA) + ELSE () + SET(EMBREE_ISA_NAME EMBREE_MAX_ISA) + ENDIF() + + IF (${${EMBREE_ISA_NAME}} STREQUAL "AVX") + SET(EMBREE_ISA_SUPPORTS_AVX TRUE) + ELSEIF (${${EMBREE_ISA_NAME}} STREQUAL "AVX2") + SET(EMBREE_ISA_SUPPORTS_AVX TRUE) + SET(EMBREE_ISA_SUPPORTS_AVX2 TRUE) + ELSEIF (${${EMBREE_ISA_NAME}} STREQUAL "AVX512KNL") + SET(EMBREE_ISA_SUPPORTS_AVX TRUE) + SET(EMBREE_ISA_SUPPORTS_AVX2 TRUE) + SET(EMBREE_ISA_SUPPORTS_AVX512 TRUE) + ENDIF() + + # Configure OSPRay ISA last after we've detected what we got w/ Embree + OSPRAY_CONFIGURE_ISPC_ISA() + +ELSE(OSPRAY_USE_EXTERNAL_EMBREE) + + # Clear out embree directories if they were previously populated by an + # external find_package() call + IF(${LAST_CONFIG_USED_EXTERNAL_EMBREE}) + UNSET(EMBREE_INCLUDE_DIRS) + UNSET(EMBREE_LIBRARIES) + UNSET(EMBREE_LIBRARY) + UNSET(EMBREE_LIBRARY_XEONPHI) + ENDIF() + + # Build Embree included in the OSPRay tree ################################## + + # NOTE(jda) - Embree assumes that OSPRAY_TASKING_TBB will be defined correctly + # in CONFIGURE_TASKING_SYSTEM() + # NOTE(jda) - Only do the Embree include once (Xeon), it will build both + # Xeon and MIC code if both are enabled. + IF (NOT THIS_IS_MIC) + SET(EMBREE_ISA_SUPPORTS_AVX TRUE) + SET(EMBREE_ISA_SUPPORTS_AVX2 TRUE) + SET(EMBREE_ISA_SUPPORTS_AVX512 TRUE) + + # Configure OSPRay ISA before building internal Embree so we know what ISA + # for Embree to build. + OSPRAY_CONFIGURE_ISPC_ISA() + + INCLUDE(build_embree) + ENDIF() + SET(EMBREE_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/ospray/embree-v2.7.1/include) + SET(EMBREE_LIBRARY embree) + SET(EMBREE_LIBRARIES ${EMBREE_LIBRARY}) + SET(EMBREE_LIBRARY_XEONPHI embree_xeonphi) + SET(LAST_CONFIG_USED_EXTERNAL_EMBREE OFF CACHE INTERNAL "" FORCE) + +ENDIF(OSPRAY_USE_EXTERNAL_EMBREE) + +# NOTE(jda) - Windows not yet handled... +IF (OSPRAY_USE_EXTERNAL_EMBREE AND NOT WIN32 AND OSPRAY_ZIP_MODE) + INSTALL(PROGRAMS ${EMBREE_LIBRARY} + DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT lib) # /intel64? + IF(OSPRAY_MIC) + INSTALL(PROGRAMS ${EMBREE_LIBRARY_XEONPHI} + DESTINATION ${CMAKE_INSTALL_LIBDIR}/mic COMPONENT lib_mic) + ENDIF() +ENDIF() diff --git a/cmake/displaycluster.cmake b/cmake/displaycluster.cmake deleted file mode 100644 index 0fdce8c3ae..0000000000 --- a/cmake/displaycluster.cmake +++ /dev/null @@ -1,39 +0,0 @@ -## ======================================================================== ## -## Copyright 2009-2016 Intel Corporation ## -## ## -## Licensed under the Apache License, Version 2.0 (the "License"); ## -## you may not use this file except in compliance with the License. ## -## You may obtain a copy of the License at ## -## ## -## http://www.apache.org/licenses/LICENSE-2.0 ## -## ## -## Unless required by applicable law or agreed to in writing, software ## -## distributed under the License is distributed on an "AS IS" BASIS, ## -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## -## See the License for the specific language governing permissions and ## -## limitations under the License. ## -## ======================================================================== ## - -OPTION(OSPRAY_DISPLAYCLUSTER "Build DisplayCluster tiled display support") -MARK_AS_ADVANCED(OSPRAY_DISPLAYCLUSTER) - -IF (OSPRAY_DISPLAYCLUSTER) - - FIND_PATH(DISPLAYCLUSTER_INCLUDE_DIR dcStream.h - $ENV{DISPLAYCLUSTER_DIR}/include - ) - - FIND_PATH(DISPLAYCLUSTER_LINK_DIR libDisplayCluster.so - $ENV{DISPLAYCLUSTER_DIR}/lib - ) - - FIND_LIBRARY(DISPLAYCLUSTER_LIBRARY NAMES libDisplayCluster.so PATHS $ENV{DISPLAYCLUSTER_DIR}/lib ${DISPLAYCLUSTER_LINK_DIR}) - - SET(DISPLAYCLUSTER_LIBRARIES ${DISPLAYCLUSTER_LIBRARY}) - - MACRO(CONFIGURE_DISPLAYCLUSTER) - INCLUDE_DIRECTORIES(${DISPLAYCLUSTER_INCLUDE_DIR}) - LINK_DIRECTORIES(${DISPLAYCLUSTER_LINK_DIR}) - ENDMACRO() - -ENDIF (OSPRAY_DISPLAYCLUSTER) diff --git a/cmake/glut.cmake b/cmake/glut.cmake index fed7e4b1b6..62ec14e036 100644 --- a/cmake/glut.cmake +++ b/cmake/glut.cmake @@ -21,9 +21,9 @@ IF (APPLE) ELSEIF (WIN32) # FindGLUT.cmake is broken for Windows in CMake until 3.0: does not support PATH IF (GLUT_ROOT_PATH) - MESSAGE(WARNING "Warning: GLUT_ROOT_PATH is depreciated.") - SET(DEPRECIATED_WIN32_INCLUDE ${GLUT_ROOT_PATH}/include) - SET(DEPRECIATED_WIN32_RELEASE ${GLUT_ROOT_PATH}/Release) + MESSAGE(WARNING "Warning: GLUT_ROOT_PATH is deprecated.") + SET(DEPRECATED_WIN32_INCLUDE ${GLUT_ROOT_PATH}/include) + SET(DEPRECATED_WIN32_RELEASE ${GLUT_ROOT_PATH}/Release) ENDIF() FIND_PATH(GLUT_INCLUDE_DIR NAMES GL/glut.h @@ -31,7 +31,7 @@ ELSEIF (WIN32) ${PROJECT_SOURCE_DIR}/../freeglut/include ${PROJECT_SOURCE_DIR}/../freeglut-MSVC-3.0.0-2.mp/include ${PROJECT_SOURCE_DIR}/../freeglut-MSVC-3.0.0-2.mp/freeglut/include ${PROJECT_SOURCE_DIR}/../freeglut-MSVC-2.8.1-1.mp/include ${PROJECT_SOURCE_DIR}/../freeglut-MSVC-2.8.1-1.mp/freeglut/include - ${DEPRECIATED_WIN32_INCLUDE} + ${DEPRECATED_WIN32_INCLUDE} ) # detect and select x64 IF (CMAKE_SIZEOF_VOID_P EQUAL 8) @@ -39,17 +39,12 @@ ELSEIF (WIN32) ENDIF() FIND_LIBRARY(GLUT_glut_LIBRARY NAMES freeglut glut glut32 - HINTS ${GLUT_INCLUDE_DIR}/../lib/${ARCH} ${FREEGLUT_ROOT_PATH}/lib/${ARCH} ${DEPRECIATED_WIN32_RELEASE} - ) - FIND_FILE(GLUT_DLL - NAMES freeglut.dll - HINTS ${GLUT_INCLUDE_DIR}/../bin/${ARCH} ${FREEGLUT_ROOT_PATH}/bin/${ARCH} + HINTS ${GLUT_INCLUDE_DIR}/../lib/${ARCH} ${FREEGLUT_ROOT_PATH}/lib/${ARCH} ${DEPRECATED_WIN32_RELEASE} ) SET(GLUT_LIBRARIES ${GLUT_glut_LIBRARY}) MARK_AS_ADVANCED( GLUT_INCLUDE_DIR GLUT_glut_LIBRARY - GLUT_DLL ) IF (NOT GLUT_INCLUDE_DIR OR NOT GLUT_glut_LIBRARY) MESSAGE(FATAL_ERROR "Could not find GLUT library. You could fetch freeglut from http://www.transmissionzero.co.uk/software/freeglut-devel/ and set the FREEGLUT_ROOT_PATH variable in cmake.") @@ -84,3 +79,17 @@ ELSE() ENDIF() INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIR} ${GLUT_INCLUDE_DIR}) + + +############################################################## +# redistribute freeglut on Windows +############################################################## + +IF (WIN32) + FIND_FILE(GLUT_DLL + NAMES freeglut.dll + HINTS ${GLUT_INCLUDE_DIR}/../bin/${ARCH} ${FREEGLUT_ROOT_PATH}/bin/${ARCH} + ) + MARK_AS_ADVANCED(GLUT_DLL) + INSTALL(PROGRAMS ${GLUT_DLL} DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT apps) # 3rd party? +ENDIF() diff --git a/cmake/ispc.cmake b/cmake/ispc.cmake index dba28e3cba..5847846d1f 100644 --- a/cmake/ispc.cmake +++ b/cmake/ispc.cmake @@ -96,6 +96,7 @@ MACRO (OSPRAY_ISPC_COMPILE) SET(ISPC_TARGET_ARGS generic-16) SET(ISPC_ADDITIONAL_ARGS ${ISPC_ADDITIONAL_ARGS} + -DOSPRAY_TARGET_MIC --opt=force-aligned-memory --emit-c++ --c++-include-file=${PROJECT_SOURCE_DIR}/ospray/common/ISPC_KNC_Backend.h diff --git a/cmake/ospray_cmake_config.cmake b/cmake/ospray_cmake_config.cmake index 906609d72d..0e7a1fecd3 100644 --- a/cmake/ospray_cmake_config.cmake +++ b/cmake/ospray_cmake_config.cmake @@ -54,8 +54,14 @@ LIST(APPEND ospray_MODULE_INSTALL_FILES ${CMAKE_SOURCE_DIR}/cmake/FindTBB.cmake) INSTALL(FILES ${ospray_MODULE_INSTALL_FILES} + ${CMAKE_SOURCE_DIR}/cmake/clang.cmake + ${CMAKE_SOURCE_DIR}/cmake/icc.cmake + ${CMAKE_SOURCE_DIR}/cmake/icc_xeonphi.cmake ${CMAKE_SOURCE_DIR}/cmake/ispc.cmake - ${CMAKE_SOURCE_DIR}/cmake/ospray.cmake + ${CMAKE_SOURCE_DIR}/cmake/gcc.cmake + ${CMAKE_SOURCE_DIR}/cmake/mpi.cmake + ${CMAKE_SOURCE_DIR}/cmake/msvc.cmake + ${CMAKE_SOURCE_DIR}/cmake/ospray_macros.cmake DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/ospray-${OSPRAY_VERSION}" COMPONENT devel ) diff --git a/cmake/ospray_cmake_config/osprayConfig.cmake.in b/cmake/ospray_cmake_config/osprayConfig.cmake.in index 02575cf234..24645027b8 100644 --- a/cmake/ospray_cmake_config/osprayConfig.cmake.in +++ b/cmake/ospray_cmake_config/osprayConfig.cmake.in @@ -60,15 +60,9 @@ set(CMAKE_MODULE_PATH ${CURRENT_CONFIG_INSTALL_DIR}) # ospray was configured & built) from the current install directory for this # this file. This allows for the install tree to be relocated, after ospray # was built, outside of CMake. -if(WIN32) - get_filename_component(CURRENT_ROOT_INSTALL_DIR - ${CURRENT_CONFIG_INSTALL_DIR}/../ ABSOLUTE - ) -else(WIN32) - get_filename_component(CURRENT_ROOT_INSTALL_DIR - ${CURRENT_CONFIG_INSTALL_DIR}/../../../ ABSOLUTE - ) -endif(WIN32) +get_filename_component(CURRENT_ROOT_INSTALL_DIR + ${CURRENT_CONFIG_INSTALL_DIR}/../../../ ABSOLUTE +) if(NOT EXISTS ${CURRENT_ROOT_INSTALL_DIR}) OSPRAY_REPORT_NOT_FOUND( @@ -79,11 +73,13 @@ if(NOT EXISTS ${CURRENT_ROOT_INSTALL_DIR}) "outside of CMake after ospray was built.") endif(NOT EXISTS ${CURRENT_ROOT_INSTALL_DIR}) +set(OSPRAY_ROOT ${CURRENT_ROOT_INSTALL_DIR}) + # Set the include directories for ospray (itself). -set(OSPRAY_INCLUDE_DIR "${CURRENT_ROOT_INSTALL_DIR}/include") +set(OSPRAY_INCLUDE_DIR "${OSPRAY_ROOT}/include") if(NOT EXISTS ${OSPRAY_INCLUDE_DIR}/ospray/version.h) OSPRAY_REPORT_NOT_FOUND( - "ospray install root: ${CURRENT_ROOT_INSTALL_DIR}, " + "ospray install root: ${OSPRAY_ROOT}, " "determined from relative path from osprayConfg.cmake install location: " "${CURRENT_CONFIG_INSTALL_DIR}, does not contain ospray headers. " "Either the install directory was deleted, or the install tree was only " @@ -104,12 +100,17 @@ set(OSPRAY_INCLUDE_DIRS # ospray build configuration -SET(OSPRAY_COMPILER_ICC @OSPRAY_COMPILER_ICC@ ) -SET(OSPRAY_COMPILER_GCC @OSPRAY_COMPILER_GCC@ ) -SET(OSPRAY_COMPILER_CLANG @OSPRAY_COMPILER_CLANG@) -SET(OSPRAY_COMPILER_MSVC @OSPRAY_COMPILER_MSVC@ ) +set(OSPRAY_VERSION @OSPRAY_VERSION@) +set(OSPRAY_SOVERSION @OSPRAY_SOVERSION@) + +set(OSPRAY_COMPILER_ICC @OSPRAY_COMPILER_ICC@) +set(OSPRAY_COMPILER_GCC @OSPRAY_COMPILER_GCC@) +set(OSPRAY_COMPILER_CLANG @OSPRAY_COMPILER_CLANG@) +set(OSPRAY_COMPILER_MSVC @OSPRAY_COMPILER_MSVC@) -SET(OSPRAY_USE_EXTERNAL_EMBREE @OSPRAY_USE_EXTERNAL_EMBREE@) +set(OSPRAY_USE_EXTERNAL_EMBREE @OSPRAY_USE_EXTERNAL_EMBREE@) +set(OSPRAY_TASKING_TBB @OSPRAY_TASKING_TBB@) +set(OSPRAY_ISPC_TARGET_LIST @OSPRAY_ISPC_TARGET_LIST@) ############################################################################### @@ -142,16 +143,25 @@ if (OSPRAY_TASKING_CILK) add_definitions(-DOSPRAY_TASKING_CILK) endif() +IF(WIN32) + SET(LIBRARY_PATH_PREFIX ${OSPRAY_ROOT}/@CMAKE_INSTALL_LIBDIR@/${CMAKE_IMPORT_LIBRARY_PREFIX}) + SET(LIBRARY_SUFFIX ${CMAKE_IMPORT_LIBRARY_SUFFIX}) +ELSE() + SET(LIBRARY_PATH_PREFIX ${OSPRAY_ROOT}/@CMAKE_INSTALL_LIBDIR@/${CMAKE_SHARED_LIBRARY_PREFIX}) + SET(LIBRARY_SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX}) +ENDIF() + if(OSPRAY_USE_EXTERNAL_EMBREE) # Find existing Embree on the machine - find_package(embree @REQUIRED_MINIMUM_EMBREE@ REQUIRED) + find_package(embree @EMBREE_VERSION_REQUIRED@ REQUIRED) else() if (APPLE) - set(EMBREE_LIBRARY ${CURRENT_ROOT_INSTALL_DIR}/@CMAKE_INSTALL_LIBDIR@/${CMAKE_SHARED_LIBRARY_PREFIX}embree.2${CMAKE_SHARED_LIBRARY_SUFFIX}) + set(EMBREE_LIBRARY ${LIBRARY_PATH_PREFIX}embree.2${LIBRARY_SUFFIX}) else() - set(EMBREE_LIBRARY ${CURRENT_ROOT_INSTALL_DIR}/@CMAKE_INSTALL_LIBDIR@/${CMAKE_SHARED_LIBRARY_PREFIX}embree${CMAKE_SHARED_LIBRARY_SUFFIX}.2) + set(EMBREE_LIBRARY ${LIBRARY_PATH_PREFIX}embree${LIBRARY_SUFFIX}.2) endif() endif() +list(APPEND OSPRAY_INCLUDE_DIRS ${EMBREE_INCLUDE_DIRS}) # Restore state set(CMAKE_CURRENT_LIST_DIR ${OSPRAY_CMAKE_CURRENT_LIST_DIR}) @@ -197,15 +207,17 @@ set(OSPRAY_LIBRARIES #ospray# NOTE(jda) - target disabled (see above) #ospray_embree# NOTE(jda) - target disabled (see above) ${EMBREE_LIBRARY} - ${CURRENT_ROOT_INSTALL_DIR}/@CMAKE_INSTALL_LIBDIR@/${CMAKE_SHARED_LIBRARY_PREFIX}ospray${CMAKE_SHARED_LIBRARY_SUFFIX} - ${CURRENT_ROOT_INSTALL_DIR}/@CMAKE_INSTALL_LIBDIR@/${CMAKE_SHARED_LIBRARY_PREFIX}ospray_common${CMAKE_SHARED_LIBRARY_SUFFIX} + ${LIBRARY_PATH_PREFIX}ospray${LIBRARY_SUFFIX} + ${LIBRARY_PATH_PREFIX}ospray_common${LIBRARY_SUFFIX} ) # Reset CMake module path to its state when this script was called. set(CMAKE_MODULE_PATH ${OSPRAY_CALLERS_CMAKE_MODULE_PATH}) +set(OSPRAY_CMAKE_ROOT ${OSPRAY_ROOT}/@CMAKE_INSTALL_LIBDIR@/cmake/ospray-@OSPRAY_VERSION@) + # Include definitions for clients to use ospray header files -set(OSPRAY_USE_FILE ${CMAKE_CURRENT_LIST_DIR}/osprayUse.cmake) +set(OSPRAY_USE_FILE ${OSPRAY_CMAKE_ROOT}/osprayUse.cmake) # OSPRAY_REPORT_NOT_FOUND() aborts, so if we made it this far, # we have found ospray and all required dependencies. diff --git a/cmake/ospray_cmake_config/osprayUse.cmake.in b/cmake/ospray_cmake_config/osprayUse.cmake.in index e1135fa897..c497f3d078 100644 --- a/cmake/ospray_cmake_config/osprayUse.cmake.in +++ b/cmake/ospray_cmake_config/osprayUse.cmake.in @@ -20,5 +20,7 @@ # which need certain preprocessor definitions based on how ospray # was built. -include(${CMAKE_CURRENT_LIST_DIR}/ispc.cmake) -include(${CMAKE_CURRENT_LIST_DIR}/ospray.cmake) +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${OSPRAY_CMAKE_ROOT}) + +include(${OSPRAY_CMAKE_ROOT}/ispc.cmake) +include(${OSPRAY_CMAKE_ROOT}/ospray_macros.cmake) diff --git a/cmake/ospray.cmake b/cmake/ospray_macros.cmake similarity index 68% rename from cmake/ospray.cmake rename to cmake/ospray_macros.cmake index 124a9a216a..00fc85db90 100644 --- a/cmake/ospray.cmake +++ b/cmake/ospray_macros.cmake @@ -14,24 +14,6 @@ ## limitations under the License. ## ## ======================================================================== ## -#include bindir - that's where ispc puts generated header files -INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR}) -SET(OSPRAY_BINARY_DIR ${CMAKE_BINARY_DIR}) -SET(OSPRAY_DIR ${PROJECT_SOURCE_DIR}) -# arch-specific cmd-line flags for various arch and compiler configs - -SET(OSPRAY_TILE_SIZE 64 CACHE INT "Tile size") -SET_PROPERTY(CACHE OSPRAY_TILE_SIZE PROPERTY STRINGS 8 16 32 64 128 256 512) - -SET(OSPRAY_PIXELS_PER_JOB 64 CACHE INT - "Must be multiple of largest vector width *and* <= OSPRAY_TILE_SIZE") - -MARK_AS_ADVANCED(OSPRAY_TILE_SIZE) -MARK_AS_ADVANCED(OSPRAY_PIXELS_PER_JOB) - -# unhide compiler to make it easier for users to see what they are using -MARK_AS_ADVANCED(CLEAR CMAKE_CXX_COMPILER) - ## Macro for printing CMake variables ## MACRO(PRINT var) MESSAGE("${var} = ${${var}}") @@ -48,11 +30,23 @@ ENDMACRO() ## Macro check for compiler support of ISA ## MACRO(OSPRAY_CHECK_COMPILER_SUPPORT ISA) - IF (${ISA} STREQUAL "AVX512" AND (NOT OSPRAY_COMPILER_ICC OR WIN32 OR APPLE)) - OSPRAY_WARN_ONCE(MISSING_AVX512 "OSPRay Currently requires ICC on Linux for KNL support. Disabling KNL ISA target.") - SET(OSPRAY_EMBREE_ENABLE_${ISA} false) + IF (${ISA} STREQUAL "AVX512") + IF (WIN32 OR APPLE) + OSPRAY_WARN_ONCE(MISSING_AVX512 + "OSPRay only supports KNL on Linux. " + "Disabling KNL ISA target.") + SET(OSPRAY_EMBREE_ENABLE_${ISA} false) + ELSEIF ((NOT OSPRAY_COMPILER_ICC) AND (NOT OSPRAY_USE_EXTERNAL_EMBREE)) + OSPRAY_WARN_ONCE(MISSING_AVX512 + "You must use ICC to compile AVX512 when using OSPRAY_USE_EXTERNAL_EMBREE=OFF. Either install and use an AVX512 compatible Embree, or switch to using the Intel Compiler.") + SET(OSPRAY_EMBREE_ENABLE_${ISA} false) + ENDIF() ELSEIF (OSPRAY_EMBREE_ENABLE_${ISA} AND NOT OSPRAY_COMPILER_SUPPORTS_${ISA}) - OSPRAY_WARN_ONCE(MISSING_${ISA} "Need at least version ${GCC_VERSION_REQUIRED_${ISA}} of gcc for ${ISA}. Disabling ${ISA}.\nTo compile for ${ISA}, please switch to either 'ICC'-compiler, or upgrade your gcc version.") + OSPRAY_WARN_ONCE(MISSING_${ISA} + "Need at least version ${GCC_VERSION_REQUIRED_${ISA}} of " + "GCC for ${ISA}. Disabling ${ISA}.\nTo compile for " + "${ISA}, please switch to either 'ICC'-compiler, or " + "upgrade your GCC version.") SET(OSPRAY_EMBREE_ENABLE_${ISA} false) ENDIF() ENDMACRO() @@ -62,6 +56,11 @@ MACRO(OSPRAY_CONFIGURE_ISPC_ISA) OSPRAY_CONFIGURE_COMPILER() + # the arch we're targeting for the non-MIC/non-xeon phi part of ospray + SET(OSPRAY_BUILD_ISA "ALL" CACHE STRING + "Target ISA (SSE, AVX, AVX2, AVX512, or ALL)") + STRING(TOUPPER ${OSPRAY_BUILD_ISA} OSPRAY_BUILD_ISA) + SET(OSPRAY_EMBREE_ENABLE_SSE true) SET(OSPRAY_EMBREE_ENABLE_AVX true) SET(OSPRAY_EMBREE_ENABLE_AVX2 true) @@ -71,23 +70,18 @@ MACRO(OSPRAY_CONFIGURE_ISPC_ISA) OSPRAY_CHECK_COMPILER_SUPPORT(AVX2) OSPRAY_CHECK_COMPILER_SUPPORT(AVX512) - # the arch we're targeting for the non-MIC/non-xeon phi part of ospray - SET(OSPRAY_BUILD_ISA "ALL" CACHE STRING - "Target ISA (SSE, AVX, AVX2, AVX512, or ALL)") - STRING(TOUPPER ${OSPRAY_BUILD_ISA} OSPRAY_BUILD_ISA) - UNSET(OSPRAY_SUPPORTED_ISAS) IF(OSPRAY_EMBREE_ENABLE_SSE) SET(OSPRAY_SUPPORTED_ISAS ${OSPRAY_SUPPORTED_ISAS} SSE) ENDIF() - IF(OSPRAY_EMBREE_ENABLE_AVX) + IF(OSPRAY_EMBREE_ENABLE_AVX AND EMBREE_ISA_SUPPORTS_AVX) SET(OSPRAY_SUPPORTED_ISAS ${OSPRAY_SUPPORTED_ISAS} AVX) ENDIF() - IF(OSPRAY_EMBREE_ENABLE_AVX2) + IF(OSPRAY_EMBREE_ENABLE_AVX2 AND EMBREE_ISA_SUPPORTS_AVX2) SET(OSPRAY_SUPPORTED_ISAS ${OSPRAY_SUPPORTED_ISAS} AVX2) ENDIF() - IF(OSPRAY_EMBREE_ENABLE_AVX512) + IF(OSPRAY_EMBREE_ENABLE_AVX512 AND EMBREE_ISA_SUPPORTS_AVX512) SET(OSPRAY_SUPPORTED_ISAS ${OSPRAY_SUPPORTED_ISAS} AVX512) ENDIF() @@ -97,23 +91,31 @@ MACRO(OSPRAY_CONFIGURE_ISPC_ISA) UNSET(OSPRAY_ISPC_TARGET_LIST) IF (OSPRAY_BUILD_ISA STREQUAL "ALL") + IF(OSPRAY_EMBREE_ENABLE_SSE) SET(OSPRAY_ISPC_TARGET_LIST ${OSPRAY_ISPC_TARGET_LIST} sse4) + MESSAGE(STATUS "OSPRay SSE ISA target enabled.") ENDIF() - IF(OSPRAY_EMBREE_ENABLE_AVX) + IF(OSPRAY_EMBREE_ENABLE_AVX AND EMBREE_ISA_SUPPORTS_AVX) SET(OSPRAY_ISPC_TARGET_LIST ${OSPRAY_ISPC_TARGET_LIST} avx) + MESSAGE(STATUS "OSPRay AVX ISA target enabled.") ENDIF() - IF(OSPRAY_EMBREE_ENABLE_AVX2) + IF(OSPRAY_EMBREE_ENABLE_AVX2 AND EMBREE_ISA_SUPPORTS_AVX2) SET(OSPRAY_ISPC_TARGET_LIST ${OSPRAY_ISPC_TARGET_LIST} avx2) + MESSAGE(STATUS "OSPRay AVX2 ISA target enabled.") ENDIF() - IF(OSPRAY_EMBREE_ENABLE_AVX512) + IF(OSPRAY_EMBREE_ENABLE_AVX512 AND EMBREE_ISA_SUPPORTS_AVX512) SET(OSPRAY_ISPC_TARGET_LIST ${OSPRAY_ISPC_TARGET_LIST} avx512knl-i32x16) + MESSAGE(STATUS "OSPRay AVX512 ISA target enabled.") ENDIF() ELSEIF (OSPRAY_BUILD_ISA STREQUAL "AVX512") IF(NOT OSPRAY_EMBREE_ENABLE_AVX512) MESSAGE(FATAL_ERROR "Compiler does not support AVX512!") + ELSEIF(NOT EMBREE_ISA_SUPPORTS_AVX512) + MESSAGE(FATAL_ERROR + "Your Embree build only supports up to ${${EMBREE_ISA_NAME}}!") ENDIF() SET(OSPRAY_ISPC_TARGET_LIST avx512knl-i32x16) @@ -121,6 +123,9 @@ MACRO(OSPRAY_CONFIGURE_ISPC_ISA) IF(NOT OSPRAY_EMBREE_ENABLE_AVX2) MESSAGE(FATAL_ERROR "Compiler does not support AVX2!") + ELSEIF(NOT EMBREE_ISA_SUPPORTS_AVX2) + MESSAGE(FATAL_ERROR + "Your Embree build only supports up to ${${EMBREE_ISA_NAME}}!") ENDIF() SET(OSPRAY_ISPC_TARGET_LIST avx2) @@ -130,6 +135,9 @@ MACRO(OSPRAY_CONFIGURE_ISPC_ISA) IF(NOT OSPRAY_EMBREE_ENABLE_AVX) MESSAGE(FATAL_ERROR "Compiler does not support AVX!") + ELSEIF(NOT EMBREE_ISA_SUPPORTS_AVX) + MESSAGE(FATAL_ERROR + "Your Embree build only supports up to ${${EMBREE_ISA_NAME}}!") ENDIF() SET(OSPRAY_ISPC_TARGET_LIST avx) @@ -142,65 +150,36 @@ MACRO(OSPRAY_CONFIGURE_ISPC_ISA) SET(OSPRAY_EMBREE_ENABLE_AVX2 false) SET(OSPRAY_EMBREE_ENABLE_AVX false) ELSE () - MESSAGE(ERROR "Invalid OSPRAY_BUILD_ISA value. Please select one of SSE, AVX, AVX2, AVX512, or ALL.") + MESSAGE(ERROR "Invalid OSPRAY_BUILD_ISA value. " + "Please select one of SSE, AVX, AVX2, AVX512, or ALL.") ENDIF() ENDMACRO() -# Configure the output directories. To allow IMPI to do its magic we -# will put *executables* into the (same) build directory, but tag -# mic-executables with ".mic". *libraries* cannot use the -# ".mic"-suffix trick, so we'll put libraries into separate -# directories (names 'intel64' and 'mic', respectively) -MACRO(CONFIGURE_OSPRAY) - OSPRAY_CONFIGURE_ISPC_ISA() - OSPRAY_CONFIGURE_TASKING_SYSTEM() - - IF("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") - SET(OSPRAY_DEBUG_BUILD ON ) - SET(OSPRAY_RELWITHDEBINFO_BUILD OFF) - SET(OSPRAY_RELEASE_BUILD OFF) - ELSEIF("${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo") - SET(OSPRAY_DEBUG_BUILD OFF) - SET(OSPRAY_RELWITHDEBINFO_BUILD ON ) - SET(OSPRAY_RELEASE_BUILD OFF) - ELSE()# Release - SET(OSPRAY_DEBUG_BUILD OFF) - SET(OSPRAY_RELWITHDEBINFO_BUILD OFF) - SET(OSPRAY_RELEASE_BUILD ON ) - ENDIF() +## Target creation macros ## - IF (WIN32) - # avoid problematic min/max defines of windows.h - ADD_DEFINITIONS(-DNOMINMAX) - ENDIF() +MACRO(OSPRAY_ADD_SUBDIRECTORY subdirectory) + SET(OSPRAY_EXE_SUFFIX "") + SET(OSPRAY_LIB_SUFFIX "") + SET(OSPRAY_ISPC_SUFFIX ".o") + SET(THIS_IS_MIC OFF) + SET(__XEON__ ON) + + ADD_SUBDIRECTORY(${subdirectory} builddir/${subdirectory}/intel64) - IF (OSPRAY_TARGET STREQUAL "mic") + IF (OSPRAY_MIC) SET(OSPRAY_EXE_SUFFIX ".mic") SET(OSPRAY_LIB_SUFFIX "_mic") SET(OSPRAY_ISPC_SUFFIX ".cpp") SET(OSPRAY_ISPC_TARGET "mic") SET(THIS_IS_MIC ON) SET(__XEON__ OFF) - INCLUDE(${PROJECT_SOURCE_DIR}/cmake/icc_xeonphi.cmake) + INCLUDE(icc_xeonphi) SET(OSPRAY_TARGET_MIC ON PARENT_SCOPE) - ELSE() - SET(OSPRAY_EXE_SUFFIX "") - SET(OSPRAY_LIB_SUFFIX "") - SET(OSPRAY_ISPC_SUFFIX ".o") - SET(THIS_IS_MIC OFF) - SET(__XEON__ ON) - ENDIF() - IF (THIS_IS_MIC) - OPTION(OSPRAY_BUILD_COI_DEVICE - "Build COI Device for OSPRay's MIC support?" ON) + ADD_SUBDIRECTORY(${subdirectory} builddir/${subdirectory}/mic) ENDIF() - - INCLUDE(${PROJECT_SOURCE_DIR}/cmake/ispc.cmake) ENDMACRO() -## Target creation macros ## - MACRO(OSPRAY_ADD_EXECUTABLE name) ADD_EXECUTABLE(${name}${OSPRAY_EXE_SUFFIX} ${ARGN}) ENDMACRO() @@ -217,11 +196,12 @@ MACRO(OSPRAY_ADD_LIBRARY name type) ENDIF () ENDFOREACH() OSPRAY_ISPC_COMPILE(${ISPC_SOURCES}) - ADD_LIBRARY(${name}${OSPRAY_LIB_SUFFIX} ${type} ${ISPC_OBJECTS} ${OTHER_SOURCES} ${ISPC_SOURCES}) + ADD_LIBRARY(${name}${OSPRAY_LIB_SUFFIX} ${type} + ${ISPC_OBJECTS} ${OTHER_SOURCES} ${ISPC_SOURCES}) IF (THIS_IS_MIC) FOREACH(src ${ISPC_OBJECTS}) - SET_SOURCE_FILES_PROPERTIES( ${src} PROPERTIES COMPILE_FLAGS -std=gnu++98 ) + SET_SOURCE_FILES_PROPERTIES(${src} PROPERTIES COMPILE_FLAGS -std=gnu++98) ENDFOREACH() ENDIF() ENDMACRO() @@ -263,14 +243,29 @@ ENDMACRO() # go into COMPONENT lib MACRO(OSPRAY_INSTALL_LIBRARY name) + # NOTE(jda) - Check if CMAKE_INSTALL_LIB/BINDIR is set, and use + # CMAKE_INSTALL_PREFIX if it's not defined. It may not be defined + # in a client project who calls this macro in their CMakeLists. + IF(NOT DEFINED CMAKE_INSTALL_LIBDIR) + SET(LOCAL_LIB_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}) + ELSE() + SET(LOCAL_LIB_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR}) + ENDIF() + + IF(NOT DEFINED CMAKE_INSTALL_BINDIR) + SET(LOCAL_BIN_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}) + ELSE() + SET(LOCAL_BIN_INSTALL_DIR ${CMAKE_INSTALL_BINDIR}) + ENDIF() + INSTALL(TARGETS ${name}${OSPRAY_LIB_SUFFIX} ${ARGN} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${LOCAL_LIB_INSTALL_DIR} COMPONENT lib${OSPRAY_LIB_SUFFIX} # on Windows put the dlls into bin - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + RUNTIME DESTINATION ${LOCAL_BIN_INSTALL_DIR} COMPONENT lib # ... and the import lib into the devel package - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${LOCAL_LIB_INSTALL_DIR} COMPONENT devel ) ENDMACRO() @@ -300,11 +295,10 @@ ENDMACRO() # OSPRAY_CREATE_LIBRARY( source1 [source2 ...] # [LINK lib1 [lib2 ...]]) # -# will create and install shared library 'ospray_' from 'sources' with +# will create and install shared library from 'sources' with # version OSPRAY_[SO]VERSION and optionally link against 'libs' -MACRO(OSPRAY_CREATE_LIBRARY name) - SET(LIBRARY_NAME ospray_${name}) +MACRO(OSPRAY_CREATE_LIBRARY LIBRARY_NAME) SET(LIBRARY_SOURCES "") SET(LINK_LIBS "") @@ -329,11 +323,10 @@ ENDMACRO() # OSPRAY_CREATE_APPLICATION( source1 [source2 ...] # [LINK lib1 [lib2 ...]]) # -# will create and install application 'osp' from 'sources' with version +# will create and install application from 'sources' with version # OSPRAY_VERSION and optionally link against 'libs' -MACRO(OSPRAY_CREATE_APPLICATION name) - SET(APP_NAME osp${name}) +MACRO(OSPRAY_CREATE_APPLICATION APP_NAME) SET(APP_SOURCES "") SET(LINK_LIBS "") @@ -387,60 +380,26 @@ ENDMACRO() ## Compiler configuration macro ## MACRO(OSPRAY_CONFIGURE_COMPILER) - # enable ability for users to force a compiler using the pre-0.8.3 method (doesn't work right now!) - SET(OSPRAY_COMPILER "" CACHE STRING "Force compiler: GCC, ICC, CLANG") - SET_PROPERTY(CACHE OSPRAY_COMPILER PROPERTY STRINGS GCC ICC CLANG) - MARK_AS_ADVANCED(OSPRAY_COMPILER) - - IF(NOT ":${OSPRAY_COMPILER}" STREQUAL ":") - STRING(TOUPPER ${OSPRAY_COMPILER} OSPRAY_COMPILER) - IF(${OSPRAY_COMPILER} STREQUAL "GCC") - FIND_PROGRAM(GCC_EXECUTABLE gcc DOC "Path to the gcc executable.") - FIND_PROGRAM(G++_EXECUTABLE g++ DOC "Path to the g++ executable.") - SET(CMAKE_C_COMPILER ${GCC_EXECUTABLE} CACHE STRING "C Compiler" FORCE) - SET(CMAKE_CXX_COMPILER ${G++_EXECUTABLE} CACHE STRING "CXX Compiler" FORCE) - SET(CMAKE_C_COMPILER "gcc") - SET(CMAKE_CXX_COMPILER "g++") - SET(CMAKE_CXX_COMPILER_ID "GNU") - ELSEIF(${OSPRAY_COMPILER} STREQUAL "ICC") - FIND_PROGRAM(ICC_EXECUTABLE icc DOC "Path to the icc executable.") - FIND_PROGRAM(ICPC_EXECUTABLE icpc DOC "Path to the icpc executable.") - SET(CMAKE_C_COMPILER ${ICC_EXECUTABLE} CACHE STRING "CXX Compiler" FORCE) - SET(CMAKE_CXX_COMPILER ${ICPC_EXECUTABLE} CACHE STRING "CXX Compiler" FORCE) - SET(CMAKE_CXX_COMPILER_ID "Intel") - ELSEIF(${OSPRAY_COMPILER} STREQUAL "CLANG") - FIND_PROGRAM(CLANG_EXECUTABLE clang DOC "Path to the clang executable.") - FIND_PROGRAM(CLANG_EXECUTABLE clang++ DOC "Path to the clang++ executable.") - SET(CMAKE_C_COMPILER ${CLANG_EXECUTABLE} CACHE STRING "C Compiler" FORCE) - SET(CMAKE_CXX_COMPILER ${CLANG_EXECUTABLE} CACHE STRING "CXX Compiler" FORCE) - SET(CMAKE_CXX_COMPILER_ID "Clang") - ENDIF() - ENDIF() + # unhide compiler to make it easier for users to see what they are using + MARK_AS_ADVANCED(CLEAR CMAKE_CXX_COMPILER) + + SET(OSPRAY_COMPILER_ICC OFF) + SET(OSPRAY_COMPILER_GCC OFF) + SET(OSPRAY_COMPILER_CLANG OFF) + SET(OSPRAY_COMPILER_MSVC OFF) IF (${CMAKE_CXX_COMPILER_ID} STREQUAL "Intel") - SET(OSPRAY_COMPILER_ICC ON ) - SET(OSPRAY_COMPILER_GCC OFF) - SET(OSPRAY_COMPILER_CLANG OFF) - SET(OSPRAY_COMPILER_MSVC OFF) - INCLUDE(${PROJECT_SOURCE_DIR}/cmake/icc.cmake) + SET(OSPRAY_COMPILER_ICC ON) + INCLUDE(icc) ELSEIF (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") - SET(OSPRAY_COMPILER_ICC OFF) - SET(OSPRAY_COMPILER_GCC ON ) - SET(OSPRAY_COMPILER_CLANG OFF) - SET(OSPRAY_COMPILER_MSVC OFF) - INCLUDE(${PROJECT_SOURCE_DIR}/cmake/gcc.cmake) + SET(OSPRAY_COMPILER_GCC ON) + INCLUDE(gcc) ELSEIF (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang") - SET(OSPRAY_COMPILER_ICC OFF) - SET(OSPRAY_COMPILER_GCC OFF) - SET(OSPRAY_COMPILER_CLANG ON ) - SET(OSPRAY_COMPILER_MSVC OFF) - INCLUDE(${PROJECT_SOURCE_DIR}/cmake/clang.cmake) + SET(OSPRAY_COMPILER_CLANG ON) + INCLUDE(clang) ELSEIF (${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") - SET(OSPRAY_COMPILER_ICC OFF) - SET(OSPRAY_COMPILER_GCC OFF) - SET(OSPRAY_COMPILER_CLANG OFF) - SET(OSPRAY_COMPILER_MSVC ON ) - INCLUDE(${PROJECT_SOURCE_DIR}/cmake/msvc.cmake) + SET(OSPRAY_COMPILER_MSVC ON) + INCLUDE(msvc) ELSE() MESSAGE(FATAL_ERROR "Unsupported compiler specified: '${CMAKE_CXX_COMPILER_ID}'") @@ -525,6 +484,12 @@ MACRO(OSPRAY_CONFIGURE_TASKING_SYSTEM) ENDIF() ELSEIF(OSPRAY_TASKING_CILK) ADD_DEFINITIONS(-DOSPRAY_TASKING_CILK) + IF (OSPRAY_COMPILER_GCC OR OSPRAY_COMPILER_CLANG) + OSPRAY_WARN_ONCE(UNSAFE_USE_OF_CILK + "You are using Cilk with GCC or Clang...use at your own risk!") + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fcilkplus") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcilkplus") + ENDIF() ELSEIF(OSPRAY_TASKING_INTERNAL) ADD_DEFINITIONS(-DOSPRAY_TASKING_INTERNAL) ELSE()#Debug diff --git a/cmake/ospray_options.cmake b/cmake/ospray_options.cmake new file mode 100644 index 0000000000..035e1b40a2 --- /dev/null +++ b/cmake/ospray_options.cmake @@ -0,0 +1,142 @@ +## ======================================================================== ## +## Copyright 2009-2016 Intel Corporation ## +## ## +## Licensed under the Apache License, Version 2.0 (the "License"); ## +## you may not use this file except in compliance with the License. ## +## You may obtain a copy of the License at ## +## ## +## http://www.apache.org/licenses/LICENSE-2.0 ## +## ## +## Unless required by applicable law or agreed to in writing, software ## +## distributed under the License is distributed on an "AS IS" BASIS, ## +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## +## See the License for the specific language governing permissions and ## +## limitations under the License. ## +## ======================================================================== ## + +############################################################## +# Global configuration options +############################################################## + +SET(OSPRAY_VERSION_MAJOR 1) +SET(OSPRAY_VERSION_MINOR 1) +SET(OSPRAY_VERSION_PATCH 0) +SET(OSPRAY_VERSION_GITHASH 0) +IF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git) + FIND_PACKAGE(Git) + IF(GIT_FOUND) + EXECUTE_PROCESS( + COMMAND ${GIT_EXECUTABLE} rev-parse HEAD + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + OUTPUT_VARIABLE "OSPRAY_VERSION_GITHASH" + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + ENDIF() +ENDIF() + +SET(OSPRAY_VERSION + ${OSPRAY_VERSION_MAJOR}.${OSPRAY_VERSION_MINOR}.${OSPRAY_VERSION_PATCH} +) +SET(OSPRAY_SOVERSION 0) + +SET(CONFIGURATION_TYPES "Debug;Release;RelWithDebInfo") +IF (WIN32) + IF (NOT OSPRAY_DEFAULT_CMAKE_CONFIGURATION_TYPES_SET) + SET(CMAKE_CONFIGURATION_TYPES "${CONFIGURATION_TYPES}" + CACHE STRING "List of generated configurations." FORCE) + SET(OSPRAY_DEFAULT_CMAKE_CONFIGURATION_TYPES_SET ON + CACHE INTERNAL "Default CMake configuration types set.") + ENDIF() +ELSE() + IF(NOT CMAKE_BUILD_TYPE) + SET(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the build type." FORCE) + SET_PROPERTY(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS ${CONFIGURATION_TYPES}) + ENDIF() +ENDIF() + +IF("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") + SET(OSPRAY_DEBUG_BUILD ON ) + SET(OSPRAY_RELWITHDEBINFO_BUILD OFF) + SET(OSPRAY_RELEASE_BUILD OFF) +ELSEIF("${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo") + SET(OSPRAY_DEBUG_BUILD OFF) + SET(OSPRAY_RELWITHDEBINFO_BUILD ON ) + SET(OSPRAY_RELEASE_BUILD OFF) +ELSE()# Release + SET(OSPRAY_DEBUG_BUILD OFF) + SET(OSPRAY_RELWITHDEBINFO_BUILD OFF) + SET(OSPRAY_RELEASE_BUILD ON ) +ENDIF() + +SET(OSPRAY_BINARY_DIR ${PROJECT_BINARY_DIR}) +SET(LIBRARY_OUTPUT_PATH ${OSPRAY_BINARY_DIR}) +SET(EXECUTABLE_OUTPUT_PATH ${OSPRAY_BINARY_DIR}) + +#include bindir - that's where ispc puts generated header files +INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR}) +SET(OSPRAY_BINARY_DIR ${CMAKE_BINARY_DIR}) +SET(OSPRAY_DIR ${PROJECT_SOURCE_DIR}) + +IF (WIN32) + # avoid problematic min/max defines of windows.h + ADD_DEFINITIONS(-DNOMINMAX) +ENDIF() + +############################################################## +# create binary packages; before any INSTALL() invocation/definition +############################################################## + +OPTION(OSPRAY_ZIP_MODE "Use tarball/zip CPack generator instead of RPM" ON) +MARK_AS_ADVANCED(OSPRAY_ZIP_MODE) + +INCLUDE(package) + +############################################################## +# OSPRay specific build options and configuration selection +############################################################## + +OPTION(OSPRAY_USE_EXTERNAL_EMBREE + "Use a pre-built Embree instead of the internally built version" ON) + +OPTION(OSPRAY_USE_EMBREE_STREAMS "Enable Streams if using Embree v2.10 or later") + +OPTION(OSPRAY_USE_HIGH_QUALITY_BVH + "Takes slighly longer to build but offers higher ray tracing performance; recommended when using Embree v2.11 or later") + +OPTION(OSPRAY_VOLUME_VOXELRANGE_IN_APP "Move 'voxelrange' computations to app?") +MARK_AS_ADVANCED(OSPRAY_VOLUME_VOXELRANGE_IN_APP) + +# Configure MIC support +IF (WIN32) + SET(OSPRAY_BUILD_MIC_SUPPORT OFF CACHE INTERNAL + "OSPRay with KNC not supported on Windows.") +ELSE() + OPTION(OSPRAY_BUILD_MIC_SUPPORT "Build OSPRay with KNC Support?") + IF (OSPRAY_BUILD_MIC_SUPPORT AND NOT OSPRAY_COMPILER_ICC) + MESSAGE(FATAL_ERROR "MIC support requires the Intel Compiler.") + ELSEIF (OSPRAY_BUILD_MIC_SUPPORT) + # Build COI device? + OPTION(OSPRAY_BUILD_COI_DEVICE + "Build COI Device for OSPRay's MIC support?" ON) + ENDIF() +ENDIF() + +OPTION(OSPRAY_BUILD_MPI_DEVICE "Add MPI Remote/Distributed rendering support?") + +SET(OSPRAY_MIC ${OSPRAY_BUILD_MIC_SUPPORT}) +SET(OSPRAY_MPI ${OSPRAY_BUILD_MPI_DEVICE}) + +SET(OSPRAY_TILE_SIZE 64 CACHE INT "Tile size") +SET_PROPERTY(CACHE OSPRAY_TILE_SIZE PROPERTY STRINGS 8 16 32 64 128 256 512) + +SET(OSPRAY_PIXELS_PER_JOB 64 CACHE INT + "Must be multiple of largest vector width *and* <= OSPRAY_TILE_SIZE") + +MARK_AS_ADVANCED(OSPRAY_TILE_SIZE) +MARK_AS_ADVANCED(OSPRAY_PIXELS_PER_JOB) + +OSPRAY_CONFIGURE_COMPILER() +OSPRAY_CONFIGURE_TASKING_SYSTEM() + +# Must be before ISA config +INCLUDE(configure_embree) diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt index f8fab0b931..56d408037c 100644 --- a/modules/CMakeLists.txt +++ b/modules/CMakeLists.txt @@ -23,6 +23,7 @@ INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR} ${EMBREE_INCLUDE_DIRS} ) + INCLUDE_DIRECTORIES_ISPC( ${PROJECT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/ospray/include diff --git a/modules/opengl/CMakeLists.txt b/modules/opengl/CMakeLists.txt index 75978b5e2f..feb4d55248 100644 --- a/modules/opengl/CMakeLists.txt +++ b/modules/opengl/CMakeLists.txt @@ -24,6 +24,6 @@ IF(NOT THIS_IS_MIC AND OSPRAY_MODULE_OPENGL_UTIL) LIST(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/modules/opengl) - OSPRAY_CREATE_LIBRARY(module_opengl_util util.cpp + OSPRAY_CREATE_LIBRARY(ospray_module_opengl_util util.cpp LINK ospray ${OPENGL_LIBRARIES}) ENDIF() diff --git a/modules/opengl/util.cpp b/modules/opengl/util.cpp index 3f0e3340c9..b119b7bfa6 100644 --- a/modules/opengl/util.cpp +++ b/modules/opengl/util.cpp @@ -188,8 +188,8 @@ namespace ospray { const float *ospDepthBuffer, const osp::vec2i &frameBufferSize) { - ospray::vec3f cameraDir = (ospray::vec3f&)cameraDir; - ospray::vec3f cameraUp = (ospray::vec3f&)cameraUp; + ospray::vec3f cameraDir = (ospray::vec3f&)_cameraDir; + ospray::vec3f cameraUp = (ospray::vec3f&)_cameraUp; // this should later be done in ISPC... const size_t ospDepthBufferWidth = (size_t)frameBufferSize.x; diff --git a/ospcommon/CMakeLists.txt b/ospcommon/CMakeLists.txt index f67d5d4420..022cf5ef24 100644 --- a/ospcommon/CMakeLists.txt +++ b/ospcommon/CMakeLists.txt @@ -15,17 +15,15 @@ ## ======================================================================== ## SET(CMAKE_THREAD_PREFER_PTHREAD TRUE) +SET(THREADS_PREFER_PTHREAD_FLAG TRUE) FIND_PACKAGE(Threads REQUIRED) +SET(LINK_LIBS ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS}) -SET(LINK_LIBS - ${CMAKE_THREAD_LIBS_INIT} - ${CMAKE_DL_LIBS} -) IF (WIN32) LIST(APPEND LINK_LIBS ws2_32) ENDIF() -OSPRAY_CREATE_LIBRARY(common +OSPRAY_CREATE_LIBRARY(ospray_common common.cpp FileName.cpp sysinfo.cpp diff --git a/ospcommon/RefCount.h b/ospcommon/RefCount.h index e446879688..677cc6c416 100644 --- a/ospcommon/RefCount.h +++ b/ospcommon/RefCount.h @@ -37,37 +37,48 @@ namespace ospcommon { public: inline RefCount(atomic_init_t val = 0) : refCounter(val) {} - virtual ~RefCount() {}; + virtual ~RefCount() {} /*! dummy copy-constructor and assignment operator because if they do not exist icc throws some error about "delted function" when auto-constructing those. they should NEVER get called, though */ - inline RefCount(const RefCount &other) { throw std::runtime_error("should not copy-construc refence-counted objects!"); } + inline RefCount(const RefCount &) + { + throw std::runtime_error("should not copy-construct refence-counted " + "objects!"); + } + /*! dummy copy-constructor and assignment operator because if they do not exist icc throws some error about "delted function" when auto-constructing those. they should NEVER get called, though */ - inline RefCount &operator=(const RefCount &other) { throw std::runtime_error("should not copy-construc refence-counted objects!"); return *this; } + inline RefCount &operator=(const RefCount &) + { + throw std::runtime_error("should not copy-construct refence-counted " + "objects!"); + return *this; + } virtual void refInc() { refCounter++; } virtual void refDec() { if ((--refCounter) == 0) delete this; } + private: atomic_t refCounter; }; - //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////// /// Reference to single object - //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////// template class Ref { public: Type* const ptr; - //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// /// Constructors, Assignment & Cast Operators - //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// __forceinline Ref( void ) : ptr(nullptr) {} __forceinline Ref(NullTy) : ptr(nullptr) {} diff --git a/ospcommon/bak.vec.h b/ospcommon/bak.vec.h deleted file mode 100644 index e77a4b6ae3..0000000000 --- a/ospcommon/bak.vec.h +++ /dev/null @@ -1,136 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2016 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "../common/common.h" - -namespace ospcommon { - - template - struct vec2_t { - typedef T scalar_t; - - inline vec2_t() {}; - inline vec2_t(const vec2_t &o) : x(o.x), y(o.y) {} - inline vec2_t(scalar_t s) : x(s), y(s) {}; - inline vec2_t(scalar_t x, scalar_t y) : x(x), y(y) {}; - - /*! return result of reduce_add() across all components */ - inline scalar_t sum() const { return x+y; } - /*! return result of reduce_mul() across all components */ - inline scalar_t product() const { return x*y; } - - T x, y; - }; - - template - struct vec3_t { - typedef T scalar_t; - - inline vec3_t() {}; - inline vec3_t(scalar_t s) : x(s), y(s) {}; - inline vec3_t(scalar_t x, scalar_t y, scalar_t z) : x(x), y(y), z(z) {}; - - /*! return result of reduce_add() across all components */ - inline scalar_t sum() const { return x+y+z; } - /*! return result of reduce_mul() across all components */ - inline scalar_t product() const { return x*y*z; } - - T x, y, z; - }; - - template - struct vec4_t { - typedef T scalar_t; - - inline vec4_t() {}; - inline vec4_t(scalar_t s) : x(s), y(s) {}; - inline vec4_t(scalar_t x, scalar_t y, scalar_t z, scalar_t w) : x(x), y(y), z(z), w(w) {}; - - /*! return result of reduce_add() across all components */ - inline scalar_t sum() const { return x+y+z+w; } - /*! return result of reduce_mul() across all components */ - inline scalar_t product() const { return x*y*z*w; } - - T x, y, z, w; - }; - - - - // ------------------------------------------------------- - // all vec2 variants - // ------------------------------------------------------- - typedef vec2_t vec2ui; - typedef vec2_t vec2i; - typedef vec2_t vec2f; - typedef vec2_t vec2d; - - // ------------------------------------------------------- - // all vec3 variants - // ------------------------------------------------------- - typedef vec3_t vec3ui; - typedef vec3_t vec3i; - typedef vec3_t vec3f; - typedef vec3_t vec3d; - - // ------------------------------------------------------- - // binary operators - // ------------------------------------------------------- -#define define_operator(operator,op) \ - template \ - inline vec2_t operator(const vec2_t &a, const vec2_t &b) \ - { return vec2_t(a.x op b.x, a.y op b.y); } \ - \ - template \ - inline vec3_t operator(const vec3_t &a, const vec3_t &b) \ - { return vec3_t(a.x op b.x, a.y op b.y, a.z op b.z); } \ - \ - template \ - inline vec4_t operator(const vec4_t &a, const vec4_t &b) \ - { return vec4_t(a.x op b.x, a.y op b.y, a.z op b.z, a.w op b.w); } \ - - define_operator(operator*,*); - define_operator(operator/,/); - define_operator(operator-,-); - define_operator(operator+,+); -#undef define_operator - - // "inherit" std::min/max/etc for basic types - using std::min; - using std::max; - - // ------------------------------------------------------- - // binary functors - // ------------------------------------------------------- -#define define_functor(f) \ - template \ - inline vec2_t f(const vec2_t &a, const vec2_t &b) \ - { return vec2_t(f(a.x,b.x),f(a.y,b.y)); } \ - \ - template \ - inline vec3_t f(const vec3_t &a, const vec3_t &b) \ - { return vec3_t(f(a.x,b.x),f(a.y,b.y),f(a.z,b.z)); } \ - \ - template \ - inline vec4_t f(const vec4_t &a, const vec4_t &b) \ - { return vec4_t(f(a.x,b.x),f(a.y,b.y),f(a.z,b.z),f(a.w,b.w)); } \ - - define_functor(min); - define_functor(max); -#undef define_functor - -} // ::ospcommon diff --git a/ospcommon/library.cpp b/ospcommon/library.cpp index 1e931294f3..8112a02053 100644 --- a/ospcommon/library.cpp +++ b/ospcommon/library.cpp @@ -41,8 +41,11 @@ namespace ospcommon { #endif #ifdef _WIN32 std::string fullName = file+".dll"; - FileName executable = getExecutableFileName(); - lib = LoadLibrary((executable.path() + fullName).c_str()); + lib = LoadLibrary(fullName.c_str()); + if (!lib) { + FileName executable = getExecutableFileName(); + lib = LoadLibrary((executable.path() + fullName).c_str()); + } #else #if defined(__MACOSX__) std::string fullName = "lib"+file+".dylib"; @@ -69,7 +72,7 @@ namespace ospcommon { } } - Library::Library(void* const lib) : lib(lib) {}; + Library::Library(void* const lib) : lib(lib) {} void* Library::getSymbol(const std::string& sym) const { diff --git a/ospcommon/malloc.cpp b/ospcommon/malloc.cpp index 32e766b648..cd3bad7c0c 100644 --- a/ospcommon/malloc.cpp +++ b/ospcommon/malloc.cpp @@ -127,7 +127,10 @@ namespace ospcommon return ptr; } - void os_commit (void* ptr, size_t bytes) { + void os_commit (void* ptr, size_t bytes) + { + (void)ptr; + (void)bytes; } size_t os_shrink(void* ptr, size_t bytesNew, size_t bytesOld) diff --git a/ospcommon/math.h b/ospcommon/math.h index 291d963232..5b50b405e4 100644 --- a/ospcommon/math.h +++ b/ospcommon/math.h @@ -184,8 +184,8 @@ namespace ospcommon template __forceinline T clamp(const T& x, const T& lower = T(zero), const T& upper = T(one)) { return max(min(x,upper),lower); } template __forceinline T clampz(const T& x, const T& upper) { return max(T(zero), min(x,upper)); } - template __forceinline T deg2rad ( const T& x ) { return x * T(1.74532925199432957692e-2f); } - template __forceinline T rad2deg ( const T& x ) { return x * T(5.72957795130823208768e1f); } + template __forceinline T deg2rad ( const T& x ) { return x * T(1.745329251994329576923690768489e-2); } + template __forceinline T rad2deg ( const T& x ) { return x * T(5.7295779513082320876798154814105e1); } template __forceinline T sin2cos ( const T& x ) { return sqrt(max(T(zero),T(one)-x*x)); } template __forceinline T cos2sin ( const T& x ) { return sin2cos(x); } diff --git a/ospcommon/platform.h b/ospcommon/platform.h index 8c328c5a73..24146f34dd 100644 --- a/ospcommon/platform.h +++ b/ospcommon/platform.h @@ -236,6 +236,24 @@ #define NOT_IMPLEMENTED FATAL(std::string(__FUNCTION__) + " not implemented") +// NOTE(jda) - These macros are used to construct the last UNUSED(...) macro, +// used to mark a variable number of arguments as unused so the +// compiler doesn't warn when -Wextra (gcc/clang/icc) is used. Only +// works with 1 to 5 passed arguments. +#define UNUSED_1(x) (void)x +#define UNUSED_2(x, y) UNUSED_1(x); UNUSED_1(y) +#define UNUSED_3(x, ...) UNUSED_2(x, UNUSED_2(__VA_ARGS__)) +#define UNUSED_4(x, ...) UNUSED_2(x, UNUSED_3(__VA_ARGS__)) +#define UNUSED_5(x, ...) UNUSED_2(x, UNUSED_4(__VA_ARGS__)) + +// NUM_ARGS(...) evaluates to the literal number of the passed-in arguments. +#define _NUM_ARGS2(X,X5,X4,X3,X2,X1,N,...) N +#define NUM_ARGS(...) _NUM_ARGS2(0,__VA_ARGS__,5,4,3,2,1,0) + +#define _UNUSED_N3(N, ...) UNUSED_##N(__VA_ARGS__) +#define _UNUSED_N2(N, ...) _UNUSED_N3(N, __VA_ARGS__) +#define UNUSED(...) _UNUSED_N2(NUM_ARGS(__VA_ARGS__), __VA_ARGS__) + //////////////////////////////////////////////////////////////////////////////// /// Basic Types //////////////////////////////////////////////////////////////////////////////// @@ -328,8 +346,4 @@ __asm__ __volatile__ ( \ IACA_SSC_MARK(111)} #define IACA_END {IACA_SSC_MARK(222) \ IACA_UD_BYTES} - -namespace ospcommon { - -} diff --git a/ospcommon/vec.cpp b/ospcommon/vec.cpp index f6c937a90c..fbef9f8a7e 100644 --- a/ospcommon/vec.cpp +++ b/ospcommon/vec.cpp @@ -20,11 +20,32 @@ namespace ospcommon { // ------------------------------------------------------- // parsing from strings // ------------------------------------------------------- + int toInt(const char *ptr) + { + assert(ptr); + int v; + int rc = sscanf(ptr,"%i",&v); + (void)rc; + assert(rc == 1); + return v; + } + + float toFloat(const char *ptr) + { + assert(ptr); + float v; + int rc = sscanf(ptr,"%f",&v); + (void)rc; + assert(rc == 1); + return v; + } + vec2f toVec2f(const char *ptr) { assert(ptr); vec2f v; int rc = sscanf(ptr,"%f %f",&v.x,&v.y); + (void)rc; assert(rc == 2); return v; } @@ -34,6 +55,7 @@ namespace ospcommon { assert(ptr); vec3f v; int rc = sscanf(ptr,"%f %f %f",&v.x,&v.y,&v.z); + (void)rc; assert(rc == 3); return v; } @@ -43,6 +65,7 @@ namespace ospcommon { assert(ptr); vec4f v; int rc = sscanf(ptr,"%f %f %f %f",&v.x,&v.y,&v.z,&v.w); + (void)rc; assert(rc == 4); return v; } @@ -52,6 +75,7 @@ namespace ospcommon { assert(ptr); vec2i v; int rc = sscanf(ptr,"%i %i",&v.x,&v.y); + (void)rc; assert(rc == 2); return v; } @@ -61,6 +85,7 @@ namespace ospcommon { assert(ptr); vec3i v; int rc = sscanf(ptr,"%i %i %i",&v.x,&v.y,&v.z); + (void)rc; assert(rc == 3); return v; } @@ -70,6 +95,7 @@ namespace ospcommon { assert(ptr); vec4i v; int rc = sscanf(ptr,"%i %i %i %i",&v.x,&v.y,&v.z,&v.w); + (void)rc; assert(rc == 4); return v; } diff --git a/ospcommon/vec.h b/ospcommon/vec.h index 18f77f04c5..fe0af816d7 100644 --- a/ospcommon/vec.h +++ b/ospcommon/vec.h @@ -35,7 +35,7 @@ namespace ospcommon { typedef T Scalar; inline vec_t() {}; - inline vec_t(scalar_t s) : x(s), y(s) {}; + inline explicit vec_t(scalar_t s) : x(s), y(s) {}; inline vec_t(scalar_t x, scalar_t y) : x(x), y(y) {}; inline vec_t(const vec_t &o) : x(o.x), y(o.y) {} @@ -156,10 +156,10 @@ namespace ospcommon { template inline vec_t op(const vec_t &v)\ { return vec_t(op(v.x),op(v.y),op(v.z),op(v.w)); }\ - unary_functor(rcp); - unary_functor(abs); - unary_functor(sin); - unary_functor(cos); + unary_functor(rcp) + unary_functor(abs) + unary_functor(sin) + unary_functor(cos) #undef unary_functor // ------------------------------------------------------- @@ -214,11 +214,11 @@ namespace ospcommon { const vec_t &b) \ { return vec_t(a op b.x,a op b.y,a op b.z,a op b.w); } \ - binary_operator(operator+,+); - binary_operator(operator-,-); - binary_operator(operator*,*); - binary_operator(operator/,/); - binary_operator(operator%,%); + binary_operator(operator+,+) + binary_operator(operator-,-) + binary_operator(operator*,*) + binary_operator(operator/,/) + binary_operator(operator%,%) #undef binary_operator // ------------------------------------------------------- @@ -257,10 +257,10 @@ namespace ospcommon { const T &b) \ { a.x op b; a.y op b; a.z op b; a.w op b; return a; } \ - binary_operator(operator+=,+=); - binary_operator(operator-=,-=); - binary_operator(operator*=,*=); - binary_operator(operator/=,/=); + binary_operator(operator+=,+=) + binary_operator(operator-=,-=) + binary_operator(operator*=,*=) + binary_operator(operator/=,/=) #undef binary_operator // ------------------------------------------------------- @@ -297,33 +297,6 @@ namespace ospcommon { inline bool operator!=(const vec_t &a, const vec_t &b) { return !(a==b); } - /*! comparison operators; we need those to be able to put vec's in std::map etc @{ */ - template - inline bool operator<(const vec_t &a, const vec_t &b) - { - return (a.x - inline bool operator<(const vec_t &a, const vec_t &b) - { - return - (a.x< b.x) || - ((a.x==b.x) && ((a.y< b.y) || - ((a.y==b.y) && (a.z - inline bool operator<(const vec_t &a, const vec_t &b) - { - return - (a.x< b.x) || - ((a.x==b.x) && ((a.y< b.y) || - ((a.y==b.y) && ((a.z< b.z) || - ((a.z==b.z) && (a.w < b.w)))))); - } - /*! @} */ - // 'anyLessThan' - return true if any component is less than the other vec's template inline bool anyLessThan(const vec_t &a, const vec_t &b) @@ -373,9 +346,14 @@ namespace ospcommon { // ------------------------------------------------------- // normalize() // ------------------------------------------------------- - template inline vec_t normalize(const vec_t &v) + template + inline vec_t normalize(const vec_t &v) { return v * rsqrt(dot(v,v)); } - + + template + inline vec_t safe_normalize(const vec_t &v) + { return v * rsqrt(max(1e-6f, dot(v,v))); } + // ------------------------------------------------------- // ostream operators // ------------------------------------------------------- @@ -409,9 +387,9 @@ namespace ospcommon { inline vec_t f(const vec_t &a, const vec_t &b) \ { return vec_t(f(a.x,b.x),f(a.y,b.y),f(a.z,b.z),f(a.w,b.w)); } \ - define_functor(min); - define_functor(max); - define_functor(divRoundUp); + define_functor(min) + define_functor(max) + define_functor(divRoundUp) #undef define_functor // ------------------------------------------------------- @@ -506,6 +484,8 @@ namespace ospcommon { // ------------------------------------------------------- // parsing from strings // ------------------------------------------------------- + OSPCOMMON_INTERFACE int toInt(const char *ptr); + OSPCOMMON_INTERFACE float toFloat(const char *ptr); OSPCOMMON_INTERFACE vec2f toVec2f(const char *ptr); OSPCOMMON_INTERFACE vec3f toVec3f(const char *ptr); OSPCOMMON_INTERFACE vec4f toVec4f(const char *ptr); @@ -515,3 +495,50 @@ namespace ospcommon { } // ::ospcommon + +/*! template specialization for std::less comparison operator; + * we need those to be able to put vec's in std::map etc @{ */ +/* Defining just operator< is prone to bugs, because a definition of an + * ordering of vectors is a bit arbitrary and depends on the context. + * For example, in box::extend we certainly want the element-wise min/max and + * not the std::min/std::max made applicable by vec3f::operator<. +*/ +namespace std { + template + struct less> + { + inline bool operator()(const ospcommon::vec_t &a, + const ospcommon::vec_t &b) const + { + return (a.x < b.x) || ((a.x == b.x) && (a.y < b.y)); + } + }; + + template + struct less> + { + inline bool operator()(const ospcommon::vec_t &a, + const ospcommon::vec_t &b) const + { + return + (a.x < b.x) || + ((a.x == b.x) && ((a.y < b.y) || + ((a.y == b.y) && (a.z < b.z)))); + } + }; + + template + struct less> + { + inline bool operator()(const ospcommon::vec_t &a, + const ospcommon::vec_t &b) const + { + return + (a.x < b.x) || + ((a.x == b.x) && ((a.y < b.y) || + ((a.y == b.y) && ((a.z < b.z) || + ((a.z == b.z) && (a.w < b.w)))))); + } + }; +} // std +/*! @} */ diff --git a/ospray/CMakeLists.txt b/ospray/CMakeLists.txt index 53b9b018ff..7ce63510be 100644 --- a/ospray/CMakeLists.txt +++ b/ospray/CMakeLists.txt @@ -25,83 +25,40 @@ MARK_AS_ADVANCED(EXP_NEW_BB_VOLUME_KERNELS) # NOTE(jda) - PThread hint used by both Embree and OSPRay SET(CMAKE_THREAD_PREFER_PTHREAD TRUE) +SET(THREADS_PREFER_PTHREAD_FLAG TRUE) # for gcc6 FIND_PACKAGE(Threads REQUIRED) # ------------------------------------------------------- -# Find or build Embree +# redistribute TBB # ------------------------------------------------------- -SET(REQUIRED_MINIMUM_EMBREE 2.7.1) - -# Do a check to see if we can find the system Embree -IF(NOT DEFINED LAST_CONFIG_USED_EXTERNAL_EMBREE) - FIND_PACKAGE(embree ${REQUIRED_MINIMUM_EMBREE} QUIET) - IF(NOT DEFINED EMBREE_INCLUDE_DIRS) - MESSAGE(WARNING - "We did not find Embree installed on your system. If you would" - " like to use a newer version of Embree than the one in the" - " OSPRay source tree (v2.7.1), please download and extract or" - " compile Embree from source, set the 'embree_DIR' environment" - " variable to where it is installed, and re-enable the" - " OSPRAY_USE_EXTERNAL_EMBREE CMake option.") - SET(OSPRAY_USE_EXTERNAL_EMBREE OFF CACHE BOOL "" FORCE) - ENDIF() -ENDIF() - -IF(OSPRAY_USE_EXTERNAL_EMBREE) - # Clear out embree directories if they were previously populated by an - # internal build - IF(NOT ${LAST_CONFIG_USED_EXTERNAL_EMBREE}) - UNSET(EMBREE_INCLUDE_DIRS) - UNSET(EMBREE_LIBRARIES) - UNSET(EMBREE_LIBRARY) - UNSET(EMBREE_LIBRARY_XEONPHI) - ENDIF() - - # Find existing Embree on the machine - FIND_PACKAGE(embree ${REQUIRED_MINIMUM_EMBREE} REQUIRED) - SET(LAST_CONFIG_USED_EXTERNAL_EMBREE ON CACHE INTERNAL "" FORCE) - - # NOTE(jda) - EMBREE_LIBRARIES is not defined until at lest v2.10.0, for now - # create a "faked" EMBREE_LIBRARIES until we set our min version - # to >= 2.10.0 of Embree - IF(NOT DEFINED EMBREE_LIBRARIES) - SET(EMBREE_LIBRARIES ${EMBREE_LIBRARY}) - ELSE() - # NOTE(jda) - We are using the updated Embree find_package() config, check - # if we need to add TBB to EMBREE_LIBRARIES - IF(${EMBREE_TASKING_TBB} AND NOT ${EMBREE_USE_PACKAGED_TBB}) - OSPRAY_WARN_ONCE(EMBREE_FORCE_TBB - "WARNING: You *MUST* have TBB installed based on the Embree we found!") - FIND_PACKAGE(TBB REQUIRED) - SET(EMBREE_LIBRARIES ${EMBREE_LIBRARIES} ${TBB_LIBRARIES}) +IF (OSPRAY_TASKING_TBB) + IF (WIN32) + SET(TBB_DLL_HINTS + ${TBB_ROOT}/../redist/${TBB_ARCH}_win/tbb/${TBB_VCVER} + ${TBB_ROOT}/../redist/${TBB_ARCH}/tbb/${TBB_VCVER} + ${TBB_ROOT}/bin/${TBB_ARCH}/${TBB_VCVER} + ) + FIND_FILE(TBB_DLL tbb.dll HINTS ${TBB_DLL_HINTS}) + FIND_FILE(TBB_DLL_MALLOC tbbmalloc.dll PATHS HINTS ${TBB_DLL_HINTS}) + MARK_AS_ADVANCED(TBB_DLL) + MARK_AS_ADVANCED(TBB_DLL_MALLOC) + INSTALL(PROGRAMS ${TBB_DLL} ${TBB_DLL_MALLOC} + DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT apps) # 3rd party? + ELSEIF (OSPRAY_ZIP_MODE) + INSTALL(PROGRAMS ${TBB_LIBRARY} ${TBB_LIBRARY_MALLOC} ${TBB_LIBRARY_DEBUG} ${TBB_LIBRARY_MALLOC_DEBUG} + DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT lib) # /intel64? + IF(OSPRAY_MIC AND TBB_FOUND_MIC) + INSTALL(PROGRAMS ${TBB_LIBRARIES_MIC} + DESTINATION ${CMAKE_INSTALL_LIBDIR}/mic COMPONENT lib_mic) ENDIF() ENDIF() -ELSE() - # Clear out embree directories if they were previously populated by an - # external find_package() call - IF(${LAST_CONFIG_USED_EXTERNAL_EMBREE}) - UNSET(EMBREE_INCLUDE_DIRS) - UNSET(EMBREE_LIBRARIES) - UNSET(EMBREE_LIBRARY) - UNSET(EMBREE_LIBRARY_XEONPHI) - ENDIF() - # Build Embree included in the OSPRay tree - - # NOTE(jda) - Embree assumes that OSPRAY_TASKING_TBB will be defined correctly - # in CONFIGURE_OSPRAY().CONFIGURE_TASKING_SYSTEM() - # NOTE(jda) - Only do the Embree include once (Xeon), it will build both - # Xeon and MIC code if both are enabled. - IF (NOT THIS_IS_MIC) - INCLUDE(../cmake/build_embree.cmake) - ENDIF() - SET(EMBREE_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/ospray/embree-v2.7.1/include) - SET(EMBREE_LIBRARY embree) - SET(EMBREE_LIBRARIES ${EMBREE_LIBRARY}) - SET(EMBREE_LIBRARY_XEONPHI embree_xeonphi) - SET(LAST_CONFIG_USED_EXTERNAL_EMBREE OFF CACHE INTERNAL "" FORCE) ENDIF() +# ------------------------------------------------------- +# Setup ospray include directories and source files +# ------------------------------------------------------- + INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/ospray/include ${CMAKE_SOURCE_DIR}/ospray @@ -117,15 +74,6 @@ INCLUDE_DIRECTORIES_ISPC( ${EMBREE_INCLUDE_DIRS} ) -SET(EMBREE_INCLUDE_DIRS ${EMBREE_INCLUDE_DIRS} PARENT_SCOPE) -SET(EMBREE_LIBRARIES ${EMBREE_LIBRARIES} PARENT_SCOPE) -SET(EMBREE_LIBRARY ${EMBREE_LIBRARY} PARENT_SCOPE) -SET(EMBREE_LIBRARY_XEONPHI ${EMBREE_LIBRARY_XEONHPI} PARENT_SCOPE) - -# ------------------------------------------------------- -# Setup ospray source files -# ------------------------------------------------------- - SET(OSPRAY_SOURCES include/ospray/ospray.h include/ospray/OSPDataType.h @@ -161,6 +109,7 @@ SET(OSPRAY_SOURCES fb/Tile.h camera/Camera.cpp + camera/Camera.ispc camera/PerspectiveCamera.ispc camera/PerspectiveCamera.cpp camera/OrthographicCamera.ispc @@ -357,7 +306,6 @@ OSPRAY_INSTALL_SDK_HEADERS( math/LinearSpace.ih math/math.ih math/random.ih - math/region.ih math/sampling.ih math/vec.ih DESTINATION math @@ -431,17 +379,7 @@ IF (OSPRAY_MPI) mpi/DistributedFrameBuffer.ispc mpi/DistributedFrameBuffer_TileTypes.cpp - fb/DisplayWall.cpp - ) -ENDIF() - -# ------------------------------------------------------- -# DisplayCluster components -# ------------------------------------------------------- -INCLUDE(${PROJECT_SOURCE_DIR}/cmake/displaycluster.cmake) - -IF (OSPRAY_DISPLAYCLUSTER) - CONFIGURE_DISPLAYCLUSTER() + ) ENDIF() # ------------------------------------------------------- @@ -479,36 +417,36 @@ IF (THIS_IS_MIC) ADD_DEFINITIONS(-DOSPRAY_TARGET_MIC) ENDIF() -OSPRAY_ADD_LIBRARY(ospray SHARED ${OSPRAY_SOURCES}) - -OSPRAY_LIBRARY_LINK_LIBRARIES(ospray +SET(OSPRAY_LIBS ospray_common ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS} ) IF (THIS_IS_MIC) - OSPRAY_LIBRARY_LINK_LIBRARIES(ospray + LIST(APPEND OSPRAY_LIBS ${EMBREE_LIBRARY_XEONPHI} ${TASKING_SYSTEM_LIBS_MIC} ) ELSE() - OSPRAY_LIBRARY_LINK_LIBRARIES(ospray + LIST(APPEND OSPRAY_LIBS ${EMBREE_LIBRARIES} ${TASKING_SYSTEM_LIBS} ) ENDIF() -IF (OSPRAY_DISPLAYCLUSTER) - OSPRAY_LIBRARY_LINK_LIBRARIES(ospray ${DISPLAYCLUSTER_LIBRARIES}) +IF (WIN32) + LIST(APPEND OSPRAY_LIBS ws2_32) ENDIF() -IF (WIN32) - OSPRAY_LIBRARY_LINK_LIBRARIES(ospray ws2_32) +OSPRAY_CREATE_LIBRARY(ospray ${OSPRAY_SOURCES} LINK ${OSPRAY_LIBS}) + +# export ISPC SDK symbols on Windows +IF (WIN32 AND OSPRAY_BUILD_ISA STREQUAL "ALL") + SET_TARGET_PROPERTIES(ospray PROPERTIES LINK_FLAGS + "/DEF:${PROJECT_SOURCE_DIR}/ospray/ospray.def") ENDIF() -OSPRAY_SET_LIBRARY_VERSION(ospray) -OSPRAY_INSTALL_LIBRARY(ospray) IF(NOT THIS_IS_MIC) # build ospTutorial, for testing @@ -530,9 +468,12 @@ IF (OSPRAY_MPI) OSPRAY_LIBRARY_LINK_LIBRARIES(ospray ${MPI_CXX_LIBRARIES}) ENDIF() - OSPRAY_ADD_EXECUTABLE(ospray_mpi_worker mpi/MPIWorker.cpp) - OSPRAY_EXE_LINK_LIBRARIES(ospray_mpi_worker ospray ospray_common) - OSPRAY_INSTALL_EXE(ospray_mpi_worker) + OSPRAY_CREATE_APPLICATION(ospray_mpi_worker + mpi/MPIWorker.cpp + LINK + ospray + ospray_common + ) ENDIF() @@ -546,14 +487,13 @@ IF (OSPRAY_BUILD_COI_DEVICE) # ------------------------------------------------------------ OSPRAY_LIBRARY_LINK_LIBRARIES(ospray ${LIBCOI_DEVICE}) # ... and add the coi worker executable - OSPRAY_ADD_EXECUTABLE(ospray_coi_worker api/COIDeviceWorker.cpp) - OSPRAY_EXE_LINK_LIBRARIES(ospray_coi_worker + OSPRAY_CREATE_APPLICATION(ospray_coi_worker + api/COIDeviceWorker.cpp + LINK ospray ospray_common ${LIBCOI_DEVICE} ) - # ------------------------------------------------------------ - OSPRAY_INSTALL_EXE(ospray_coi_worker) ELSE() # ------------------------------------------------------------ # host-side of COI device: just link libospray to coi host libs diff --git a/ospray/api/API.cpp b/ospray/api/API.cpp index 6172704eab..51438d2baa 100644 --- a/ospray/api/API.cpp +++ b/ospray/api/API.cpp @@ -111,7 +111,7 @@ extern "C" void ospInit(int *_ac, const char **_av) if (_ac && _av) { // we're only supporting local rendering for now - network device // etc to come. - for (int i=1;i<*_ac;i++) { + for (int i = 1; i < *_ac; i++) { if (std::string(_av[i]) == "--osp:mpi") { #ifdef OSPRAY_MPI diff --git a/ospray/api/COIDeviceHost.cpp b/ospray/api/COIDeviceHost.cpp index f53f22f38e..1de3604ee7 100644 --- a/ospray/api/COIDeviceHost.cpp +++ b/ospray/api/COIDeviceHost.cpp @@ -965,8 +965,10 @@ namespace ospray { fb->hostMem = new int32[size.x*size.y]; fb->coiBuffer = new COIBUFFER[engines.size()]; fb->size = size; + const size_t stride = (size.x + 15) & ~15; // COI FB is padded to 16 + const size_t coi_pixels = stride * size.y; for (int i = 0; i < engines.size(); i++) { - result = COIBufferCreate(size.x*size.y*sizeof(int32), + result = COIBufferCreate(coi_pixels*sizeof(int32), COI_BUFFER_NORMAL,COI_OPTIMIZE_HUGE_PAGE_SIZE, //COI_MAP_READ_WRITE, nullptr,1,&engines[i]->coiProcess, @@ -1007,26 +1009,28 @@ namespace ospray { // ------------------------------------------------------- // trigger N copies... // ------------------------------------------------------- + const size_t stride = (fb->size.x + 15) & ~15; // COI FB is padded to 16 + const size_t coi_pixels = stride * fb->size.y; for (int i = 0; i < numEngines; i++) { bzero(&doneCopy[i],sizeof(COIEVENT)); - devBuffer[i] = new int32[fb->size.x*fb->size.y]; + devBuffer[i] = new int32[coi_pixels]; result = COIBufferRead(fb->coiBuffer[i],0,devBuffer[i], - fb->size.x*fb->size.y*sizeof(int32), + coi_pixels*sizeof(int32), COI_COPY_USE_DMA,0,nullptr,&doneCopy[i]); Assert(result == COI_SUCCESS); } // ------------------------------------------------------- // do 50 assemblies... // ------------------------------------------------------- + const size_t sizeX = fb->size.x; + const size_t sizeY = fb->size.y; + const size_t numTilesX = divRoundUp(sizeX,(size_t)TILE_SIZE); + const size_t numTilesY = divRoundUp(sizeY,(size_t)TILE_SIZE); for (int engineID = 0; engineID < numEngines; engineID++) { - const size_t sizeX = fb->size.x; - const size_t sizeY = fb->size.y; COIEventWait(1,&doneCopy[engineID],-1,1,nullptr,nullptr); uint32 *src = (uint32*)devBuffer[engineID]; uint32 *dst = (uint32*)fb->hostMem; - const size_t numTilesX = divRoundUp(sizeX,(size_t)TILE_SIZE); - const size_t numTilesY = divRoundUp(sizeY,(size_t)TILE_SIZE); //NOTE(jda) - can this be parallelized? for (size_t tileY=0;tileY @@ -38,15 +40,16 @@ namespace ospray { << type << "' for the first time" << std::endl; std::string creatorName = "ospray_create_camera__"+std::string(type); - creatorFct creator = (creatorFct)getSymbol(creatorName); //dlsym(RTLD_DEFAULT,creatorName.c_str()); + creatorFct creator = (creatorFct)getSymbol(creatorName); cameraRegistry[type] = creator; if (creator == NULL) { if (ospray::logLevel >= 1) std::cout << "#ospray: could not find camera type '" << type << "'" << std::endl; return NULL; } - Camera *camera = (*creator)(); camera->managedObjectType = OSP_CAMERA; - return(camera); + Camera *camera = (*creator)(); + camera->managedObjectType = OSP_CAMERA; + return camera; } void Camera::commit() @@ -56,6 +59,13 @@ namespace ospray { dir = getParam3f("dir", vec3f(0.f, 0.f, 1.f)); up = getParam3f("up", vec3f(0.f, 1.f, 0.f)); nearClip = getParam1f("near_clip", getParam1f("nearClip", 1e-6f)); + + imageStart = getParam2f("image_start", getParam2f("imageStart", vec2f(0.f))); + imageEnd = getParam2f("image_end", getParam2f("imageEnd", vec2f(1.f))); + + ispc::Camera_set(getIE(), nearClip, + (const ispc::vec2f&)imageStart, + (const ispc::vec2f&)imageEnd); } } // ::ospray diff --git a/ospray/camera/Camera.h b/ospray/camera/Camera.h index d8d09fb7b1..361e9276b7 100644 --- a/ospray/camera/Camera.h +++ b/ospray/camera/Camera.h @@ -20,12 +20,12 @@ #include "common/Ray.h" namespace ospray { - - //! base camera class abstraction + + //! base camera class abstraction /*! the base class itself does not do anything useful; look into perspectivecamera etc for that */ - struct Camera : public ManagedObject { - //! \brief common function to help printf-debugging + struct OSPRAY_SDK_INTERFACE Camera : public ManagedObject { + //! \brief common function to help printf-debugging /*! Every derived class should overrride this! */ virtual std::string toString() const { return "ospray::Camera (base class)"; } virtual void commit(); @@ -39,21 +39,22 @@ namespace ospray { vec3f dir; // main direction of the camera in world-space vec3f up; // up direction of the camera in world-space float nearClip; // near clipping distance + // definition of the image region, may even be outside of [0..1]^2 + // to simulate sensor shift + vec2f imageStart; // lower left corner + vec2f imageEnd; // upper right corner }; /*! \brief registers a internal ospray::'ClassName' camera under - the externally accessible name "external_name" - + the externally accessible name "external_name" + \internal This currently works by defining a extern "C" function with a given predefined name that creates a new instance of this camera. By having this symbol in the shared lib ospray can lateron always get a handle to this fct and create an instance of this camera. */ -#define OSP_REGISTER_CAMERA(InternalClassName,external_name) \ - extern "C" OSPRAY_INTERFACE Camera *ospray_create_camera__##external_name() \ - { \ - return new InternalClassName; \ - } \ +#define OSP_REGISTER_CAMERA(InternalClass, external_name) \ + OSP_REGISTER_OBJECT(Camera, camera, InternalClass, external_name) } // ::ospray diff --git a/ospray/camera/Camera.ih b/ospray/camera/Camera.ih index d25a52ccfa..eb913409ec 100644 --- a/ospray/camera/Camera.ih +++ b/ospray/camera/Camera.ih @@ -17,6 +17,7 @@ #pragma once #include "../common/Ray.ih" +#include "math/box.ih" /*! \file camera.ih Defines the abstract base class of an ISPC-side camera */ @@ -31,7 +32,7 @@ struct CameraSample { }; /*! \brief Fct pointer type for 'virtual' method that sets a pixel */ -typedef void (*Camera_initRay)(uniform Camera *uniform, +typedef void (*Camera_initRay)(uniform Camera *uniform, varying Ray &ray, const varying CameraSample &sample); @@ -48,5 +49,10 @@ struct Camera unused. */ float nearClip; /*!< \brief near clipping plane. */ + box2f subImage; //!< viewable tile / subregion to compute, [0..1]^2 x [0..1]^2 }; +inline vec2f Camera_subRegion(const uniform Camera *uniform self, const vec2f &screen) +{ + return lerp(screen, self->subImage.lower, self->subImage.upper); +} diff --git a/ospray/math/region.ih b/ospray/camera/Camera.ispc similarity index 74% rename from ospray/math/region.ih rename to ospray/camera/Camera.ispc index a95aac826f..e1310c3cfd 100644 --- a/ospray/math/region.ih +++ b/ospray/camera/Camera.ispc @@ -14,19 +14,16 @@ // limitations under the License. // // ======================================================================== // -#pragma once +#include "Camera.ih" -#include "vec.ih" -struct region1f { - float lower; - float upper; -}; - -inline region1f make_region1f(const float lower, const float upper) -{ region1f ret; ret.lower = lower; ret.upper = upper; return ret; } - -struct region2i { - vec2i lower; - vec2i upper; -}; +export void Camera_set(void *uniform _self, + const uniform float nearClip, + const uniform vec2f &imageStart, + const uniform vec2f &imageEnd) +{ + uniform Camera *uniform self = (uniform Camera *uniform)_self; + self->nearClip = nearClip; + self->subImage.lower = imageStart; + self->subImage.upper = imageEnd; +} diff --git a/ospray/camera/OrthographicCamera.cpp b/ospray/camera/OrthographicCamera.cpp index 89ec20dbe2..1b3af5546c 100644 --- a/ospray/camera/OrthographicCamera.cpp +++ b/ospray/camera/OrthographicCamera.cpp @@ -51,8 +51,7 @@ namespace ospray { (const ispc::vec3f&)dir, (const ispc::vec3f&)pos_00, (const ispc::vec3f&)pos_du, - (const ispc::vec3f&)pos_dv, - nearClip); + (const ispc::vec3f&)pos_dv); } OSP_REGISTER_CAMERA(OrthographicCamera, orthographic); diff --git a/ospray/camera/OrthographicCamera.h b/ospray/camera/OrthographicCamera.h index d20cb61bbb..c0a4290236 100644 --- a/ospray/camera/OrthographicCamera.h +++ b/ospray/camera/OrthographicCamera.h @@ -26,7 +26,7 @@ namespace ospray { projections, without support for Depth of Field or Motion Blur \ingroup ospray_supported_cameras - + A simple orthographic camera. This camera type is loaded by passing the type string "orthographic" to \ref ospNewCamera @@ -44,14 +44,14 @@ namespace ospray { */ //! Implements a simple orthographic camera (see \subpage orthographic_camera) - struct OrthographicCamera : public Camera { + struct OSPRAY_SDK_INTERFACE OrthographicCamera : public Camera { /*! \brief constructor \internal also creates the ispc-side data structure */ OrthographicCamera(); - //! \brief common function to help printf-debugging + //! \brief common function to help printf-debugging /*! Every derived class should overrride this! */ virtual std::string toString() const { return "ospray::OrthographicCamera"; } virtual void commit(); - + public: // ------------------------------------------------------------------ // the parameters we 'parsed' from our parameters diff --git a/ospray/camera/OrthographicCamera.ispc b/ospray/camera/OrthographicCamera.ispc index 9194e0c94b..4994e7a414 100644 --- a/ospray/camera/OrthographicCamera.ispc +++ b/ospray/camera/OrthographicCamera.ispc @@ -23,10 +23,12 @@ void OrthographicCamera_initRay(uniform Camera *uniform _self, uniform OrthographicCamera *uniform self = (uniform OrthographicCamera *uniform)_self; + const vec2f screen = Camera_subRegion(_self, sample.screen); + const vec3f dir = self->dir; const vec3f org = self->pos_00 - + sample.screen.x * self->pos_du - + sample.screen.y * self->pos_dv; + + screen.x * self->pos_du + + screen.y * self->pos_dv; setRay(ray, org, dir, self->super.nearClip, infinity); } @@ -49,8 +51,7 @@ export void OrthographicCamera_set(void *uniform _self, const uniform vec3f &dir, const uniform vec3f &pos_00, const uniform vec3f &pos_du, - const uniform vec3f &pos_dv, - const uniform float nearClip) + const uniform vec3f &pos_dv) { uniform OrthographicCamera *uniform self = (uniform OrthographicCamera *uniform)_self; @@ -58,5 +59,4 @@ export void OrthographicCamera_set(void *uniform _self, self->pos_00 = pos_00; self->pos_du = pos_du; self->pos_dv = pos_dv; - self->super.nearClip = nearClip; } diff --git a/ospray/camera/PanoramicCamera.cpp b/ospray/camera/PanoramicCamera.cpp index 827475f35a..255104061f 100644 --- a/ospray/camera/PanoramicCamera.cpp +++ b/ospray/camera/PanoramicCamera.cpp @@ -44,8 +44,7 @@ namespace ospray { ispc::PanoramicCamera_set(getIE(), (const ispc::vec3f&)pos, - (const ispc::LinearSpace3f&)frame, - nearClip); + (const ispc::LinearSpace3f&)frame); } OSP_REGISTER_CAMERA(PanoramicCamera,panoramic); diff --git a/ospray/camera/PanoramicCamera.h b/ospray/camera/PanoramicCamera.h index 4bf73f162b..af17eecaaf 100644 --- a/ospray/camera/PanoramicCamera.h +++ b/ospray/camera/PanoramicCamera.h @@ -26,7 +26,7 @@ namespace ospray { without support for Depth of Field or Motion Blur \ingroup ospray_supported_cameras - + A simple panoramic camera. This camera type is loaded by passing the type string "panoramic" to \ref ospNewCamera @@ -42,10 +42,10 @@ namespace ospray { */ //! Implements a simple panoramic camera (see \subpage panoramic_camera) - struct PanoramicCamera : public Camera { + struct OSPRAY_SDK_INTERFACE PanoramicCamera : public Camera { /*! \brief constructor \internal also creates the ispc-side data structure */ PanoramicCamera(); - //! \brief common function to help printf-debugging + //! \brief common function to help printf-debugging /*! Every derived class should overrride this! */ virtual std::string toString() const { return "ospray::PanoramicCamera"; } virtual void commit(); diff --git a/ospray/camera/PanoramicCamera.ispc b/ospray/camera/PanoramicCamera.ispc index 3c845532c0..911849dee1 100644 --- a/ospray/camera/PanoramicCamera.ispc +++ b/ospray/camera/PanoramicCamera.ispc @@ -23,10 +23,12 @@ void PanoramicCamera_initRay(uniform Camera *uniform _self, { uniform PanoramicCamera *uniform self = (uniform PanoramicCamera *uniform)_self; + const vec2f screen = Camera_subRegion(_self, sample.screen); + const vec3f org = self->pos; - const float phi = two_pi * sample.screen.x; - const float theta = -M_PI * sample.screen.y; + const float phi = two_pi * screen.x; + const float theta = -M_PI * screen.y; float sinTheta, cosTheta; sincos(theta, &sinTheta, &cosTheta); @@ -53,11 +55,9 @@ export void *uniform PanoramicCamera_create(void *uniform cppE) export void PanoramicCamera_set(void *uniform _self, const uniform vec3f &pos, - const uniform linear3f &frame, - const uniform float nearClip) + const uniform linear3f &frame) { uniform PanoramicCamera *uniform self = (uniform PanoramicCamera *uniform)_self; self->pos = pos; self->frame = frame; - self->super.nearClip = nearClip; } diff --git a/ospray/camera/PerspectiveCamera.cpp b/ospray/camera/PerspectiveCamera.cpp index 870d49f8b0..b3011a0905 100644 --- a/ospray/camera/PerspectiveCamera.cpp +++ b/ospray/camera/PerspectiveCamera.cpp @@ -41,23 +41,38 @@ namespace ospray { aspect = getParamf("aspect", 1.f); apertureRadius = getParamf("apertureRadius", 0.f); focusDistance = getParamf("focusDistance", 1.f); - - vec2f imageStart = getParam2f("imageStart", vec2f(0.f)); - vec2f imageEnd = getParam2f("imageEnd", vec2f(1.f)); - - assert(imageStart.x >= 0.f && imageStart.x <= 1.f); - assert(imageStart.y >= 0.f && imageStart.y <= 1.f); - assert(imageEnd.x >= 0.f && imageEnd.x <= 1.f); - assert(imageEnd.y >= 0.f && imageEnd.y <= 1.f); - + architectural = getParam1i("architectural", false); + stereoMode = (StereoMode)getParam1i("stereoMode", OSP_STEREO_NONE); + // the default 63.5mm represents the average human IPD + interpupillaryDistance = getParamf("interpupillaryDistance", 0.0635f); + // ------------------------------------------------------------------ // now, update the local precomputed values // ------------------------------------------------------------------ dir = normalize(dir); vec3f dir_du = normalize(cross(dir, up)); - vec3f dir_dv = cross(dir_du, dir); + vec3f dir_dv; + if (architectural) + dir_dv = normalize(up); // orient film to be parallel to 'up' and shift such that 'dir' is centered + else + dir_dv = cross(dir_du, dir); // rotate film to be perpendicular to 'dir' - float imgPlane_size_y = 2.f*tanf(fovy/2.f*M_PI/180.); + vec3f org = pos; + const vec3f ipd_offset = 0.5f * interpupillaryDistance * dir_du; + + switch (stereoMode) { + case OSP_STEREO_LEFT: + org -= ipd_offset; + break; + case OSP_STEREO_RIGHT: + org += ipd_offset; + break; + case OSP_STEREO_SIDE_BY_SIDE: + aspect *= 0.5f; + break; + } + + float imgPlane_size_y = 2.f*tanf(deg2rad(0.5f*fovy)); float imgPlane_size_x = imgPlane_size_y * aspect; dir_du *= imgPlane_size_x; @@ -75,18 +90,18 @@ namespace ospray { } ispc::PerspectiveCamera_set(getIE(), - (const ispc::vec3f&)pos, + (const ispc::vec3f&)org, (const ispc::vec3f&)dir_00, (const ispc::vec3f&)dir_du, (const ispc::vec3f&)dir_dv, - (const ispc::vec2f&)imageStart, - (const ispc::vec2f&)imageEnd, scaledAperture, aspect, - nearClip); + stereoMode == OSP_STEREO_SIDE_BY_SIDE, + (const ispc::vec3f&)ipd_offset); } OSP_REGISTER_CAMERA(PerspectiveCamera,perspective); OSP_REGISTER_CAMERA(PerspectiveCamera,thinlens); + OSP_REGISTER_CAMERA(PerspectiveCamera,stereo); } // ::ospray diff --git a/ospray/camera/PerspectiveCamera.h b/ospray/camera/PerspectiveCamera.h index e98ce69ecb..e1f89eb79d 100644 --- a/ospray/camera/PerspectiveCamera.h +++ b/ospray/camera/PerspectiveCamera.h @@ -26,7 +26,7 @@ namespace ospray { camera) for perspective rendering, without support for Depth of Field or Motion Blur \ingroup ospray_supported_cameras - + A simple perspective camera. This camera type is loaded by passing the type string "perspective" to \ref ospNewCamera @@ -44,14 +44,14 @@ namespace ospray { */ //! Implements a simple perspective camera (see \subpage perspective_camera) - struct PerspectiveCamera : public Camera { + struct OSPRAY_SDK_INTERFACE PerspectiveCamera : public Camera { /*! \brief constructor \internal also creates the ispc-side data structure */ PerspectiveCamera(); - //! \brief common function to help printf-debugging + //! \brief common function to help printf-debugging /*! Every derived class should overrride this! */ virtual std::string toString() const { return "ospray::PerspectiveCamera"; } virtual void commit(); - + public: // ------------------------------------------------------------------ // the parameters we 'parsed' from our parameters @@ -60,6 +60,15 @@ namespace ospray { float aspect; float apertureRadius; float focusDistance; + bool architectural; // orient image plane to be parallel to 'up' and shift the lens + typedef enum { + OSP_STEREO_NONE, + OSP_STEREO_LEFT, + OSP_STEREO_RIGHT, + OSP_STEREO_SIDE_BY_SIDE + } StereoMode; + StereoMode stereoMode; + float interpupillaryDistance; // distance between the two cameras (stereo) }; - + } // ::ospray diff --git a/ospray/camera/PerspectiveCamera.ih b/ospray/camera/PerspectiveCamera.ih index e92f50ae1e..bcc3bfa51c 100644 --- a/ospray/camera/PerspectiveCamera.ih +++ b/ospray/camera/PerspectiveCamera.ih @@ -26,12 +26,12 @@ struct PerspectiveCamera { 'inherit' from Camera */ Camera super; - vec3f org; //!< position of camera + vec3f org; //!< position of camera, already contains shift when STEREO_{LEFT|RIGHT} vec3f dir_00; //!< direction of ray with screenSample=(0,0); scaled to focusDistance vec3f dir_du; //!< delta of ray direction between two pixels in X; scaled to focusDistance vec3f dir_dv; //!< delta of ray direction between two pixels in Y; scaled to focusDistance - vec2f imageStart; //!< where the viewable tile begins [0..1] - vec2f imageEnd; //!< where the viewable tile ends [0..1] float scaledAperture; //!< radius of aperture, divided by horizontal image plane size float aspect; //!< image plane size x / y + bool side_by_side; //!< stereo mode SIDE_BY_SIDE + vec3f ipd_offset; //!< shift of camera position for left/right eye (only when SIDE_BY_SIDE) }; diff --git a/ospray/camera/PerspectiveCamera.ispc b/ospray/camera/PerspectiveCamera.ispc index 853ab66e17..a037c65259 100644 --- a/ospray/camera/PerspectiveCamera.ispc +++ b/ospray/camera/PerspectiveCamera.ispc @@ -24,21 +24,30 @@ void PerspectiveCamera_initRay(uniform Camera *uniform _self, uniform PerspectiveCamera *uniform self = (uniform PerspectiveCamera *uniform)_self; - uniform vec2f& imageStart = self->imageStart; - uniform vec2f& imageEnd = self->imageEnd; - + vec2f screen = sample.screen; vec3f org = self->org; + + if (self->side_by_side) { + screen.x *= 2.f; + if (screen.x < 1.f) { + org = org - self->ipd_offset; + } else { + org = org + self->ipd_offset; + screen.x -= 1.f; + } + } + + screen = Camera_subRegion(_self, screen); + vec3f dir = self->dir_00 - + ((imageStart.x * self->dir_du) - + (sample.screen.x * (self->dir_du * (imageEnd.x - imageStart.x)))) - + ((imageStart.y * self->dir_dv) - + (sample.screen.y * (self->dir_dv * (imageEnd.y - imageStart.y)))); + + screen.x * self->dir_du + + screen.y * self->dir_dv; if (self->super.doesDOF) { const vec3f llp = uniformSampleDisk(self->scaledAperture, sample.lens); // transform local lens point to focal plane (dir_XX are prescaled in this case) const vec3f lp = (llp.x * self->dir_du) - + ((llp.y * self->aspect) * self->dir_dv); + + ((llp.y * self->aspect) * self->dir_dv); org = org + lp; dir = dir - lp; } @@ -65,11 +74,10 @@ export void PerspectiveCamera_set(void *uniform _self, const uniform vec3f &dir_00, const uniform vec3f &dir_du, const uniform vec3f &dir_dv, - const uniform vec2f &imageStart, - const uniform vec2f &imageEnd, const uniform float scaledAperture, const uniform float aspect, - const uniform float nearClip) + const uniform bool side_by_side, + const uniform vec3f &ipd_offset) { uniform PerspectiveCamera *uniform self = (uniform PerspectiveCamera *uniform)_self; @@ -77,10 +85,9 @@ export void PerspectiveCamera_set(void *uniform _self, self->dir_00 = dir_00; self->dir_du = dir_du; self->dir_dv = dir_dv; - self->imageStart = imageStart; - self->imageEnd = imageEnd; - self->super.nearClip = nearClip; self->scaledAperture = scaledAperture; self->super.doesDOF = scaledAperture > 0.f; self->aspect = aspect; + self->side_by_side = side_by_side; + self->ipd_offset = ipd_offset; } diff --git a/ospray/common/Data.cpp b/ospray/common/Data.cpp index 18ad44d9b6..6759f08331 100644 --- a/ospray/common/Data.cpp +++ b/ospray/common/Data.cpp @@ -25,8 +25,8 @@ namespace ospray { Data::Data(size_t numItems, OSPDataType type, void *init, int flags) : numItems(numItems), numBytes(numItems * sizeOf(type)), - type(type), - flags(flags) + flags(flags), + type(type) { /* two notes here: a) i'm using embree's 'new' to enforce alignment @@ -55,7 +55,7 @@ namespace ospray { { if (type == OSP_OBJECT) { Data **child = (Data **)data; - for (int i=0;irefDec(); + for (uint32_t i = 0; i < numItems; i++) if (child[i]) child[i]->refDec(); } if (!(flags & OSP_DATA_SHARED_BUFFER)) alignedFree(data); } diff --git a/ospray/common/Data.h b/ospray/common/Data.h index 34353d9237..95216f12ce 100644 --- a/ospray/common/Data.h +++ b/ospray/common/Data.h @@ -16,14 +16,14 @@ #pragma once -// ospray +// ospray #include "Managed.h" namespace ospray { /*! \brief defines a data array (aka "buffer") type that contains 'n' items of a given type */ - struct Data : public ManagedObject + struct OSPRAY_SDK_INTERFACE Data : public ManagedObject { virtual void commit() { notifyListenersThatObjectGotChanged(); } diff --git a/ospray/common/Managed.cpp b/ospray/common/Managed.cpp index 707f668adb..02c88a9669 100644 --- a/ospray/common/Managed.cpp +++ b/ospray/common/Managed.cpp @@ -22,15 +22,15 @@ namespace ospray { /*! \brief constructor */ ManagedObject::ManagedObject() - : ID(-1), ispcEquivalent(NULL), managedObjectType(OSP_UNKNOWN) + : ID(-1), ispcEquivalent(nullptr), managedObjectType(OSP_UNKNOWN) {} /*! \brief destructor */ ManagedObject::~ManagedObject() { - // it is OK to potentially delete NULL, nothing bad happens ==> no need to check + // it is OK to potentially delete nullptr, nothing bad happens ==> no need to check ispc::delete_uniform(ispcEquivalent); - ispcEquivalent = NULL; + ispcEquivalent = nullptr; } /*! \brief commit the object's outstanding changes (such as changed parameters etc) */ @@ -60,7 +60,9 @@ namespace ospray { /*! \brief gets called whenever any of this node's dependencies got changed */ void ManagedObject::dependencyGotChanged(ManagedObject *object) - {} + { + UNUSED(object); + } void ManagedObject::Param::set(ManagedObject *object) { @@ -95,11 +97,11 @@ namespace ospray { if (type == OSP_STRING && ptr) free(ptr); type = OSP_OBJECT; - ptr = NULL; + ptr = nullptr; } ManagedObject::Param::Param(const char *name) - : name(NULL), type(OSP_FLOAT), ptr(NULL) + : ptr(nullptr), type(OSP_FLOAT), name(nullptr) { Assert(name); f[0] = 0; @@ -123,7 +125,7 @@ namespace ospray { for (size_t i=0 ; i < paramList.size() ; i++) { if (!strcmp(paramList[i]->name,name)) return paramList[i]; } - if (!addIfNotExist) return NULL; + if (!addIfNotExist) return nullptr; paramList.push_back(new Param(name)); return paramList[paramList.size()-1]; } @@ -137,16 +139,16 @@ namespace ospray { return (T&)param->FIELD; \ } - define_getparam(ManagedObject *, Object, OSP_OBJECT, ptr); - define_getparam(int32, 1i, OSP_INT, i); - define_getparam(vec3i, 3i, OSP_INT3, i); - define_getparam(vec3f, 3f, OSP_FLOAT3, f); - define_getparam(vec3fa, 3f, OSP_FLOAT3, f); - define_getparam(vec4f, 4f, OSP_FLOAT4, f); - define_getparam(vec2f, 2f, OSP_FLOAT2, f); - define_getparam(float, 1f, OSP_FLOAT, f); - define_getparam(float, f, OSP_FLOAT, f); - define_getparam(const char *, String, OSP_STRING, ptr); + define_getparam(ManagedObject *, Object, OSP_OBJECT, ptr) + define_getparam(int32, 1i, OSP_INT, i) + define_getparam(vec3i, 3i, OSP_INT3, i) + define_getparam(vec3f, 3f, OSP_FLOAT3, f) + define_getparam(vec3fa, 3f, OSP_FLOAT3, f) + define_getparam(vec4f, 4f, OSP_FLOAT4, f) + define_getparam(vec2f, 2f, OSP_FLOAT2, f) + define_getparam(float, 1f, OSP_FLOAT, f) + define_getparam(float, f, OSP_FLOAT, f) + define_getparam(const char *, String, OSP_STRING, ptr) #undef define_getparam diff --git a/ospray/common/Managed.h b/ospray/common/Managed.h index 252eb68a6f..e050900077 100644 --- a/ospray/common/Managed.h +++ b/ospray/common/Managed.h @@ -16,11 +16,11 @@ #pragma once -// ospray +// ospray #include "ospray/OSPDataType.h" #include "common/OSPCommon.h" #include "common/ObjectHandle.h" -// stl +// stl #include #include @@ -29,7 +29,7 @@ namespace ospray { /*! forward-def so param can use a pointer to data */ struct Data; - /*! \brief defines a basic object whose lifetime is managed by ospray + /*! \brief defines a basic object whose lifetime is managed by ospray One of the core concepts of ospray is that all logical objects in ospray -- renderers, geometries, models, camera, data @@ -37,7 +37,7 @@ namespace ospray { class that provides a certain kind of common, shared infrastructure: -
+
Reference counting
All ospray objects are reference counted, and will automatically live as long as any other object @@ -99,11 +99,11 @@ namespace ospray { whatever parameters that camera may need to properly operate have to be specified via parameters, without the API even knowing what those parameters that might be.
- +
*/ - struct ManagedObject : public RefCount + struct OSPRAY_SDK_INTERFACE ManagedObject : public RefCount { /*! \brief constructor */ ManagedObject(); @@ -117,8 +117,8 @@ namespace ospray { /*! \brief commit the object's outstanding changes (such as changed * parameters etc) */ virtual void commit(); - - //! \brief common function to help printf-debugging + + //! \brief common function to help printf-debugging /*! \detailed Every derived class should overrride this! */ virtual std::string toString() const; @@ -131,9 +131,9 @@ namespace ospray { /*! \brief container for _any_ sort of parameter an app can assign to an ospray object */ - struct Param { + struct OSPRAY_SDK_INTERFACE Param { Param(const char *name); - ~Param() { clear(); }; + ~Param() { clear(); } /*! clear parameter to 'invalid type and value'; free/de-refcount data if * reqd' */ @@ -142,19 +142,19 @@ namespace ospray { /*! set parameter to a 'pointer to object' type, and given pointer */ void set(ManagedObject *ptr); - //! set parameter to a 'c-string' type + //! set parameter to a 'c-string' type /* \internal this function creates and keeps a *copy* of the passed * string! */ void set(const char *s); - //! set parameter to a 'c-string' type + //! set parameter to a 'c-string' type /* \internal this function does *not* copy whatever data this pointer points to (it doesn't have the info to do so), so this pointer belongs to the application, and it can not be used remotely */ void set(void *v); - /*! set parameter to given value and type + /*! set parameter to given value and type @{ */ void set(const float &v) { clear(); type = OSP_FLOAT; f[0] = v; } void set(const int &v) { clear(); type = OSP_INT; i[0] = v; } @@ -176,7 +176,7 @@ namespace ospray { union { float f[4]; int32 i[4]; - uint32 ui[4]; + uint32 ui[4]; int64 l; ManagedObject *ptr; const char *s; @@ -192,7 +192,7 @@ namespace ospray { Param *findParam(const char *name, bool addIfNotExist = false); /*! \brief check if a given parameter is available */ - bool hasParam(const char *name) + bool hasParam(const char *name) { return findParam(name,false) != nullptr; } /*! \brief set given parameter to given data array */ @@ -205,8 +205,8 @@ namespace ospray { /*! @{ */ /*! \brief find the named parameter, and return its object value if - available; else return 'default' value - + available; else return 'default' value + The returned managed object will *not* automatically have its refcount increased; it is up to the callee to properly do that (typically by assigning to a proper 'ref' @@ -241,7 +241,7 @@ namespace ospray { /*! \brief gets called whenever any of this node's dependencies got * changed */ virtual void dependencyGotChanged(ManagedObject *object); - + //! \brief Will notify all listeners that we got changed /*! \detailed will call 'dependencyGotChanged' on each of the objects in 'objectsListeningForChanges' */ @@ -267,7 +267,7 @@ namespace ospray { // ------------------------------------------------------- - // member variables + // member variables // ------------------------------------------------------- //! \brief List of managed objects that want to get notified @@ -281,7 +281,7 @@ namespace ospray { _has_ to properly unregister itself as a listenere before it dies */ std::set objectsListeningForChanges; - + /*! \brief list of parameters attached to this object */ std::vector paramList; @@ -297,4 +297,14 @@ namespace ospray { }; + +#define OSP_REGISTER_OBJECT(Object, object_name, InternalClass, external_name) \ + extern "C" OSPRAY_DLLEXPORT \ + Object *ospray_create_##object_name##__##external_name() \ + { \ + return new InternalClass; \ + } \ + /* additional declaration to avoid "extra ;" -Wpedantic warnings */ \ + Object *ospray_create_##object_name##__##external_name() + } // ::ospray diff --git a/ospray/common/Material.h b/ospray/common/Material.h index 995f84d508..9facb1b0a6 100644 --- a/ospray/common/Material.h +++ b/ospray/common/Material.h @@ -23,7 +23,7 @@ namespace ospray { /*! \brief implements the basic abstraction for anything that is a 'material'. Note that different renderers will probably define different materials, so the same "logical" material (such a as a "diffuse gray" material) may look differently */ - struct Material : public ManagedObject + struct OSPRAY_SDK_INTERFACE Material : public ManagedObject { //! \brief common function to help printf-debugging /*! Every derived class should overrride this! */ @@ -50,7 +50,7 @@ namespace ospray { */ affine2f getTextureTransform(const char* texture_name); - /*! \brief creates an abstract material class of given type + /*! \brief creates an abstract material class of given type The respective material type must be a registered material type in either ospray proper or any already loaded module. For @@ -69,10 +69,7 @@ namespace ospray { lateron always get a handle to this fct and create an instance of this material. */ -#define OSP_REGISTER_MATERIAL(InternalClassName,external_name) \ - extern "C" OSPRAY_INTERFACE Material *ospray_create_material__##external_name() \ - { \ - return new InternalClassName; \ - } \ +#define OSP_REGISTER_MATERIAL(InternalClass, external_name) \ + OSP_REGISTER_OBJECT(Material, material, InternalClass, external_name) } // ::ospray diff --git a/ospray/common/Model.h b/ospray/common/Model.h index 59a4aed632..d0bd4d4735 100644 --- a/ospray/common/Model.h +++ b/ospray/common/Model.h @@ -37,17 +37,17 @@ namespace ospray { against, and that one can afterwards 'query' for certain properties (like the shading normal or material for a given ray/model intersection) */ - struct Model : public ManagedObject + struct OSPRAY_SDK_INTERFACE Model : public ManagedObject { Model(); - //! \brief common function to help printf-debugging + //! \brief common function to help printf-debugging virtual std::string toString() const { return "ospray::Model"; } virtual void finalize(); - typedef std::vector > GeometryVector; - typedef std::vector > VolumeVector; - + using GeometryVector = std::vector>; + using VolumeVector = std::vector>; + //! \brief vector of all geometries used in this model GeometryVector geometry; //! \brief vector of all volumes used in this model @@ -61,7 +61,7 @@ namespace ospray { // #endif //! \brief the embree scene handle for this geometry - RTCScene embreeSceneHandle; + RTCScene embreeSceneHandle; box3f bounds; }; diff --git a/ospray/common/Model.ih b/ospray/common/Model.ih index 5729a89d85..5aab59022a 100644 --- a/ospray/common/Model.ih +++ b/ospray/common/Model.ih @@ -122,7 +122,7 @@ inline void postIntersect(uniform Model *uniform model, if ((flags & DG_NG_FACEFORWARD) == DG_NG_FACEFORWARD) if (dot(ray.dir,dg.Ng) >= 0.f) dg.Ng = neg(dg.Ng); if ((flags & DG_NS_FACEFORWARD) == DG_NS_FACEFORWARD) - if (dot(ray.dir,dg.Ns) >= 0.f) dg.Ns = neg(dg.Ns); + if (dot(dg.Ng,dg.Ns) < 0.f) dg.Ns = neg(dg.Ns); #undef DG_NG_FACEFORWARD #undef DG_NS_FACEFORWARD diff --git a/ospray/common/Model.ispc b/ospray/common/Model.ispc index 2db65c6069..af8bc61a5d 100644 --- a/ospray/common/Model.ispc +++ b/ospray/common/Model.ispc @@ -40,13 +40,22 @@ export void Model_init(void *uniform _model, if (model->embreeSceneHandle) rtcDeleteScene(model->embreeSceneHandle); + uniform RTCSceneFlags scene_flags = RTC_SCENE_STATIC; +#ifdef OSPRAY_USE_HIGH_QUALITY_BVH + scene_flags |= RTC_SCENE_HIGH_QUALITY; +#endif + + uniform RTCAlgorithmFlags traversal_flags = + RTC_INTERSECT_UNIFORM | RTC_INTERSECT_VARYING; + +#if (RTCORE_VERSION_MAJOR >= 2 && RTCORE_VERSION_MINOR >= 10 && defined(OSPRAY_USE_EMBREE_STREAMS)) + traversal_flags |= RTC_INTERSECT_STREAM; +#endif + model->embreeSceneHandle = rtcDeviceNewScene((RTCDevice)embreeDevice, - //RTC_SCENE_STATIC|RTC_SCENE_HIGH_QUALITY, - RTC_SCENE_STATIC,//|RTC_SCENE_COMPACT, - //RTC_SCENE_DYNAMIC, - //RTC_SCENE_DYNAMIC|RTC_SCENE_COMPACT, - RTC_INTERSECT_UNIFORM|RTC_INTERSECT_VARYING); - + scene_flags, + traversal_flags); + if (model->geometry) delete[] model->geometry; model->geometryCount = numGeometries; if (numGeometries > 0) diff --git a/ospray/common/OSPCommon.cpp b/ospray/common/OSPCommon.cpp index b182debd8c..023dbc661e 100644 --- a/ospray/common/OSPCommon.cpp +++ b/ospray/common/OSPCommon.cpp @@ -15,19 +15,22 @@ // ======================================================================== // #include "OSPCommon.h" -#ifdef OSPRAY_USE_INTERNAL_TASKING -# include "common/tasking/TaskSys.h" +#if defined(OSPRAY_TASKING_TBB) +# include +#elif defined(OSPRAY_TASKING_CILK) +# include +#elif defined(OSPRAY_TASKING_OMP) +# include +#elif defined(OSPRAY_TASKING_INTERNAL) +# include "common/tasking/TaskSys.h" #endif -#include "common/tasking/async.h" // embree #include "embree2/rtcore.h" #include "ospcommon/sysinfo.h" -//stl -#include namespace ospray { - RTCDevice g_embreeDevice = NULL; + RTCDevice g_embreeDevice = nullptr; /*! 64-bit malloc. allows for alloc'ing memory larger than 64 bits */ extern "C" void *malloc64(size_t size) @@ -45,8 +48,7 @@ namespace ospray { numbers mean increasing verbosity of log messages */ uint32_t logLevel = 0; bool debugMode = false; - int32_t numThreads = -1; //!< for default (==maximum) number of - // OSPRay/Embree threads + int numThreads = -1; WarnOnce::WarnOnce(const std::string &s) : s(s) @@ -126,7 +128,16 @@ namespace ospray { } } -#ifdef OSPRAY_TASKING_INTERNAL +#if defined(OSPRAY_TASKING_TBB) + static tbb::task_scheduler_init tbb_init(numThreads); + UNUSED(tbb_init); +#elif defined(OSPRAY_TASKING_CILK) + __cilkrts_set_param("nworkers", std::to_string(numThreads).c_str()); +#elif defined(OSPRAY_TASKING_OMP) + if (numThreads > 0) { + omp_set_num_threads(numThreads); + } +#elif defined(OSPRAY_TASKING_INTERNAL) try { ospray::Task::initTaskSystem(debugMode ? 0 : numThreads); } catch (const std::runtime_error &e) { diff --git a/ospray/common/OSPCommon.h b/ospray/common/OSPCommon.h index 2fc1fd7bd1..891f133650 100644 --- a/ospray/common/OSPCommon.h +++ b/ospray/common/OSPCommon.h @@ -94,10 +94,12 @@ namespace ospray { # else # define OSPRAY_INTERFACE __declspec(dllimport) # endif +# define OSPRAY_DLLEXPORT __declspec(dllexport) #else # define OSPRAY_INTERFACE +# define OSPRAY_DLLEXPORT #endif - +#define OSPRAY_SDK_INTERFACE OSPRAY_INTERFACE // for MIC, disable the 'variable declared bbut never referenced' // warning, else the ISPC-generated code produces _far_ too many such @@ -124,10 +126,10 @@ namespace embree { // #if defined(__MIC__) // #pragma message("using aligned opeartor new (this is knc, right!?)...") -// void* operator new(size_t size) { return embree::alignedMalloc(size); } -// void operator delete(void* ptr) { embree::alignedFree(ptr); } -// void* operator new[](size_t size) throws { return embree::alignedMalloc(size); } -// void operator delete[](void* ptr) { embree::alignedFree(ptr); } +// void* operator new(size_t size) { return embree::alignedMalloc(size); } +// void operator delete(void* ptr) { embree::alignedFree(ptr); } +// void* operator new[](size_t size) throws { return embree::alignedMalloc(size); } +// void operator delete[](void* ptr) { embree::alignedFree(ptr); } // #endif @@ -173,12 +175,12 @@ namespace ospray { inline size_t rdtsc() { return ospcommon::rdtsc(); } /*! logging level (cmdline: --osp:loglevel \) */ - extern uint32 logLevel; + extern uint32_t logLevel; /*! whether we're running in debug mode (cmdline: --osp:debug) */ extern bool debugMode; /*! number of Embree threads to use, 0 for the default number. (cmdline: --osp:numthreads \) */ - extern int32 numThreads; + extern int numThreads; /*! size of OSPDataType */ OSPRAY_INTERFACE size_t sizeOf(const OSPDataType); @@ -189,7 +191,7 @@ namespace ospray { /*! size of OSPTextureFormat */ OSPRAY_INTERFACE size_t sizeOf(const OSPTextureFormat); - struct WarnOnce { + struct OSPRAY_SDK_INTERFACE WarnOnce { WarnOnce(const std::string &s); private: const std::string s; diff --git a/ospray/common/OSPConfig.h.in b/ospray/common/OSPConfig.h.in index f6b4a8c556..8812145b31 100644 --- a/ospray/common/OSPConfig.h.in +++ b/ospray/common/OSPConfig.h.in @@ -24,18 +24,18 @@ dimension) */ #define RENDERTILE_PIXELS_PER_JOB @OSPRAY_PIXELS_PER_JOB@ -#cmakedefine OSPRAY_EXP_DATA_PARALLEL -#ifdef OSPRAY_EXP_DATA_PARALLEL -# define EXP_DATA_PARALLEL 1 -#endif - #cmakedefine OSPRAY_MIC_COI -#cmakedefine OSPRAY_DISPLAYCLUSTER #cmakedefine OSPRAY_MPI +#cmakedefine OSPRAY_USE_EMBREE_STREAMS +#cmakedefine OSPRAY_USE_HIGH_QUALITY_BVH #ifdef OSPRAY_MPI #cmakedefine OSPRAY_EXP_IMAGE_COMPOSITING #cmakedefine OSPRAY_EXP_DISTRIBUTED_VOLUME #cmakedefine OSPRAY_EXP_ALPHA_BLENDING +#cmakedefine OSPRAY_EXP_DATA_PARALLEL +#ifdef OSPRAY_EXP_DATA_PARALLEL +#define EXP_DATA_PARALLEL 1 +#endif #endif #cmakedefine OSPRAY_VOLUME_VOXELRANGE_IN_APP #cmakedefine OSPRAY_PIN_ASYNC diff --git a/ospray/common/ObjectHandle.cpp b/ospray/common/ObjectHandle.cpp index 784f1518e0..d089ddb4c8 100644 --- a/ospray/common/ObjectHandle.cpp +++ b/ospray/common/ObjectHandle.cpp @@ -33,6 +33,7 @@ namespace ospray { { freedHandles.push((int64)*this); } + ObjectHandle ObjectHandle::alloc() { ObjectHandle h; @@ -90,6 +91,6 @@ namespace ospray { return(nullHandle); } - const ObjectHandle ObjectHandle::nullHandle(0); + const ObjectHandle nullHandle(0); } // ::ospray diff --git a/ospray/common/ObjectHandle.h b/ospray/common/ObjectHandle.h index d58efd2d6e..48bd1412c9 100644 --- a/ospray/common/ObjectHandle.h +++ b/ospray/common/ObjectHandle.h @@ -31,25 +31,24 @@ namespace ospray { /*! abstraction for a remotely-held 'managed object'. the handle refers to both 'owner' (the machine that has it) as well as to a local ID (by which that owner can look it up). Note that other - ranks may also have copies of that object. + ranks may also have copies of that object. note that the 'null handle' is '0', not -1. This allows an app to test the handled resturend from ospNewXXX calls for null just as if they were pointers (and thus, 'null' objects are consistent between local and mpi rendering) */ - struct ObjectHandle { + union OSPRAY_SDK_INTERFACE ObjectHandle { static ObjectHandle alloc(); void free(); - inline ObjectHandle(const int64 i = 0) : i64(i) {}; - inline ObjectHandle(const ObjectHandle &other) : i64(other.i64) {}; - inline ObjectHandle &operator=(const ObjectHandle &other) { i64=other.i64; return *this; } + inline ObjectHandle(const int64 i = 0) { i64 = i; } + inline ObjectHandle(const ObjectHandle &other) { i64 = other.i64; } + inline ObjectHandle &operator=(const ObjectHandle &other) + { i64 = other.i64; return *this; } - union { - struct { int32 ID; int32 owner; } i32; - int64 i64; - }; + struct { int32 ID; int32 owner; } i32; + int64 i64; /*! look up an object by handle, and return it. must be a defiend handle */ ManagedObject *lookup() const; @@ -78,12 +77,13 @@ namespace ospray { /*! cast to int64 to allow fast operations with this type */ inline operator int64() const { return i64; } - static const ObjectHandle nullHandle; }; - inline bool operator==(const ObjectHandle &a, const ObjectHandle &b) - { return a.i64==b.i64; } - inline bool operator!=(const ObjectHandle &a, const ObjectHandle &b) - { return a.i64!=b.i64; } + extern const ObjectHandle nullHandle; + + inline bool operator==(const ObjectHandle &a, const ObjectHandle &b) + { return a.i64 == b.i64; } + inline bool operator!=(const ObjectHandle &a, const ObjectHandle &b) + { return a.i64 != b.i64; } } // ::ospray diff --git a/ospray/common/ProducerConsumerQueue.h b/ospray/common/ProducerConsumerQueue.h index b97d2692de..7c0bb4af8d 100644 --- a/ospray/common/ProducerConsumerQueue.h +++ b/ospray/common/ProducerConsumerQueue.h @@ -110,7 +110,7 @@ namespace ospray { { SCOPED_LOCK(mutex); wasEmpty = content.empty(); - for (int i=0;i threads; - TaskSys() - : activeListFirst(nullptr), activeListLast(nullptr), - initialized(false), running(false) - {} - ~TaskSys(); }; @@ -109,7 +104,7 @@ namespace ospray { } Ref front = activeListFirst; - if (front->numJobsStarted >= front->numJobsInTask) { + if (front->numJobsStarted >= int(front->numJobsInTask)) { if (activeListFirst == activeListLast) { activeListFirst = activeListLast = nullptr; } else { @@ -178,8 +173,8 @@ namespace ospray { { running = false; tasksAvailable.notify_all(); - for (int i = 0; i < threads.size(); ++i) { - join(threads[i]); + for (auto &thread : threads) { + join(thread); } } @@ -208,7 +203,7 @@ namespace ospray { } /* generate all threads */ - for (size_t t=1; tgetParamString("hostname", "localhost"); - streamName = po->getParamString("streamName", "ospray"); - - std::cerr << "connecting to host " << hostname << " for stream " << streamName << std::endl; - - // connect to DisplayCluster at given hostname. - dcSocket = dcStreamConnect(hostname); - - if(!dcSocket) - std::cerr << "could not connect to DisplayCluster at " << hostname << std::endl; -#else - std::cout << "#osp:dw: display cluster support not compiled in" << std::endl; -#endif - } - - void DisplayWallPO::Instance::beginFrame() - { - frameIndex++; - -#ifdef OSPRAY_DISPLAYCLUSTER - dcStreamSetFrameIndex(frameIndex); -#endif - } - - void DisplayWallPO::Instance::postAccum(Tile &tile) - { -#ifdef OSPRAY_DISPLAYCLUSTER - if(!dcSocket) - return; - - uint32 colorBuffer[TILE_SIZE*TILE_SIZE]; - - size_t pixelID = 0; - for (size_t iy=0;iy 0 && size.y > 0); } + void FrameBuffer::beginFrame() + { + frameID++; + ispc::FrameBuffer_set_frameID(getIE(), frameID); + } + /*! helper function for debugging. write out given pixels in PPM format */ void writePPM(const std::string &fileName, const vec2i &size, @@ -81,4 +90,112 @@ namespace ospray { } + TileError::TileError(const vec2i &_numTiles) + : numTiles(_numTiles) + , tiles(_numTiles.x * _numTiles.y) + { + if (tiles > 0) + tileErrorBuffer = (float*)alignedMalloc(sizeof(float) * tiles); + else + tileErrorBuffer = nullptr; + + // maximum number of regions: all regions are of size 3 are split in half + errorRegion.reserve(divRoundUp(tiles * 2, 3)); + } + + TileError::~TileError() + { + alignedFree(tileErrorBuffer); + } + + void TileError::clear() + { + for (int i = 0; i < tiles; i++) + tileErrorBuffer[i] = inf; + + errorRegion.clear(); + // initially create one region covering the complete image + errorRegion.push_back(box2i(vec2i(0), numTiles)); + } + + float TileError::operator[](const vec2i &tile) const + { + if (tiles <= 0) + return inf; + + return tileErrorBuffer[tile.y * numTiles.x + tile.x]; + } + + void TileError::update(const vec2i &tile, const float err) + { + if (tiles > 0) + tileErrorBuffer[tile.y * numTiles.x + tile.x] = err; + } + +#ifdef OSPRAY_MPI + void TileError::sync() + { + if (tiles <= 0) + return; + + int rc = MPI_Bcast(tileErrorBuffer, tiles, MPI_FLOAT, 0, MPI_COMM_WORLD); + mpi::checkMpiError(rc); + } +#endif + + float TileError::refine(const float errorThreshold) + { + if (tiles <= 0) + return inf; + + // process regions first, but don't process newly split regions again + int regions = errorThreshold > 0.f ? errorRegion.size() : 0; + for (int i = 0; i < regions; i++) { + box2i& region = errorRegion[i]; + float err = 0.f; + float maxErr = 0.0f; + for (int y = region.lower.y; y < region.upper.y; y++) + for (int x = region.lower.x; x < region.upper.x; x++) { + int idx = y * numTiles.x + x; + err += tileErrorBuffer[idx]; + maxErr = std::max(maxErr, tileErrorBuffer[idx]); + } + // set all tiles of this region to local max error to enforce their + // refinement as a group + for (int y = region.lower.y; y < region.upper.y; y++) + for (int x = region.lower.x; x < region.upper.x; x++) { + int idx = y * numTiles.x + x; + tileErrorBuffer[idx] = maxErr; + } + vec2i size = region.size(); + int area = reduce_mul(size); + err /= area; // avg + if (err < 4.f*errorThreshold) { // split region? + if (area <= 2) { // would just contain single tile after split: remove + regions--; + errorRegion[i] = errorRegion[regions]; + errorRegion[regions]= errorRegion.back(); + errorRegion.pop_back(); + i--; + continue; + } + vec2i split = region.lower + size / 2; // TODO: find split with equal + // variance + errorRegion.push_back(region); // region ref might become invalid + if (size.x > size.y) { + errorRegion[i].upper.x = split.x; + errorRegion.back().lower.x = split.x; + } else { + errorRegion[i].upper.y = split.y; + errorRegion.back().lower.y = split.y; + } + } + } + + float maxErr = 0.0f; + for (int i = 0; i < tiles; i++) + maxErr = std::max(maxErr, tileErrorBuffer[i]); + + return maxErr; + } } // ::ospray diff --git a/ospray/fb/FrameBuffer.h b/ospray/fb/FrameBuffer.h index 50e0449720..5cf4544440 100644 --- a/ospray/fb/FrameBuffer.h +++ b/ospray/fb/FrameBuffer.h @@ -24,7 +24,7 @@ namespace ospray { /*! abstract frame buffer class */ - struct FrameBuffer : public ManagedObject { + struct OSPRAY_SDK_INTERFACE FrameBuffer : public ManagedObject { /*! app-mappable format of the color buffer. make sure that this matches the definition on the ISPC side */ typedef OSPFrameBufferFormat ColorBufferFormat; @@ -75,6 +75,10 @@ namespace ospray { /*! buffer format of the color buffer */ ColorBufferFormat colorBufferFormat; + //! This marks the global number of frames that have been rendered since + //! the last ospFramebufferClear() has been called. + int32 frameID; + /*! how often has been accumulated into that tile Note that it is up to the application to properly reset the accumulationIDs (using ospClearAccum(fb)) if anything @@ -82,6 +86,8 @@ namespace ospray { virtual int32 accumID(const vec2i &tile) = 0; virtual float tileError(const vec2i &tile) = 0; + void beginFrame(); + //! returns error of frame virtual float endFrame(const float errorThreshold) = 0; @@ -96,4 +102,23 @@ namespace ospray { void writePFM(const std::string &fileName, const vec2i &size, const int channel, const float *pixels); + // manages error per tile and adaptive regions, for variance estimation / stopping + class TileError { + public: + TileError(const vec2i &numTiles); + ~TileError(); + void clear(); + float operator[](const vec2i &tile) const; + void update(const vec2i &tile, const float error); +#ifdef OSPRAY_MPI + void sync(); // broadcast tileErrorBuffer to all workers +#endif + float refine(const float errorThreshold); + + private: + vec2i numTiles; + int tiles; + float *tileErrorBuffer; /*!< holds error per tile, for variance estimation / stopping */ + std::vector errorRegion; // image regions (in #tiles) which do not yet estimate the error on tile base + }; } // ::ospray diff --git a/ospray/fb/FrameBuffer.ih b/ospray/fb/FrameBuffer.ih index 5c75910a2b..262deee18d 100644 --- a/ospray/fb/FrameBuffer.ih +++ b/ospray/fb/FrameBuffer.ih @@ -37,6 +37,7 @@ struct FrameBuffer { vec2i size; /*!< size (width x height) of frame buffer, in pixels */ vec2f rcpSize; /*! one over size (precomputed) */ + int32 frameID; FrameBuffer_ColorBufferFormat colorBufferFormat; diff --git a/ospray/fb/FrameBuffer.ispc b/ospray/fb/FrameBuffer.ispc index f41abf12bc..f94f4b934f 100644 --- a/ospray/fb/FrameBuffer.ispc +++ b/ospray/fb/FrameBuffer.ispc @@ -38,3 +38,9 @@ void FrameBuffer_set(FrameBuffer *uniform self, self->rcpSize.y = 1.f/size_y; self->colorBufferFormat = (uniform FrameBuffer_ColorBufferFormat)colorBufferFormat; } + +export void FrameBuffer_set_frameID(void *uniform _self, uniform int32 frameID) +{ + uniform FrameBuffer *uniform self = (uniform FrameBuffer *uniform)_self; + self->frameID = frameID; +} diff --git a/ospray/fb/LocalFB.cpp b/ospray/fb/LocalFB.cpp index d9b90c8f40..984dbc3cf1 100644 --- a/ospray/fb/LocalFB.cpp +++ b/ospray/fb/LocalFB.cpp @@ -28,6 +28,7 @@ namespace ospray { void *colorBufferToUse) : FrameBuffer(size, colorBufferFormat, hasDepthBuffer, hasAccumBuffer, hasVarianceBuffer) + , tileErrorRegion(hasVarianceBuffer ? getNumTiles() : vec2i(0)) { Assert(size.x > 0); Assert(size.y > 0); @@ -66,12 +67,8 @@ namespace ospray { if (hasVarianceBuffer) { varianceBuffer = (vec4f*)alignedMalloc(sizeof(vec4f)*size.x*size.y); - tileErrorBuffer = (float*)alignedMalloc(sizeof(float)*getTotalTiles()); - // maximum number of regions: all regions are of size 3 are split in half - errorRegion.reserve(divRoundUp(getTotalTiles()*2, 3)); } else { varianceBuffer = NULL; - tileErrorBuffer = NULL; } ispcEquivalent = ispc::LocalFrameBuffer_create(this,size.x,size.y, @@ -80,8 +77,7 @@ namespace ospray { depthBuffer, accumBuffer, varianceBuffer, - tileAccumID, - tileErrorBuffer); + tileAccumID); } LocalFrameBuffer::~LocalFrameBuffer() @@ -91,7 +87,6 @@ namespace ospray { alignedFree(accumBuffer); alignedFree(varianceBuffer); alignedFree(tileAccumID); - alignedFree(tileErrorBuffer); } std::string LocalFrameBuffer::toString() const @@ -101,6 +96,7 @@ namespace ospray { void LocalFrameBuffer::clear(const uint32 fbChannelFlags) { + frameID = -1; // we increment at the start of the frame if (fbChannelFlags & OSP_FB_ACCUM) { // it is only necessary to reset the accumID, // LocalFrameBuffer_accumulateTile takes care of clearing the @@ -109,12 +105,7 @@ namespace ospray { // always also clear error buffer (if present) if (hasVarianceBuffer) { - for (int i = 0; i < getTotalTiles(); i++) - tileErrorBuffer[i] = inf; - - errorRegion.clear(); - // initially create one region covering the complete image - errorRegion.push_back(box2i(vec2i(0), getNumTiles())); + tileErrorRegion.clear(); } } } @@ -123,8 +114,11 @@ namespace ospray { { if (pixelOp) pixelOp->preAccum(tile); - if (accumBuffer) - ispc::LocalFrameBuffer_accumulateTile(getIE(),(ispc::Tile&)tile); + if (accumBuffer) { + const float err = ispc::LocalFrameBuffer_accumulateTile(getIE(),(ispc::Tile&)tile); + if ((tile.accumID & 1) == 1) + tileErrorRegion.update(tile.region.lower/TILE_SIZE, err); + } if (pixelOp) pixelOp->postAccum(tile); if (colorBuffer) { @@ -151,64 +145,12 @@ namespace ospray { float LocalFrameBuffer::tileError(const vec2i &tile) { - const int idx = tile.y * numTiles.x + tile.x; - return hasVarianceBuffer ? tileErrorBuffer[idx] : inf; + return tileErrorRegion[tile]; } float LocalFrameBuffer::endFrame(const float errorThreshold) { - if (hasVarianceBuffer) { - // process regions first, but don't process newly split regions again - int regions = errorThreshold > 0.f ? errorRegion.size() : 0; - for (int i = 0; i < regions; i++) { - box2i& region = errorRegion[i]; - float err = 0.f; - float maxErr = 0.0f; - for (int y = region.lower.y; y < region.upper.y; y++) - for (int x = region.lower.x; x < region.upper.x; x++) { - int idx = y * numTiles.x + x; - err += tileErrorBuffer[idx]; - maxErr = std::max(maxErr, tileErrorBuffer[idx]); - } - // set all tiles of this region to local max error to enforce their - // refinement as a group - for (int y = region.lower.y; y < region.upper.y; y++) - for (int x = region.lower.x; x < region.upper.x; x++) { - int idx = y * numTiles.x + x; - tileErrorBuffer[idx] = maxErr; - } - vec2i size = region.size(); - int area = reduce_mul(size); - err /= area; // avg - if (err < 4.f*errorThreshold) { // split region? - if (area <= 2) { // would just contain single tile after split: remove - regions--; - errorRegion[i] = errorRegion[regions]; - errorRegion[regions]= errorRegion.back(); - errorRegion.pop_back(); - i--; - continue; - } - vec2i split = region.lower + size / 2; // TODO: find split with equal - // variance - errorRegion.push_back(region); // region ref might become invalid - if (size.x > size.y) { - errorRegion[i].upper.x = split.x; - errorRegion.back().lower.x = split.x; - } else { - errorRegion[i].upper.y = split.y; - errorRegion.back().lower.y = split.y; - } - } - } - - float maxErr = 0.0f; - for (int i = 0; i < getTotalTiles(); i++) - maxErr = std::max(maxErr, tileErrorBuffer[i]); - - return maxErr; - } else - return inf; + return tileErrorRegion.refine(errorThreshold); } const void *LocalFrameBuffer::mapDepthBuffer() @@ -225,7 +167,10 @@ namespace ospray { void LocalFrameBuffer::unmap(const void *mappedMem) { - Assert(mappedMem == colorBuffer || mappedMem == depthBuffer ); + if (!(mappedMem == colorBuffer || mappedMem == depthBuffer)) { + throw std::runtime_error("ERROR: unmapping a pointer not created by " + "OSPRay!"); + } this->refDec(); } diff --git a/ospray/fb/LocalFB.h b/ospray/fb/LocalFB.h index ce051ddd64..f1d8791107 100644 --- a/ospray/fb/LocalFB.h +++ b/ospray/fb/LocalFB.h @@ -30,8 +30,7 @@ namespace ospray { vec4f *accumBuffer; /*!< one RGBA per pixel, may be NULL */ vec4f *varianceBuffer; /*!< one RGBA per pixel, may be NULL, accumulates every other sample, for variance estimation / stopping */ int32 *tileAccumID; //< holds accumID per tile, for adaptive accumulation - float *tileErrorBuffer; /*!< holds error per tile, for variance estimation / stopping */ - std::vector errorRegion; // image regions (in #tiles) which do not yet estimate the error on tile base + TileError tileErrorRegion; /*!< holds error per tile and adaptive regions, for variance estimation / stopping */ LocalFrameBuffer(const vec2i &size, ColorBufferFormat colorBufferFormat, diff --git a/ospray/fb/LocalFB.ih b/ospray/fb/LocalFB.ih index 1b026e3063..50ebf5ba1d 100644 --- a/ospray/fb/LocalFB.ih +++ b/ospray/fb/LocalFB.ih @@ -20,6 +20,17 @@ #include "fb/FrameBuffer.ih" #include "render/util.ih" +// we assume aligned memory access on KNC +// ==> need to pad framebuffer width to multiple of 16 +// may test for undocumented #ifdef ISPC_FORCE_ALIGNED_MEMORY +#ifdef OSPRAY_TARGET_MIC + #define FB_PADDED + #define FB_STRIDE stride +#else + #define FB_STRIDE super.size.x +#endif + + /*! a Local FrameBuffer that stores all pixel values (color, depth, accum) in a plain 2D array of pixels (one array per component) */ struct LocalFB @@ -30,6 +41,8 @@ struct LocalFB uniform vec4f *accumBuffer; uniform vec4f *varianceBuffer; // accumulates every other sample, for variance estimation / stopping uniform int32 *tileAccumID; //< holds accumID per tile, for adaptive accumulation - uniform float *tileErrorBuffer; // store error per tile vec2i numTiles; +#ifdef FB_PADDED + int32 stride; // on MIC framebuffer width is padded to be multiple of 16 +#endif }; diff --git a/ospray/fb/LocalFB.ispc b/ospray/fb/LocalFB.ispc index 49308da2b5..07783168a1 100644 --- a/ospray/fb/LocalFB.ispc +++ b/ospray/fb/LocalFB.ispc @@ -40,7 +40,7 @@ export void LocalFrameBuffer_writeTile_##name(void *uniform _fb, \ for (uint32 iix = tile.region.lower.x+programIndex; \ iixsuper.size.x+iix; \ + uint32 pixelID = iiy*fb->FB_STRIDE+iix; \ unmasked { \ varying vec4f col = make_vec4f(varyTile->r[chunkID], \ varyTile->g[chunkID], \ @@ -66,13 +66,15 @@ template_writeTile(RGBA32F, vec4f, cvt_nop); //! \brief accumulate tile into BOTH accum buffer AND tile. /*! \detailed After this call, the frame buffer will contain 'prev accum value + tile value', while the tile will contain '(prev - accum value + tile value/numAccums' */ -export void LocalFrameBuffer_accumulateTile(void *uniform _fb, + accum value + tile value/numAccums' + return tile error */ +export uniform float LocalFrameBuffer_accumulateTile(void *uniform _fb, uniform Tile &tile) { uniform LocalFB *uniform fb = (uniform LocalFB *uniform)_fb; uniform vec4f *uniform accum = fb->accumBuffer; - if (!accum) return; + if (!accum) + return inf; VaryingTile *uniform varyTile = (VaryingTile *uniform)&tile; @@ -141,16 +143,16 @@ export void LocalFrameBuffer_accumulateTile(void *uniform _fb, // error is also only updated every other frame to avoid alternating error // (get a monotone sequence) + uniform float errf = inf; if (variance && (tile.accumID & 1) == 1) { uniform vec2i dia = tile.region.upper - tile.region.lower; uniform float cntu = (uniform float)dia.x * dia.y; - const uniform float errf = reduce_add(err) * rsqrtf(cntu); + errf = reduce_add(err) * rsqrtf(cntu); // print("[%, %]: \t%\t%\n", tileIdx.x, tileIdx.y, errf); - fb->tileErrorBuffer[tileId] = errf; } + return errf; } - export void *uniform LocalFrameBuffer_create(void *uniform cClassPtr, const uniform uint32 size_x, const uniform uint32 size_y, @@ -159,8 +161,7 @@ export void *uniform LocalFrameBuffer_create(void *uniform cClassPtr, void *uniform depthBuffer, void *uniform accumBuffer, void *uniform varianceBuffer, - void *uniform tileAccumID, - void *uniform tileErrorBuffer) + void *uniform tileAccumID) { uniform LocalFB *uniform self = uniform new uniform LocalFB; FrameBuffer_Constructor(&self->super,cClassPtr); @@ -172,6 +173,13 @@ export void *uniform LocalFrameBuffer_create(void *uniform cClassPtr, self->varianceBuffer = (uniform vec4f *uniform)varianceBuffer; self->numTiles = (self->super.size+(TILE_SIZE-1))/TILE_SIZE; self->tileAccumID = (uniform int32 *uniform)tileAccumID; - self->tileErrorBuffer = (uniform float *uniform)tileErrorBuffer; + +#ifdef FB_PADDED + self->stride = (size_x+15)&~15; // pad to 16 + // on COI/MIC depth buffer is allocated locally without stride + // disable it (cannot be mapped anyway on COI) to avoid writing over the end + self->depthBuffer = NULL; +#endif + return self; } diff --git a/ospray/fb/PixelOp.cpp b/ospray/fb/PixelOp.cpp index 443b79092a..89a428e5ce 100644 --- a/ospray/fb/PixelOp.cpp +++ b/ospray/fb/PixelOp.cpp @@ -29,6 +29,7 @@ namespace ospray { PixelOp::Instance *PixelOp::createInstance(FrameBuffer *fb, PixelOp::Instance *prev) { + UNUSED(fb, prev); return nullptr; } diff --git a/ospray/fb/PixelOp.h b/ospray/fb/PixelOp.h index 8fd2b2553f..89d6f545c9 100644 --- a/ospray/fb/PixelOp.h +++ b/ospray/fb/PixelOp.h @@ -32,16 +32,16 @@ namespace ospray { sending tiles to a display wall, etc. PixelOps are intentionally 'stateless' in that it they should be pure functors that can be applied to different frame buffers, potentially at the same - time. + time. To allow a pixelop to maintain some sort of state for a frame, the 'beginframe', a pixelop is supposed to create and return a state every time it gets "attached" to a frame buffer, and this - state then gets passed every time a frame buffer gets started, + state then gets passed every time a frame buffer gets started, */ - struct PixelOp : public ManagedObject + struct OSPRAY_SDK_INTERFACE PixelOp : public ManagedObject { - struct Instance : public RefCount + struct OSPRAY_SDK_INTERFACE Instance : public RefCount { FrameBuffer *fb; /*! gets called every time the frame buffer got 'commit'ted */ @@ -50,7 +50,7 @@ namespace ospray { virtual void beginFrame() {} /*! gets called once at the end of the frame */ virtual void endFrame() {} - + /*! called whenever a new tile comes in from a renderer, but _before_ the tile gets written/accumulated into the frame buffer. this way we can, for example, fill in missing @@ -59,16 +59,16 @@ namespace ospray { etcpp. In distriubuted mode, it is undefined if this op gets executed on the node that _produces_ the tile, or on the node that _owns_ the tile (and its accum buffer data) */ - virtual void preAccum(Tile &tile) {} + virtual void preAccum(Tile &tile) { UNUSED(tile); } /*! called right after the tile got accumulated; i.e., the tile's RGBA values already contain the accu-buffer blended values (assuming an accubuffer exists), and this function defines how these pixels are being processed before written into the color buffer */ - virtual void postAccum(Tile &tile) {} + virtual void postAccum(Tile &tile) { UNUSED(tile); } - //! \brief common function to help printf-debugging + //! \brief common function to help printf-debugging /*! Every derived class should overrride this! */ virtual std::string toString() const; }; @@ -76,7 +76,7 @@ namespace ospray { //! \brief create an instance of this pixel op virtual Instance *createInstance(FrameBuffer *fb, PixelOp::Instance *prev); - /*! \brief creates an abstract renderer class of given type + /*! \brief creates an abstract renderer class of given type The respective renderer type must be a registered renderer type in either ospray proper or any already loaded module. For @@ -86,18 +86,15 @@ namespace ospray { }; /*! \brief registers a internal ospray:: renderer under - the externally accessible name "external_name" - + the externally accessible name "external_name" + \internal This currently works by defining a extern "C" function with a given predefined name that creates a new instance of this renderer. By having this symbol in the shared lib ospray can lateron always get a handle to this fct and create an instance of this renderer. */ -#define OSP_REGISTER_PIXEL_OP(InternalClassName,external_name) \ - extern "C" PixelOp *ospray_create_pixel_op__##external_name() \ - { \ - return new InternalClassName; \ - } \ - +#define OSP_REGISTER_PIXEL_OP(InternalClass, external_name) \ + OSP_REGISTER_OBJECT(PixelOp, pixel_op, InternalClass, external_name) + } diff --git a/ospray/fb/Tile.h b/ospray/fb/Tile.h index f41b4f32b2..5735704bdb 100644 --- a/ospray/fb/Tile.h +++ b/ospray/fb/Tile.h @@ -37,7 +37,7 @@ namespace ospray { agree on which fields will be set. Similarly, the frame buffer may actually use uchars, but the tile will always store floats. */ - struct __aligned(64) Tile { + struct OSPRAY_SDK_INTERFACE __aligned(64) Tile { // make sure this tile is 64-byte aligned when alloc'ed ALIGNED_STRUCT; diff --git a/ospray/fb/Tile.ih b/ospray/fb/Tile.ih index 8705e4ae5b..a9135bbf81 100644 --- a/ospray/fb/Tile.ih +++ b/ospray/fb/Tile.ih @@ -17,7 +17,7 @@ #pragma once #include "../common/OSPCommon.ih" -#include "../math/region.ih" +#include "../math/box.ih" /*! a screen tile. the memory layout of this class has to _exactly_ match the (C++-)one in tile.h */ diff --git a/ospray/geometry/Cylinders.cpp b/ospray/geometry/Cylinders.cpp index 5d4b00b3c8..91f68b3b5a 100644 --- a/ospray/geometry/Cylinders.cpp +++ b/ospray/geometry/Cylinders.cpp @@ -45,10 +45,13 @@ namespace ospray { materialList = getParamData("materialList"); colorData = getParamData("color"); - if (cylinderData.ptr == NULL || bytesPerCylinder == 0) - throw std::runtime_error("#ospray:geometry/cylinders: no 'cylinders' data specified"); + if (cylinderData.ptr == NULL || bytesPerCylinder == 0) { + throw std::runtime_error("#ospray:geometry/cylinders: no 'cylinders'" + " data specified"); + } numCylinders = cylinderData->numBytes / bytesPerCylinder; - std::cout << "#osp: creating 'cylinders' geometry, #cylinders = " << numCylinders << std::endl; + std::cout << "#osp: creating 'cylinders' geometry, #cylinders = " + << numCylinders << std::endl; if (_materialList) { free(_materialList); @@ -56,8 +59,9 @@ namespace ospray { } if (materialList) { - void **ispcMaterials = (void**) malloc(sizeof(void*) * materialList->numItems); - for (int i=0;inumItems;i++) { + void **ispcMaterials = + (void**) malloc(sizeof(void*) * materialList->numItems); + for (uint32_t i = 0; i < materialList->numItems; i++) { Material *m = ((Material**)materialList->data)[i]; ispcMaterials[i] = m?m->getIE():NULL; } diff --git a/ospray/geometry/Cylinders.h b/ospray/geometry/Cylinders.h index c792912b2d..bb2cdf725b 100644 --- a/ospray/geometry/Cylinders.h +++ b/ospray/geometry/Cylinders.h @@ -21,7 +21,7 @@ /*! @{ \ingroup ospray_module_streamlines */ namespace ospray { - /*! \defgroup geometry_cylinders Cylinders ("cylinders") + /*! \defgroup geometry_cylinders Cylinders ("cylinders") \ingroup ospray_supported_geometries @@ -57,8 +57,8 @@ namespace ospray { Implements the \ref geometry_cylinders geometry */ - struct Cylinders : public Geometry { - //! \brief common function to help printf-debugging + struct OSPRAY_SDK_INTERFACE Cylinders : public Geometry { + //! \brief common function to help printf-debugging virtual std::string toString() const { return "ospray::Cylinders"; } /*! \brief integrates this geometry's primitives into the respective model's acceleration structure */ @@ -66,7 +66,7 @@ namespace ospray { float radius; //!< default radius, if no per-cylinder radius was specified. int32 materialID; - + size_t numCylinders; size_t bytesPerCylinder; //!< num bytes per cylinder int64 offset_v0; diff --git a/ospray/geometry/Geometry.h b/ospray/geometry/Geometry.h index 98a32ea911..e4155a41e6 100644 --- a/ospray/geometry/Geometry.h +++ b/ospray/geometry/Geometry.h @@ -34,12 +34,12 @@ namespace ospray { as a set of individual triangle meshes that each have a different material (and their own connectivity and vertex sharing info), but that together form a single model with a single accel structure */ - struct Geometry : public ManagedObject + struct OSPRAY_SDK_INTERFACE Geometry : public ManagedObject { //! constructor Geometry() : bounds(empty) { managedObjectType = OSP_GEOMETRY; } - //! set given geometry's material. + //! set given geometry's material. /*! all material assignations should go through this function; the 'material' field itself is private). This allows the respective geometry's derived instance to always properly set @@ -48,26 +48,25 @@ namespace ospray { virtual void setMaterial(Material *mat); //! get material assigned to this geometry - virtual Material *getMaterial() const { return material.ptr; }; + virtual Material *getMaterial() const { return material.ptr; } - //! \brief common function to help printf-debugging + //! \brief common function to help printf-debugging virtual std::string toString() const { return "ospray::Geometry"; } /*! \brief integrates this geometry's primitives into the respective model's acceleration structure */ - virtual void finalize(Model *model) {} + virtual void finalize(Model *model) { UNUSED(model); } - /*! \brief creates an abstract geometry class of given type + /*! \brief creates an abstract geometry class of given type The respective geometry type must be a registered geometry type in either ospray proper or any already loaded module. For geometry types specified in special modules, make sure to call ospLoadModule first. */ - static Geometry *createGeometry(const char *type); + static Geometry *createGeometry(const char *type); box3f bounds; - private: //! material associated to this geometry /*! this field is private to make sure it is only set through 'setMaterial' (see comment there) */ @@ -75,18 +74,15 @@ namespace ospray { }; /*! \brief registers a internal ospray:: geometry under - the externally accessible name "external_name" - + the externally accessible name "external_name" + \internal This currently works by defining a extern "C" function with a given predefined name that creates a new instance of this geometry. By having this symbol in the shared lib ospray can lateron always get a handle to this fct and create an instance of this geometry. */ -#define OSP_REGISTER_GEOMETRY(InternalClassName,external_name) \ - extern "C" OSPRAY_INTERFACE ospray::Geometry *ospray_create_geometry__##external_name() \ - { \ - return new InternalClassName; \ - } \ - +#define OSP_REGISTER_GEOMETRY(InternalClass, external_name) \ + OSP_REGISTER_OBJECT(Geometry, geometry, InternalClass, external_name) + } // ::ospray diff --git a/ospray/geometry/Instance.h b/ospray/geometry/Instance.h index 2707bb51d2..8a1fc977be 100644 --- a/ospray/geometry/Instance.h +++ b/ospray/geometry/Instance.h @@ -21,7 +21,7 @@ namespace ospray { - /*! \defgroup geometry_instance Instancing ("instance") + /*! \defgroup geometry_instance Instancing ("instance") \brief Implements instancing via a single instance of another model. @@ -46,11 +46,11 @@ namespace ospray { /*! \brief A Single Instance */ - struct Instance : public Geometry + struct OSPRAY_SDK_INTERFACE Instance : public Geometry { /*! Constructor */ Instance(); - //! \brief common function to help printf-debugging + //! \brief common function to help printf-debugging virtual std::string toString() const { return "ospray::Instance"; } /*! \brief integrates this geometry's primitives into the respective model's acceleration structure */ @@ -61,7 +61,7 @@ namespace ospray { /*! reference to instanced model. Must be a *model* that we're instancing, not a geometry */ Ref instancedScene; /*! geometry ID of this geometry in the parent model */ - uint32 embreeGeomID; + uint32 embreeGeomID; }; } // ::ospray diff --git a/ospray/geometry/Isosurfaces.h b/ospray/geometry/Isosurfaces.h index a5d1885705..75e5034655 100644 --- a/ospray/geometry/Isosurfaces.h +++ b/ospray/geometry/Isosurfaces.h @@ -21,7 +21,7 @@ namespace ospray { - /*! \defgroup geometry_isosurfaces Isosurfaces ("isosurfaces") + /*! \defgroup geometry_isosurfaces Isosurfaces ("isosurfaces") \ingroup ospray_supported_geometries @@ -47,12 +47,12 @@ namespace ospray { Implements the \ref geometry_isosurfaces geometry */ - struct Isosurfaces : public Geometry + struct OSPRAY_SDK_INTERFACE Isosurfaces : public Geometry { //! constructor Isosurfaces(); - //! \brief common function to help printf-debugging + //! \brief common function to help printf-debugging virtual std::string toString() const { return "ospray::Isosurfaces"; } /*! \brief integrates this geometry's primitives into the respective diff --git a/ospray/geometry/Isosurfaces.ispc b/ospray/geometry/Isosurfaces.ispc index d5503cfcbc..3009fe83c5 100644 --- a/ospray/geometry/Isosurfaces.ispc +++ b/ospray/geometry/Isosurfaces.ispc @@ -77,7 +77,11 @@ void Isosurfaces_intersect(uniform Isosurfaces *uniform self, if (!isnan(sample0+sample)) { for (uniform int i=0; inumIsovalues; i++) { if ((self->isovalues[i] - sample0) * (self->isovalues[i] - sample) <= 0.f) { - const float tIso = t0 + (self->isovalues[i] - sample0) * rcpf(sample - sample0) * (t - t0); + const float rcpSamp = rcpf(sample - sample0); + float tIso = infinity; + if (!isnan(rcpSamp)) { + tIso = t0 + (self->isovalues[i] - sample0) * rcpf(sample - sample0) * (t - t0); + } if (tIso < tHit) { tHit = tIso; diff --git a/ospray/geometry/Slices.h b/ospray/geometry/Slices.h index e3ba3790ec..727fdf8313 100644 --- a/ospray/geometry/Slices.h +++ b/ospray/geometry/Slices.h @@ -21,7 +21,7 @@ namespace ospray { - /*! \defgroup geometry_slices Slices ("slices") + /*! \defgroup geometry_slices Slices ("slices") \ingroup ospray_supported_geometries @@ -47,8 +47,8 @@ namespace ospray { Implements the \ref geometry_slices geometry */ - struct Slices : public Geometry { - //! \brief common function to help printf-debugging + struct OSPRAY_SDK_INTERFACE Slices : public Geometry { + //! \brief common function to help printf-debugging virtual std::string toString() const { return "ospray::Slices"; } /*! \brief integrates this geometry's primitives into the respective diff --git a/ospray/geometry/Spheres.cpp b/ospray/geometry/Spheres.cpp index 2f21a98827..fd7d096b3c 100644 --- a/ospray/geometry/Spheres.cpp +++ b/ospray/geometry/Spheres.cpp @@ -81,7 +81,7 @@ namespace ospray { if (materialList) { void **ispcMaterials = (void**) malloc(sizeof(void*) * materialList->numItems); - for (int i=0;inumItems;i++) { + for (uint32_t i = 0; i < materialList->numItems; i++) { Material *m = ((Material**)materialList->data)[i]; ispcMaterials[i] = m?m->getIE():NULL; } diff --git a/ospray/geometry/Spheres.h b/ospray/geometry/Spheres.h index 876b99ba86..28e0538faa 100644 --- a/ospray/geometry/Spheres.h +++ b/ospray/geometry/Spheres.h @@ -21,7 +21,7 @@ namespace ospray { /*! @{ \ingroup ospray_module_streamlines */ - /*! \defgroup geometry_spheres Spheres ("spheres") + /*! \defgroup geometry_spheres Spheres ("spheres") \ingroup ospray_supported_geometries @@ -54,8 +54,8 @@ namespace ospray { Implements the \ref geometry_spheres geometry */ - struct Spheres : public Geometry { - //! \brief common function to help printf-debugging + struct OSPRAY_SDK_INTERFACE Spheres : public Geometry { + //! \brief common function to help printf-debugging virtual std::string toString() const { return "ospray::Spheres"; } /*! \brief integrates this geometry's primitives into the respective model's acceleration structure */ @@ -63,7 +63,7 @@ namespace ospray { float radius; //!< default radius, if no per-sphere radius was specified. int32 materialID; - + size_t numSpheres; size_t bytesPerSphere; //!< num bytes per sphere int64 offset_center; @@ -76,7 +76,7 @@ namespace ospray { void *_materialList; /*! data array from which we read the per-sphere color data; if NULL we do not have per-sphere data */ - Ref colorData; + Ref colorData; /*! stride in colorData array for accessing i'th sphere's color. color of sphere i will be read as 3 floats from 'colorOffset+i*colorStride */ diff --git a/ospray/geometry/Spheres.ispc b/ospray/geometry/Spheres.ispc index 144292c420..543b5e8ffd 100644 --- a/ospray/geometry/Spheres.ispc +++ b/ospray/geometry/Spheres.ispc @@ -71,18 +71,28 @@ static void Spheres_postIntersect(uniform Geometry *uniform geometry, dg.color = *((vec4f *)(self->color_data+colorAddr)); } - if ((flags & DG_MATERIALID) && (self->offset_materialID >= 0)) { - const uniform int32 primsPerPage = (1024*1024*64); - if (any(ray.primID >= primsPerPage )) { - const int primPageID = ray.primID / primsPerPage; - const int localPrimID = ray.primID % primsPerPage; - foreach_unique(primPage in primPageID) { - uniform uint8 *uniform pagePtr = self->data - + (((int64)primPage) - * primsPerPage - * self->bytesPerSphere); - uniform uint8 *varying spherePtr = pagePtr - + self->bytesPerSphere*localPrimID; + if (flags & DG_MATERIALID) { + if (self->offset_materialID >= 0) { + const uniform int32 primsPerPage = (1024*1024*64); + if (any(ray.primID >= primsPerPage )) { + const int primPageID = ray.primID / primsPerPage; + const int localPrimID = ray.primID % primsPerPage; + foreach_unique(primPage in primPageID) { + uniform uint8 *uniform pagePtr = self->data + + (((int64)primPage) + * primsPerPage + * self->bytesPerSphere); + uniform uint8 *varying spherePtr = pagePtr + + self->bytesPerSphere*localPrimID; + dg.materialID = + *((uniform uint32 *varying)(spherePtr+self->offset_materialID)); + if (self->materialList) { + dg.material = self->materialList[dg.materialID]; + } + } + } else { + uniform uint8 *varying spherePtr = self->data + + self->bytesPerSphere*ray.primID; dg.materialID = *((uniform uint32 *varying)(spherePtr+self->offset_materialID)); if (self->materialList) { @@ -90,10 +100,7 @@ static void Spheres_postIntersect(uniform Geometry *uniform geometry, } } } else { - uniform uint8 *varying spherePtr = self->data - + self->bytesPerSphere*ray.primID; - dg.materialID = - *((uniform uint32 *varying)(spherePtr+self->offset_materialID)); + dg.materialID = self->materialID; if (self->materialList) { dg.material = self->materialList[dg.materialID]; } diff --git a/ospray/geometry/StreamLines.h b/ospray/geometry/StreamLines.h index 0c9533f547..dc446deed5 100644 --- a/ospray/geometry/StreamLines.h +++ b/ospray/geometry/StreamLines.h @@ -22,7 +22,7 @@ namespace ospray { /*! @{ \ingroup ospray_module_streamlines */ - /*! \defgroup geometry_streamlines Stream Lines ("streamlines") + /*! \defgroup geometry_streamlines Stream Lines ("streamlines") \ingroup ospray_supported_geometries @@ -79,8 +79,8 @@ namespace ospray { Implements the \ref geometry_streamlines geometry */ - struct StreamLines : public Geometry { - //! \brief common function to help printf-debugging + struct OSPRAY_SDK_INTERFACE StreamLines : public Geometry { + //! \brief common function to help printf-debugging virtual std::string toString() const { return "ospray::StreamLines"; } /*! \brief integrates this geometry's primitives into the respective model's acceleration structure */ diff --git a/ospray/geometry/TriangleMesh.cpp b/ospray/geometry/TriangleMesh.cpp index 735b7e2bc7..de4e8be21b 100644 --- a/ospray/geometry/TriangleMesh.cpp +++ b/ospray/geometry/TriangleMesh.cpp @@ -90,7 +90,7 @@ namespace ospray { this->normal = normalData ? (float*)normalData->data : NULL; this->color = colorData ? (vec4f*)colorData->data : NULL; this->texcoord = texcoordData ? (vec2f*)texcoordData->data : NULL; - this->prim_materialID = prim_materialIDData ? (uint32*)prim_materialIDData->data : NULL; + this->prim_materialID = prim_materialIDData ? (uint32_t*)prim_materialIDData->data : NULL; this->materialList = materialListData ? (ospray::Material**)materialListData->data : NULL; if (materialList && !ispcMaterialPtrs) { @@ -187,7 +187,7 @@ namespace ospray { bounds = empty; - for (int i=0;i= 2) @@ -210,7 +210,7 @@ namespace ospray { geom_materialID, getMaterial()?getMaterial()->getIE():NULL, ispcMaterialPtrs, - (uint32*)prim_materialID); + (uint32_t*)prim_materialID); } OSP_REGISTER_GEOMETRY(TriangleMesh,triangles); diff --git a/ospray/geometry/TriangleMesh.h b/ospray/geometry/TriangleMesh.h index 5efa14a974..7752c75676 100644 --- a/ospray/geometry/TriangleMesh.h +++ b/ospray/geometry/TriangleMesh.h @@ -21,7 +21,7 @@ namespace ospray { - /*! \defgroup geometry_trianglemesh Triangle Meshes ("trianglemesh") + /*! \defgroup geometry_trianglemesh Triangle Meshes ("trianglemesh") \brief Implements a traditional triangle mesh (indexed face set) geometry @@ -69,7 +69,7 @@ namespace ospray { - a 'prim.materialID' array (Data type), indexing into - a 'materialList' array (holding the OSPMaterial pointers) */ - struct TriangleMesh : public Geometry + struct OSPRAY_SDK_INTERFACE TriangleMesh : public Geometry { TriangleMesh(); diff --git a/ospray/include/ospray/ospray.h b/ospray/include/ospray/ospray.h index 888de11db5..1f3dba5427 100644 --- a/ospray/include/ospray/ospray.h +++ b/ospray/include/ospray/ospray.h @@ -369,7 +369,7 @@ extern "C" { Valid flags that can be OR'ed together into the flags value: - OSP_DATA_SHARED_BUFFER: indicates that the buffer can be shared with the app. - In this case the calling program guarantees that the 'init' pointer will remain + In this case the calling program guarantees that the 'source' pointer will remain valid for the duration that this data array is being used. */ OSPRAY_INTERFACE OSPData ospNewData(size_t numItems, diff --git a/ospray/lights/AmbientLight.h b/ospray/lights/AmbientLight.h index 2f43090a29..30f3802b1b 100644 --- a/ospray/lights/AmbientLight.h +++ b/ospray/lights/AmbientLight.h @@ -21,7 +21,7 @@ namespace ospray { //! an AmbientLight is a constant light that is present everywhere - class AmbientLight : public Light { + class OSPRAY_SDK_INTERFACE AmbientLight : public Light { public: AmbientLight(); diff --git a/ospray/lights/AmbientLight.ispc b/ospray/lights/AmbientLight.ispc index 2772a7581a..8944ada3c5 100644 --- a/ospray/lights/AmbientLight.ispc +++ b/ospray/lights/AmbientLight.ispc @@ -49,13 +49,13 @@ Light_SampleRes AmbientLight_sample(const uniform Light* uniform super, Light_EvalRes AmbientLight_eval(const uniform Light* uniform super, const DifferentialGeometry& dg, - const vec3f& dir) + const vec3f& dir, + const float maxDist) { uniform AmbientLight* uniform self = (uniform AmbientLight* uniform)super; Light_EvalRes res; - res.radiance = self->radiance; - res.dist = inf; + res.radiance = inf <= maxDist ? self->radiance : make_vec3f(0.f); res.pdf = cosineSampleHemispherePDF(max(dot(dg.Ns, dir), 0.f)); return res; diff --git a/ospray/lights/DirectionalLight.cpp b/ospray/lights/DirectionalLight.cpp index d5566c14c8..ba2dd4509d 100644 --- a/ospray/lights/DirectionalLight.cpp +++ b/ospray/lights/DirectionalLight.cpp @@ -38,7 +38,7 @@ namespace ospray { direction = -normalize(direction); // the ispc::DirLight expects direction towards light source angularDiameter = clamp(angularDiameter, 0.f, 180.f); - const float cosAngle = cos(deg2rad(0.5f*angularDiameter)); + const float cosAngle = ospcommon::cos(deg2rad(0.5f*angularDiameter)); ispc::DirectionalLight_set(getIE(), (ispc::vec3f&)direction, (ispc::vec3f&)radiance, cosAngle); } diff --git a/ospray/lights/DirectionalLight.h b/ospray/lights/DirectionalLight.h index d07c6b2804..4e43bbe61b 100644 --- a/ospray/lights/DirectionalLight.h +++ b/ospray/lights/DirectionalLight.h @@ -22,16 +22,16 @@ namespace ospray { /*! a DirectionalLight is a singular light which is infinitely distant and * thus projects parallel rays of light across the entire scene */ - class DirectionalLight : public Light { + class OSPRAY_SDK_INTERFACE DirectionalLight : public Light { public: DirectionalLight(); - + //! toString is used to aid in printf debugging virtual std::string toString() const { return "ospray::DirectionalLight"; } - + //! Copy understood parameters into member parameters virtual void commit(); - + private: vec3f direction; //!< Direction of the emitted rays vec3f color; //!< RGB color of the emitted light diff --git a/ospray/lights/DirectionalLight.ispc b/ospray/lights/DirectionalLight.ispc index aa9f8300af..1e71370d8b 100644 --- a/ospray/lights/DirectionalLight.ispc +++ b/ospray/lights/DirectionalLight.ispc @@ -56,18 +56,18 @@ Light_SampleRes DirectionalLight_sample(const uniform Light* uniform super, Light_EvalRes DirectionalLight_eval(const uniform Light* uniform super, const DifferentialGeometry&, - const vec3f& dir) + const vec3f& dir, + const float maxDist) { uniform DirectionalLight* uniform self = (uniform DirectionalLight* uniform)super; Light_EvalRes res; - res.dist = inf; + res.radiance = make_vec3f(0.f); - if (self->cosAngle < COS_ANGLE_MAX && dot(self->frame.vz, dir) > self->cosAngle) { + if (inf <= maxDist + && self->cosAngle < COS_ANGLE_MAX + && dot(self->frame.vz, dir) > self->cosAngle) { res.radiance = self->radiance * self->pdf; res.pdf = self->pdf; - } else { - res.radiance = make_vec3f(0.f); - res.pdf = 0.f; } return res; diff --git a/ospray/lights/HDRILight.h b/ospray/lights/HDRILight.h index 2f2e422284..02f0512ec2 100644 --- a/ospray/lights/HDRILight.h +++ b/ospray/lights/HDRILight.h @@ -23,7 +23,7 @@ namespace ospray { /*! a SpotLight is a singular light emitting from a point uniformly into a * cone of directions bounded by halfAngle */ - class HDRILight : public Light { + class OSPRAY_SDK_INTERFACE HDRILight : public Light { public: HDRILight(); ~HDRILight(); diff --git a/ospray/lights/HDRILight.ispc b/ospray/lights/HDRILight.ispc index 3e18938770..31de637e70 100644 --- a/ospray/lights/HDRILight.ispc +++ b/ospray/lights/HDRILight.ispc @@ -77,10 +77,15 @@ Light_SampleRes HDRILight_sample(const uniform Light* uniform super, Light_EvalRes HDRILight_eval(const uniform Light* uniform super, const DifferentialGeometry&, - const vec3f& dir) + const vec3f& dir, + const float maxDist) { uniform HDRILight* uniform self = (uniform HDRILight* uniform)super; Light_EvalRes res; + res.radiance = make_vec3f(0.f); + + if (inf > maxDist) + return res; const vec3f localDir = self->world2light * dir; @@ -89,7 +94,6 @@ Light_EvalRes HDRILight_eval(const uniform Light* uniform super, const vec2f uv = make_vec2f(u, v); res.radiance = get3f(self->map, uv) * self->intensity; - res.dist = inf; // domain of Distribution2D is shifted by half a texel compared to texture // atan2 can get negative, shift can lead to values > 1.f: reproject to [0..1) diff --git a/ospray/lights/Light.h b/ospray/lights/Light.h index d8238cdf4e..d946910446 100644 --- a/ospray/lights/Light.h +++ b/ospray/lights/Light.h @@ -21,7 +21,7 @@ namespace ospray { //! Base class for Light objects - struct Light : public ManagedObject { + struct OSPRAY_SDK_INTERFACE Light : public ManagedObject { //! Create a light of the given type static Light *createLight(const char *type); @@ -32,10 +32,7 @@ namespace ospray { virtual std::string toString() const { return "ospray::Light"; } }; -#define OSP_REGISTER_LIGHT(InternalClassName, external_name) \ - extern "C" OSPRAY_INTERFACE ospray::Light *ospray_create_light__##external_name() \ - { \ - return new InternalClassName; \ - } +#define OSP_REGISTER_LIGHT(InternalClass, external_name) \ + OSP_REGISTER_OBJECT(Light, light, InternalClass, external_name) } diff --git a/ospray/lights/Light.ih b/ospray/lights/Light.ih index fb07620072..51d1d9fc5a 100644 --- a/ospray/lights/Light.ih +++ b/ospray/lights/Light.ih @@ -39,14 +39,14 @@ typedef Light_SampleRes (*Light_SampleFunc)(const uniform Light* uniform, struct Light_EvalRes { vec3f radiance; //!< radiance that arrives at the given point (not weighted by pdf) - float dist; //!< distance from the given point and direction to the light source float pdf; //!< probability density that the direction would have been sampled }; -//! compute the radiance, distance and pdf caused by the light source (pointed to by the given direction) +//! compute the radiance and pdf caused by the light source (pointed to by the given direction up until maxDist) typedef Light_EvalRes (*Light_EvalFunc)(const uniform Light* uniform, const DifferentialGeometry&, //! point to evaluate illumination for >*/ - const vec3f& dir); //! direction towards the light source, normalized >*/ + const vec3f& dir, //! direction towards the light source, normalized >*/ + const float maxDist); //! maximum distance to look for light contribution >*/ struct Light @@ -55,7 +55,7 @@ struct Light Light_EvalFunc eval; }; -Light_EvalRes Light_eval(const uniform Light* uniform self, const DifferentialGeometry& dg, const vec3f& dir); +Light_EvalRes Light_eval(const uniform Light* uniform, const DifferentialGeometry&, const vec3f&, const float); inline void Light_Constructor(uniform Light* uniform self) { diff --git a/ospray/lights/Light.ispc b/ospray/lights/Light.ispc index 89b8aacbc6..a9053a1897 100644 --- a/ospray/lights/Light.ispc +++ b/ospray/lights/Light.ispc @@ -18,11 +18,10 @@ Light_EvalRes Light_eval(const uniform Light* uniform, const DifferentialGeometry&, - const vec3f&) + const vec3f&, + const float) { Light_EvalRes res; res.radiance = make_vec3f(0.f); - res.dist = inf; - res.pdf = 0.f; return res; } diff --git a/ospray/lights/PointLight.h b/ospray/lights/PointLight.h index 10bcb6f6f4..58def016fd 100644 --- a/ospray/lights/PointLight.h +++ b/ospray/lights/PointLight.h @@ -21,7 +21,7 @@ namespace ospray { //! a PointLight is a singular light emitting from a point uniformly into all directions - class PointLight : public Light { + class OSPRAY_SDK_INTERFACE PointLight : public Light { public: PointLight(); diff --git a/ospray/lights/PointLight.ispc b/ospray/lights/PointLight.ispc index 50b3f56385..e0e80805f0 100644 --- a/ospray/lights/PointLight.ispc +++ b/ospray/lights/PointLight.ispc @@ -79,13 +79,12 @@ Light_SampleRes PointLight_sample(const uniform Light* uniform super, Light_EvalRes PointLight_eval(const uniform Light* uniform super, const DifferentialGeometry& dg, - const vec3f& dir) + const vec3f& dir, + const float maxDist) { const PointLight* uniform self = (PointLight* uniform)super; Light_EvalRes res; res.radiance = make_vec3f(0.f); - res.dist = inf; - res.pdf = 0.f; if (self->radius > 0.f) { const vec3f A = self->position - dg.P; @@ -99,9 +98,9 @@ Light_EvalRes PointLight_eval(const uniform Light* uniform super, const float t_near = (b - sqrt(radical)) / (2.f*a); const float t_far = (b + sqrt(radical)) / (2.f*a); - if (t_far > 0.0f) { + if (t_far > 0.0f & t_near <= maxDist) { // TODO: handle interior case - res.dist = t_near; + const float sinTheta2 = sqr(self->radius) * rcp(centerDist2); const float cosTheta = sqrt(1.f - sinTheta2); res.pdf = uniformSampleConePDF(cosTheta); diff --git a/ospray/lights/QuadLight.h b/ospray/lights/QuadLight.h index f73b40a0d8..0700f5e8f3 100644 --- a/ospray/lights/QuadLight.h +++ b/ospray/lights/QuadLight.h @@ -22,7 +22,7 @@ namespace ospray { /*! a QuadLight is a virtual area light uniformly emitting from a rectangular * area into the positive half space */ - class QuadLight : public Light { + class OSPRAY_SDK_INTERFACE QuadLight : public Light { public: QuadLight(); diff --git a/ospray/lights/QuadLight.ispc b/ospray/lights/QuadLight.ispc index e55d3d1ac2..014ffc39e0 100644 --- a/ospray/lights/QuadLight.ispc +++ b/ospray/lights/QuadLight.ispc @@ -64,13 +64,12 @@ Light_SampleRes QuadLight_sample(const uniform Light* uniform super, Light_EvalRes QuadLight_eval(const uniform Light* uniform super, const DifferentialGeometry& dg, - const vec3f& dir) + const vec3f& dir, + const float maxDist) { uniform QuadLight* uniform self = (uniform QuadLight* uniform)super; Light_EvalRes res; res.radiance = make_vec3f(0.f); - res.pdf = 0.f; - res.dist = inf; // backfacing? const float cosd = dot(self->nnormal, dir); @@ -89,9 +88,11 @@ Light_EvalRes QuadLight_eval(const uniform Light* uniform super, const float rcosd = rcp(cosd); const float dist = dot(self->nnormal, c) * rcosd; + if (dist > maxDist) + return res; + res.radiance = self->radiance; res.pdf = self->ppdf * sqr(dist) * rcosd; - res.dist = dist; return res; } diff --git a/ospray/lights/SpotLight.cpp b/ospray/lights/SpotLight.cpp index 04525966c2..695b89a007 100644 --- a/ospray/lights/SpotLight.cpp +++ b/ospray/lights/SpotLight.cpp @@ -52,8 +52,8 @@ namespace ospray { direction = normalize(direction); openingAngle = clamp(openingAngle, 0.f, 180.f); penumbraAngle = clamp(penumbraAngle, 0.f, 0.5f*openingAngle); - const float cosAngleMax = cos(deg2rad(0.5f*openingAngle)); - const float cosAngleMin = cos(deg2rad(0.5f*openingAngle - penumbraAngle)); + const float cosAngleMax = ospcommon::cos(deg2rad(0.5f*openingAngle)); + const float cosAngleMin = ospcommon::cos(deg2rad(0.5f*openingAngle - penumbraAngle)); const float cosAngleScale = 1.0f/(cosAngleMin - cosAngleMax); ispc::SpotLight_set(getIE(), diff --git a/ospray/lights/SpotLight.h b/ospray/lights/SpotLight.h index b3f5530b66..5a3b686c02 100644 --- a/ospray/lights/SpotLight.h +++ b/ospray/lights/SpotLight.h @@ -22,7 +22,7 @@ namespace ospray { /*! a SpotLight is a singular light emitting from a point uniformly into a * cone of directions bounded by halfAngle */ - class SpotLight : public Light { + class OSPRAY_SDK_INTERFACE SpotLight : public Light { public: SpotLight(); diff --git a/ospray/lights/SpotLight.ispc b/ospray/lights/SpotLight.ispc index eb802ed945..9254f12171 100644 --- a/ospray/lights/SpotLight.ispc +++ b/ospray/lights/SpotLight.ispc @@ -72,13 +72,12 @@ Light_SampleRes SpotLight_sample(const uniform Light* uniform super, Light_EvalRes SpotLight_eval(const uniform Light* uniform super, const DifferentialGeometry& dg, - const vec3f& dir) + const vec3f& dir, + const float maxDist) { const SpotLight* uniform self = (SpotLight* uniform)super; Light_EvalRes res; res.radiance = make_vec3f(0.f); - res.dist = inf; - res.pdf = 0.f; if (self->radius > 0.f) { // intersect disk @@ -88,13 +87,14 @@ Light_EvalRes SpotLight_eval(const uniform Light* uniform super, const float dp = dot(vp, self->frame.vz); if (dp > 0.f) { // in front of light? const float t = dp*rcp(cosAngle); - const vec3f vd = vp + t * dir; - if (dot(vd, vd) < sqr(self->radius)) { // inside disk? - const float angularAttenuation = min((cosAngle - self->cosAngleMax) * self->cosAngleScale, 1.f); - const float pdf = self->diskPdf * cosAngle; - res.radiance = self->power * (angularAttenuation * pdf); // *sqr(t)/sqr(t) cancels - res.dist = t; - res.pdf = pdf * sqr(t); + if (t <= maxDist) { + const vec3f vd = vp + t * dir; + if (dot(vd, vd) < sqr(self->radius)) { // inside disk? + const float angularAttenuation = min((cosAngle - self->cosAngleMax) * self->cosAngleScale, 1.f); + const float pdf = self->diskPdf * cosAngle; + res.radiance = self->power * (angularAttenuation * pdf); // *sqr(t)/sqr(t) cancels + res.pdf = pdf * sqr(t); + } } } } diff --git a/ospray/math/box.ih b/ospray/math/box.ih index 96da72f246..d7de5ce849 100644 --- a/ospray/math/box.ih +++ b/ospray/math/box.ih @@ -74,37 +74,96 @@ inline uniform box1f make_box1f(const uniform float f) /*! construct 1f range from lower and upper value */ inline uniform box1f make_box1f(const uniform float lo, const uniform float hi) { uniform box1f bb; bb.lower = lo; bb.upper = hi; return bb; } +inline varying box1f make_box1f(const varying float lo, const varying float hi) +{ varying box1f bb; bb.lower = lo; bb.upper = hi; return bb; } inline uniform box1f box_extend(const uniform box1f &a, const uniform box1f &b) { return make_box1f(min(a.lower,b.lower),max(a.upper,b.upper)); } + +// ------------------------------------------------------- +// box2 'constructors' +// ------------------------------------------------------- + +#define MAKE_BOX_CONSTRUCTORS_uv_2T_fromVec2(univary,Tabb,otherT) \ + inline univary box2##Tabb make_box2##Tabb(const univary vec2##otherT lower, \ + const univary vec2##otherT upper) { \ + univary box2##Tabb bb; \ + bb.lower.x = lower.x; \ + bb.lower.y = lower.y; \ + bb.upper.x = upper.x; \ + bb.upper.y = upper.y; \ + return bb; \ + } + +#define MAKE_BOX_CONSTRUCTORS_uv_2T_fromBox2(univary,Tabb,otherT) \ + inline univary box2##Tabb make_box2##Tabb(const univary box2##otherT other) {\ + univary box2##Tabb bb; \ + bb.lower.x = other.lower.x; \ + bb.lower.y = other.lower.y; \ + bb.upper.x = other.upper.x; \ + bb.upper.y = other.upper.y; \ + return bb; \ + } + +#define MAKE_BOX_CONSTRUCTORS_uv_2T_empty(Tabb) \ + inline uniform box2##Tabb make_box2##Tabb##_empty() { \ + return make_box2##Tabb(make_vec2##Tabb(inf), make_vec2##Tabb(neg_inf)); \ + } + +#define MAKE_BOX_CONSTRUCTORS_uv_2T(univary,Tabb) \ + MAKE_BOX_CONSTRUCTORS_uv_2T_fromVec2(univary,Tabb,f) \ + MAKE_BOX_CONSTRUCTORS_uv_2T_fromVec2(univary,Tabb,i) \ + \ + MAKE_BOX_CONSTRUCTORS_uv_2T_fromBox2(univary,Tabb,f) \ + MAKE_BOX_CONSTRUCTORS_uv_2T_fromBox2(univary,Tabb,i) + +#define MAKE_BOX_CONSTRUCTORS_uv_2(univary) \ + MAKE_BOX_CONSTRUCTORS_uv_2T(univary,i) \ + MAKE_BOX_CONSTRUCTORS_uv_2T(univary,f) \ + +#define MAKE_BOX_CONSTRUCTORS_uv(univary) \ + MAKE_BOX_CONSTRUCTORS_uv_2(univary) + +MAKE_BOX_CONSTRUCTORS_uv(uniform) +MAKE_BOX_CONSTRUCTORS_uv(varying) +MAKE_BOX_CONSTRUCTORS_uv_2T_empty(f) + +#undef MAKE_BOX_CONSTRUCTORS_uv_2T_fromVec2 +#undef MAKE_BOX_CONSTRUCTORS_uv_2T_fromBox2 +#undef MAKE_BOX_CONSTRUCTORS_uv_2T_empty +#undef MAKE_BOX_CONSTRUCTORS_uv_2T +#undef MAKE_BOX_CONSTRUCTORS_uv_2 +#undef MAKE_BOX_CONSTRUCTORS_uv + + // ------------------------------------------------------- -// box3f 'constructors' +// box3 'constructors' // ------------------------------------------------------- -#define MAKE_BOX_CONSTRUCTORS_uv_3T_fromVec3(univary,Tabb,otherT) \ +#define MAKE_BOX_CONSTRUCTORS_uv_3T_fromVec3(univary,Tabb,otherT) \ inline univary box3##Tabb make_box3##Tabb(const univary vec3##otherT lower, \ - const univary vec3##otherT upper) { \ - univary box3##Tabb bb; \ - bb.lower.x = lower.x; \ - bb.lower.y = lower.y; \ - bb.lower.z = lower.z; \ - bb.upper.x = upper.x; \ - bb.upper.y = upper.y; \ - bb.upper.z = upper.z; \ - return bb; \ + const univary vec3##otherT upper) { \ + univary box3##Tabb bb; \ + bb.lower.x = lower.x; \ + bb.lower.y = lower.y; \ + bb.lower.z = lower.z; \ + bb.upper.x = upper.x; \ + bb.upper.y = upper.y; \ + bb.upper.z = upper.z; \ + return bb; \ } -#define MAKE_BOX_CONSTRUCTORS_uv_3T_fromBox3(univary,Tabb,otherT) \ - inline univary box3##Tabb make_box3##Tabb(const univary box3##otherT other) { \ - univary box3##Tabb bb; \ - bb.lower.x = other.lower.x; \ - bb.lower.y = other.lower.y; \ - bb.lower.z = other.lower.z; \ - bb.upper.x = other.upper.x; \ - bb.upper.y = other.upper.y; \ - bb.upper.z = other.upper.z; \ - return bb; \ +#define MAKE_BOX_CONSTRUCTORS_uv_3T_fromBox3(univary,Tabb,otherT) \ + inline univary box3##Tabb make_box3##Tabb(const univary box3##otherT other) {\ + univary box3##Tabb bb; \ + bb.lower.x = other.lower.x; \ + bb.lower.y = other.lower.y; \ + bb.lower.z = other.lower.z; \ + bb.upper.x = other.upper.x; \ + bb.upper.y = other.upper.y; \ + bb.upper.z = other.upper.z; \ + return bb; \ } #define MAKE_BOX_CONSTRUCTORS_uv_3T_empty(Tabb) \ @@ -112,21 +171,21 @@ inline uniform box1f box_extend(const uniform box1f &a, const uniform box1f &b) return make_box3##Tabb(make_vec3##Tabb(inf), make_vec3##Tabb(neg_inf)); \ } -#define MAKE_BOX_CONSTRUCTORS_uv_3T(univary,Tabb) \ - MAKE_BOX_CONSTRUCTORS_uv_3T_fromVec3(univary,Tabb,f) \ - MAKE_BOX_CONSTRUCTORS_uv_3T_fromVec3(univary,Tabb,fa) \ - MAKE_BOX_CONSTRUCTORS_uv_3T_fromVec3(univary,Tabb,i) \ - \ - MAKE_BOX_CONSTRUCTORS_uv_3T_fromBox3(univary,Tabb,f) \ - MAKE_BOX_CONSTRUCTORS_uv_3T_fromBox3(univary,Tabb,fa) \ +#define MAKE_BOX_CONSTRUCTORS_uv_3T(univary,Tabb) \ + MAKE_BOX_CONSTRUCTORS_uv_3T_fromVec3(univary,Tabb,f) \ + MAKE_BOX_CONSTRUCTORS_uv_3T_fromVec3(univary,Tabb,fa) \ + MAKE_BOX_CONSTRUCTORS_uv_3T_fromVec3(univary,Tabb,i) \ + \ + MAKE_BOX_CONSTRUCTORS_uv_3T_fromBox3(univary,Tabb,f) \ + MAKE_BOX_CONSTRUCTORS_uv_3T_fromBox3(univary,Tabb,fa) \ MAKE_BOX_CONSTRUCTORS_uv_3T_fromBox3(univary,Tabb,i) -#define MAKE_BOX_CONSTRUCTORS_uv_3(univary) \ - MAKE_BOX_CONSTRUCTORS_uv_3T(univary,i) \ - MAKE_BOX_CONSTRUCTORS_uv_3T(univary,f) \ +#define MAKE_BOX_CONSTRUCTORS_uv_3(univary) \ + MAKE_BOX_CONSTRUCTORS_uv_3T(univary,i) \ + MAKE_BOX_CONSTRUCTORS_uv_3T(univary,f) \ MAKE_BOX_CONSTRUCTORS_uv_3T(univary,fa) -#define MAKE_BOX_CONSTRUCTORS_uv(univary) \ +#define MAKE_BOX_CONSTRUCTORS_uv(univary) \ MAKE_BOX_CONSTRUCTORS_uv_3(univary) MAKE_BOX_CONSTRUCTORS_uv(uniform) @@ -141,34 +200,40 @@ MAKE_BOX_CONSTRUCTORS_uv_3T_empty(fa) #undef MAKE_BOX_CONSTRUCTORS_uv_3 #undef MAKE_BOX_CONSTRUCTORS_uv + // ------------------------------------------------------- -// box3 'operations' +// box 'operations' // ------------------------------------------------------- -#define MAKE_BOX_OPERATIONS_uv_3T(univary,T) \ - inline univary vec3##T box_size(univary box3##T bb) { \ +#define MAKE_BOX_OPERATIONS_uv_N_T(univary, N, T) \ + inline univary vec##N##T box_size(univary box##N##T bb) { \ return bb.upper - bb.lower; \ } \ \ - inline univary box3##T \ - box_extend(const univary box3##T bb, const univary vec3##T v) { \ - return make_box3##T(min(bb.lower,v), max(bb.upper,v)); \ + inline univary box##N##T \ + box_extend(const univary box##N##T bb, const univary vec##N##T v) { \ + return make_box##N##T(min(bb.lower,v), max(bb.upper,v)); \ } \ \ - inline univary box3##T \ - box_extend(const univary box3##T bb, const univary box3##T other) { \ - return make_box3##T(min(bb.lower,other.lower), max(bb.upper,other.upper)); \ + inline univary box##N##T \ + box_extend(const univary box##N##T bb, const univary box##N##T other) { \ + return make_box##N##T(min(bb.lower,other.lower), max(bb.upper,other.upper));\ } +#define MAKE_BOX_OPERATIONS_uv_N(univary, N) \ + MAKE_BOX_OPERATIONS_uv_N_T(univary, N, i) \ + MAKE_BOX_OPERATIONS_uv_N_T(univary, N, f) + #define MAKE_BOX_OPERATIONS_uv(univary) \ - MAKE_BOX_OPERATIONS_uv_3T(univary,i) \ - MAKE_BOX_OPERATIONS_uv_3T(univary,f) \ - MAKE_BOX_OPERATIONS_uv_3T(univary,fa) + MAKE_BOX_OPERATIONS_uv_N(univary, 2) \ + MAKE_BOX_OPERATIONS_uv_N(univary, 3) \ + MAKE_BOX_OPERATIONS_uv_N_T(univary, 3, fa) MAKE_BOX_OPERATIONS_uv(uniform) MAKE_BOX_OPERATIONS_uv(varying) -#undef MAKE_BOX_OPERATIONS_uv_3T +#undef MAKE_BOX_OPERATIONS_uv_N_T +#undef MAKE_BOX_OPERATIONS_uv_N #undef MAKE_BOX_OPERATIONS_uv //! print given box to stdout @@ -176,3 +241,8 @@ void print_box(const uniform box3f &bbox); //! print given box to stdout void print_box(const uniform box3fa &bbox); + +// this is just a renaming - in some cases the code reads cleaner if we're +// talking about 'regions' than about boxes +typedef box1f region1f; +typedef box2i region2i; diff --git a/ospray/math/vec.ih b/ospray/math/vec.ih index e35fc9d9d6..ac395c00aa 100644 --- a/ospray/math/vec.ih +++ b/ospray/math/vec.ih @@ -498,6 +498,10 @@ inline uniform bool eq(const uniform vec2f a, const uniform vec2f b) { return a.x==b.x && a.y==b.y; } inline bool eq(const vec2f a, const vec2f b) { return a.x==b.x & a.y==b.y; } +inline uniform bool eq(const uniform vec3f a, const uniform float b) +{ return a.x==b && a.y==b && a.z==b; } +inline bool eq(const vec3f a, const float b) +{ return a.x==b & a.y==b & a.z==b; } inline uniform bool eq(const uniform vec3f a, const uniform vec3f b) { return a.x==b.x && a.y==b.y && a.z==b.z; } inline bool eq(const vec3f a, const vec3f b) @@ -511,6 +515,10 @@ inline uniform bool ne(const uniform vec2f a, const uniform vec2f b) { return !eq(a,b); } inline bool ne(const vec2f a, const vec2f b) { return !eq(a,b); } +inline uniform bool ne(const uniform vec3f a, const uniform float b) +{ return !eq(a,b); } +inline bool ne(const vec3f a, const float b) +{ return !eq(a,b); } inline uniform bool ne(const uniform vec3f a, const uniform vec3f b) { return !eq(a,b); } inline bool ne(const vec3f a, const vec3f b) @@ -654,46 +662,48 @@ inline uniform vec4f make_vec4f(const uniform vec3f rgb, const uniform float a) // inline vec3f rcp(const vec3f v) // { return make_vec3f(rcp(v.x),rcp(v.y),rcp(v.z)); } -#define __define_lerp2(ABB) \ - inline uniform vec2##ABB lerp(uniform float factor, const uniform vec2##ABB a, const uniform vec2##ABB b) \ +#define __define_lerp2_uv(univar,ABB) \ + inline univar vec2##ABB lerp(univar float factor, const univar vec2##ABB a, const univar vec2##ABB b) \ { \ return make_vec2##ABB(lerp(factor, a.x, b.x), lerp(factor, a.y, b.y)); \ } \ - inline vec2##ABB lerp(float factor, const vec2##ABB a, const vec2##ABB b) \ + inline univar vec2##ABB lerp(univar vec2f factor, const univar vec2##ABB a, const univar vec2##ABB b) \ { \ - return make_vec2##ABB(lerp(factor, a.x, b.x), lerp(factor, a.y, b.y)); \ + return make_vec2##ABB(lerp(factor.x, a.x, b.x), lerp(factor.y, a.y, b.y)); \ } -#define __define_lerp3(ABB) \ - inline uniform vec3##ABB lerp(uniform float factor, const uniform vec3##ABB a, const uniform vec3##ABB b) \ - { \ - return make_vec3##ABB(lerp(factor, a.x, b.x), lerp(factor, a.y, b.y), lerp(factor, a.z, b.z)); \ - } \ - inline vec3##ABB lerp(float factor, const vec3##ABB a, const vec3##ABB b) \ - { \ - return make_vec3##ABB(lerp(factor, a.x, b.x), lerp(factor, a.y, b.y), lerp(factor, a.z, b.z)); \ - } \ +#define __define_lerp2(ABB) \ + __define_lerp2_uv(uniform,ABB) \ + __define_lerp2_uv(varying,ABB) -#define __define_lerp3a(ABB) \ - inline uniform vec3##ABB##a lerp(uniform float factor, const uniform vec3##ABB##a a, const uniform vec3##ABB##a b) \ +#define __define_lerp3_uv(univar,ABB) \ + inline univar vec3##ABB lerp(univar float factor, const univar vec3##ABB a, const univar vec3##ABB b) \ { \ - return make_vec3##ABB##a(lerp(factor, a.x, b.x), lerp(factor, a.y, b.y), lerp(factor, a.z, b.z), lerp(factor, a.w, b.w)); \ + return make_vec3##ABB(lerp(factor, a.x, b.x), lerp(factor, a.y, b.y), lerp(factor, a.z, b.z)); \ } \ - inline vec3##ABB##a lerp(float factor, const vec3##ABB##a a, const vec3##ABB##a b) \ + inline univar vec3##ABB lerp(univar vec3f factor, const univar vec3##ABB a, const univar vec3##ABB b) \ { \ - return make_vec3##ABB##a(lerp(factor, a.x, b.x), lerp(factor, a.y, b.y), lerp(factor, a.z, b.z)); \ + return make_vec3##ABB(lerp(factor.x, a.x, b.x), lerp(factor.y, a.y, b.y), lerp(factor.z, a.z, b.z)); \ } -#define __define_lerp4(ABB) \ - inline uniform vec4##ABB lerp(uniform float factor, const uniform vec4##ABB a, const uniform vec4##ABB b) \ +#define __define_lerp3(ABB) \ + __define_lerp3_uv(uniform,ABB) \ + __define_lerp3_uv(varying,ABB) + +#define __define_lerp4_uv(univar,ABB) \ + inline univar vec4##ABB lerp(univar float factor, const univar vec4##ABB a, const univar vec4##ABB b) \ { \ return make_vec4##ABB(lerp(factor, a.x, b.x), lerp(factor, a.y, b.y), lerp(factor, a.z, b.z), lerp(factor, a.w, b.w)); \ } \ - inline vec4##ABB lerp(float factor, const vec4##ABB a, const vec4##ABB b) \ + inline univar vec4##ABB lerp(univar vec4f factor, const univar vec4##ABB a, const univar vec4##ABB b) \ { \ - return make_vec4##ABB(lerp(factor, a.x, b.x), lerp(factor, a.y, b.y), lerp(factor, a.z, b.z), lerp(factor, a.w, b.w)); \ + return make_vec4##ABB(lerp(factor.x, a.x, b.x), lerp(factor.y, a.y, b.y), lerp(factor.z, a.z, b.z), lerp(factor.w, a.w, b.w)); \ } +#define __define_lerp4(ABB) \ + __define_lerp4_uv(uniform,ABB) \ + __define_lerp4_uv(varying,ABB) + __define_lerp2(f) __define_lerp2(i) __define_lerp2(ui) @@ -702,9 +712,6 @@ __define_lerp3(f) __define_lerp3(i) __define_lerp3(ui) __define_lerp3(uc) -//__define_lerp3a(i) -//__define_lerp3a(ui) -//__define_lerp3a(uc) __define_lerp4(f) __define_lerp4(i) __define_lerp4(ui) diff --git a/ospray/mpi/CommandStream.h b/ospray/mpi/CommandStream.h index 342f0cae77..6016f146ce 100644 --- a/ospray/mpi/CommandStream.h +++ b/ospray/mpi/CommandStream.h @@ -22,12 +22,6 @@ namespace ospray { namespace mpi { - inline void checkMpiError(int rc) - { - if (rc != MPI_SUCCESS) - throw std::runtime_error("MPI Error"); - } - /*! \brief abstraction for a binary command stream */ /*! abstracts the concept of the mpi device writing commands and parameters, and the respective worker reading and unpacking @@ -58,7 +52,7 @@ namespace ospray { } inline void send(size_t i) { - int rc = MPI_Bcast(&i,1,MPI_AINT,MPI_ROOT,mpi::worker.comm); + int rc = MPI_Bcast((void*)&i,1,MPI_AINT,MPI_ROOT,mpi::worker.comm); checkMpiError(rc); } inline void send(const vec2f &v) @@ -88,7 +82,7 @@ namespace ospray { } inline void send(uint32 i) { - int rc = MPI_Bcast(&i,1,MPI_INT,MPI_ROOT,mpi::worker.comm); + int rc = MPI_Bcast((void*)&i,1,MPI_INT,MPI_ROOT,mpi::worker.comm); checkMpiError(rc); } inline void send(const ObjectHandle &h) @@ -119,7 +113,7 @@ namespace ospray { inline size_t get_size_t() { size_t v; - int rc = MPI_Bcast(&v,1,MPI_AINT,0,mpi::app.comm); + int rc = MPI_Bcast((void*)&v,1,MPI_AINT,0,mpi::app.comm); checkMpiError(rc); return v; } @@ -141,42 +135,42 @@ namespace ospray { inline ObjectHandle get_handle() { ObjectHandle v; - int rc = MPI_Bcast(&v,2,MPI_INT,0,mpi::app.comm); + int rc = MPI_Bcast((void*)&v,2,MPI_INT,0,mpi::app.comm); checkMpiError(rc); return v; } inline vec2i get_vec2i() { vec2i v; - int rc = MPI_Bcast(&v,2,MPI_INT,0,mpi::app.comm); + int rc = MPI_Bcast((void*)&v,2,MPI_INT,0,mpi::app.comm); checkMpiError(rc); return v; } inline vec2f get_vec2f() { vec2f v; - int rc = MPI_Bcast(&v,2,MPI_FLOAT,0,mpi::app.comm); + int rc = MPI_Bcast((void*)&v,2,MPI_FLOAT,0,mpi::app.comm); checkMpiError(rc); return v; } inline vec3f get_vec3f() { vec3f v; - int rc = MPI_Bcast(&v,3,MPI_FLOAT,0,mpi::app.comm); + int rc = MPI_Bcast((void*)&v,3,MPI_FLOAT,0,mpi::app.comm); checkMpiError(rc); return v; } inline vec4f get_vec4f() { vec4f v; - int rc = MPI_Bcast(&v,4,MPI_FLOAT,0,mpi::app.comm); + int rc = MPI_Bcast((void*)&v,4,MPI_FLOAT,0,mpi::app.comm); checkMpiError(rc); return v; } inline vec3i get_vec3i() { vec3i v; - int rc = MPI_Bcast(&v,3,MPI_INT,0,mpi::app.comm); + int rc = MPI_Bcast((void*)&v,3,MPI_INT,0,mpi::app.comm); checkMpiError(rc); return v; } diff --git a/ospray/mpi/DistributedFrameBuffer.cpp b/ospray/mpi/DistributedFrameBuffer.cpp index 9a16ad428f..f5635300c2 100644 --- a/ospray/mpi/DistributedFrameBuffer.cpp +++ b/ospray/mpi/DistributedFrameBuffer.cpp @@ -62,7 +62,7 @@ namespace ospray { /*! color buffer and depth buffer on master */ - enum { + enum COMMANDTAG { /*! command tag that identifies a CommLayer::message as a write tile command. this is a command using for sending a tile of new samples to another instance of the framebuffer (the one @@ -82,11 +82,7 @@ namespace ospray { does not actually care about the pixel data - we still have to let the master know when we're done. */ MASTER_WRITE_TILE_NONE, - } COMMANDTAG; - - // Helper functions ///////////////////////////////////////////////////////// - - inline int clientRank(int clientID) { return clientID+1; } + }; // DistributedFrameBuffer definitions /////////////////////////////////////// @@ -97,11 +93,10 @@ namespace ospray { bool hasDepthBuffer, bool hasAccumBuffer, bool hasVarianceBuffer) - : mpi::async::CommLayer::Object(comm,myID), - FrameBuffer(numPixels,colorBufferFormat,hasDepthBuffer, + : FrameBuffer(numPixels,colorBufferFormat,hasDepthBuffer, hasAccumBuffer,hasVarianceBuffer), - accumId(0), - tileErrorBuffer(nullptr), + mpi::async::CommLayer::Object(comm,myID), + tileErrorRegion(hasVarianceBuffer ? getNumTiles() : vec2i(0)), localFBonMaster(nullptr), frameMode(WRITE_ONCE), frameIsActive(false), @@ -113,12 +108,15 @@ namespace ospray { comm->registerObject(this,myID); createTiles(); + const size_t bytes = sizeof(int32)*getTotalTiles(); + tileAccumID = (int32*)alignedMalloc(bytes); + memset(tileAccumID, 0, bytes); if (comm->group->rank == 0) { if (colorBufferFormat == OSP_FB_NONE) { - cout << "#osp:mpi:dfb: we're the master, but framebuffer has 'NONE' " - << "format; creating distributed frame buffer WITHOUT having a " - << "mappable copy on the master" << endl; + DBG(cout << "#osp:mpi:dfb: we're the master, but framebuffer has 'NONE' " + << "format; creating distributed frame buffer WITHOUT having a " + << "mappable copy on the master" << endl); } else { localFBonMaster = new LocalFrameBuffer(numPixels, colorBufferFormat, @@ -126,22 +124,16 @@ namespace ospray { false, false); } - if (hasVarianceBuffer) { - tileErrorBuffer = - (float*)alignedMalloc(sizeof(float)*numTiles.x*numTiles.y); - } } - - ispc::DFB_set(getIE(), numPixels.x, numPixels.y, colorBufferFormat); } DFB::~DistributedFrameBuffer() { freeTiles(); - alignedFree(tileErrorBuffer); + alignedFree(tileAccumID); } - void DFB::startNewFrame() + void DFB::startNewFrame(const float errorThreshold) { std::vector delayedMessage; { @@ -149,9 +141,6 @@ namespace ospray { DBG(printf("rank %i starting new frame\n",mpi::world.rank)); assert(!frameIsActive); - if (hasAccumBuffer) - accumId++; - if (pixelOp) pixelOp->beginFrame(); @@ -162,8 +151,19 @@ namespace ospray { // the mutex delayedMessage = this->delayedMessage; this->delayedMessage.clear(); + + tileErrorRegion.sync(); numTilesCompletedThisFrame = 0; - numTilesToMasterThisFrame = 0; + + if (hasAccumBuffer) { + // increment accumID only for active tiles + for (int t = 0; t < getTotalTiles(); t++) + if (tileError(vec2i(t, 0)) <= errorThreshold) { + if (IamTheMaster() || allTiles[t]->mine()) + numTilesCompletedThisFrame++; + } else + tileAccumID[t]++; + } frameIsDone = false; @@ -179,6 +179,10 @@ namespace ospray { // might actually want to move this to a thread: for (auto &msg : delayedMessage) this->incoming(msg); + + if (numTilesCompletedThisFrame + == (IamTheMaster() ? getTotalTiles() : myTiles.size())) + closeCurrentFrame(); } void DFB::freeTiles() @@ -214,10 +218,10 @@ namespace ospray { { size_t tileID = 0; vec2i numPixels = getNumPixels(); - for (size_t y = 0; y < numPixels.y; y += TILE_SIZE) { - for (size_t x = 0; x < numPixels.x; x += TILE_SIZE, tileID++) { + for (int y = 0; y < numPixels.y; y += TILE_SIZE) { + for (int x = 0; x < numPixels.x; x += TILE_SIZE, tileID++) { size_t ownerID = tileID % (comm->group->size - 1); - if (clientRank(ownerID) == comm->group->rank) { + if (workerRank(ownerID) == comm->group->rank) { TileData *td = createTile(vec2i(x, y), tileID, ownerID); myTiles.push_back(td); allTiles.push_back(td); @@ -279,9 +283,12 @@ namespace ospray { void DFB::processMessage(MasterTileMessage *msg) { - { /* nothing to do for 'none' tiles */ } - if (hasVarianceBuffer && (accumId & 1) == 1) - tileErrorBuffer[getTileIDof(msg->coords)] = msg->error; + /* just update error for 'none' tiles */ + if (hasVarianceBuffer) { + const vec2i tileID = msg->coords/TILE_SIZE; + if ((accumID(tileID) & 1) == 1) + tileErrorRegion.update(tileID, msg->error); + } // and finally, tell the master that this tile is done auto *tileDesc = this->getTileDescFor(msg->coords); @@ -302,7 +309,7 @@ namespace ospray { DBG(printf("rank %i: tilecompleted %i,%i\n",mpi::world.rank, tile->begin.x,tile->begin.y)); if (IamTheMaster()) { - size_t numTilesCompletedByMyTile = 0; + int numTilesCompletedByMyTile = 0; /*! we will not do anything with the tile other than mark it's done */ { SCOPED_LOCK(mutex); @@ -361,7 +368,7 @@ namespace ospray { numTilesCompletedByMe = ++numTilesCompletedThisFrame; DBG(printf("rank %i: MARKING AS COMPLETED %i,%i -> %i %i\n", mpi::world.rank, - tile->begin.x,tile->begin.y,numTilesCompletedThisFrame, + tile->begin.x,tile->begin.y,(int)numTilesCompletedThisFrame, numTiles.x*numTiles.y)); } @@ -421,7 +428,7 @@ namespace ospray { frameDoneCond.notify_all(); } - //! write given tile data into the frame buffer, sending to remove owner if + //! write given tile data into the frame buffer, sending to remote owner if //! required void DFB::setTile(ospray::Tile &tile) { @@ -455,6 +462,7 @@ namespace ospray { */ void DFB::clear(const uint32 fbChannelFlags) { + frameID = -1; // we increment at the start of the frame if (!myTiles.empty()) { parallel_for(myTiles.size(), [&](int taskIndex){ TileData *td = this->myTiles[taskIndex]; @@ -478,36 +486,25 @@ namespace ospray { } if (hasAccumBuffer && (fbChannelFlags & OSP_FB_ACCUM)) { - accumId = -1; // we increment at the start of the frame - - // always also clear error buffer (if present) - if (tileErrorBuffer) { - const int tiles = numTiles.x*numTiles.y; - for (int i = 0; i < tiles; i++) - tileErrorBuffer[i] = inf; - } + // we increment at the start of the frame + memset(tileAccumID, -1, getTotalTiles()*sizeof(int32)); + tileErrorRegion.clear(); } } + int32 DFB::accumID(const vec2i &tile) + { + return tileAccumID[tile.y * numTiles.x + tile.x]; + } + float DFB::tileError(const vec2i &tile) { - if (tileErrorBuffer) - return tileErrorBuffer[getTileIDof(tile)]; - else - return inf; + return tileErrorRegion[tile]; } - float DFB::endFrame(const float /*errorThreshold*/) + float DFB::endFrame(const float errorThreshold) { - if (tileErrorBuffer) { - float maxErr = 0.0f; - const int tiles = numTiles.x*numTiles.y; - for (int i = 0; i < tiles; i++) - maxErr = std::max(maxErr, tileErrorBuffer[i]); - - return maxErr; - } else - return inf; + return tileErrorRegion.refine(errorThreshold); } } // ::ospray diff --git a/ospray/mpi/DistributedFrameBuffer.h b/ospray/mpi/DistributedFrameBuffer.h index b2c6fe0da1..56fa7de7cd 100644 --- a/ospray/mpi/DistributedFrameBuffer.h +++ b/ospray/mpi/DistributedFrameBuffer.h @@ -40,7 +40,7 @@ namespace ospray { DistributedFrameBuffer(mpi::async::CommLayer *comm, const vec2i &numPixels, size_t myHandle, - ColorBufferFormat colorBufferFormat, + ColorBufferFormat, bool hasDepthBuffer, bool hasAccumBuffer, bool hasVarianceBuffer); @@ -73,7 +73,7 @@ namespace ospray { and wants the (distributed) frame buffer to process it */ void setTile(ospray::Tile &tile) override; - void startNewFrame(); + void startNewFrame(const float errorThreshold); void closeCurrentFrame(); void waitUntilFinished(); @@ -82,7 +82,7 @@ namespace ospray { // remaining framebuffer interface // ================================================================== - int32 accumID(const vec2i &) override { return accumId; } + int32 accumID(const vec2i &) override; float tileError(const vec2i &tile) override; float endFrame(const float errorThreshold) override; @@ -95,7 +95,7 @@ namespace ospray { //! recipient's job to properly delete the message. void incoming(mpi::async::CommLayer::Message *msg) override; - //! process a client-to-client write tile message */ + //! process an empty client-to-master write tile message */ void processMessage(MasterTileMessage *msg); //! process a (non-empty) write tile message at the master @@ -121,17 +121,18 @@ namespace ospray { void tileIsCompleted(TileData *tile); //! number of tiles that "I" own - inline size_t numMyTiles() const { return myTiles.size(); } - inline bool IamTheMaster() const { return comm->IamTheMaster(); } + size_t numMyTiles() const { return myTiles.size(); } + bool IamTheMaster() const { return comm->IamTheMaster(); } + static int32 workerRank(int id) { return mpi::async::CommLayer::workerRank(id); } /*! return tile descriptor for given pixel coordinates. this tile ! may or may not belong to current instance */ - inline TileDesc *getTileDescFor(const vec2i &coords) const + TileDesc *getTileDescFor(const vec2i &coords) const { return allTiles[getTileIDof(coords)]; } /*! return the tile ID for given pair of coordinates. this tile may or may not belong to current instance */ - inline size_t getTileIDof(const vec2i &c) const + size_t getTileIDof(const vec2i &c) const { return (c.x/TILE_SIZE)+(c.y/TILE_SIZE)*numTiles.x; } //! \brief common function to help printf-debugging @@ -143,10 +144,10 @@ namespace ospray { WRITE_ONCE, ALPHA_BLEND, Z_COMPOSITE } FrameMode; - int accumId; + int32 *tileAccumID; //< holds accumID per tile, for adaptive accumulation + //!< holds error per tile and adaptive regions, for variance estimation / stopping + TileError tileErrorRegion; - //! holds error per tile, for variance estimation / stopping - float *tileErrorBuffer; /*! local frame buffer on the master used for storing the final tiles. will be null on all workers, and _may_ be null on the @@ -159,14 +160,11 @@ namespace ospray { TileData *createTile(const vec2i &xy, size_t tileID, size_t ownerID); void freeTiles(); - /*! number of tiles written this frame */ - size_t numTilesCompletedThisFrame; - - /*! number of tiles we've (already) sent to the master this frame - (used to track when current node is done with this frame - we - are done exactly once we've completed sending the last tile to + /*! #tiles we've (already) sent to / received by the master this frame + (used to track when current node is done with this frame - we are done + exactly once we've completed sending / receiving the last tile to / by the master) */ - size_t numTilesToMasterThisFrame; + size_t numTilesCompletedThisFrame; /*! vector of info for *all* tiles. Each logical tile in the screen has an entry here */ @@ -206,8 +204,11 @@ namespace ospray { inline void DistributedFrameBuffer::processMessage(MasterTileMessage_FB *msg) { - if (hasVarianceBuffer && (accumId & 1) == 1) - tileErrorBuffer[getTileIDof(msg->coords)] = msg->error; + if (hasVarianceBuffer) { + const vec2i tileID = msg->coords/TILE_SIZE; + if ((accumID(tileID) & 1) == 1) + tileErrorRegion.update(tileID, msg->error); + } vec2i numPixels = getNumPixels(); diff --git a/ospray/mpi/DistributedFrameBuffer.ispc b/ospray/mpi/DistributedFrameBuffer.ispc index f21163160a..15ff54f371 100644 --- a/ospray/mpi/DistributedFrameBuffer.ispc +++ b/ospray/mpi/DistributedFrameBuffer.ispc @@ -60,15 +60,17 @@ export uniform float DFB_accumulate_##name(void *uniform _self, \ VaryingTile *uniform variance, \ void *uniform _color, \ uniform float cntu, \ - uniform int accumID, \ uniform bool hasAccumBuffer, \ uniform bool hasVarianceBuffer) \ { \ + const uniform int accumID = tile->accumID; \ + const uniform vec2i size = box_size(tile->region); \ + const uniform int maxi = size.y*(TILE_SIZE/programCount); \ DistributedFrameBuffer *uniform self = (DistributedFrameBuffer*)_self; \ dst_fmt *uniform color = (dst_fmt*uniform)_color; \ uniform float errf = inf; \ if (!hasAccumBuffer || accumID < 1) { \ - for (uniform int i=0;ir[i], tile->g[i], tile->b[i], tile->a[i]);\ accum->r[i] = col.x; \ accum->g[i] = col.y; \ @@ -85,7 +87,7 @@ export uniform float DFB_accumulate_##name(void *uniform _self, \ const uniform float rcpAccumID = rcpf(accumID+1); \ const uniform float accHalfScale = rcpf(accumID/2+1); \ float err = 0.f; \ - for (uniform int i=0;ir[i], tile->g[i], tile->b[i]); \ vec4f col = make_vec4f(col3, tile->a[i]) \ + make_vec4f(accum->r[i], accum->g[i], accum->b[i], accum->a[i]); \ @@ -111,7 +113,8 @@ export uniform float DFB_accumulate_##name(void *uniform _self, \ const float den2 = reduce_add(acc3); \ if (den2 > 0.0f) { \ const vec3f diff = absf(acc3 - accHalfScale * vari); \ - err += reduce_add(diff) * rsqrtf(den2); \ + if ((i*programCount % TILE_SIZE) + programIndex < size.x) \ + err += reduce_add(diff) * rsqrtf(den2); \ } \ } \ \ diff --git a/ospray/mpi/DistributedFrameBuffer_TileTypes.cpp b/ospray/mpi/DistributedFrameBuffer_TileTypes.cpp index 005cd15e35..91b36cdfdc 100644 --- a/ospray/mpi/DistributedFrameBuffer_TileTypes.cpp +++ b/ospray/mpi/DistributedFrameBuffer_TileTypes.cpp @@ -24,7 +24,7 @@ namespace ospray { TileDesc::TileDesc(DFB *dfb, const vec2i &begin, size_t tileID, size_t ownerID) - : tileID(tileID), ownerID(ownerID), dfb(dfb), begin(begin) + : dfb(dfb), begin(begin), tileID(tileID), ownerID(ownerID) {} TileData::TileData(DFB *dfb, const vec2i &begin, @@ -64,7 +64,6 @@ namespace ospray { (ispc::VaryingTile*)&this->variance, &this->color, pixelsf, - dfb->accumId, dfb->hasAccumBuffer, dfb->hasVarianceBuffer); break; @@ -76,7 +75,6 @@ namespace ospray { (ispc::VaryingTile*)&this->variance, &this->color, pixelsf, - dfb->accumId, dfb->hasAccumBuffer, dfb->hasVarianceBuffer); break; @@ -91,7 +89,6 @@ namespace ospray { (ispc::VaryingTile*)&this->variance, &this->color, pixelsf, - dfb->accumId, dfb->hasAccumBuffer, dfb->hasVarianceBuffer); break; @@ -124,7 +121,7 @@ namespace ospray { currentGeneration++; missingInCurrentGeneration = expectedInNextGeneration; expectedInNextGeneration = 0; - for (int i=0;itile.generation == currentGeneration) { --missingInCurrentGeneration; @@ -136,7 +133,7 @@ namespace ospray { if (missingInCurrentGeneration == 0) { Tile **tileArray = STACK_BUFFER(Tile*, bufferedTile.size()); - for (int i = 0; i < bufferedTile.size(); i++) { + for (uint32_t i = 0; i < bufferedTile.size(); i++) { tileArray[i] = &bufferedTile[i]->tile; } @@ -195,7 +192,7 @@ namespace ospray { ispc::DFB_zComposite((ispc::VaryingTile*)&tile, (ispc::VaryingTile*)&this->compositedTileData); - done = (++numPartsComposited == dfb->comm->numWorkers()); + done = (++numPartsComposited == size_t(dfb->comm->numWorkers())); } if (done) { diff --git a/ospray/mpi/DistributedFrameBuffer_TileTypes.h b/ospray/mpi/DistributedFrameBuffer_TileTypes.h index b741dc6c39..ab239a994b 100644 --- a/ospray/mpi/DistributedFrameBuffer_TileTypes.h +++ b/ospray/mpi/DistributedFrameBuffer_TileTypes.h @@ -22,7 +22,7 @@ namespace ospray { - class DistributedFrameBuffer; + struct DistributedFrameBuffer; // ------------------------------------------------------- /*! keeps the book-keeping of one tile of the frame buffer. note @@ -38,6 +38,8 @@ namespace ospray { size_t tileID, size_t ownerID); + virtual ~TileDesc() {} + /*! returns whether this tile is one of this particular node's tiles */ virtual bool mine() const { return false; } diff --git a/ospray/mpi/MPICommon.cpp b/ospray/mpi/MPICommon.cpp index 7ef51f6938..7503d15db0 100644 --- a/ospray/mpi/MPICommon.cpp +++ b/ospray/mpi/MPICommon.cpp @@ -42,9 +42,10 @@ namespace ospray { MPI_CALL(Comm_size(MPI_COMM_WORLD,&world.size)); mpi::async::CommLayer::WORLD = new mpi::async::CommLayer; - mpi::async::Group *worldGroup = mpi::async::createGroup("world",MPI_COMM_WORLD, - mpi::async::CommLayer::WORLD, - 290374); + mpi::async::Group *worldGroup = + mpi::async::createGroup(MPI_COMM_WORLD, + mpi::async::CommLayer::WORLD, + 290374); mpi::async::CommLayer::WORLD->group = worldGroup; } diff --git a/ospray/mpi/MPICommon.h b/ospray/mpi/MPICommon.h index b986beaec9..dbc81be377 100644 --- a/ospray/mpi/MPICommon.h +++ b/ospray/mpi/MPICommon.h @@ -32,24 +32,29 @@ namespace ospray { /*! Helper class for MPI Programming */ namespace mpi { + inline void checkMpiError(int rc) + { + if (rc != MPI_SUCCESS) + throw std::runtime_error("MPI Error"); + } + //! abstraction for an MPI group. /*! it's the responsiblity of the respective mpi setup routines to fill in the proper values */ struct Group { /*! whether the current process/thread is a member of this gorup */ - bool containsMe; + bool containsMe {false}; /*! communictor for this group. intercommunicator if i'm a member of this gorup; else it's an intracommunicator */ - MPI_Comm comm; + MPI_Comm comm {MPI_COMM_NULL}; /*! my rank in this group if i'm a member; else set to MPI_ROOT */ - int rank; + int rank {-1}; /*! size of this group if i'm a member, else size of remote group this intracommunicaotr refers to */ - int size; + int size {-1}; - Group() : size(-1), rank(-1), comm(MPI_COMM_NULL), containsMe(false) {}; #if 1 // this is the RIGHT naming convention - old code has them all inside out. void makeIntraComm() diff --git a/ospray/mpi/MPIDevice.cpp b/ospray/mpi/MPIDevice.cpp index 645955ce0d..54f1615d1e 100644 --- a/ospray/mpi/MPIDevice.cpp +++ b/ospray/mpi/MPIDevice.cpp @@ -307,7 +307,8 @@ namespace ospray { throw std::runtime_error("OSPRay MPI: no fork() yet on Windows"); #else if (fork()) { - system(systemCommand); + auto result = system(systemCommand); + (void)result; cout << "OSPRay worker process has died - killing application" << endl; exit(0); @@ -343,6 +344,7 @@ namespace ospray { void initDistributedAPI(int *ac, char ***av, OSPDRenderMode mpiMode) { + UNUSED(mpiMode); int initialized = false; MPI_CALL(Initialized(&initialized)); if (initialized) @@ -366,6 +368,7 @@ namespace ospray { int *_ac, const char **_av) : currentApiMode(OSPD_MODE_MASTERED) { + UNUSED(_ac, _av); auto logLevelFromEnv = getEnvVar("OSPRAY_LOG_LEVEL"); if (logLevelFromEnv.first && logLevel == 0) logLevel = logLevelFromEnv.second; @@ -384,7 +387,9 @@ namespace ospray { TiledLoadBalancer::instance = new mpi::staticLoadBalancer::Master; } - MPIDevice::~MPIDevice() { + + MPIDevice::~MPIDevice() + { cmd.newCommand(CMD_FINALIZE); cmd.flush(); async::shutdown(); @@ -424,8 +429,6 @@ namespace ospray { const void *MPIDevice::frameBufferMap(OSPFrameBuffer _fb, OSPFrameBufferChannel channel) { - int rc; - ObjectHandle handle = (const ObjectHandle &)_fb; FrameBuffer *fb = (FrameBuffer *)handle.lookup(); @@ -464,6 +467,10 @@ namespace ospray { cmd.send(handle); cmd.flush(); + if (handle.defined()){ + handle.lookup()->commit(); + } + MPI_Barrier(MPI_COMM_WORLD); } @@ -520,6 +527,7 @@ namespace ospray { /*! assign (named) string parameter to an object */ void MPIDevice::setVoidPtr(OSPObject _object, const char *bufName, void *v) { + UNUSED(_object, bufName, v); throw std::runtime_error("setting a void pointer as parameter to an " "object is not allowed in MPI mode"); } @@ -615,6 +623,11 @@ namespace ospray { Assert(_object); Assert(bufName); + const ObjectHandle handle = (const ObjectHandle&)_object; + if (handle.defined()){ + handle.lookup()->set(bufName, f); + } + cmd.newCommand(CMD_SET_FLOAT); cmd.send((const ObjectHandle &)_object); cmd.send(bufName); @@ -753,6 +766,10 @@ namespace ospray { ObjectHandle handle = ObjectHandle::alloc(); + // create renderer to hold some parameters locally (in particular + // errorThreshold) + ObjectHandle::assign(handle, new Renderer); + cmd.newCommand(CMD_NEW_RENDERER); cmd.send(handle); cmd.send(type); @@ -824,6 +841,7 @@ namespace ospray { MPI_Status status; int rc = MPI_Recv(&numFails,1,MPI_INT, 0,MPI_ANY_TAG,mpi::worker.comm,&status); + (void)rc; if (numFails == 0) return (OSPMaterial)(int64)handle; else { @@ -868,6 +886,7 @@ namespace ospray { MPI_Status status; int rc = MPI_Recv(&numFails,1,MPI_INT, 0,MPI_ANY_TAG,mpi::worker.comm,&status); + (void)rc; if (numFails==0) return (OSPLight)(int64)handle; else { @@ -928,21 +947,19 @@ namespace ospray { OSPRenderer _renderer, const uint32 fbChannelFlags) { - const ObjectHandle handle = (const ObjectHandle&)_fb; - // const ObjectHandle handle = (const ObjectHandle&)_sc; - // SwapChain *sc = (SwapChain *)handle.lookup(); - FrameBuffer *fb = (FrameBuffer *)handle.lookup(); - // Assert(sc); + const ObjectHandle fb_handle = (const ObjectHandle&)_fb; + const ObjectHandle renderer_handle = (const ObjectHandle&)_renderer; - //FrameBuffer *fb = sc->getFrontBuffer(); - // FrameBuffer *fb = sc->getBackBuffer(); cmd.newCommand(CMD_RENDER_FRAME); - cmd.send((const ObjectHandle&)_fb); - cmd.send((const ObjectHandle&)_renderer); + cmd.send(fb_handle); + cmd.send(renderer_handle); cmd.send((int32)fbChannelFlags); cmd.flush(); - return TiledLoadBalancer::instance->renderFrame(NULL,fb,fbChannelFlags); + FrameBuffer *fb = (FrameBuffer *)fb_handle.lookup(); + Renderer *renderer = (Renderer *)renderer_handle.lookup(); + + return TiledLoadBalancer::instance->renderFrame(renderer,fb,fbChannelFlags); } //! release (i.e., reduce refcount of) given object diff --git a/ospray/mpi/MPILoadBalancer.cpp b/ospray/mpi/MPILoadBalancer.cpp index cc07814aa7..23f14a53d2 100644 --- a/ospray/mpi/MPILoadBalancer.cpp +++ b/ospray/mpi/MPILoadBalancer.cpp @@ -35,15 +35,18 @@ namespace ospray { namespace staticLoadBalancer { - float Master::renderFrame(Renderer *tiledRenderer, + float Master::renderFrame(Renderer *renderer, FrameBuffer *fb, const uint32 channelFlags) { + UNUSED(channelFlags); async_beginFrame(); DistributedFrameBuffer *dfb = dynamic_cast(fb); assert(dfb); - dfb->startNewFrame(); + dfb->beginFrame(); + + dfb->startNewFrame(renderer->errorThreshold); /* the client will do its magic here, and the distributed frame buffer will be writing tiles here, without us doing anything ourselves */ @@ -51,7 +54,7 @@ namespace ospray { async_endFrame(); - return dfb->endFrame(0.f); + return dfb->endFrame(renderer->errorThreshold); } std::string Master::toString() const @@ -59,16 +62,16 @@ namespace ospray { return "ospray::mpi::staticLoadBalancer::Master"; } - float Slave::renderFrame(Renderer *tiledRenderer, + float Slave::renderFrame(Renderer *renderer, FrameBuffer *fb, const uint32 channelFlags) { async_beginFrame(); auto *dfb = dynamic_cast(fb); - dfb->startNewFrame(); + dfb->startNewFrame(renderer->errorThreshold); - void *perFrameData = tiledRenderer->beginFrame(fb); + void *perFrameData = renderer->beginFrame(fb); const int ALLTASKS = fb->getTotalTiles(); int NTASKS = ALLTASKS / worker.size; @@ -87,7 +90,10 @@ namespace ospray { const size_t tile_y = tileID / numTiles_x; const size_t tile_x = tileID - tile_y*numTiles_x; const vec2i tileId(tile_x, tile_y); - const int32 accumID = fb->accumID(tileID); + const int32 accumID = fb->accumID(tileId); + + if (fb->tileError(tileId) <= renderer->errorThreshold) + return; #ifdef __MIC__ # define MAX_TILE_SIZE 32 @@ -102,9 +108,9 @@ namespace ospray { Tile __aligned(64) tile(tileId, fb->size, accumID); #endif - // serial_for(numJobs(tiledRenderer->spp, accumID), [&](int tid){ - parallel_for(numJobs(tiledRenderer->spp, accumID), [&](int tid){ - tiledRenderer->renderTile(perFrameData, tile, tid); + // serial_for(numJobs(renderer->spp, accumID), [&](int tid){ + parallel_for(numJobs(renderer->spp, accumID), [&](int tid){ + renderer->renderTile(perFrameData, tile, tid); }); fb->setTile(tile); @@ -114,7 +120,7 @@ namespace ospray { }); dfb->waitUntilFinished(); - tiledRenderer->endFrame(perFrameData,channelFlags); + renderer->endFrame(perFrameData,channelFlags); async_endFrame(); diff --git a/ospray/mpi/MPIWorker.cpp b/ospray/mpi/MPIWorker.cpp index 5c202f708f..63b8faef6f 100644 --- a/ospray/mpi/MPIWorker.cpp +++ b/ospray/mpi/MPIWorker.cpp @@ -38,6 +38,7 @@ namespace ospray { } int rc; + (void)rc; mpi::init(&ac,av); worker.comm = world.comm; worker.makeIntraComm(); diff --git a/ospray/mpi/async/BatchedIsendIrecvMessaging.cpp b/ospray/mpi/async/BatchedIsendIrecvMessaging.cpp index 17a8154109..9f927539fe 100644 --- a/ospray/mpi/async/BatchedIsendIrecvMessaging.cpp +++ b/ospray/mpi/async/BatchedIsendIrecvMessaging.cpp @@ -33,14 +33,18 @@ namespace ospray { enum { RECV_WINDOW_SIZE = 48 }; enum { PROC_WINDOW_SIZE = 20 }; - BatchedIsendIrecvImpl::Group::Group(const std::string &name, MPI_Comm comm, - Consumer *consumer, int32 tag) + BatchedIsendIrecvImpl::Group::Group(MPI_Comm comm, + Consumer *consumer, + int32 tag) : async::Group(comm,consumer,tag), - sendThread(this), recvThread(this), procThread(this), shouldExit(false) + sendThread(this), + procThread(this), + recvThread(this), + shouldExit(false) { - recvThread.start(); sendThread.start(); procThread.start(); + recvThread.start(); } void BatchedIsendIrecvImpl::SendThread::run() @@ -49,16 +53,15 @@ namespace ospray { Action *actions[SEND_WINDOW_SIZE]; MPI_Request request[SEND_WINDOW_SIZE]; while (1) { - // usleep(80); size_t numActions = 0; while (numActions == 0){ numActions = g->sendQueue.getSomeFor(actions,SEND_WINDOW_SIZE, - std::chrono::milliseconds(1)); + std::chrono::milliseconds(1)); if (g->shouldExit.load()){ return; } } - for (int i=0;idata,action->size,MPI_BYTE, action->addr.rank,g->tag,g->comm,&request[i])); @@ -68,7 +71,7 @@ namespace ospray { // failed statuses back? MPI_CALL(Waitall(numActions,request,MPI_STATUSES_IGNORE)); - for (int i=0;idata); delete action; @@ -166,7 +169,7 @@ namespace ospray { return; } } - for (int i=0;iconsumer->process(action->addr,action->data,action->size); delete action; @@ -176,7 +179,8 @@ namespace ospray { void BatchedIsendIrecvImpl::Group::shutdown() { - std::cout << "#osp:mpi:BatchIsendIrecvMessaging:Group shutting down" << std::endl; + std::cout << "#osp:mpi:BatchIsendIrecvMessaging:Group shutting down" + << std::endl; shouldExit.store(true); sendThread.join(); recvThread.join(); @@ -199,18 +203,17 @@ namespace ospray { mpi::world.rank,mpi::world.size); fflush(0); mpi::world.barrier(); - for (int i=0;ishutdown(); MPI_CALL(Finalize()); } - async::Group *BatchedIsendIrecvImpl::createGroup(const std::string &name, - MPI_Comm comm, - Consumer *consumer, - int32 tag) + async::Group *BatchedIsendIrecvImpl::createGroup(MPI_Comm comm, + Consumer *consumer, + int32 tag) { - Group *g = new Group(name,comm,consumer,tag); + Group *g = new Group(comm,consumer,tag); myGroups.push_back(g); return g; } diff --git a/ospray/mpi/async/BatchedIsendIrecvMessaging.h b/ospray/mpi/async/BatchedIsendIrecvMessaging.h index b60b15ae0d..d6f1401e25 100644 --- a/ospray/mpi/async/BatchedIsendIrecvMessaging.h +++ b/ospray/mpi/async/BatchedIsendIrecvMessaging.h @@ -38,7 +38,7 @@ namespace ospray { #ifdef OSPRAY_PIN_ASYNC embree::setAffinity(58); // 58 #endif - }; + } virtual void run(); Group *group; @@ -50,7 +50,7 @@ namespace ospray { #ifdef OSPRAY_PIN_ASYNC embree::setAffinity(55); // 55 #endif - }; + } virtual void run(); Group *group; @@ -61,7 +61,7 @@ namespace ospray { #ifdef OSPRAY_PIN_ASYNC embree::setAffinity(57); // 56 #endif - }; + } virtual void run(); Group *group; @@ -79,8 +79,7 @@ namespace ospray { struct Group : public mpi::async::Group { - Group(const std::string &name, MPI_Comm comm, - Consumer *consumer, int32 tag = MPI_ANY_TAG); + Group(MPI_Comm comm, Consumer *consumer, int32 tag = MPI_ANY_TAG); void shutdown(); /*! the queue new send requests are put into; the send @@ -100,14 +99,13 @@ namespace ospray { virtual void init(); virtual void shutdown(); - virtual async::Group *createGroup(const std::string &name, - MPI_Comm comm, - Consumer *consumer, - int32 tag = MPI_ANY_TAG); + virtual async::Group *createGroup(MPI_Comm comm, + Consumer *consumer, + int32 tag = MPI_ANY_TAG); virtual void send(const Address &dest, void *msgPtr, int32 msgSize); std::vector myGroups; }; - }; + } } } diff --git a/ospray/mpi/async/CommLayer.cpp b/ospray/mpi/async/CommLayer.cpp index fb552438d6..d46097bd33 100644 --- a/ospray/mpi/async/CommLayer.cpp +++ b/ospray/mpi/async/CommLayer.cpp @@ -26,19 +26,22 @@ namespace ospray { namespace mpi { namespace async { - CommLayer *CommLayer::WORLD = NULL; + CommLayer *CommLayer::WORLD = nullptr; CommLayer::Object::Object(CommLayer *comm, ObjectID myID) : myID(myID), comm(comm) { master = mpi::async::CommLayer::Address(comm->masterRank(),myID); worker = new mpi::async::CommLayer::Address[comm->numWorkers()]; - for (int i=0;inumWorkers();i++) + for (int i = 0 ; i < comm->numWorkers(); i++) worker[i] = mpi::async::CommLayer::Address(comm->workerRank(i),myID); } - void CommLayer::process(const mpi::Address &source, void *message, int32 size) + void CommLayer::process(const mpi::Address &source, + void *message, + int32 size) { + UNUSED(size); Message *msg = (Message*)message; Object *obj = nullptr; @@ -47,8 +50,10 @@ namespace ospray { obj = registry[msg->dest.objectID]; } - if (!obj) - throw std::runtime_error("#osp:mpi:CommLayer: no object with given ID"); + if (!obj) { + throw std::runtime_error("#osp:mpi:CommLayer: no object with given " + "ID"); + } msg->source.rank = source.rank; obj->incoming(msg); diff --git a/ospray/mpi/async/CommLayer.h b/ospray/mpi/async/CommLayer.h index 5b6396e2d7..8ab86ae54e 100644 --- a/ospray/mpi/async/CommLayer.h +++ b/ospray/mpi/async/CommLayer.h @@ -113,8 +113,8 @@ namespace ospray { int32 rank() const { return group->rank; } int32 numWorkers() const { return group->size - 1; } - int32 masterRank() const { return 0; } - int32 workerRank(int clientID) const { return 1+clientID; } + static int32 masterRank() { return 0; } + static int32 workerRank(int clientID) { return 1+clientID; } bool IamTheMaster() const { return group->rank == masterRank(); } //! mutex to protect the registry Mutex mutex; diff --git a/ospray/mpi/async/Messaging.cpp b/ospray/mpi/async/Messaging.cpp index 55dd7c838d..ab406032fe 100644 --- a/ospray/mpi/async/Messaging.cpp +++ b/ospray/mpi/async/Messaging.cpp @@ -26,14 +26,10 @@ namespace ospray { AsyncMessagingImpl *AsyncMessagingImpl::global = NULL; - Group::Group(//const std::string &name, - MPI_Comm comm, - Consumer *consumer, int32 tag) - : tag(tag), consumer(consumer) + Group::Group(MPI_Comm comm, Consumer *consumer, int32 tag) + : consumer(consumer), tag(tag) { - int rc = MPI_SUCCESS; MPI_CALL(Comm_dup(comm,&this->comm)); - // this->comm = comm; MPI_CALL(Comm_rank(comm,&rank)); MPI_CALL(Comm_size(comm,&size)); } @@ -57,11 +53,10 @@ namespace ospray { // extern Group *WORLD; } - Group *createGroup(const std::string &name, MPI_Comm comm, - Consumer *consumer, int32 tag) + Group *createGroup(MPI_Comm comm, Consumer *consumer, int32 tag) { initAsync(); - return AsyncMessagingImpl::global->createGroup(name,comm,consumer,tag); + return AsyncMessagingImpl::global->createGroup(comm,consumer,tag); } void shutdown() diff --git a/ospray/mpi/async/Messaging.h b/ospray/mpi/async/Messaging.h index d8ba415319..3516ff72ff 100644 --- a/ospray/mpi/async/Messaging.h +++ b/ospray/mpi/async/Messaging.h @@ -78,10 +78,9 @@ namespace ospray { struct AsyncMessagingImpl { virtual void init() = 0; virtual void shutdown() = 0; - virtual Group *createGroup(const std::string &name, - MPI_Comm comm, - Consumer *consumer, - int32 tag = MPI_ANY_TAG) = 0; + virtual Group *createGroup(MPI_Comm comm, + Consumer *consumer, + int32 tag = MPI_ANY_TAG) = 0; virtual void send(const Address &dest, void *msgPtr, int32 msgSize) = 0; static AsyncMessagingImpl *global; @@ -89,14 +88,15 @@ namespace ospray { /*! @{ The actual asynchronous messaging API */ - Group *createGroup(const std::string &name, MPI_Comm comm, - Consumer *consumer, int32 tag = MPI_ANY_TAG); - void shutdown(); + Group *createGroup(MPI_Comm comm, + Consumer *consumer, + int32 tag = MPI_ANY_TAG); + void shutdown(); /*! send a asynchronous message to the address specified. the 'group' in said address HAS to be a group created via 'async::Group' */ - void send(const Address &dest, void *msgPtr, int32 msgSize); + void send(const Address &dest, void *msgPtr, int32 msgSize); /*! @} */ } // ::ospray::mpi::async diff --git a/ospray/mpi/async/MultiIsendIrecvMessaging.cpp b/ospray/mpi/async/MultiIsendIrecvMessaging.cpp index 3d1a37c55e..cbc4a6d65c 100644 --- a/ospray/mpi/async/MultiIsendIrecvMessaging.cpp +++ b/ospray/mpi/async/MultiIsendIrecvMessaging.cpp @@ -29,14 +29,17 @@ namespace ospray { namespace mpi { namespace async { - MultiIsendIrecvImpl::Group::Group(const std::string &name, MPI_Comm comm, - Consumer *consumer, int32 tag) + MultiIsendIrecvImpl::Group::Group(MPI_Comm comm, + Consumer *consumer, + int32 tag) : async::Group(comm,consumer,tag), - sendThread(this), recvThread(this), procThread(this) + sendThread(this), + procThread(this), + recvThread(this) { - recvThread.start(); sendThread.start(); procThread.start(); + recvThread.start(); } void MultiIsendIrecvImpl::SendThread::run() @@ -46,7 +49,9 @@ namespace ospray { Action *action = nullptr; size_t numActions = 0; while (numActions == 0){ - numActions = g->sendQueue.getSomeFor(&action,1,std::chrono::milliseconds(1)); + numActions = g->sendQueue.getSomeFor(&action, + 1, + std::chrono::milliseconds(1)); if (g->shouldExit.load()){ return; } @@ -145,18 +150,17 @@ namespace ospray { printf("#osp:mpi:MultiIsendIrecvMessaging shutting down %i/%i\n",mpi::world.rank,mpi::world.size); fflush(0); mpi::world.barrier(); - for (int i=0;ishutdown(); MPI_CALL(Finalize()); } - async::Group *MultiIsendIrecvImpl::createGroup(const std::string &name, - MPI_Comm comm, - Consumer *consumer, - int32 tag) + async::Group *MultiIsendIrecvImpl::createGroup(MPI_Comm comm, + Consumer *consumer, + int32 tag) { - Group *g = new Group(name,comm,consumer,tag); + Group *g = new Group(comm,consumer,tag); myGroups.push_back(g); return g; } diff --git a/ospray/mpi/async/MultiIsendIrecvMessaging.h b/ospray/mpi/async/MultiIsendIrecvMessaging.h index 3a3cf42961..787da9d6f2 100644 --- a/ospray/mpi/async/MultiIsendIrecvMessaging.h +++ b/ospray/mpi/async/MultiIsendIrecvMessaging.h @@ -68,8 +68,7 @@ namespace ospray { struct Group : public mpi::async::Group { - Group(const std::string &name, MPI_Comm comm, - Consumer *consumer, int32 tag = MPI_ANY_TAG); + Group(MPI_Comm comm, Consumer *consumer, int32 tag = MPI_ANY_TAG); void shutdown(); /*! the queue new send requests are put into; the send @@ -89,14 +88,13 @@ namespace ospray { virtual void init(); virtual void shutdown(); - virtual async::Group *createGroup(const std::string &name, - MPI_Comm comm, - Consumer *consumer, - int32 tag = MPI_ANY_TAG); + virtual async::Group *createGroup(MPI_Comm comm, + Consumer *consumer, + int32 tag = MPI_ANY_TAG); virtual void send(const Address &dest, void *msgPtr, int32 msgSize); std::vector myGroups; }; - }; + } } } diff --git a/ospray/mpi/async/SimpleSendRecvMessaging.cpp b/ospray/mpi/async/SimpleSendRecvMessaging.cpp index 4a5b3a4e71..57d1dc125b 100644 --- a/ospray/mpi/async/SimpleSendRecvMessaging.cpp +++ b/ospray/mpi/async/SimpleSendRecvMessaging.cpp @@ -81,8 +81,9 @@ namespace ospray { extern "C" void async_endFrame() {} #endif - SimpleSendRecvImpl::Group::Group(const std::string &name, MPI_Comm comm, - Consumer *consumer, int32 tag) + SimpleSendRecvImpl::Group::Group(MPI_Comm comm, + Consumer *consumer, + int32 tag) : async::Group(comm,consumer,tag), sendThread(this), recvThread(this), procThread(this) { @@ -99,16 +100,20 @@ namespace ospray { Action *action = nullptr; size_t numActions = 0; while (numActions == 0){ - numActions = g->sendQueue.getSomeFor(&action,1,std::chrono::milliseconds(1)); + numActions = g->sendQueue.getSomeFor(&action, + 1, + std::chrono::milliseconds(1)); if (g->shouldExit.load()){ return; } } +#if PROFILE_MPI double t0 = getSysTime(); +#endif MPI_CALL(Send(action->data,action->size,MPI_BYTE, action->addr.rank,g->tag,action->addr.group->comm)); - double t1 = getSysTime(); #if PROFILE_MPI + double t1 = getSysTime(); if (logIt) { t_send += (t1-t0); b_sent += action->size; @@ -160,11 +165,14 @@ namespace ospray { MPI_CALL(Get_count(&status,MPI_BYTE,&action->size)); action->data = malloc(action->size); +#if PROFILE_MPI double t0 = getSysTime(); - MPI_CALL(Recv(action->data,action->size,MPI_BYTE,status.MPI_SOURCE,status.MPI_TAG, +#endif + MPI_CALL(Recv(action->data,action->size, + MPI_BYTE,status.MPI_SOURCE,status.MPI_TAG, g->comm,MPI_STATUS_IGNORE)); - double t1 = getSysTime(); #if PROFILE_MPI + double t1 = getSysTime(); if (logIt) { t_recv += (t1-t0); b_recv += action->size; @@ -221,18 +229,17 @@ namespace ospray { printf("#osp:mpi:SimpleSendRecvMessaging shutting down %i/%i\n",mpi::world.rank,mpi::world.size); fflush(0); mpi::world.barrier(); - for (int i=0;ishutdown(); MPI_CALL(Finalize()); } - async::Group *SimpleSendRecvImpl::createGroup(const std::string &name, - MPI_Comm comm, + async::Group *SimpleSendRecvImpl::createGroup(MPI_Comm comm, Consumer *consumer, int32 tag) { - Group *g = new Group(name,comm,consumer,tag); + Group *g = new Group(comm,consumer,tag); myGroups.push_back(g); return g; } diff --git a/ospray/mpi/async/SimpleSendRecvMessaging.h b/ospray/mpi/async/SimpleSendRecvMessaging.h index b62b04adc2..258d326149 100644 --- a/ospray/mpi/async/SimpleSendRecvMessaging.h +++ b/ospray/mpi/async/SimpleSendRecvMessaging.h @@ -62,8 +62,7 @@ namespace ospray { struct Group : public mpi::async::Group { - Group(const std::string &name, MPI_Comm comm, - Consumer *consumer, int32 tag = MPI_ANY_TAG); + Group(MPI_Comm comm, Consumer *consumer, int32 tag = MPI_ANY_TAG); void shutdown(); /*! the queue new send requests are put into; the send @@ -83,14 +82,13 @@ namespace ospray { virtual void init(); virtual void shutdown(); - virtual async::Group *createGroup(const std::string &name, - MPI_Comm comm, - Consumer *consumer, - int32 tag = MPI_ANY_TAG); + virtual async::Group *createGroup(MPI_Comm comm, + Consumer *consumer, + int32 tag = MPI_ANY_TAG); virtual void send(const Address &dest, void *msgPtr, int32 msgSize); std::vector myGroups; }; - }; + } } } diff --git a/ospray/mpi/worker.cpp b/ospray/mpi/worker.cpp index a4634c5d0f..6fd74cc4d2 100644 --- a/ospray/mpi/worker.cpp +++ b/ospray/mpi/worker.cpp @@ -81,7 +81,7 @@ namespace ospray { */ void runWorker() { - Ref device = ospray::api::Device::current.dynamicCast(); + auto device = ospray::api::Device::current.dynamicCast(); // initialize embree. (we need to do this here rather than in // ospray::init() because in mpi-mode the latter is also called @@ -223,6 +223,7 @@ namespace ospray { int myFail = (material == NULL); int sumFail = 0; rc = MPI_Allreduce(&myFail,&sumFail,1,MPI_INT,MPI_SUM,worker.comm); + (void)rc; if (sumFail == 0) { material->refInc(); cmd.free(type); @@ -393,7 +394,7 @@ namespace ospray { this stage */ ObjectHandle *asHandle = (ObjectHandle *)data->data; ManagedObject **asObjPtr = (ManagedObject **)data->data; - for (int i=0;irefInc(); @@ -405,7 +406,7 @@ namespace ospray { case ospray::CMD_NEW_TEXTURE2D: { const ObjectHandle handle = cmd.get_handle(); - Texture2D *texture2D = NULL; + Texture2D *texture2D = nullptr; const vec2i sz = cmd.get_vec2i(); const int32 type = cmd.get_int32(); @@ -509,6 +510,7 @@ namespace ospray { case ospray::CMD_RELEASE: { const ObjectHandle handle = cmd.get_handle(); ManagedObject *obj = handle.lookup(); + (void)obj; Assert(obj); handle.freeObject(); } break; diff --git a/ospray/ospray.def b/ospray/ospray.def new file mode 100644 index 0000000000..3833674e61 --- /dev/null +++ b/ospray/ospray.def @@ -0,0 +1,76 @@ +EXPORTS +BlockBrickedVolume_Constructor___un_3C_s_5B_unBlockBrickedVolume_5D__3E_un_3C_unv_3E_CuniREFs_5B__c_unvec3i_5D_avx +BlockBrickedVolume_Constructor___un_3C_s_5B_unBlockBrickedVolume_5D__3E_un_3C_unv_3E_CuniREFs_5B__c_unvec3i_5D_avx2 +BlockBrickedVolume_Constructor___un_3C_s_5B_unBlockBrickedVolume_5D__3E_un_3C_unv_3E_CuniREFs_5B__c_unvec3i_5D_sse4 +Distribution2D_create___s_5B__c_unvec2i_5D_un_3C_unf_3E_avx +Distribution2D_create___s_5B__c_unvec2i_5D_un_3C_unf_3E_avx2 +Distribution2D_create___s_5B__c_unvec2i_5D_un_3C_unf_3E_sse4 +Distribution2D_destroy___un_3C_s_5B_unDistribution2D_5D__3E_avx +Distribution2D_destroy___un_3C_s_5B_unDistribution2D_5D__3E_avx2 +Distribution2D_destroy___un_3C_s_5B_unDistribution2D_5D__3E_sse4 +Distribution2D_pdf___un_3C_s_5B__c_unDistribution2D_5D__3E_REFs_5B__c_vyvec2f_5D_avx +Distribution2D_pdf___un_3C_s_5B__c_unDistribution2D_5D__3E_REFs_5B__c_vyvec2f_5D_avx2 +Distribution2D_pdf___un_3C_s_5B__c_unDistribution2D_5D__3E_REFs_5B__c_vyvec2f_5D_sse4 +Distribution2D_sample___un_3C_s_5B__c_unDistribution2D_5D__3E_REFs_5B__c_vyvec2f_5D_avx +Distribution2D_sample___un_3C_s_5B__c_unDistribution2D_5D__3E_REFs_5B__c_vyvec2f_5D_avx2 +Distribution2D_sample___un_3C_s_5B__c_unDistribution2D_5D__3E_REFs_5B__c_vyvec2f_5D_sse4 +FrameBuffer_Constructor___un_3C_s_5B_unFrameBuffer_5D__3E_un_3C_unv_3E_avx +FrameBuffer_Constructor___un_3C_s_5B_unFrameBuffer_5D__3E_un_3C_unv_3E_avx2 +FrameBuffer_Constructor___un_3C_s_5B_unFrameBuffer_5D__3E_un_3C_unv_3E_sse4 +FrameBuffer_set___un_3C_s_5B_unFrameBuffer_5D__3E_CunuCunuuniavx +FrameBuffer_set___un_3C_s_5B_unFrameBuffer_5D__3E_CunuCunuuniavx2 +FrameBuffer_set___un_3C_s_5B_unFrameBuffer_5D__3E_CunuCunuunisse4 +Geometry_Constructor___un_3C_s_5B_unGeometry_5D__3E_un_3C_unv_3E_un_3C____un_3C_s_5B_unGeometry_5D__3E_un_3C_s_5B_unModel_5D__3E_REFs_5B_vyDifferentialGeometry_5D_REFs_5B__c_vyRay_5D_unI_3E_un_3C_s_5B_unModel_5D__3E_uniun_3C_s_5B_unMaterial_5D__3E_avx +Geometry_Constructor___un_3C_s_5B_unGeometry_5D__3E_un_3C_unv_3E_un_3C____un_3C_s_5B_unGeometry_5D__3E_un_3C_s_5B_unModel_5D__3E_REFs_5B_vyDifferentialGeometry_5D_REFs_5B__c_vyRay_5D_unI_3E_un_3C_s_5B_unModel_5D__3E_uniun_3C_s_5B_unMaterial_5D__3E_avx2 +Geometry_Constructor___un_3C_s_5B_unGeometry_5D__3E_un_3C_unv_3E_un_3C____un_3C_s_5B_unGeometry_5D__3E_un_3C_s_5B_unModel_5D__3E_REFs_5B_vyDifferentialGeometry_5D_REFs_5B__c_vyRay_5D_unI_3E_un_3C_s_5B_unModel_5D__3E_uniun_3C_s_5B_unMaterial_5D__3E_sse4 +GridAccelerator_createInstance___un_3C_unv_3E_avx +GridAccelerator_createInstance___un_3C_unv_3E_avx2 +GridAccelerator_createInstance___un_3C_unv_3E_sse4 +GridAccelerator_destroy___un_3C_s_5B_unGridAccelerator_5D__3E_avx +GridAccelerator_destroy___un_3C_s_5B_unGridAccelerator_5D__3E_avx2 +GridAccelerator_destroy___un_3C_s_5B_unGridAccelerator_5D__3E_sse4 +GridAccelerator_intersect___un_3C_s_5B_unGridAccelerator_5D__3E_unfREFs_5B_vyRay_5D_avx +GridAccelerator_intersect___un_3C_s_5B_unGridAccelerator_5D__3E_unfREFs_5B_vyRay_5D_avx2 +GridAccelerator_intersect___un_3C_s_5B_unGridAccelerator_5D__3E_unfREFs_5B_vyRay_5D_sse4 +GridAccelerator_intersectIsosurface___un_3C_s_5B_unGridAccelerator_5D__3E_unfun_3C_unf_3E_uniREFs_5B_vyRay_5D_avx +GridAccelerator_intersectIsosurface___un_3C_s_5B_unGridAccelerator_5D__3E_unfun_3C_unf_3E_uniREFs_5B_vyRay_5D_avx2 +GridAccelerator_intersectIsosurface___un_3C_s_5B_unGridAccelerator_5D__3E_unfun_3C_unf_3E_uniREFs_5B_vyRay_5D_sse4 +Light_eval___un_3C_s_5B__c_unLight_5D__3E_REFs_5B__c_vyDifferentialGeometry_5D_REFs_5B__c_vyvec3f_5D_Cvyfavx +Light_eval___un_3C_s_5B__c_unLight_5D__3E_REFs_5B__c_vyDifferentialGeometry_5D_REFs_5B__c_vyvec3f_5D_Cvyfavx2 +Light_eval___un_3C_s_5B__c_unLight_5D__3E_REFs_5B__c_vyDifferentialGeometry_5D_REFs_5B__c_vyvec3f_5D_Cvyfsse4 +Renderer_Constructor___un_3C_s_5B_unRenderer_5D__3E_un_3C_unv_3E_avx +Renderer_Constructor___un_3C_s_5B_unRenderer_5D__3E_un_3C_unv_3E_avx2 +Renderer_Constructor___un_3C_s_5B_unRenderer_5D__3E_un_3C_unv_3E_sse4 +Renderer_Constructor___un_3C_s_5B_unRenderer_5D__3E_un_3C_unv_3E_un_3C_unv_3E_un_3C_unv_3E_Cuniavx +Renderer_Constructor___un_3C_s_5B_unRenderer_5D__3E_un_3C_unv_3E_un_3C_unv_3E_un_3C_unv_3E_Cuniavx2 +Renderer_Constructor___un_3C_s_5B_unRenderer_5D__3E_un_3C_unv_3E_un_3C_unv_3E_un_3C_unv_3E_Cunisse4 +SharedStructuredVolume_Constructor___un_3C_s_5B_unSharedStructuredVolume_5D__3E_un_3C_unv_3E_CuniREFs_5B__c_unvec3i_5D_un_3C_Cunv_3E_avx +SharedStructuredVolume_Constructor___un_3C_s_5B_unSharedStructuredVolume_5D__3E_un_3C_unv_3E_CuniREFs_5B__c_unvec3i_5D_un_3C_Cunv_3E_avx2 +SharedStructuredVolume_Constructor___un_3C_s_5B_unSharedStructuredVolume_5D__3E_un_3C_unv_3E_CuniREFs_5B__c_unvec3i_5D_un_3C_Cunv_3E_sse4 +StructuredVolume_Constructor___un_3C_s_5B_unStructuredVolume_5D__3E_un_3C_unv_3E_REFs_5B__c_unvec3i_5D_avx +StructuredVolume_Constructor___un_3C_s_5B_unStructuredVolume_5D__3E_un_3C_unv_3E_REFs_5B__c_unvec3i_5D_avx2 +StructuredVolume_Constructor___un_3C_s_5B_unStructuredVolume_5D__3E_un_3C_unv_3E_REFs_5B__c_unvec3i_5D_sse4 +Volume_Constructor___un_3C_s_5B_unVolume_5D__3E_un_3C_unv_3E_avx +Volume_Constructor___un_3C_s_5B_unVolume_5D__3E_un_3C_unv_3E_avx2 +Volume_Constructor___un_3C_s_5B_unVolume_5D__3E_un_3C_unv_3E_sse4 +delete_uniform___un_3C_unv_3E_avx +delete_uniform___un_3C_unv_3E_avx2 +delete_uniform___un_3C_unv_3E_sse4 +delete_uniform_avx +delete_uniform_avx2 +delete_uniform_sse4 +error_handler___Cvyenum_5B_RTCError_5D_vy_3C_Cunt_3E_avx +error_handler___Cvyenum_5B_RTCError_5D_vy_3C_Cunt_3E_avx2 +error_handler___Cvyenum_5B_RTCError_5D_vy_3C_Cunt_3E_sse4 +precomputedHalton_create___avx +precomputedHalton_create___avx2 +precomputedHalton_create___sse4 +precomputedZOrder_create___avx +precomputedZOrder_create___avx2 +precomputedZOrder_create___sse4 +print_box___REFs_5B__c_unbox3f_5D_avx +print_box___REFs_5B__c_unbox3f_5D_avx2 +print_box___REFs_5B__c_unbox3f_5D_sse4 +print_box___REFs_5B__c_unbox3fa_5D_avx +print_box___REFs_5B__c_unbox3fa_5D_avx2 +print_box___REFs_5B__c_unbox3fa_5D_sse4 diff --git a/ospray/render/LoadBalancer.cpp b/ospray/render/LoadBalancer.cpp index aacbbf81a8..54f805e51a 100644 --- a/ospray/render/LoadBalancer.cpp +++ b/ospray/render/LoadBalancer.cpp @@ -20,22 +20,13 @@ #include "common/tasking/parallel_for.h" // ospc #include "ospcommon/sysinfo.h" -// stl -#include namespace ospray { using std::cout; using std::endl; - TiledLoadBalancer *TiledLoadBalancer::instance = NULL; - - LocalTiledLoadBalancer::LocalTiledLoadBalancer() -#ifdef OSPRAY_TASKING_TBB - : tbb_init(numThreads) -#endif - { - } + TiledLoadBalancer *TiledLoadBalancer::instance = nullptr; /*! render a frame via the tiled load balancer */ float LocalTiledLoadBalancer::renderFrame(Renderer *renderer, diff --git a/ospray/render/LoadBalancer.h b/ospray/render/LoadBalancer.h index 5aaf70c39a..8825b743ef 100644 --- a/ospray/render/LoadBalancer.h +++ b/ospray/render/LoadBalancer.h @@ -23,11 +23,6 @@ #include "fb/FrameBuffer.h" #include "render/Renderer.h" -// tbb -#ifdef OSPRAY_TASKING_TBB -# include -#endif - namespace ospray { @@ -37,8 +32,8 @@ namespace ospray { static TiledLoadBalancer *instance; virtual std::string toString() const = 0; virtual float renderFrame(Renderer *tiledRenderer, - FrameBuffer *fb, - const uint32 channelFlags) = 0; + FrameBuffer *fb, + const uint32 channelFlags) = 0; static size_t numJobs(const int spp, int accumID) { @@ -53,19 +48,13 @@ namespace ospray { rendering on a local machine, without any cross-node communication/load balancing at all (even if there are multiple application ranks each doing local rendering on their own) */ - struct LocalTiledLoadBalancer : public TiledLoadBalancer + struct OSPRAY_SDK_INTERFACE LocalTiledLoadBalancer : public TiledLoadBalancer { - LocalTiledLoadBalancer(); - float renderFrame(Renderer *renderer, - FrameBuffer *fb, - const uint32 channelFlags) override; + FrameBuffer *fb, + const uint32 channelFlags) override; std::string toString() const override; - -#ifdef OSPRAY_TASKING_TBB - tbb::task_scheduler_init tbb_init; -#endif }; //! tiled load balancer for local rendering on the given machine @@ -73,7 +62,7 @@ namespace ospray { rendering on a local machine, without any cross-node communication/load balancing at all (even if there are multiple application ranks each doing local rendering on their own) */ - struct InterleavedTiledLoadBalancer : public TiledLoadBalancer + struct OSPRAY_SDK_INTERFACE InterleavedTiledLoadBalancer : public TiledLoadBalancer { size_t deviceID; size_t numDevices; @@ -91,8 +80,8 @@ namespace ospray { std::string toString() const override; float renderFrame(Renderer *tiledRenderer, - FrameBuffer *fb, - const uint32 channelFlags) override; + FrameBuffer *fb, + const uint32 channelFlags) override; }; } // ::ospray diff --git a/ospray/render/Renderer.cpp b/ospray/render/Renderer.cpp index e80cddafff..3c905a4f1b 100644 --- a/ospray/render/Renderer.cpp +++ b/ospray/render/Renderer.cpp @@ -126,6 +126,7 @@ namespace ospray { void *Renderer::beginFrame(FrameBuffer *fb) { this->currentFB = fb; + fb->beginFrame(); return ispc::Renderer_beginFrame(getIE(),fb->getIE()); } diff --git a/ospray/render/Renderer.h b/ospray/render/Renderer.h index 4bf03e02e9..7b99caa82a 100644 --- a/ospray/render/Renderer.h +++ b/ospray/render/Renderer.h @@ -34,7 +34,7 @@ namespace ospray { tile renderer, but this abstraction level also allows for frame compositing or even projection/splatting based approaches */ - struct Renderer : public ManagedObject { + struct OSPRAY_SDK_INTERFACE Renderer : public ManagedObject { Renderer() : spp(1), errorThreshold(0.0f) {} /*! \brief creates an abstract renderer class of given type @@ -73,10 +73,10 @@ namespace ospray { virtual void renderTile(void *perFrameData, Tile &tile, size_t jobID) const; /*! \brief create a material of given type */ - virtual Material *createMaterial(const char *type) { return NULL; } + virtual Material *createMaterial(const char *type); /*! \brief create a light of given type */ - virtual Light *createLight(const char *type) { return NULL; } + virtual Light *createLight(const char *type); virtual OSPPickResult pick(const vec2f &screenPos); @@ -104,6 +104,20 @@ namespace ospray { }; + // Inlined function definitions ///////////////////////////////////////////// + + inline Material *Renderer::createMaterial(const char *type) + { + UNUSED(type); + return nullptr; + } + + inline Light *Renderer::createLight(const char *type) + { + UNUSED(type); + return nullptr; + } + /*! \brief registers a internal ospray:: renderer under the externally accessible name "external_name" @@ -113,11 +127,8 @@ namespace ospray { lateron always get a handle to this fct and create an instance of this renderer. */ -#define OSP_REGISTER_RENDERER(InternalClassName,external_name) \ - extern "C" OSPRAY_INTERFACE Renderer *ospray_create_renderer__##external_name() \ - { \ - return new InternalClassName; \ - } +#define OSP_REGISTER_RENDERER(InternalClass, external_name) \ + OSP_REGISTER_OBJECT(Renderer, renderer, InternalClass, external_name) } // ::ospray diff --git a/ospray/render/Renderer.ispc b/ospray/render/Renderer.ispc index 273cfdb646..0fb1060efb 100644 --- a/ospray/render/Renderer.ispc +++ b/ospray/render/Renderer.ispc @@ -212,6 +212,7 @@ export void Renderer_renderTile(void *uniform _self, uniform Tile &tile, uniform int jobID) { + //print("Renderer_renderTile\n"); uniform Renderer *uniform self = (uniform Renderer *uniform)_self; self->renderTile(self, perFrameData, tile, jobID); } diff --git a/ospray/render/pathtracer/PathTracer.cpp b/ospray/render/pathtracer/PathTracer.cpp index 4bbc0b7d92..65e07a7b97 100644 --- a/ospray/render/pathtracer/PathTracer.cpp +++ b/ospray/render/pathtracer/PathTracer.cpp @@ -58,9 +58,10 @@ namespace ospray { lightArray.clear(); - if (lightData) - for (int i = 0; i < lightData->size(); i++) + if (lightData) { + for (uint32_t i = 0; i < lightData->size(); i++) lightArray.push_back(((Light**)lightData->data)[i]->getIE()); + } void **lightPtr = lightArray.empty() ? NULL : &lightArray[0]; @@ -81,5 +82,6 @@ namespace ospray { { printf("Loaded plugin 'pathtracer' ...\n"); } -}; + +} diff --git a/ospray/render/pathtracer/PathTracer.ispc b/ospray/render/pathtracer/PathTracer.ispc index 4af410023d..d059ac3c65 100644 --- a/ospray/render/pathtracer/PathTracer.ispc +++ b/ospray/render/pathtracer/PathTracer.ispc @@ -65,10 +65,10 @@ vec3f transparentShadow(const uniform PathTracer* uniform self, lightContrib = lightContrib * transparency; - /*! Compute simple volumetric effect. */ - if (ne(medium.transmission, make_vec3f(1.f))) - lightContrib = lightContrib * powf(medium.transmission, - shadowRay.t - shadowRay.t0); + // compute attenuation with Beer's law + if (ne(medium.attenuation, 0.f)) + lightContrib = lightContrib + * expf(medium.attenuation * (shadowRay.t - shadowRay.t0)); if (reduce_max(lightContrib) <= self->minContribution) return lightContrib; @@ -90,9 +90,9 @@ vec3f transparentShadow(const uniform PathTracer* uniform self, } ScreenSample PathTraceIntegrator_Li(const uniform PathTracer* uniform self, - const vec2f &pixel, // normalized, i.e. in [0..1] - Ray &ray, - varying RandomTEA* uniform rng) + const vec2f &pixel, // normalized, i.e. in [0..1] + Ray &ray, + varying RandomTEA* uniform rng) { ScreenSample sample; sample.alpha = 1.f; @@ -110,10 +110,6 @@ ScreenSample PathTraceIntegrator_Li(const uniform PathTracer* uniform self, lastDg.Ns = ray.dir; lastDg.Ng = ray.dir; - DifferentialGeometry previousDg; - - bool insideSolid = false;// Quick fix for glass absorption. - do { traceRay(self->super.model, ray); @@ -140,8 +136,8 @@ ScreenSample PathTraceIntegrator_Li(const uniform PathTracer* uniform self, // add light from virtual lights by intersecting them for (uniform int i = 0; i < self->numLights; i++) { const uniform Light *uniform l = self->lights[i]; - Light_EvalRes le = l->eval(l, lastDg, ray.dir); - if (le.dist <= maxLightDist) + Light_EvalRes le = l->eval(l, lastDg, ray.dir, maxLightDist); + if (reduce_max(le.radiance) > 0.0f) L = L + Lw * le.radiance * misHeuristic(lastBSDFPdf, le.pdf); } @@ -228,29 +224,14 @@ ScreenSample PathTraceIntegrator_Li(const uniform PathTracer* uniform self, Lw = Lw * fs.weight; - // compute simple volumetric effect - const vec3f transmission = currentMedium.transmission; - if (ne(transmission,make_vec3f(1.f))) { - Lw = Lw * powf(transmission, ray.t); - } - - if (insideSolid) {// For absorbing translucent materials. - foreach_unique(uniMat in dg.material) { - uniform PathTraceMaterial* uniform m = (uniform PathTraceMaterial *)uniMat; - if (m != NULL) { - Lw = Lw * m->getAbsorption(m, previousDg, ray.t); - } - } + // compute attenuation with Beer's law + if (ne(currentMedium.attenuation, 0.f)) { + Lw = Lw * expf(currentMedium.attenuation * ray.t); } // update currentMedium if we hit a medium interface // TODO: support nested dielectrics if (fs.type & BSDF_TRANSMISSION) { - - // This is a quick fix for glass. This only works if all solid objects are disjoint - // (some space is between them and they don't overlap). - insideSolid = !insideSolid; - foreach_unique(uniMat in dg.material) { uniform PathTraceMaterial* uniform m = (uniform PathTraceMaterial *)uniMat; if (m != NULL) { @@ -266,8 +247,6 @@ ScreenSample PathTraceIntegrator_Li(const uniform PathTracer* uniform self, lastDg = dg; } - previousDg = dg; - // continue the path straightPath &= eq(ray.dir, fs.wi); setRay(ray, dg.P, fs.wi, self->super.epsilon, inf); @@ -332,14 +311,6 @@ inline ScreenSample PathTracer_renderPixel(uniform PathTracer *uniform self, -unmasked void *uniform PathTracer_beginFrame(uniform Renderer *uniform _self, - uniform FrameBuffer *uniform fb) -{ - _self->fb = fb; - return NULL; -} - - void PathTracer_renderTileJob(uniform PathTracer *uniform self, uniform Tile &tile, uniform int taskIndex) @@ -404,11 +375,9 @@ export void* uniform PathTracer_create(void *uniform cppE) { uniform PathTracer *uniform self = uniform new uniform PathTracer; Renderer_Constructor(&self->super,cppE); - self->super.renderTile = PathTracer_renderTile; - self->super.beginFrame = PathTracer_beginFrame; + self->super.renderTile = PathTracer_renderTile; PathTracer_set(self, 20, 0.01f, inf, NULL, NULL, 0); - precomputeZOrder(); return self; diff --git a/ospray/render/pathtracer/bsdfs/ShadingContext.ih b/ospray/render/pathtracer/bsdfs/ShadingContext.ih index acb20ee4bc..ece77ec5c9 100644 --- a/ospray/render/pathtracer/bsdfs/ShadingContext.ih +++ b/ospray/render/pathtracer/bsdfs/ShadingContext.ih @@ -18,7 +18,7 @@ #include "math/LinearSpace.ih" -#define SHADINGCONTEXT_SIZE (16*1024) +#define SHADINGCONTEXT_SIZE (programCount*2048) #define SHADINGCONTEXT_ALIGNMENT 64 struct ShadingContext @@ -41,7 +41,8 @@ inline void* uniform ShadingContext_alloc(uniform ShadingContext* uniform self, //print("ShadingContext_alloc: %, %\n", this->size, size); void* uniform ptr = &self->data[self->size]; self->size = (self->size + size + SHADINGCONTEXT_ALIGNMENT - 1) & ((uint32)(-SHADINGCONTEXT_ALIGNMENT)); - //if (self->size > SHADINGCONTEXT_SIZE) throw std::runtime_error("out of memory for ShadingContext allocation"); + if (self->size > SHADINGCONTEXT_SIZE) + print("#osp:PT: out of memory for ShadingContext allocation!\n"); return ptr; } diff --git a/ospray/render/pathtracer/materials/Glass.cpp b/ospray/render/pathtracer/materials/Glass.cpp index 38a43c2ec4..924920b5a4 100644 --- a/ospray/render/pathtracer/materials/Glass.cpp +++ b/ospray/render/pathtracer/materials/Glass.cpp @@ -22,40 +22,31 @@ namespace ospray { namespace pathtracer { struct Glass : public ospray::Material { //! \brief common function to help printf-debugging - /*! Every derived class should overrride this! */ + /*! Every derived class should override this! */ virtual std::string toString() const { return "ospray::pathtracer::Glass"; } //! \brief commit the material's parameters virtual void commit() { if (getIE() != NULL) return; - const vec3f& transmissionInside - = getParam3f("transmissionInside",vec3f(1.f)); - const vec3f& transmissionOutside - = getParam3f("transmissionOutside",vec3f(1.f)); const float etaInside = getParamf("etaInside", getParamf("eta", 1.5f)); const float etaOutside = getParamf("etaOutside", 1.f);; - const float absorptionDistance = getParamf("absorptionDistance", 0.0f); - // Why is "absorptionColor" not found, while "color" is found??? - const vec3f& absorptionColor = getParam3f("color",vec3f(1.f)); - - - Texture2D *map_Kd = (Texture2D*)getParamObject("map_Kd", getParamObject("map_kd", getParamObject("colorMap", NULL))); - affine2f xform_Kd = getTextureTransform("map_kd") * getTextureTransform("colorMap"); - + const vec3f& attenuationColorInside + = getParam3f("attenuationColorInside", getParam3f("attenuationColor", + getParam3f("color", vec3f(1.f)))); + const vec3f& attenuationColorOutside + = getParam3f("attenuationColorOutside", vec3f(1.f)); + const float attenuationDistance = getParamf("attenuationDistance", 1.0f); ispcEquivalent = ispc::PathTracer_Glass_create(); ispc::PathTracer_Glass_set( ispcEquivalent, etaInside, - (const ispc::vec3f&)transmissionInside, + (const ispc::vec3f&)attenuationColorInside, etaOutside, - (const ispc::vec3f&)transmissionOutside, - absorptionDistance, - (const ispc::vec3f&)absorptionColor, - map_Kd ? map_Kd->getIE() : NULL, - (const ispc::AffineSpace2f&)xform_Kd); + (const ispc::vec3f&)attenuationColorOutside, + attenuationDistance); } }; diff --git a/ospray/render/pathtracer/materials/Glass.ispc b/ospray/render/pathtracer/materials/Glass.ispc index 3a4ccdcc87..0ceae2d508 100644 --- a/ospray/render/pathtracer/materials/Glass.ispc +++ b/ospray/render/pathtracer/materials/Glass.ispc @@ -24,12 +24,6 @@ struct Glass Medium mediumInside; Medium mediumOutside; - - float absorptionDistance; - vec3f absorptionColor; - vec3f absorption_k; - - TextureParam colorMap; }; /////////////////////////////////////////////////////////////////////////////// @@ -75,102 +69,30 @@ void Glass_selectNextMedium(const uniform PathTraceMaterial* uniform super, currentMedium = self->mediumOutside; } -vec3f Glass_getAbsorption(const uniform PathTraceMaterial* uniform material, - const DifferentialGeometry& dg, - const float & distance) -{ - const uniform Glass* uniform self = (const uniform Glass* uniform)material; - - vec3f r = make_vec3f(1.0f); - - // Beer's law for glass absorption. - - vec3f k = make_vec3f(0.0f); - - if (self->colorMap.map != NULL) { - // Using a 2D texture for absorption color will cause the glass color - // to be view-dependent. As you move the camera the colors - // will change dynamically. This is fun, but entirely not physically correct. - // The correct thing is to have a 3D texture with ray-marching through - // the solid to integrate the absorption, and be view-independent. - - vec3f color = get3f(self->colorMap, dg.st); - - if (self->absorptionDistance > 0) { - if (color.x > 0) - k.x = log(color.x)/self->absorptionDistance; - - if (color.y > 0) - k.y = log(color.y)/self->absorptionDistance; - - if (color.z > 0) - k.z = log(color.z)/self->absorptionDistance; - } - } else { - k = self->absorption_k; - } - - if (k.x != 0) - r.x = expf(k.x * distance); - if (k.y != 0) - r.y = expf(k.y * distance); - if (k.z != 0) - r.z = expf(k.z * distance); - - return r; -} - /////////////////////////////////////////////////////////////////////////////// // External API export void PathTracer_Glass_set( void* uniform _self, const uniform float iorInside, - const uniform vec3f & transmissionInside, + const uniform vec3f & attenuationColorInside, const uniform float iorOutside, - const uniform vec3f & transmissionOutside, - const uniform float absDistance, - const uniform vec3f & absColor, - void* uniform map_Kd, - const uniform affine2f & xform_Kd) + const uniform vec3f & attenuationColorOutside, + const uniform float attenuationDistance) { uniform Glass* uniform self = (uniform Glass* uniform)_self; self->mediumInside.ior = iorInside; - self->mediumInside.transmission = transmissionInside; + self->mediumInside.attenuation = logf(attenuationColorInside) / attenuationDistance; self->mediumOutside.ior = iorOutside; - self->mediumOutside.transmission = transmissionOutside; - self->absorptionDistance = absDistance; - self->absorptionColor = absColor; - self->colorMap = make_TextureParam((uniform Texture2D*)map_Kd, xform_Kd); - - if (absDistance > 0) { - if (absColor.x > 0) - self->absorption_k.x = log(absColor.x)/absDistance; - else - self->absorption_k.x = 0; - - if (absColor.y > 0) - self->absorption_k.y = log(absColor.y)/absDistance; - else - self->absorption_k.y = 0; - - if (absColor.z > 0) - self->absorption_k.z = log(absColor.z)/absDistance; - else - self->absorption_k.z = 0; - } -} - -void Glass_Constructor(uniform Glass* uniform self) -{ - PathTraceMaterial_Constructor(&self->super, Glass_getBSDF, - Glass_getTransparency, Glass_selectNextMedium, Glass_getAbsorption); + self->mediumOutside.attenuation = logf(attenuationColorOutside) / attenuationDistance; } export void* uniform PathTracer_Glass_create() { uniform Glass* uniform self = uniform new uniform Glass; - Glass_Constructor(self); + PathTraceMaterial_Constructor(&self->super, Glass_getBSDF, + Glass_getTransparency, Glass_selectNextMedium); + return self; } diff --git a/ospray/render/pathtracer/materials/Material.ih b/ospray/render/pathtracer/materials/Material.ih index ba074c65fb..3a9e9d9c13 100644 --- a/ospray/render/pathtracer/materials/Material.ih +++ b/ospray/render/pathtracer/materials/Material.ih @@ -35,6 +35,7 @@ typedef const varying BSDF* uniform (*PathTraceMaterial_GetBSDFFunc)(const unifo /*! The medium this ray travels inside. */ const Medium& currentMedium); +// shortcut: compute transmission of material, for transparent shadows, neglecting refraction typedef vec3f (*PathTraceMaterial_GetTransparencyFunc)(const uniform PathTraceMaterial* uniform self, /*! The point to shade on a surface. */ const DifferentialGeometry& dg, @@ -46,22 +47,15 @@ typedef vec3f (*PathTraceMaterial_GetTransparencyFunc)(const uniform PathTraceMa typedef void (*PathTraceMaterial_SelectNextMediumFunc)(const uniform PathTraceMaterial* uniform self, Medium& currentMedium); -typedef vec3f (*PathTraceMaterial_GetAbsorptionFunc)( - const uniform PathTraceMaterial* uniform self, - const DifferentialGeometry& dg, - const float & distance); - struct PathTraceMaterial { Material material; PathTraceMaterial_GetBSDFFunc getBSDF; PathTraceMaterial_GetTransparencyFunc getTransparency; PathTraceMaterial_SelectNextMediumFunc selectNextMedium; - PathTraceMaterial_GetAbsorptionFunc getAbsorption; }; void PathTraceMaterial_Constructor(uniform PathTraceMaterial* uniform self, uniform PathTraceMaterial_GetBSDFFunc getBSDF, - uniform PathTraceMaterial_GetTransparencyFunc getTransparency, - uniform PathTraceMaterial_SelectNextMediumFunc selectNextMedium, - uniform PathTraceMaterial_GetAbsorptionFunc getAbsorption); + uniform PathTraceMaterial_GetTransparencyFunc getTransparency = NULL, + uniform PathTraceMaterial_SelectNextMediumFunc selectNextMedium = NULL); diff --git a/ospray/render/pathtracer/materials/Material.ispc b/ospray/render/pathtracer/materials/Material.ispc index f4b6a4a88c..e8df0cbf26 100644 --- a/ospray/render/pathtracer/materials/Material.ispc +++ b/ospray/render/pathtracer/materials/Material.ispc @@ -28,22 +28,12 @@ void PathTraceMaterial_selectNextMedium(const uniform PathTraceMaterial* uniform Medium& currentMedium) { /* do nothing by default */ } -vec3f PathTraceMaterial_getAbsorption( - const uniform PathTraceMaterial* uniform self, - const DifferentialGeometry& dg, - const float & distance) -{ - return make_vec3f(1.0f); -} - void PathTraceMaterial_Constructor(uniform PathTraceMaterial* uniform self, uniform PathTraceMaterial_GetBSDFFunc getBSDF, uniform PathTraceMaterial_GetTransparencyFunc getTransparency, - uniform PathTraceMaterial_SelectNextMediumFunc selectNextMedium, - uniform PathTraceMaterial_GetAbsorptionFunc getAbsorption) + uniform PathTraceMaterial_SelectNextMediumFunc selectNextMedium) { self->getBSDF = getBSDF; self->getTransparency = getTransparency ? getTransparency : PathTraceMaterial_getTransparency; self->selectNextMedium = selectNextMedium ? selectNextMedium : PathTraceMaterial_selectNextMedium; - self->getAbsorption = getAbsorption ? getAbsorption : PathTraceMaterial_getAbsorption; } diff --git a/ospray/render/pathtracer/materials/Matte.ispc b/ospray/render/pathtracer/materials/Matte.ispc index 211729cce0..5b6b52997a 100644 --- a/ospray/render/pathtracer/materials/Matte.ispc +++ b/ospray/render/pathtracer/materials/Matte.ispc @@ -40,7 +40,7 @@ const varying BSDF* uniform Matte_getBSDF(const uniform PathTraceMaterial* unifo inline void Matte_Constructor(uniform Matte* uniform self, const uniform vec3f& reflectance) { - PathTraceMaterial_Constructor(&self->super, Matte_getBSDF, NULL, NULL, NULL); + PathTraceMaterial_Constructor(&self->super, Matte_getBSDF); self->reflectance = reflectance; } diff --git a/ospray/render/pathtracer/materials/Medium.ih b/ospray/render/pathtracer/materials/Medium.ih index 427b5e55a5..1dd102fcae 100644 --- a/ospray/render/pathtracer/materials/Medium.ih +++ b/ospray/render/pathtracer/materials/Medium.ih @@ -18,30 +18,31 @@ struct Medium { - vec3f transmission; //!< Transmissivity of medium. + vec3f attenuation; //!< negative Napierian attenuation coefficient, + // i.e. wrt. the natural base e float ior; //!< Refraction index of medium. }; -inline Medium make_Medium(const vec3f transmission, const float ior) +inline Medium make_Medium(const vec3f attenuation, const float ior) { Medium m; - m.transmission = transmission; + m.attenuation = attenuation; m.ior = ior; return m; } inline Medium make_Medium_vacuum() { - return make_Medium(make_vec3f(1.0f),1.0f); + return make_Medium(make_vec3f(0.0f), 1.0f); } inline bool eq(const Medium &a, const Medium &b) { - return (a.ior == b.ior) & eq(a.transmission, b.transmission); + return (a.ior == b.ior) & eq(a.attenuation, b.attenuation); } inline bool eq(const Medium &a, const uniform Medium &b) { - return (a.ior == b.ior) & eq(a.transmission, b.transmission); + return (a.ior == b.ior) & eq(a.attenuation, b.attenuation); } inline uniform bool eq(const uniform Medium &a, const uniform Medium &b) { - return (a.ior == b.ior) & eq(a.transmission, b.transmission); + return (a.ior == b.ior) & eq(a.attenuation, b.attenuation); } diff --git a/ospray/render/pathtracer/materials/Metal.ispc b/ospray/render/pathtracer/materials/Metal.ispc index 3618832943..0269603b11 100644 --- a/ospray/render/pathtracer/materials/Metal.ispc +++ b/ospray/render/pathtracer/materials/Metal.ispc @@ -49,7 +49,7 @@ void Metal_Constructor(uniform Metal* uniform self, const uniform vec3f& k, uniform float roughness) { - PathTraceMaterial_Constructor(&self->super, Metal_getBSDF, NULL, NULL, NULL); + PathTraceMaterial_Constructor(&self->super, Metal_getBSDF); self->reflectance = reflectance; self->eta = eta; self->k = k; diff --git a/ospray/render/pathtracer/materials/MetallicPaint.ispc b/ospray/render/pathtracer/materials/MetallicPaint.ispc index 05dca17df0..65f5dafb25 100644 --- a/ospray/render/pathtracer/materials/MetallicPaint.ispc +++ b/ospray/render/pathtracer/materials/MetallicPaint.ispc @@ -63,7 +63,7 @@ inline void MetallicPaint_Constructor(uniform MetallicPaint* uniform self, const uniform float glitterSpread, const uniform float ior) { - PathTraceMaterial_Constructor(&self->super, MetallicPaint_getBSDF, NULL, NULL, NULL); + PathTraceMaterial_Constructor(&self->super, MetallicPaint_getBSDF); self->shadeColor = shadeColor; self->glitterColor = glitterColor; self->glitterSpread = glitterSpread; diff --git a/ospray/render/pathtracer/materials/OBJ.cpp b/ospray/render/pathtracer/materials/OBJ.cpp index 3271ef05b0..e430a8fde3 100644 --- a/ospray/render/pathtracer/materials/OBJ.cpp +++ b/ospray/render/pathtracer/materials/OBJ.cpp @@ -44,13 +44,18 @@ namespace ospray { linear2f rot_Bump = xform_Bump.l.orthogonal().transposed(); const float d = getParam1f("d", getParam1f("alpha", 1.f)); - const vec3f Kd = getParam3f("Kd", getParam3f("kd", getParam3f("color", vec3f(0.8f)))); - const vec3f Ks = getParam3f("Ks", getParam3f("ks", vec3f(0.f))); + vec3f Kd = getParam3f("Kd", getParam3f("kd", getParam3f("color", vec3f(0.8f)))); + vec3f Ks = getParam3f("Ks", getParam3f("ks", vec3f(0.f))); const float Ns = getParam1f("Ns", getParam1f("ns", 10.f)); - const vec3f Tf = getParam3f("Tf", getParam3f("tf", vec3f(0.0f))); + vec3f Tf = vec3f(1.0-d)*getParam3f("Tf", getParam3f("tf", vec3f(0.0f))); - if (reduce_max(Kd + Ks + Tf) > 1.0) - std::cout << "#osp:PT: warning: OBJ material produces energy (Kd + Ks + Tf must be <= 1)" << std::endl; + const float color_total = reduce_max(Kd + Ks + Tf); + if (color_total > 1.0) { + std::cout << "#osp:PT: warning: OBJ material produces energy (Kd + Ks + Tf = " << color_total << ", should be <= 1). Scaling down to 1." << std::endl; + Kd /= color_total; + Ks /= color_total; + Tf /= color_total; + } ispc::PathTracer_OBJ_set(ispcEquivalent, map_d ? map_d->getIE() : NULL, (const ispc::AffineSpace2f&)xform_d, @@ -68,6 +73,6 @@ namespace ospray { }; OSP_REGISTER_MATERIAL(OBJMaterial,PathTracer_OBJMaterial); - OSP_REGISTER_MATERIAL(OBJMaterial,PathTracer_default) + OSP_REGISTER_MATERIAL(OBJMaterial,PathTracer_default); } } diff --git a/ospray/render/pathtracer/materials/OBJ.ispc b/ospray/render/pathtracer/materials/OBJ.ispc index 80f51268b0..254b39fc76 100644 --- a/ospray/render/pathtracer/materials/OBJ.ispc +++ b/ospray/render/pathtracer/materials/OBJ.ispc @@ -60,7 +60,7 @@ const varying BSDF* uniform OBJ_getBSDF(const uniform PathTraceMaterial* uniform vec2f rotNormal = self->rot_Bump * make_vec2f(localNormal.x, localNormal.y); localNormal.x = rotNormal.x; localNormal.y = rotNormal.y; // transform to world space and align to tangents/texture coordinates - linear3f f = make_LinearSpace3f(normalize(dg.dPds), normalize(dg.dPdt), dg.Ng); + linear3f f = make_LinearSpace3f(normalize(dg.dPds), normalize(dg.dPdt), dg.Ns); shadingNormal = f * localNormal; // in general f is not ortho-normal, thus need to re-normalize shadingNormal = normalize(shadingNormal); @@ -135,7 +135,7 @@ vec3f OBJ_getTransparency(const uniform PathTraceMaterial* uniform super, void OBJ_Constructor(uniform OBJ* uniform self) { - PathTraceMaterial_Constructor(&self->super, OBJ_getBSDF, OBJ_getTransparency, NULL, NULL); + PathTraceMaterial_Constructor(&self->super, OBJ_getBSDF, OBJ_getTransparency); uniform affine2f xform = make_AffineSpace2f_identity(); diff --git a/ospray/render/pathtracer/materials/Plastic.ispc b/ospray/render/pathtracer/materials/Plastic.ispc index 8a1ef20e71..2d24dc9e52 100644 --- a/ospray/render/pathtracer/materials/Plastic.ispc +++ b/ospray/render/pathtracer/materials/Plastic.ispc @@ -56,7 +56,7 @@ void Plastic_Constructor(uniform Plastic* uniform self, uniform float roughness, uniform float thickness) { - PathTraceMaterial_Constructor(&self->super, Plastic_getBSDF, NULL, NULL, NULL); + PathTraceMaterial_Constructor(&self->super, Plastic_getBSDF); self->pigmentColor = pigmentColor; self->eta = rcp(ior); self->roughness = roughness; diff --git a/ospray/render/pathtracer/materials/ThinGlass.ispc b/ospray/render/pathtracer/materials/ThinGlass.ispc index b176764b7a..cc1c12fead 100644 --- a/ospray/render/pathtracer/materials/ThinGlass.ispc +++ b/ospray/render/pathtracer/materials/ThinGlass.ispc @@ -57,7 +57,7 @@ void ThinGlass_Constructor(uniform ThinGlass* uniform self, const uniform vec3f& transmission, uniform float thickness) { - PathTraceMaterial_Constructor(&self->super, ThinGlass_getBSDF, ThinGlass_getTransparency, NULL, NULL); + PathTraceMaterial_Constructor(&self->super, ThinGlass_getBSDF, ThinGlass_getTransparency); self->eta = rcp(ior); self->transmission = transmission; self->thickness = thickness; diff --git a/ospray/render/pathtracer/materials/Velvet.ispc b/ospray/render/pathtracer/materials/Velvet.ispc index 8c6a9b116d..7925189928 100644 --- a/ospray/render/pathtracer/materials/Velvet.ispc +++ b/ospray/render/pathtracer/materials/Velvet.ispc @@ -64,7 +64,7 @@ void Velvet_Constructor(uniform Velvet* uniform self, uniform float horizonScatteringFallOff, uniform float backScattering) { - PathTraceMaterial_Constructor(&self->super, Velvet_getBSDF, NULL, NULL, NULL); + PathTraceMaterial_Constructor(&self->super, Velvet_getBSDF); self->reflectance = reflectance; self->horizonScatteringColor = horizonScatteringColor; self->horizonScatteringFallOff = horizonScatteringFallOff; diff --git a/ospray/render/raycast/RaycastRenderer.ispc b/ospray/render/raycast/RaycastRenderer.ispc index fd91077360..f922341327 100644 --- a/ospray/render/raycast/RaycastRenderer.ispc +++ b/ospray/render/raycast/RaycastRenderer.ispc @@ -91,7 +91,9 @@ void RaycastRenderer_renderSample_Ng(uniform Renderer *uniform _self, if (sample.ray.geomID < 0) sample.rgb = make_vec3f(1.f); else { - sample.rgb = absf(sample.ray.Ng); + DifferentialGeometry dg; + postIntersect(self->super.model, dg, sample.ray, DG_NORMALIZE | DG_NG); + sample.rgb = absf(dg.Ng); } } diff --git a/ospray/render/scivis/SciVisRenderer.cpp b/ospray/render/scivis/SciVisRenderer.cpp index fdf3aff99b..937fcf6362 100644 --- a/ospray/render/scivis/SciVisRenderer.cpp +++ b/ospray/render/scivis/SciVisRenderer.cpp @@ -37,11 +37,11 @@ namespace ospray { lightArray.clear(); if (lightData) { - for (int i = 0; i < lightData->size(); i++) + for (uint32_t i = 0; i < lightData->size(); i++) lightArray.push_back(((Light**)lightData->data)[i]->getIE()); } - void **lightPtr = lightArray.empty() ? NULL : &lightArray[0]; + void **lightPtr = lightArray.empty() ? nullptr : &lightArray[0]; const bool shadowsEnabled = getParam1i("shadowsEnabled", 0); @@ -50,6 +50,7 @@ namespace ospray { int numAOSamples = getParam1i("aoSamples", 0); float rayLength = getParam1f("aoOcclusionDistance", 1e20f); float aoWeight = getParam1f("aoWeight", 0.25f); + const bool oneSidedLighting = getParam1i("oneSidedLighting", 1); ispc::SciVisRenderer_set(getIE(), shadowsEnabled, @@ -58,7 +59,8 @@ namespace ospray { rayLength, aoWeight, lightPtr, - lightArray.size()); + lightArray.size(), + oneSidedLighting); } SciVisRenderer::SciVisRenderer() @@ -69,6 +71,7 @@ namespace ospray { /*! \brief create a material of given type */ Material *SciVisRenderer::createMaterial(const char *type) { + UNUSED(type); return new SciVisMaterial; } diff --git a/ospray/render/scivis/SciVisRenderer.ispc b/ospray/render/scivis/SciVisRenderer.ispc index c9189b9f33..338fd8da1f 100644 --- a/ospray/render/scivis/SciVisRenderer.ispc +++ b/ospray/render/scivis/SciVisRenderer.ispc @@ -39,6 +39,7 @@ struct SciVisRenderer const uniform Light *uniform *uniform lights; uint32 numLights; + bool oneSidedLighting; bool shadowsEnabled; @@ -61,6 +62,19 @@ struct SciVisShadingInfo vec3f geometryColor; }; +inline float lightAlpha(const uniform SciVisRenderer *uniform self, + Ray &ray, uniform Model *uniform model, + const float weight, + int remaining_depth, + const varying float &rayOffset, + const varying vec3i &sampleID, + const uniform float &quality); + +inline Volume * +SciVisRenderer_intersectVolumes(const uniform SciVisRenderer *uniform renderer, + varying Ray &ray, + const varying float &rayOffset); + // Function definitions /////////////////////////////////////////////////////// inline void initShadingInfo(varying SciVisShadingInfo &info) @@ -128,7 +142,7 @@ inline float calculateAO(const uniform SciVisRenderer *uniform self, varying RandomTEA* const uniform rng = &rng_state; RandomTEA__Constructor(rng, (self->super.fb->size.x * iy) + ix, accumID); - int hits = 0; + float hits = 0.f; const linear3f localToWorld = frame(dg.Ns); for (uniform int i = 0; i < self->aoSamples; i++) { @@ -139,8 +153,26 @@ inline float calculateAO(const uniform SciVisRenderer *uniform self, Ray ao_ray; setRay(ao_ray, dg.P + (1e-3f * dg.Ns), ao_dir, self->super.epsilon, self->aoRayLength); + //shade volumes if (dot(ao_ray.dir, dg.Ns) < 0.05f || isOccluded(self->super.model,ao_ray)) - hits++; + hits+=1.f; + else + { + const float epsilon = self->volumeEpsilon*10.f; + const float rayOffset = epsilon*s.x + epsilon; + if (SciVisRenderer_intersectVolumes(self, ao_ray, rayOffset)) + { + //hits++; + ao_ray.geomID = -1; + // ao_ray.dir = neg(ao_ray.dir); + // ao_ray.t0 = rayOffset; + // ao_ray.t = -1; + hits += (1.f- lightAlpha(self, ao_ray, self->super.model, + 1.0f, + self->maxDepth, + rayOffset, sampleID,0.1f)); + } + } } // the cosTheta of cosineSampleHemispherePDF and dot(dg.Ns, ao_dir) cancel @@ -159,57 +191,8 @@ inline void shadeAO(const uniform SciVisRenderer *uniform self, if (self->aoRayLength > 0.f) ao *= calculateAO(self, sampleID, dg); // Blend AO w/ diffuse term - color = color + info.local_opacity * info.Kd * ao; - } -} - -// Lighting functions // - -inline float lightAlpha(Ray &ray, uniform Model *uniform model, - const float weight, - int remaining_depth, - const uniform float epsilon) -{ - float alpha = 1.f; - const float org_t_max = ray.t; - - while (1) { - traceRay(model,ray); - - if (ray.geomID < 0) return alpha; - - DifferentialGeometry dg; - postIntersect(model, dg, ray, DG_MATERIALID | DG_TEXCOORD | DG_COLOR); - - uniform SciVisMaterial *scivisMaterial = - (uniform SciVisMaterial *)dg.material; - - float material_opacity = 1.f; - - if(scivisMaterial == NULL) { - material_opacity = dg.color.w; - } else { - foreach_unique( mat in scivisMaterial ) { - material_opacity = mat->d * get1f(mat->map_d, dg.st, 1.f); - if (mat->map_Kd) { - vec4f Kd_from_map = get4f(mat->map_Kd,dg.st); - material_opacity *= Kd_from_map.w; - } - } - } - - alpha = alpha * (1.f - material_opacity); - - if (alpha * weight < ALPHA_THRESHOLD) return alpha; - - if (--remaining_depth <= 0) - return 0.f; - - ray.t0 = ray.t + epsilon; - ray.t = org_t_max; - ray.primID = -1; - ray.geomID = -1; - ray.instID = -1; + vec3f aoColor = make_vec3f(0.5f, 0.7f, 1.f); + color = color + info.local_opacity * info.Kd * ao*aoColor; } } @@ -218,7 +201,9 @@ inline void shadeLights(const uniform SciVisRenderer *uniform self, const varying DifferentialGeometry &dg, const varying SciVisShadingInfo &info, const varying int path_depth, - varying vec3f &color) + varying vec3f &color, const varying float &rayOffset, + const varying vec3i &sampleID, + const uniform float &quality) { const vec3f R = ray.dir - ((2.f * dot(ray.dir, dg.Ns)) * dg.Ns); const vec3f P = dg.P + self->super.epsilon * dg.Ng; @@ -230,22 +215,33 @@ inline void shadeLights(const uniform SciVisRenderer *uniform self, const Light_SampleRes light = l->sample(l, dg, s); if (reduce_max(light.weight) > 0.f) { // any potential contribution? - const float cosNL = abs(dot(light.dir, dg.Ns)); + float cosNL = dot(light.dir, dg.Ns); + if (self->oneSidedLighting) { + if (cosNL < 0.0f) + continue; + } + else + cosNL = abs(cosNL); const float cosLR = max(0.f, dot(light.dir, R)); - const vec3f brdf = info.Kd * cosNL + info.Ks * powf(cosLR, info.Ns); + vec3f specular = info.Ks * powf(cosLR, info.Ns*.3f); + specular.x = clamp(specular.x); + specular.y = clamp(specular.y); + specular.z = clamp(specular.z); + const vec3f brdf = info.Kd * cosNL + specular; const vec3f light_contrib = info.local_opacity * brdf * light.weight; - if (self->shadowsEnabled) { + if (self->shadowsEnabled) + { const float max_contrib = reduce_max(light_contrib); if (max_contrib > .01f) { Ray shadowRay; setRay(shadowRay, P, light.dir); - const float light_alpha = lightAlpha(shadowRay, + const float light_alpha = lightAlpha(self, shadowRay, self->super.model, max_contrib, self->maxDepth - path_depth, - self->super.epsilon); + rayOffset, sampleID, quality); color = color + light_alpha * light_contrib; } } else { @@ -259,7 +255,8 @@ inline void shadeLights(const uniform SciVisRenderer *uniform self, inline vec4f SciVisRenderer_computeVolumeSample(SciVisRenderer *uniform renderer, Volume *uniform volume, - varying Ray &ray) + varying Ray &ray, const varying float &rayOffset, + const varying vec3i &sampleID) { // Sample the volume at the hit point in world coordinates. const vec3f coordinates = ray.org + ray.t0 * ray.dir; @@ -270,6 +267,11 @@ inline vec4f SciVisRenderer_computeVolumeSample(SciVisRenderer *uniform renderer volume->transferFunction->getColorForValue(volume->transferFunction, sample); + // Look up the opacity associated with the volume sample. + const float sampleOpacity = + volume->transferFunction->getOpacityForValue(volume->transferFunction, + sample); + // Compute gradient shading, if enabled. if(volume->gradientShadingEnabled) { @@ -295,29 +297,205 @@ inline vec4f SciVisRenderer_computeVolumeSample(SciVisRenderer *uniform renderer 1.f : abs(dot(safe_normalize(light.dir), gradient)); - shadedColor = shadedColor + sampleColor * cosNL * light.weight; + shadedColor = shadedColor + sampleColor * cosNL * light.weight * one_over_pi /*BRDF normalization to match surface shading*/; } - sampleColor = shadedColor; - } + //sampleColor = shadedColor; - // Look up the opacity associated with the volume sample. - const float sampleOpacity = - volume->transferFunction->getOpacityForValue(volume->transferFunction, - sample); + dg.color = make_vec4f(sampleColor, 1); + dg.Ng = dg.Ns; + SciVisShadingInfo info; + initShadingInfo(info); - // Advance the ray for the next sample. - volume->intersect(volume, ray); + //hardcode volume spec for now + info.Ks = make_vec3f(.3f,.3f,.3f); + info.Ns = 20.0f; + info.local_opacity=1.f; + dg.material = 0; + shadeMaterials(dg, info); + + vec3f litColor = make_vec3f(0.0f); + shadeLights(renderer, ray, dg, info, 1, litColor, rayOffset, sampleID,1.f); + sampleColor = litColor; + } // return the color contribution for this sample only (do not accumulate) return clamp(sampleOpacity / volume->samplingRate) * make_vec4f(sampleColor.x, sampleColor.y, sampleColor.z, 1.0f); } +// Volume shading // +// quality is from 0 - 1. 1 being best. +vec4f SciVisRenderer_computeVolumeInterval(const SciVisRenderer *uniform renderer, + Volume *uniform volume, + varying Ray &ray, float tBegin, + float tEnd, float maxOpacity, bool isShadowRay, const varying float &rayOffset, const varying vec3i &sampleID, const uniform float& quality) +{ + vec3f singleCoordinates; + float singleMax = -1.f; + float singleMin = 0.01f; + ray.t0 = tBegin; + float tSkipped = -1; //for adaptive, skip adapting sampling rate up to this value + vec4f intervalColor = make_vec4f(0.f); + volume->intersect(volume, ray); + uniform float oneOverQuality = (1.f/quality); + float samplingRate = volume->samplingRate*quality; + float lastSample = -1.f; + float adaptiveScalar = volume->adaptiveScalar*quality; + float maxSamplingRate = volume->adaptiveMaxSamplingRate*quality; //2.f nyquist frequency + float adaptiveBacktrack = volume->adaptiveBacktrack*oneOverQuality; + // maxSamplingRate = 0.125; + while (ray.t0 < tEnd && intervalColor.w < maxOpacity) + { + // Sample the volume at the hit point in world coordinates. + const vec3f coordinates = ray.org + ray.t0 * ray.dir; + const float sample = volume->computeSample(volume, coordinates); + if (lastSample == -1.f) + lastSample = sample; + + // Look up the color associated with the volume sample. + // Look up the opacity associated with the volume sample. + vec3f sampleColor; + float sampleOpacity; + if (volume->preIntegration) + { + sampleOpacity = volume->transferFunction->getIntegratedOpacityForValue(volume->transferFunction, + lastSample, sample); + } + else + { + sampleOpacity = volume->transferFunction->getOpacityForValue(volume->transferFunction, + sample); + } + + if (volume->adaptiveSampling && sampleOpacity > adaptiveBacktrack && ray.t0 > tSkipped) // adaptive backtack + { + tSkipped = ray.t0; + //adaptively refine sampling rate + float newSamplingRate = min(adaptiveScalar*sampleOpacity,maxSamplingRate); + if (newSamplingRate > samplingRate + 0.01f) + { + samplingRate = newSamplingRate; + ray.t0 = max(ray.t0-ray.time, tBegin); + volume->intersectAdaptive(volume, ray, samplingRate); + lastSample = -1; + continue; + } + } + + if (!isShadowRay) + { + if (volume->preIntegration) + { + sampleColor = volume->transferFunction->getIntegratedColorForValue(volume->transferFunction, lastSample, sample); + lastSample = sample; + } + else + { + sampleColor = volume->transferFunction->getColorForValue(volume->transferFunction, + sample); + } + + // Compute gradient shading, if enabled. + if(volume->gradientShadingEnabled) + { + if (volume->singleShade && sampleOpacity*(1.0f - intervalColor.w) > singleMax && sampleOpacity > singleMin) + { + singleMax = sampleOpacity*(1.0f - intervalColor.w); + singleCoordinates = coordinates; + } + else if (!volume->singleShade) + { + // Use volume gradient as the normal. + const vec3f gradient = + safe_normalize(volume->computeGradient(volume, coordinates)); + + // Setup differential geometry for the volume sample point. + DifferentialGeometry dg; + dg.Ng = gradient; + if (dot(ray.dir,dg.Ng) >= 0.f) dg.Ng = neg(dg.Ng); //face forward + dg.Ns = dg.Ng; + dg.P = coordinates + dg.Ns*renderer->volumeEpsilon; + + //sampleColor = shadedColor; + + dg.color = make_vec4f(sampleColor, 1); + dg.Ng = dg.Ns; + SciVisShadingInfo info; + initShadingInfo(info); + + //hardcode volume spec for now + info.Ks = volume->specular*sampleOpacity; + info.Ns = 20.0f; + info.local_opacity=sampleOpacity; + dg.material = 0; + shadeMaterials(dg, info); + + vec3f litColor = make_vec3f(0.0f); + shadeLights(renderer, ray, dg, info, 0, litColor, rayOffset, sampleID, quality); + sampleColor = litColor; + } + } + } + if (volume->adaptiveSampling) + { + // ray.time = absolute step length. convert to effective sampling rate + float dt = 1.0f/((ray.time)/volume->samplingStep); + vec4f contribution = clamp(sampleOpacity / dt) + * make_vec4f(sampleColor.x, sampleColor.y, sampleColor.z, 1.0f); + intervalColor = intervalColor + (1.0f - intervalColor.w) * contribution; + //adaptively refine sampling rate + if (ray.t0 > tSkipped) + samplingRate = max(min(adaptiveScalar*sampleOpacity,maxSamplingRate)/*nyquist frequency*/,volume->samplingRate); + volume->intersectAdaptive(volume, ray, samplingRate); + } + else + { + vec4f contribution = clamp(sampleOpacity / volume->samplingRate) + * make_vec4f(sampleColor.x, sampleColor.y, sampleColor.z, 1.0f); + intervalColor = intervalColor + (1.0f - intervalColor.w) * contribution; + volume->intersect(volume, ray); + } + } + if(!isShadowRay && volume->gradientShadingEnabled && volume->singleShade && singleMax >= singleMin) + { + // Use volume gradient as the normal. + const vec3f gradient = + safe_normalize(volume->computeGradient(volume, singleCoordinates)); + + // Setup differential geometry for the volume sample point. + DifferentialGeometry dg; + dg.Ng = gradient; + if (dot(ray.dir,dg.Ng) >= 0.f) dg.Ng = neg(dg.Ng); //face forward + dg.Ns = dg.Ng; + dg.P = singleCoordinates + dg.Ns*renderer->volumeEpsilon; + + // Compute lighting. + vec3f shadedColor = make_vec3f(0.f); + + dg.color = intervalColor; + SciVisShadingInfo info; + initShadingInfo(info); + + //hardcode volume spec for now + info.Ks = volume->specular*singleMax; + info.Ns = 20.0f; + info.local_opacity=intervalColor.w; + dg.material = 0; + shadeMaterials(dg, info); + + vec3f litColor = make_vec3f(0.0f); + shadeAO(renderer, sampleID, dg, info, litColor); + shadeLights(renderer, ray, dg, info, 0, litColor, rayOffset, sampleID, quality); + intervalColor = make_vec4f(litColor,intervalColor.w); + } + return intervalColor; +} + inline vec4f SciVisRenderer_computeGeometrySample(SciVisRenderer *uniform self, const varying vec3i &sampleID, - varying Ray &ray) + varying Ray &ray, const varying float &rayOffset) { vec3f color = make_vec3f(0.f); float path_opacity = 1.f; @@ -357,7 +535,7 @@ vec4f SciVisRenderer_computeGeometrySample(SciVisRenderer *uniform self, if (info.local_opacity > 0.01f) { // worth shading? shadeAO(self, sampleID, dg, info, color); - shadeLights(self, ray, dg, info, path_depth, color); + shadeLights(self, ray, dg, info, path_depth, color, rayOffset,sampleID,1.f); } // Kill path when reached max depth or if remaining contribution too low @@ -383,7 +561,7 @@ vec4f SciVisRenderer_computeGeometrySample(SciVisRenderer *uniform self, * infinity. */ inline Volume * -SciVisRenderer_intersectVolumes(uniform SciVisRenderer *uniform renderer, +SciVisRenderer_intersectVolumes(const uniform SciVisRenderer *uniform renderer, varying Ray &ray, const varying float &rayOffset) { @@ -432,6 +610,91 @@ SciVisRenderer_intersectVolumes(uniform SciVisRenderer *uniform renderer, return volume; } +// Lighting functions // + +inline float lightAlpha(const uniform SciVisRenderer *uniform self, + Ray &ray, uniform Model *uniform model, + const float weight, + int remaining_depth, + const varying float &rayOffset, + const varying vec3i &sampleID, + const uniform float &quality) +{ + float alpha = 1.f; + const float org_t_max = ray.t; + + while (1) { + // Get first intersected volume for each ray and set the ray bounds. + float org_t = ray.t; + float org_t0 = ray.t0; + Volume *volume = SciVisRenderer_intersectVolumes(self, ray, rayOffset); + float volumeT = ray.t; + float volumeT0 = ray.t0; + ray.t = org_t; + ray.t0 = org_t0; + + traceRay(model,ray); + + if (!(volumeT0 <= 0.f || volumeT0 <= ray.t)) + volume = NULL; + + if (!volume && ray.geomID < 0) return alpha; + + float material_opacity = 1.f; + + if (!volume) + { + DifferentialGeometry dg; + postIntersect(model, dg, ray, DG_MATERIALID | DG_TEXCOORD | DG_COLOR); + + uniform SciVisMaterial *scivisMaterial = + (uniform SciVisMaterial *)dg.material; + + if(scivisMaterial == NULL) { + material_opacity = dg.color.w; + } else { + foreach_unique( mat in scivisMaterial ) { + material_opacity = mat->d * get1f(mat->map_d, dg.st, 1.f); + if (mat->map_Kd) { + vec4f Kd_from_map = get4f(mat->map_Kd,dg.st); + material_opacity *= Kd_from_map.w; + } + } + } + } + else + { + ray.t = org_t; + ray.t0 = org_t0; + // print("found volume intersection!\n"); + // Provide ray offset for use with isosurface geometries (this value + // ignored elsewhere). + ray.time = -rayOffset * volume->samplingStep; + ray.t = volumeT; + float tBegin = max(volumeT0,0.f); + float tEnd = volumeT+self->volumeEpsilon; + foreach_unique (v in volume) + { + vec4f volumeColor = SciVisRenderer_computeVolumeInterval(self, v, ray, tBegin, tEnd, 1.f, 1, rayOffset, sampleID, quality*.5f); + material_opacity = volumeColor.w; + } + } + + alpha = alpha * (1.f - material_opacity); + + if (alpha * weight < ALPHA_THRESHOLD) return alpha; + + if (--remaining_depth <= 0) + return alpha; + + ray.t0 = ray.t + rayOffset; + ray.t = org_t_max; + ray.primID = -1; + ray.geomID = -1; + ray.instID = -1; + } +} + /*! This function intersects the volume and geometries. */ void SciVisRenderer_intersect(uniform SciVisRenderer *uniform renderer, varying Ray &ray, @@ -460,7 +723,7 @@ void SciVisRenderer_intersect(uniform SciVisRenderer *uniform renderer, // Initial trace through geometries. vec4f geometryColor = SciVisRenderer_computeGeometrySample(renderer, - sampleID, geometryRay); + sampleID, geometryRay, rayOffset); // Depth is the first volume bounding box or geometry hit depth = min(ray.t0, geometryRay.t); @@ -493,12 +756,21 @@ void SciVisRenderer_intersect(uniform SciVisRenderer *uniform renderer, // Compute the volume sample at the current position and advance the ray vec4f volumeColor; + float tBegin = ray.t0; + float tEnd = min(geometryRay.t,ray.t); foreach_unique (v in volume) - volumeColor = SciVisRenderer_computeVolumeSample(renderer, v, ray); + { + //volumeColor = SciVisRenderer_computeVolumeSample(renderer, v, ray); + // Advance the ray for the next sample. + //volume->intersect(v, ray); + + //interval sampling + volumeColor = SciVisRenderer_computeVolumeInterval(renderer, v, ray, tBegin, tEnd, .99f - color.w, 0, rayOffset, sampleID, 1.f); + } // Volume contribution. color = color + (1.0f - color.w) * volumeColor; - + ray.t0 = tEnd + renderer->volumeEpsilon; } } else {// firstHit == geometryRay.t @@ -520,7 +792,7 @@ void SciVisRenderer_intersect(uniform SciVisRenderer *uniform renderer, // Trace next geometry ray. geometryColor = SciVisRenderer_computeGeometrySample(renderer, - sampleID, geometryRay); + sampleID, geometryRay, rayOffset); } } @@ -595,7 +867,9 @@ export void SciVisRenderer_set(void *uniform _self, const uniform float aoRayLength, const uniform float aoWeight, void **uniform lights, - const uniform uint32 numLights) + const uniform uint32 numLights, + const uniform bool oneSidedLighting + ) { uniform SciVisRenderer *uniform self = (uniform SciVisRenderer *uniform)_self; @@ -609,6 +883,7 @@ export void SciVisRenderer_set(void *uniform _self, self->lights = (const uniform Light *uniform *uniform)lights; self->numLights = numLights; + self->oneSidedLighting = oneSidedLighting; } export void *uniform SciVisRenderer_create(void *uniform cppE) @@ -617,7 +892,7 @@ export void *uniform SciVisRenderer_create(void *uniform cppE) Renderer_Constructor(&self->super,cppE); self->super.renderSample = SciVisRenderer_renderSample; self->super.beginFrame = SciVisRenderer_beginFrame; - SciVisRenderer_set(self, true, 10, 4, infinity, 0.25f, NULL, 0); + SciVisRenderer_set(self, true, 10, 4, infinity, 0.25f, NULL, 0, true); return self; -} +} \ No newline at end of file diff --git a/ospray/render/simpleAO/SimpleAO.cpp b/ospray/render/simpleAO/SimpleAO.cpp index bd7d0b92a9..b94344f90e 100644 --- a/ospray/render/simpleAO/SimpleAO.cpp +++ b/ospray/render/simpleAO/SimpleAO.cpp @@ -28,7 +28,7 @@ namespace ospray { SimpleAO::SimpleAO(int defaultNumSamples) : defaultNumSamples(defaultNumSamples) { - ispcEquivalent = ispc::SimpleAO_create(this,NULL,NULL); + ispcEquivalent = ispc::SimpleAO_create(this); } /*! \brief create a material of given type */ @@ -57,22 +57,13 @@ namespace ospray { // OSP_REGISTER_RENDERER(SimpleAO, ao); /*! \note Reintroduce aoX renderers for compatibility, they should be - depricated!*/ - -#define OSP_REGISTER_AO_RENDERER(external_name, nSamples) \ - extern "C" OSPRAY_INTERFACE \ - Renderer *ospray_create_renderer__##external_name() \ - { \ - SimpleAO *renderer = new SimpleAO(nSamples); \ - return renderer; \ - } - - OSP_REGISTER_AO_RENDERER(ao, 4 ); - OSP_REGISTER_AO_RENDERER(ao1, 1 ); - OSP_REGISTER_AO_RENDERER(ao2, 2 ); - OSP_REGISTER_AO_RENDERER(ao4, 4 ); - OSP_REGISTER_AO_RENDERER(ao8, 8 ); - OSP_REGISTER_AO_RENDERER(ao16, 16); + deprecated!*/ + OSP_REGISTER_RENDERER(SimpleAO(4), ao); + OSP_REGISTER_RENDERER(SimpleAO(1), ao1); + OSP_REGISTER_RENDERER(SimpleAO(2), ao2); + OSP_REGISTER_RENDERER(SimpleAO(4), ao4); + OSP_REGISTER_RENDERER(SimpleAO(8), ao8); + OSP_REGISTER_RENDERER(SimpleAO(16), ao16); } // ::ospray diff --git a/ospray/render/simpleAO/SimpleAO.ispc b/ospray/render/simpleAO/SimpleAO.ispc index f9331b916a..b1009d45d6 100644 --- a/ospray/render/simpleAO/SimpleAO.ispc +++ b/ospray/render/simpleAO/SimpleAO.ispc @@ -170,12 +170,10 @@ void SimpleAO_renderSample(uniform Renderer *uniform _self, } -export void *uniform SimpleAO_create(void *uniform cppE, - void *uniform _model, - void *uniform _camera) +export void *uniform SimpleAO_create(void *uniform cppE) { uniform SimpleAO *uniform self = uniform new uniform SimpleAO; - Renderer_Constructor(&self->super, cppE, _model, _camera, 1); + Renderer_Constructor(&self->super, cppE, NULL, NULL, 1); self->super.renderSample = SimpleAO_renderSample; return self; } diff --git a/ospray/render/util.h b/ospray/render/util.h index 622e722b25..411829ee7e 100644 --- a/ospray/render/util.h +++ b/ospray/render/util.h @@ -18,7 +18,7 @@ /*! \file render/util.h Defines some utility functions shaared by different shading codes */ -#include "ospray/common/OSPCommon.h" +#include "common/OSPCommon.h" namespace ospray { diff --git a/ospray/render/volume/RaycastVolumeRenderer.cpp b/ospray/render/volume/RaycastVolumeRenderer.cpp index 485b29c4fc..c7c36e8c2c 100644 --- a/ospray/render/volume/RaycastVolumeRenderer.cpp +++ b/ospray/render/volume/RaycastVolumeRenderer.cpp @@ -36,6 +36,7 @@ namespace ospray { Material *RaycastVolumeRenderer::createMaterial(const char *type) { + UNUSED(type); return new RaycastVolumeMaterial; } @@ -46,12 +47,12 @@ namespace ospray { CacheForBlockTiles(size_t numBlocks) : numBlocks(numBlocks), blockTile(new Tile *[numBlocks]) { - for (int i = 0; i < numBlocks; i++) blockTile[i] = nullptr; + for (size_t i = 0; i < numBlocks; i++) blockTile[i] = nullptr; } ~CacheForBlockTiles() { - for (int i = 0; i < numBlocks; i++) + for (size_t i = 0; i < numBlocks; i++) if (blockTile[i]) delete blockTile[i]; delete[] blockTile; @@ -123,7 +124,7 @@ namespace ospray { const size_t tile_y = taskIndex / numTiles_x; const size_t tile_x = taskIndex - tile_y*numTiles_x; const vec2i tileId(tile_x, tile_y); - const int32 accumID = fb->accumID(tileID); + const int32 accumID = fb->accumID(tileId); Tile bgTile(tileId, fb->size, accumID); Tile fgTile(bgTile); @@ -131,7 +132,7 @@ namespace ospray { CacheForBlockTiles blockTileCache(numBlocks); bool *blockWasVisible = STACK_BUFFER(bool, numBlocks); - for (int i = 0; i < numBlocks; i++) + for (size_t i = 0; i < numBlocks; i++) blockWasVisible[i] = false; bool renderForeAndBackground = @@ -160,7 +161,7 @@ namespace ospray { // be coming in generation #1 size_t totalBlocksInTile = 0; - for (int blockID = 0; blockID < numBlocks; blockID++) { + for (size_t blockID = 0; blockID < numBlocks; blockID++) { if (blockWasVisible[blockID]) totalBlocksInTile++; } @@ -193,7 +194,7 @@ namespace ospray { // _across_all_clients_, but we only have to send ours (assuming // that all clients together send exactly as many as the owner // told the DFB to expect) - for (int blockID = 0; blockID < numBlocks; blockID++) { + for (size_t blockID = 0; blockID < numBlocks; blockID++) { Tile *tile = blockTileCache.blockTile[blockID]; if (tile == nullptr) continue; @@ -201,6 +202,7 @@ namespace ospray { tile->region = bgTile.region; tile->fbSize = bgTile.fbSize; tile->rcp_fbSize = bgTile.rcp_fbSize; + tile->accumID = accumID; tile->generation = 1; tile->children = 0; //nextGenTile-1; @@ -217,11 +219,9 @@ namespace ospray { float RaycastVolumeRenderer::renderFrame(FrameBuffer *fb, const uint32 channelFlags) { - int workerRank = ospray::core::getWorkerRank(); - using DDBV = DataDistributedBlockedVolume; std::vector ddVolumeVec; - for (int volumeID = 0; volumeID < model->volume.size(); volumeID++) { + for (size_t volumeID = 0; volumeID < model->volume.size(); volumeID++) { const DDBV* ddv = dynamic_cast(model->volume[volumeID].ptr); if (!ddv) continue; ddVolumeVec.push_back(ddv); @@ -264,13 +264,9 @@ namespace ospray { dfb->setFrameMode(DistributedFrameBuffer::ALPHA_BLEND); - // note: we can NEVER be the master, since the master doesn't even - // have an instance of this renderer class - - assert(workerRank >= 0); - Renderer::beginFrame(fb); - dfb->startNewFrame(); + dfb->startNewFrame(errorThreshold); if (ddVolumeVec.size() > 1) { /* note: our assumption below is that all blocks together are diff --git a/ospray/render/volume/RaycastVolumeRenderer.ispc b/ospray/render/volume/RaycastVolumeRenderer.ispc index 2467b02bf7..203d0ed484 100644 --- a/ospray/render/volume/RaycastVolumeRenderer.ispc +++ b/ospray/render/volume/RaycastVolumeRenderer.ispc @@ -72,7 +72,8 @@ RaycastVolumeRenderer_computeVolumeSample(RaycastVolumeRenderer *uniform self, (gradient.x == 0.f && gradient.y == 0.f && gradient.z == 0.f) ? 1.f : abs(dot(safe_normalize(light.dir), gradient)); - shadedColor = shadedColor + sampleColor * cosNL * light.weight; + // BRDF normalization to match surface shading + shadedColor = shadedColor + sampleColor * cosNL * light.weight * one_over_pi; } sampleColor = shadedColor; @@ -83,7 +84,7 @@ RaycastVolumeRenderer_computeVolumeSample(RaycastVolumeRenderer *uniform self, // Set the color contribution for this sample only (do not accumulate). color - = clamp(sampleOpacity / volume->samplingRate) + = clamp(sampleOpacity / volume->samplingRate) * make_vec4f(sampleColor.x, sampleColor.y, sampleColor.z, 1.0f); // Advance the ray for the next sample. @@ -423,7 +424,7 @@ void RaycastVolumeRenderer_renderSample(Renderer *uniform pointer, *passInfo, rayOffset, color, depth); } else { uniform PassInfo dummyPassInfo; - dummyPassInfo.region = make_region1f(0.f,inf); + dummyPassInfo.region = make_box1f(0.f,inf); dummyPassInfo.useBG = true; dummyPassInfo.block = NULL; RaycastVolumeRenderer_intersect(self, sample.ray, @@ -496,7 +497,7 @@ inline void DDVR_renderSample(RaycastVolumeRenderer *uniform self, uniform bool isMyTile) { // ray interval that overlaps _any_ block - region1f blockRegion = make_region1f(+inf,-inf); + region1f blockRegion = make_box1f(+inf,-inf); float org_ray_t0 = fgSample.ray.t0; float org_ray_t1 = fgSample.ray.t; for (uniform int blockID=0;blockIDdata; ispc::LinearTransferFunction_setOpacityValues(ispcEquivalent, opacityValues->numItems, (float *)opacityValues->data); diff --git a/ospray/transferFunction/LinearTransferFunction.h b/ospray/transferFunction/LinearTransferFunction.h index 0faa0b3648..23cb509066 100644 --- a/ospray/transferFunction/LinearTransferFunction.h +++ b/ospray/transferFunction/LinearTransferFunction.h @@ -28,7 +28,7 @@ namespace ospray { /*! \brief A concrete implementation of the TransferFunction class for piecewise linear transfer functions. */ - class LinearTransferFunction : public TransferFunction + class OSPRAY_SDK_INTERFACE LinearTransferFunction : public TransferFunction { public: diff --git a/ospray/transferFunction/LinearTransferFunction.ih b/ospray/transferFunction/LinearTransferFunction.ih index 6400a95a5b..d3884b4297 100644 --- a/ospray/transferFunction/LinearTransferFunction.ih +++ b/ospray/transferFunction/LinearTransferFunction.ih @@ -27,11 +27,13 @@ struct LinearTransferFunction { //! Transfer function opacity values and count. uniform float *uniform opacityValues; - uniform int opacityValueCount; + uniform int opacityValueCount; + uniform float* uniform opacityPITable; //! Transfer function color values and count. uniform vec3f *uniform colorValues; uniform int colorValueCount; + uniform vec3f *uniform colorPITable; //! A 2D array that contains precomputed minimum and maximum opacity values for a transfer function. vec2f minMaxOpacityInRange[PRECOMPUTED_OPACITY_SUBRANGE_COUNT][PRECOMPUTED_OPACITY_SUBRANGE_COUNT]; diff --git a/ospray/transferFunction/LinearTransferFunction.ispc b/ospray/transferFunction/LinearTransferFunction.ispc index a842fe6f26..7ba031e766 100644 --- a/ospray/transferFunction/LinearTransferFunction.ispc +++ b/ospray/transferFunction/LinearTransferFunction.ispc @@ -56,6 +56,184 @@ LinearTransferFunction_getColorForValue(const void *uniform _self, + remainder * self->colorValues[min(index + 1, self->colorValueCount - 1)]); } +inline varying float +LinearTransferFunction_getIntegratedOpacityForValue(const void *uniform _self, + varying float value1, varying float value2) +{ + if (value1 > value2) + { + float tmpVal = value1; + value1 = value2; + value2 = tmpVal; + } + // Return 0 for NaN values. + if (isnan(value1) || isnan(value2)) return 0.0f; + + // Cast to the actual TransferFunction subtype. + const LinearTransferFunction *uniform self + = (const LinearTransferFunction *uniform) _self; + + // No opacity values may be available. + if (self->opacityValueCount == 0) + return 1.0f; + + // Clamp the value to the lower bound of the value range. + if (value2 <= self->super.valueRange.x) + value2 = self->super.valueRange.x; + + // Clamp the value to the lower bound of the value range. + if (value1 <= self->super.valueRange.x) + value1 = self->super.valueRange.x; + + // Clamp the value to the upper bound of the value range. + if (value2 >= self->super.valueRange.y) + value2 = self->super.valueRange.y; + + // Clamp the value to the upper bound of the value range. + if (value1 >= self->super.valueRange.y) + value1 = self->super.valueRange.y; + + // Map the value into the range [0.0, numValues). + const float remapped1 + = (value1 - self->super.valueRange.x) + / (self->super.valueRange.y - self->super.valueRange.x) + * (self->opacityValueCount - 1.0f); + + const float remapped2 + = (value2 - self->super.valueRange.x) + / (self->super.valueRange.y - self->super.valueRange.x) + * (self->opacityValueCount - 1.0f); + + // Compute the opacity index and fractional offset. + int index1 = floor(remapped1); + float remainder1 = remapped1 - index1; + + // The interpolated opacity. + float interpval1 = + (1.0f - remainder1) * self->opacityValues[index1] + + remainder1 * self->opacityValues[min(index1 + 1, self->opacityValueCount - 1)]; + + // Compute the opacity index and fractional offset. + int index2 = floor(remapped2); + float remainder2 = remapped2 - index2; + + // The interpolated opacity. + float interpval2 = + (1.0f - remainder2) * self->opacityValues[index2] + + remainder2 * self->opacityValues[min(index2 + 1, self->opacityValueCount - 1)]; + + float ret = 0.f; + + // ret += interpval2 + interpval1; + // int numAdded = 0; + // for (int i=index1+1;iopacityValueCount;i++) + // { + // ret += self->opacityValues[i]; + // numAdded++; + // } + // ret = ret / (2.f+numAdded); + + //return ret; + if (index2 - index1 > 1) + ret += self->opacityPITable[(index1+1)+(index2-1)*self->opacityValueCount]; + return (ret + interpval1 + interpval2)/(index2-index1+1); +} + +inline varying vec3f +LinearTransferFunction_getIntegratedColorForValue(const void *uniform _self, + varying float value1, varying float value2) +{ + //TODO: use lookup table, but for now I don't notice much of a slowdown + // Return (0,0,0) for NaN values. + if (isnan(value1) || isnan(value2)) + return make_vec3f(0.0f); + + // Cast to the actual TransferFunction subtype. + const LinearTransferFunction *uniform self + = (const LinearTransferFunction *uniform) _self; + + // No color values may be available. + if (self->colorValueCount == 0) + return make_vec3f(1.0f); + + if (value1 > value2) + { + float tmpVal = value1; + value1 = value2; + value2 = tmpVal; + } + + // Clamp the value to the upper bound of the value range. + if (value1 > self->super.valueRange.y) + value1 = self->super.valueRange.y; + + // Clamp the value to the upper bound of the value range. + if (value2 > self->super.valueRange.y) + value2 = self->super.valueRange.y; + + // Clamp the value to the upper bound of the value range. + if (value1 < self->super.valueRange.x) + value1 = self->super.valueRange.x; + + // Clamp the value to the upper bound of the value range. + if (value2 < self->super.valueRange.x) + value2 = self->super.valueRange.x; + + // Map the value into the range [0.0, 1.0]. + value1 + = (value1 - self->super.valueRange.x) + / (self->super.valueRange.y - self->super.valueRange.x) + * (self->colorValueCount - 1.0f); + + // Compute the color index and fractional offset. + int index1 = floor(value1); + float remainder1 = value1 - index1; + // The interpolated opacity. + int oindex1 = min((value1)/((float)(self->colorValueCount-1))*((float)(self->opacityValueCount-1)),self->opacityValueCount-1); + float opacity1 = + (1.0f - remainder1) * self->opacityValues[oindex1] + + remainder1 * self->opacityValues[min(oindex1 + 1, self->opacityValueCount - 1)]; + + // The interpolated color. + vec3f interpColor1 = ((1.0f - remainder1) * self->colorValues[index1] + + remainder1 * self->colorValues[min(index1 + 1, self->colorValueCount - 1)]); + + // Map the value into the range [0.0, 1.0]. + value2 + = (value2 - self->super.valueRange.x) + / (self->super.valueRange.y - self->super.valueRange.x) + * (self->colorValueCount - 1.0f); + + // Compute the color index and fractional offset. + int index2 = floor(value2); + float remainder2 = value2 - index2; + int oindex2 = min((value2)/((float)(self->colorValueCount-1))*((float)(self->opacityValueCount-1)),self->opacityValueCount-1); + float opacity2 = + (1.0f - remainder1) * self->opacityValues[oindex2] + + remainder1 * self->opacityValues[min(oindex2 + 1, self->opacityValueCount - 1)]; + + // The interpolated color. + vec3f interpColor2 = ((1.0f - remainder2) * self->colorValues[index2] + + remainder2 * self->colorValues[min(index2 + 1, self->colorValueCount - 1)]); + + vec3f ret = make_vec3f(0.f); + + // ret = interpColor1 + interpColor2; + // int numAdded = 0; + // for (int i=index1+1;icolorValueCount;i++) + // { + // ret = ret + self->colorValues[i]; + // numAdded++; + // } + // ret = ret / (2.f+numAdded); + + // return ret; + //if (index2 - index1 >= 2) + // ret = self->colorPITable[(index1+1)+(index2-1)*self->colorValueCount]; + float dev = max((index2-index1+1.f),2.f); + return (ret + (interpColor1*opacity1 + interpColor2*opacity2)*2.f/(opacity1+opacity2+1e-5f))/dev; +} + uniform vec2f LinearTransferFunction_getMinMaxOpacityInRange(void *uniform _self, const uniform vec2f &range) @@ -174,9 +352,15 @@ export void *uniform LinearTransferFunction_createInstance() // Function to get the interpolated color for a given value. self->super.getColorForValue = LinearTransferFunction_getColorForValue; + // Function to get the interpolated color for a given value. + self->super.getIntegratedColorForValue = LinearTransferFunction_getIntegratedColorForValue; + // Function to get the interpolated opacity for a given value. self->super.getOpacityForValue = LinearTransferFunction_getOpacityForValue; + // Function to get the interpolated opacity for a given value. + self->super.getIntegratedOpacityForValue = LinearTransferFunction_getIntegratedOpacityForValue; + // Virtual function to look up the maximum opacity based on an input range. self->super.getMaxOpacityInRange = LinearTransferFunction_getMaxOpacityInRange; @@ -186,10 +370,12 @@ export void *uniform LinearTransferFunction_createInstance() // Transfer function colors and count. self->colorValues = NULL; self->colorValueCount = 0; + self->colorPITable = NULL; // Transfer function opacity values and count. self->opacityValues = NULL; self->opacityValueCount = 0; + self->opacityPITable = NULL; // The default transfer function value range. self->super.valueRange = make_vec2f(0.0f, 1.0f); @@ -198,6 +384,66 @@ export void *uniform LinearTransferFunction_createInstance() return self; } +void LinearTransferFunction_precomputePreIntegratedOpacityValues(void* uniform _self) +{ + // Cast to the actual TransferFunction subtype. + LinearTransferFunction *uniform self + = (LinearTransferFunction *uniform) _self; + + if (self->opacityPITable) + delete[] self->opacityPITable; + self->opacityPITable = uniform new uniform float[self->opacityValueCount*self->opacityValueCount]; + + for(int i=0;iopacityValueCount;i++) + { + for(int j=0;jopacityValueCount;j++) + { + if (j < i) + continue; + float val = 0.f; + for (int k = i; k <= j; k++) + val += self->opacityValues[k]; + self->opacityPITable[j*self->opacityValueCount+i] = val; + } + } +} + +void LinearTransferFunction_precomputePreIntegratedColorValues(void* uniform _self) +{ + // Cast to the actual TransferFunction subtype. + LinearTransferFunction *uniform self + = (LinearTransferFunction *uniform) _self; + + if (self->colorPITable) + delete[] self->colorPITable; + self->colorPITable = uniform new uniform vec3f[self->colorValueCount*self->colorValueCount]; + + for(int i=0;icolorValueCount;i++) + { + for(int j=0;jcolorValueCount;j++) + { + if (j < i) + continue; + vec3f val = make_vec3f(0.f); + float opacityAccum = 0.f; + for (int k = i; k <= j; k++) + { + const float interp = ((float)k)/(float)self->colorValueCount; + float opacity = 1.f; + if (self->opacityValueCount > 0) + { + opacity = self->opacityValues[interp*self->opacityValueCount]; + } + val = val + self->colorValues[k]*opacity; + opacityAccum += opacity; + } + if (opacityAccum > 0.f) + val = val/opacityAccum; + self->colorPITable[j*self->colorValueCount+i] = val; + } + } +} + export void LinearTransferFunction_destroy(void *uniform _self) { // Cast to the actual TransferFunction subtype. @@ -232,6 +478,7 @@ export void LinearTransferFunction_setColorValues(void *uniform _self, for (uniform size_t i=0; i < count; i++) self->colorValues[i] = source[i]; + LinearTransferFunction_precomputePreIntegratedColorValues(_self); } export void LinearTransferFunction_setOpacityValues(void *uniform _self, @@ -260,4 +507,6 @@ export void LinearTransferFunction_setOpacityValues(void *uniform _self, // Precompute the min / max opacity ranges. LinearTransferFunction_precomputeMinMaxOpacityRanges(_self); + LinearTransferFunction_precomputePreIntegratedOpacityValues(_self); + } diff --git a/ospray/transferFunction/TransferFunction.cpp b/ospray/transferFunction/TransferFunction.cpp index 12d06419e3..4f7ebe2f97 100644 --- a/ospray/transferFunction/TransferFunction.cpp +++ b/ospray/transferFunction/TransferFunction.cpp @@ -37,7 +37,7 @@ namespace ospray { return((*symbolRegistry[type])()); // Otherwise construct the name of the creation function to look for. - std::string creationFunctionName = "ospray_create_transfer_function_" + type; + std::string creationFunctionName = "ospray_create_transfer_function__" + type; // Look for the named function. symbolRegistry[type] = (creationFunctionPointer) getSymbol(creationFunctionName); diff --git a/ospray/transferFunction/TransferFunction.h b/ospray/transferFunction/TransferFunction.h index 532d283989..1b330bf15e 100644 --- a/ospray/transferFunction/TransferFunction.h +++ b/ospray/transferFunction/TransferFunction.h @@ -18,31 +18,18 @@ #include "common/Managed.h" -/*! \brief Define a function to create an instance of the InternalClass - associated with ExternalName. - - \internal The function generated by this macro is used to create an - instance of a concrete subtype of an abstract base class. This - macro is needed since the subclass type may not be known to OSPRay - at build time. Rather, the subclass can be defined in an external - module and registered with OSPRay using this macro. -*/ -#define OSP_REGISTER_TRANSFER_FUNCTION(InternalClass, ExternalName) \ - extern "C" OSPRAY_INTERFACE TransferFunction *ospray_create_transfer_function_##ExternalName() \ - { return(new InternalClass()); } - namespace ospray { /*! \brief A TransferFunction is an abstraction that maps a value to a color and opacity for rendering. - + The actual mapping is unknown to this class, and is implemented in subclasses. A type string specifies a particular concrete implementation to createInstance(). This type string must be registered in OSPRay proper, or in a loaded module using OSP_REGISTER_TRANSFER_FUNCTION. */ - class TransferFunction : public ManagedObject + class OSPRAY_SDK_INTERFACE TransferFunction : public ManagedObject { public: @@ -65,5 +52,16 @@ namespace ospray { }; -} // ::ospray +/*! \brief Define a function to create an instance of the InternalClass + associated with external_name. + + \internal The function generated by this macro is used to create an + instance of a concrete subtype of an abstract base class. This + macro is needed since the subclass type may not be known to OSPRay + at build time. Rather, the subclass can be defined in an external + module and registered with OSPRay using this macro. +*/ +#define OSP_REGISTER_TRANSFER_FUNCTION(InternalClass, external_name) \ + OSP_REGISTER_OBJECT(TransferFunction, transfer_function, InternalClass, external_name) +} // ::ospray diff --git a/ospray/transferFunction/TransferFunction.ih b/ospray/transferFunction/TransferFunction.ih index b090661e77..5ae7a6631f 100644 --- a/ospray/transferFunction/TransferFunction.ih +++ b/ospray/transferFunction/TransferFunction.ih @@ -29,9 +29,18 @@ struct TransferFunction { varying vec3f (*getColorForValue)(const void *uniform transferFunction, varying float value); + + //! Interpolated color for the given value. + varying vec3f (*getIntegratedColorForValue)(const void *uniform transferFunction, + varying float value1, varying float value2); + //! Interpolated opacity for the given value. varying float (*getOpacityForValue)(const void *uniform transferFunction, varying float value); + + //! Interpolated opacity for the given value. + varying float (*getIntegratedOpacityForValue)(const void *uniform transferFunction, + varying float value1, varying float value2); //! Virtual function to look up the maximum opacity value based on an input range. varying float (*getMaxOpacityInRange)(void *uniform transferFunction, diff --git a/ospray/volume/BlockBrickedVolume.h b/ospray/volume/BlockBrickedVolume.h index 0089bae0b5..7c95d2c068 100644 --- a/ospray/volume/BlockBrickedVolume.h +++ b/ospray/volume/BlockBrickedVolume.h @@ -24,7 +24,7 @@ namespace ospray { //! with 64-bit addressing in which the voxel data is laid out in //! memory in multiple pages each in brick order. //! - class BlockBrickedVolume : public StructuredVolume { + class OSPRAY_SDK_INTERFACE BlockBrickedVolume : public StructuredVolume { public: ~BlockBrickedVolume(); diff --git a/ospray/volume/DataDistributedBlockedVolume.cpp b/ospray/volume/DataDistributedBlockedVolume.cpp index fb04b5bb27..d533d1f35a 100644 --- a/ospray/volume/DataDistributedBlockedVolume.cpp +++ b/ospray/volume/DataDistributedBlockedVolume.cpp @@ -42,7 +42,7 @@ namespace ospray { StructuredVolume::commit(); - for (int i=0;iisMine) { continue; @@ -61,7 +61,7 @@ namespace ospray { void DataDistributedBlockedVolume::updateEditableParameters() { StructuredVolume::updateEditableParameters(); - for (int i=0;iisMine) { @@ -132,7 +132,7 @@ namespace ospray { finalRegionSize = regionSize; } - for (int i=0;i 0.0f) return; + if (maximumOpacity > 0.0f) + { + return; + } + + // Exit bound of the grid cell in world coordinates. + vec3f farBound; + volume->transformLocalToWorld(volume, + float_cast(cellIndex + + nextCellIndex << + CELL_WIDTH_BITCOUNT), + farBound); + + // Identify the distance along the ray to the exit points on the cell. + const vec3f maximum = ray_rdir * (farBound - ray.org); + const float exitDist = min(min(ray.t, maximum.x), + min(maximum.y, maximum.z)); + + // Advance the ray so the next hit point will be outside the empty cell. + ray.t0 += ceil(abs(exitDist - ray.t0) / step) * step; + } +} + +void GridAccelerator_intersectAdaptive(GridAccelerator *uniform accelerator, + const varying float step, varying Ray &ray) +{ + // The associated volume. + StructuredVolume *uniform volume = + (StructuredVolume *uniform) accelerator->volume; + + // Tentatively advance the ray. + ray.t0 += step; + ray.time = step; + + const vec3f ray_rdir = rcp(ray.dir); + // sign of direction determines near/far index + const vec3i nextCellIndex = make_vec3i(1 - (intbits(ray.dir.x) >> 31), + 1 - (intbits(ray.dir.y) >> 31), + 1 - (intbits(ray.dir.z) >> 31)); + + while (ray.t0 < ray.t) { + + // Compute the hit point in the local coordinate system. + vec3f localCoordinates; + volume->transformWorldToLocal(volume, + ray.org + ray.t0 * ray.dir, + localCoordinates); + + // Compute the 3D index of the cell containing the hit point. + vec3i cellIndex = integer_cast(localCoordinates) >> CELL_WIDTH_BITCOUNT; + + // If we visited this cell before then it must not be empty. + if (ray.geomID == cellIndex.x && + ray.primID == cellIndex.y && + ray.instID == cellIndex.z) + return; + + // Track the hit cell. + ray.geomID = cellIndex.x; + ray.primID = cellIndex.y; + ray.instID = cellIndex.z; + + // Get the volumetric value range of the cell. + vec2f cellRange; + GridAccelerator_getCellRange(accelerator, cellIndex, cellRange); + + // Get the maximum opacity in the volumetric value range. + float maximumOpacity = + volume->super.transferFunction->getMaxOpacityInRange(volume->super.transferFunction, + cellRange); + + // Return the hit point if the grid cell is not fully transparent. + if (maximumOpacity > 0.0f) + { + //adaptive sampling based on maximum opacity in cell + //ray.t0 -= step; + //float adaptiveStep = min(1.f/(maximumOpacity), 2.f)*step; + //print("maximum %\n", maximumOpacity); + //adaptiveStep = step; + //ray.t0 += adaptiveStep; + //ray.time = adaptiveStep; + return; + } // Exit bound of the grid cell in world coordinates. vec3f farBound; diff --git a/ospray/volume/SharedStructuredVolume.h b/ospray/volume/SharedStructuredVolume.h index 8b736208bd..1f40f4ae6b 100644 --- a/ospray/volume/SharedStructuredVolume.h +++ b/ospray/volume/SharedStructuredVolume.h @@ -24,7 +24,7 @@ namespace ospray { //! in which the voxel data is laid out in memory in XYZ order and //! provided via a shared data buffer. //! - class SharedStructuredVolume : public StructuredVolume { + class OSPRAY_SDK_INTERFACE SharedStructuredVolume : public StructuredVolume { public: //! Constructor. diff --git a/ospray/volume/SharedStructuredVolume.ispc b/ospray/volume/SharedStructuredVolume.ispc index 77ca4106e2..d719c27301 100644 --- a/ospray/volume/SharedStructuredVolume.ispc +++ b/ospray/volume/SharedStructuredVolume.ispc @@ -272,7 +272,7 @@ void SharedStructuredVolume_Constructor(SharedStructuredVolume *uniform self, if (voxelType == OSP_UCHAR) bytesPerVoxel = sizeof(uniform uint8); - if (voxelType == OSP_USHORT) + else if (voxelType == OSP_USHORT) bytesPerVoxel = sizeof(uniform uint16); else if (voxelType == OSP_FLOAT) bytesPerVoxel = sizeof(uniform float); diff --git a/ospray/volume/StructuredVolume.h b/ospray/volume/StructuredVolume.h index ac1b2f7740..1e855570ca 100644 --- a/ospray/volume/StructuredVolume.h +++ b/ospray/volume/StructuredVolume.h @@ -33,10 +33,10 @@ namespace ospray { type string passed to Volume::createInstance() specifies a particular concrete implementation. This type string must be registered in OSPRay proper, or in a loaded module via - OSP_REGISTER_VOLUME. To place the volume in world coordinates, + OSP_REGISTER_VOLUME. To place the volume in world coordinates, modify the gridOrigin and gridSpacing to translate and scale the volume. */ - class StructuredVolume : public Volume { + class OSPRAY_SDK_INTERFACE StructuredVolume : public Volume { public: //! Constructor. @@ -145,7 +145,7 @@ namespace ospray { #endif template void StructuredVolume::upsampleRegion(const T *source, T *out, const vec3i ®ionSize, const vec3i &scaledRegionSize){ - for (size_t z = 0; z < scaledRegionSize.z; ++z){ + for (int z = 0; z < scaledRegionSize.z; ++z){ parallel_for(scaledRegionSize.x * scaledRegionSize.y, [&](int taskID){ int x = taskID % scaledRegionSize.x; int y = taskID / scaledRegionSize.x; diff --git a/ospray/volume/StructuredVolume.ispc b/ospray/volume/StructuredVolume.ispc index ca9ee1656b..d35453cf02 100644 --- a/ospray/volume/StructuredVolume.ispc +++ b/ospray/volume/StructuredVolume.ispc @@ -112,6 +112,7 @@ inline varying vec3f StructuredVolume_computeGradient(void *uniform _volume, con #endif } +// ray.time is set to interval length of intersected sample inline void StructuredVolume_intersect(void *uniform _volume, varying Ray &ray) { // Cast to the actual Volume subtype. @@ -122,8 +123,19 @@ inline void StructuredVolume_intersect(void *uniform _volume, varying Ray &ray) // Compute the next hit point using a spatial acceleration structure. GridAccelerator_intersect(volume->accelerator, step, ray); +} + +// ray.time is set to interval length of intersected sample +inline void StructuredVolume_intersectAdaptive(void *uniform _volume, varying Ray &ray, const varying float samplingRate) +{ + // Cast to the actual Volume subtype. + StructuredVolume *uniform volume = (StructuredVolume *uniform) _volume; + + // The recommended step size for ray casting based volume renderers. + const varying float step = volume->super.samplingStep / samplingRate; -//ray.t0 += step; + // Compute the next hit point using a spatial acceleration structure. + GridAccelerator_intersectAdaptive(volume->accelerator, step, ray); } inline void StructuredVolume_intersectIsosurface(void *uniform _volume, uniform float *uniform isovalues, uniform int numIsovalues, varying Ray &ray) @@ -167,6 +179,7 @@ void StructuredVolume_Constructor(StructuredVolume *uniform volume, volume->super.computeSample = StructuredVolume_computeSample; volume->super.computeGradient = StructuredVolume_computeGradient; volume->super.intersect = StructuredVolume_intersect; + volume->super.intersectAdaptive = StructuredVolume_intersectAdaptive; volume->super.intersectIsosurface = StructuredVolume_intersectIsosurface; } diff --git a/ospray/volume/Volume.cpp b/ospray/volume/Volume.cpp index 68b28334bc..0863c9c9f9 100644 --- a/ospray/volume/Volume.cpp +++ b/ospray/volume/Volume.cpp @@ -52,7 +52,7 @@ namespace ospray { if (symbolRegistry.count(type) == 0) { // Construct the name of the creation function to look for. - std::string creationFunctionName = "ospray_create_volume_" + type; + std::string creationFunctionName = "ospray_create_volume__" + type; // Look for the named function. symbolRegistry[type] = @@ -123,10 +123,34 @@ namespace ospray { getParam1i("gradientShadingEnabled", 0)); + ispc::Volume_setPreIntegration(ispcEquivalent, + getParam1i("preIntegration", + 0)); + + ispc::Volume_setSingleShade(ispcEquivalent, + getParam1i("singleShade", + 1)); + + ispc::Volume_setAdaptiveSampling(ispcEquivalent, + getParam1i("adaptiveSampling", + 1)); + + ispc::Volume_setAdaptiveScalar(ispcEquivalent, + getParam1f("adaptiveScalar", 15.0f)); + + ispc::Volume_setAdaptiveMaxSamplingRate(ispcEquivalent, + getParam1f("adaptiveMaxSamplingRate", 0.7f)); + + ispc::Volume_setAdaptiveBacktrack(ispcEquivalent, + getParam1f("adaptiveBacktrack", 0.03f)); + // Set the recommended sampling rate for ray casting based renderers. ispc::Volume_setSamplingRate(ispcEquivalent, getParam1f("samplingRate", 1.0f)); + vec3f specular = getParam3f("specular", vec3f(0.3f)); + ispc::Volume_setSpecular(ispcEquivalent, (const ispc::vec3f &)specular); + // Set the transfer function. TransferFunction *transferFunction = (TransferFunction *) getParamObject("transferFunction", NULL); diff --git a/ospray/volume/Volume.h b/ospray/volume/Volume.h index 6f8f885fd5..72f5a220a0 100644 --- a/ospray/volume/Volume.h +++ b/ospray/volume/Volume.h @@ -18,26 +18,11 @@ #include "common/Managed.h" -/*! \brief Define a function to create an instance of the InternalClass - associated with ExternalName. - - \internal The function generated by this macro is used to create an - instance of a concrete subtype of an abstract base class. This - macro is needed since the subclass type may not be known to OSPRay - at build time. Rather, the subclass can be defined in an external - module and registered with OSPRay using this macro. -*/ -#define OSP_REGISTER_VOLUME(InternalClass, ExternalName) \ - extern "C" OSPRAY_INTERFACE Volume *ospray_create_volume_##ExternalName() \ - { \ - return(new InternalClass()); \ - } - namespace ospray { /*! \brief A Volume is an abstraction for the concrete object which performs the volume sampling. - + The actual memory layout, dimensionality, and source of samples are unknown to this class. Subclasses may implement structured volumes, unstructured volumes, radial basis functions, etc. A @@ -45,12 +30,12 @@ namespace ospray { createInstance(). This type string must be registered either in OSPRay proper, or in a loaded module using OSP_REGISTER_VOLUME. */ - class Volume : public ManagedObject + class OSPRAY_SDK_INTERFACE Volume : public ManagedObject { public: #if EXP_DATA_PARALLEL - struct DataParallelPiece : public RefCount { + struct OSPRAY_SDK_INTERFACE DataParallelPiece : public RefCount { /*! world space bounding box of this piece. it is assumed that this covers all the space that rays should be integrating over; so _including_ any ghost cells if those are required @@ -106,5 +91,16 @@ namespace ospray { virtual void finish(); }; -} // ::ospray +/*! \brief Define a function to create an instance of the InternalClass + associated with external_name. + + \internal The function generated by this macro is used to create an + instance of a concrete subtype of an abstract base class. This + macro is needed since the subclass type may not be known to OSPRay + at build time. Rather, the subclass can be defined in an external + module and registered with OSPRay using this macro. +*/ +#define OSP_REGISTER_VOLUME(InternalClass, external_name) \ + OSP_REGISTER_OBJECT(Volume, volume, InternalClass, external_name) +} // ::ospray diff --git a/ospray/volume/Volume.ih b/ospray/volume/Volume.ih index 55f363f894..72e40f56ed 100644 --- a/ospray/volume/Volume.ih +++ b/ospray/volume/Volume.ih @@ -42,12 +42,32 @@ struct Volume { //! Allow the renderer to perform gradient shading. uniform bool gradientShadingEnabled; + //! Only shade maximum opacity point, if gradientShadingEnabled == 1 + uniform bool singleShade; + + //! Integrates over transfer function values, good for high frequency tf + uniform bool preIntegration; + + //! Adaptively alter the sampling rate according to the sampled values + uniform bool adaptiveSampling; + + //! scalar to multiply step size for adaptive calculation + uniform float adaptiveScalar; + + //! maximum adaptive sampling rate + uniform float adaptiveMaxSamplingRate; + + //! what value to backstep for adaptie sampling, will step back and sample finely + uniform float adaptiveBacktrack; + //! Recommended sampling step size for ray casting based renderers, set by the underlying volume implementation. uniform float samplingStep; //! Recommended sampling rate for the renderer. uniform float samplingRate; + uniform vec3f specular; + //! Color and opacity transfer function. TransferFunction *uniform transferFunction; @@ -65,6 +85,9 @@ struct Volume { //! Find the next hit point in the volume for ray casting based renderers. void (*uniform intersect)(void *uniform _self, varying Ray &ray); + //! Find the next hit point in the volume for ray casting based renderers. + void (*uniform intersectAdaptive)(void *uniform _self, varying Ray &ray, const varying float samplingRate); + //! Find the next isosurface hit point in the volume for ray casting based renderers. void (*uniform intersectIsosurface)(void *uniform _self, uniform float *uniform isovalues, diff --git a/ospray/volume/Volume.ispc b/ospray/volume/Volume.ispc index f3a5f7c924..49de491372 100644 --- a/ospray/volume/Volume.ispc +++ b/ospray/volume/Volume.ispc @@ -44,12 +44,54 @@ export void Volume_setGradientShadingEnabled(void *uniform _self, const uniform self->gradientShadingEnabled = value; } +export void Volume_setPreIntegration(void *uniform _self, const uniform bool &value) +{ + uniform Volume *uniform self = (uniform Volume *uniform)_self; + self->preIntegration = value; +} + +export void Volume_setSingleShade(void *uniform _self, const uniform bool &value) +{ + uniform Volume *uniform self = (uniform Volume *uniform)_self; + self->singleShade = value; +} + +export void Volume_setAdaptiveSampling(void *uniform _self, const uniform bool &value) +{ + uniform Volume *uniform self = (uniform Volume *uniform)_self; + self->adaptiveSampling = value; +} + +export void Volume_setAdaptiveScalar(void *uniform _self, const uniform float &value) +{ + uniform Volume *uniform self = (uniform Volume *uniform)_self; + self->adaptiveScalar = value; +} + +export void Volume_setAdaptiveMaxSamplingRate(void *uniform _self, const uniform float &value) +{ + uniform Volume *uniform self = (uniform Volume *uniform)_self; + self->adaptiveMaxSamplingRate = value; +} + +export void Volume_setAdaptiveBacktrack(void *uniform _self, const uniform float &value) +{ + uniform Volume *uniform self = (uniform Volume *uniform)_self; + self->adaptiveBacktrack = value; +} + export void Volume_setSamplingRate(void *uniform _self, const uniform float value) { uniform Volume *uniform self = (uniform Volume *uniform)_self; self->samplingRate = value; } +export void Volume_setSpecular(void *uniform _self, const uniform vec3f &value) +{ + uniform Volume *uniform self = (uniform Volume *uniform)_self; + self->specular = value; +} + export void Volume_setTransferFunction(void *uniform _self, void *uniform value) { uniform Volume *uniform self = (uniform Volume *uniform)_self; diff --git a/scripts/bench/README b/scripts/bench/README new file mode 100644 index 0000000000..b6b0a3818a --- /dev/null +++ b/scripts/bench/README @@ -0,0 +1,32 @@ +Running Benchmarks +------------------ + +1. Build OSPRay + +Compile OSPRay in a build directory of your choosing. We will refer +to this directory as ${OSPRAY_BUILD_DIR}. + +2. Fetch bechmark data using provided script + +In ${OSPRAY_BUILD_DIR}, run the "get_benchmark_data.sh" script. Thus +from a "build" directory inside your cloned OSPRay source, you would +run: + +% ../scripts/bench/get_benchmark_data.sh + +3. Run benchmark script + +In ${OSPRAY_BUILD_DIR}, run the "run_benchmark.sh" script. Using the +same directory structure from step 2, you would run: + +% ../scripts/bench/run_benchmark_sh + +The benchmarks will use a 1024x1024 frame buffer by default, which can +be modified by passing the width and height to the script. For example, +to run the benchmarks at 1024x768, you would run: + +% ../scripts/bench/run_benchmark_sh 1024 768 + +The images rendered for each benchmark are saved into a directory (which +is created if it doesn't exist) "test_images", where each image is saved +as a .ppm file. diff --git a/scripts/bench/get_benchmark_data.sh b/scripts/bench/get_benchmark_data.sh new file mode 100755 index 0000000000..fb0cbfb0c3 --- /dev/null +++ b/scripts/bench/get_benchmark_data.sh @@ -0,0 +1,38 @@ +#!/bin/sh + +data_dir="test_data" + +# Create data directory and fill it +if [ ! -d ${data_dir} ]; then + mkdir ${data_dir} +fi + +cd ${data_dir} + +# FIU +fiu="fiu.bz2" +if [ ! -e ${fiu} ]; then + wget http://sdvis.org/~jdamstut/test_data/${fiu} + tar -xaf ${fiu} +fi + +# HEPTANE +csafe="csafe.bz2" +if [ ! -e ${csafe} ]; then + wget http://sdvis.org/~jdamstut/test_data/${csafe} + tar -xaf ${csafe} +fi + +# MAGNETIC +magnetic="magnetic-512-volume.bz2" +if [ ! -e ${magnetic} ]; then + wget http://sdvis.org/~jdamstut/test_data/${magnetic} + tar -xaf ${magnetic} +fi + +# LLNL ISO +llnl_iso="llnl-2048-iso.tar.bz2" +if [ ! -e ${llnl_iso} ]; then + wget http://sdvis.org/~jdamstut/test_data/${llnl_iso} + tar -xaf ${llnl_iso} +fi diff --git a/scripts/bench/run_benchmark.sh b/scripts/bench/run_benchmark.sh new file mode 100755 index 0000000000..4c5b87b6ed --- /dev/null +++ b/scripts/bench/run_benchmark.sh @@ -0,0 +1,189 @@ +#!/bin/sh + +if [ $# -lt 2 ]; then + echo "No dimensions passed, using defaults" + bench_img_width=1024 + bench_img_height=1024 +else + bench_img_width=$1 + bench_img_height=$2 +fi + +echo "All tests run at $bench_img_width x $bench_img_height" + +exe="./ospBenchmark -w $bench_img_width -h $bench_img_height" + +img_dir="test_images" + +# Create image directory +if [ ! -d ${img_dir} ]; then + mkdir ${img_dir} +fi + +# Test counter +test_num=0 + +# FIU TESTS ################################################################# + +fiu="test_data/fiu-groundwater.xml" + +echo -n "test[$test_num] : " + +# FIU/scivis/view 1 +${exe} ${fiu} \ + -vp 500.804565 277.327850 -529.199829 \ + -vu 0.000000 1.000000 0.000000 \ + -vi 21.162066 -62.059830 -559.833313 \ + -r scivis \ + -i ${img_dir}/test_${test_num} + +echo " : FIU/scivis/view 1" + +test_num=$((test_num+1)) + +echo -n "test[$test_num] : " + +# FIU/scivis/view 2 +${exe} ${fiu} \ + -vp -29.490566 80.756294 -526.728516 \ + -vu 0.000000 1.000000 0.000000 \ + -vi 21.111689 12.973234 -443.164886 \ + -r scivis \ + -i ${img_dir}/test_${test_num} + +echo " : FIU/scivis/view 2" + +test_num=$((test_num+1)) + +# HEPTANE TESTS ############################################################## + +csafe="test_data/csafe-heptane-302-volume.osp" + +echo -n "test[$test_num] : " + +# CSAFE/scivis/view 1 +${exe} ${csafe} \ + -r scivis \ + -vp 286.899994 422.800018 -30.200012 \ + -vi 151.000000 151.000000 151.000000 \ + -vu 0 1 0 \ + -tfc 0 0 0 0.00 \ + -tfc 1 0 0 0.11 \ + -tfc 1 1 0 0.22 \ + -tfc 1 1 1 0.33 \ + -tfs 0.25 \ + -i ${img_dir}/test_${test_num} + +echo " : CSAFE/scivis/view 1" + +test_num=$((test_num+1)) + +echo -n "test[$test_num] : " + +# CSAFE/scivis/view 2 +${exe} ${csafe} \ + -r scivis \ + -vp -36.2362 86.8541 230.026 \ + -vi 150.5 150.5 150.5 \ + -vu 0 0 1 \ + -tfc 0 0 0 0.00 \ + -tfc 1 0 0 0.11 \ + -tfc 1 1 0 0.22 \ + -tfc 1 1 1 0.33 \ + -tfs 0.25 \ + -i ${img_dir}/test_${test_num} + +echo " : CSAFE/scivis/view 2" + +test_num=$((test_num+1)) + +# MAGNETIC TESTS ############################################################# + +magnetic="test_data/magnetic-512-volume.osp" + +echo -n "test[$test_num] : " + +# MAGNETIC/scivis/view 1 +${exe} ${magnetic} \ + -r scivis \ + -vp 255.5 -1072.12 255.5 \ + -vi 255.5 255.5 255.5 \ + -vu 0 0 1 \ + -tfc 0.1 0.1 0.1 0 \ + -tfc 0 0 1 0.25 \ + -tfc 1 0 0 1 \ + -tfs 1 \ + -i ${img_dir}/test_${test_num} + +echo " : MAGNETIC/scivis/view 1" + +test_num=$((test_num+1)) + +echo -n "test[$test_num] : " + +# MAGNETIC/scivis/view 2 +${exe} ${magnetic} \ + -r scivis \ + -vp 431.923 -99.5843 408.068 \ + -vi 255.5 255.5 255.5 \ + -vu 0 0 1 \ + -tfc 0.1 0.1 0.1 0 \ + -tfc 0 0 1 0.25 \ + -tfc 1 0 0 1 \ + -tfs 1 \ + -i ${img_dir}/test_${test_num} + +echo " : MAGNETIC/scivis/view 2" + +test_num=$((test_num+1)) + +echo -n "test[$test_num] : " + +# MAGNETIC/scivis/view 2 + isosurface +${exe} ${magnetic} \ + -r scivis \ + -vp 431.923 -99.5843 408.068 \ + -vi 255.5 255.5 255.5 \ + -vu 0 0 1 \ + -tfc 0.1 0.1 0.1 0 \ + -tfc 0 0 1 0.25 \ + -tfc 1 0 0 1 \ + -tfs 1 \ + -is 2.0 \ + -i ${img_dir}/test_${test_num} + +echo " : MAGNETIC/scivis/view 2 + isosurface" + +test_num=$((test_num+1)) + +# LLNL ISO TESTS ############################################################ + +llnl_iso="test_data/llnl-2048-iso.xml" + +echo -n "test[$test_num] : " + +# LLNL_ISO/scivis/view 1 +${exe} ${llnl_iso} \ + -r scivis \ + -vp 3371.659912 210.557999 -443.156006 \ + -vu -0.000000 -0.000000 -1.000000 \ + -vi 1439.359985 1005.450012 871.119019 \ + -i ${img_dir}/test_${test_num} + +echo " : LLNL-ISO/scivis/view 1" + +test_num=$((test_num+1)) + +echo -n "test[$test_num] : " + +# LLNL_ISO/scivis/view 2 +${exe} ${llnl_iso} \ + -r scivis \ + -vp 2056.597168 999.748108 402.587219 \ + -vu -0.000000 -0.000000 -1.000000 \ + -vi 1439.358887 1005.449951 871.118164 \ + -i ${img_dir}/test_${test_num} + +echo " : LLNL-ISO/scivis/view 2" + +test_num=$((test_num+1)) diff --git a/scripts/build_gitlab/win.bat b/scripts/build_gitlab/win.bat index f0709ec108..f56d7a5bca 100755 --- a/scripts/build_gitlab/win.bat +++ b/scripts/build_gitlab/win.bat @@ -27,7 +27,6 @@ cmake -L ^ -D OSPRAY_BUILD_MIC_SUPPORT=OFF ^ -D OSPRAY_BUILD_MPI_DEVICE=ON ^ -D OSPRAY_USE_EXTERNAL_EMBREE=ON ^ --D embree_DIR=..\..\embree\lib\cmake\embree-2.9.0 ^ -D USE_IMAGE_MAGICK=OFF ^ .. diff --git a/scripts/release/linux.sh b/scripts/release/linux.sh index 6b0ab33af0..22cee3dba6 100755 --- a/scripts/release/linux.sh +++ b/scripts/release/linux.sh @@ -45,8 +45,8 @@ ROOT_DIR=$PWD DEP_DIR=$ROOT_DIR/deps DEP_LOCATION=http://sdvis.org/ospray/download/dependencies/linux -DEP_EMBREE=embree_dynamic-2.9.0.x86_64.linux -DEP_ISPC=ispc-v1.9.0-linux +DEP_EMBREE=embree-2.11.0.x86_64.linux +DEP_ISPC=ispc-v1.9.1-linux DEP_TBB=tbb44_20160413oss DEP_TARBALLS="$DEP_EMBREE.tar.gz $DEP_ISPC.tar.gz ${DEP_TBB}_lin.tgz" diff --git a/scripts/release/macosx.sh b/scripts/release/macosx.sh index 34b150b3cd..bc3d3e67f3 100755 --- a/scripts/release/macosx.sh +++ b/scripts/release/macosx.sh @@ -31,8 +31,8 @@ ROOT_DIR=$PWD DEP_DIR=$ROOT_DIR/deps DEP_LOCATION=http://sdvis.org/ospray/download/dependencies/osx -DEP_EMBREE=embree-2.9.0.x86_64.macosx -DEP_ISPC=ispc-v1.9.0-osx +DEP_EMBREE=embree-2.11.0.x86_64.macosx +DEP_ISPC=ispc-v1.9.1-osx DEP_TBB=tbb44_20160413oss DEP_TARBALLS="$DEP_EMBREE.tar.gz $DEP_ISPC.tar.gz ${DEP_TBB}_osx.tgz" diff --git a/scripts/release/win.bat b/scripts/release/win.bat index b729ee414e..791b5f9e6f 100755 --- a/scripts/release/win.bat +++ b/scripts/release/win.bat @@ -16,7 +16,6 @@ rem limitations under the License. rem rem ======================================================================== rem setlocal -rem set TBB_PATH_LOCAL=%cd%\tbb md build_release cd build_release @@ -24,12 +23,11 @@ cd build_release rem set release settings cmake -L ^ -G "Visual Studio 12 2013 Win64" ^ --T "Intel C++ Compiler 16.0" ^ +-T "Intel C++ Compiler 17.0" ^ -D OSPRAY_ZIP_MODE=OFF ^ -D OSPRAY_BUILD_ISA=ALL ^ -D OSPRAY_BUILD_MIC_SUPPORT=OFF ^ -D OSPRAY_USE_EXTERNAL_EMBREE=ON ^ --D embree_DIR=..\..\embree\lib\cmake\embree-2.9.0 ^ -D USE_IMAGE_MAGICK=OFF ^ -D CMAKE_INSTALL_INCLUDEDIR=include ^ -D CMAKE_INSTALL_LIBDIR=lib ^ @@ -37,15 +35,17 @@ cmake -L ^ -D CMAKE_INSTALL_DOCDIR=doc ^ -D CMAKE_INSTALL_BINDIR=bin ^ .. -rem -D TBB_ROOT=%TBB_PATH_LOCAL% ^ +if %ERRORLEVEL% GEQ 1 goto abort rem compile and create installers # option '--clean-first' somehow conflicts with options after '--' for msbuild cmake --build . --config Release --target PACKAGE -- /m /nologo +if %ERRORLEVEL% GEQ 1 goto abort rem create ZIP files cmake -D OSPRAY_ZIP_MODE=ON .. cmake --build . --config Release --target PACKAGE -- /m /nologo +if %ERRORLEVEL% GEQ 1 goto abort cd .. diff --git a/scripts/release/win.sh b/scripts/release/win.sh index 66d5260ecc..c2da3fef17 100755 --- a/scripts/release/win.sh +++ b/scripts/release/win.sh @@ -27,12 +27,11 @@ cd build_release # set release settings cmake -L \ -G "Visual Studio 12 2013 Win64" \ --T "Intel C++ Compiler 16.0" \ +-T "Intel C++ Compiler 17.0" \ -D OSPRAY_ZIP_MODE=OFF \ -D OSPRAY_BUILD_ISA=ALL \ -D OSPRAY_BUILD_MIC_SUPPORT=OFF \ -D OSPRAY_USE_EXTERNAL_EMBREE=ON \ --D embree_DIR=../../embree/lib/cmake/embree-2.9.0 \ -D USE_IMAGE_MAGICK=OFF \ -D CMAKE_INSTALL_INCLUDEDIR=include \ -D CMAKE_INSTALL_LIBDIR=lib \ @@ -40,7 +39,6 @@ cmake -L \ -D CMAKE_INSTALL_DOCDIR=doc \ -D CMAKE_INSTALL_BINDIR=bin \ .. -# -D TBB_ROOT=%TBB_PATH_LOCAL% \ # compile and create installers # option '--clean-first' somehow conflicts with options after '--' for msbuild