diff --git a/.gitignore b/.gitignore index 47a826c56e..8eb2a3180e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,16 @@ bin *.user* build +build_release *.sw? tags .ycm_extra_conf.pyc *.autosave +*.gz +*.rpm +*.zip +deps +tbb +embree +ispc +ospray-doc diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000000..92ca363043 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,151 @@ +stages: + - build + - deploy + +### BUILD JOBS ### + +build-centos6-gcc: + type: build + script: + - scripts/build_gitlab/linux.sh + tags: + - centos6 + - gcc + - build + +build-centos7-gcc: + type: build + script: + - scripts/build_gitlab/linux.sh + tags: + - centos7 + - gcc + - build + +build-fedora-gcc: + type: build + script: + - scripts/build_gitlab/linux.sh + tags: + - fedora + - gcc + - build + +build-ubuntu-gcc: + type: build + script: + - scripts/build_gitlab/linux.sh + tags: + - ubuntu + - gcc + - build + +#build-ubuntu-clang: +# type: build +# script: +# - export CC=clang +# - export CXX=clang++ +# - scripts/build_gitlab/linux.sh +# tags: +# - ubuntu +# - clang + +build-sles-gcc: + type: build + script: + - scripts/build_gitlab/linux.sh + tags: + - sles + - gcc + - build + +build-osx-clang: + type: build + script: + - scripts/build_gitlab/osx.sh + tags: + - osx + - clang + - build + +build-windows-msvc: + type: build + script: + - call scripts\build_gitlab\win.bat + tags: + - msvc + - build + - win7 + +### RELEASE JOBS ### + +#release-linux-gcc: +# type: deploy +# script: +# - module load gcc +# - export CC=gcc +# - export CXX=g++ +# - export OSPRAY_RELEASE_NO_VERIFY=1 +# - scripts/release/linux.sh +# tags: +# - gcc +# - release +# - centos6 +# only: +# - devel +# - master +# artifacts: +# paths: +# - build_release/*.gz + +release-linux-icc: + type: deploy + script: + - module load intel + - export CC=icc + - export CXX=icpc + - scripts/release/linux.sh + tags: + - icc + - release + - centos6 + only: + - devel + - master + artifacts: + paths: + - build_release/*.gz + +release-osx-clang: + type: deploy + script: + - export CC=clang + - export CXX=clang++ + - scripts/release/macosx.sh + tags: + - clang + - release + - osx + only: + - devel + - master + artifacts: + paths: + - build_release/*.gz + - build_release/*.dmg + +release-windows: + type: deploy + script: + - call scripts\release\win.bat + tags: + - msvc + - release + - win7 + only: + - devel + - master + artifacts: + paths: + - build_release\ospray*.zip + - build_release\ospray*.exe diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b6a012777..899ea57a57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,49 @@ Version History --------------- +### Changes in v0.10.0: + +- Added new tasking options: `Cilk`, `Internal`, and `Debug` + - Provides more ways for OSPRay to interact with calling + application tasking systems + - `Cilk`: Use Intel® Cilk™ Plus language extensions (ICC only) + - `Internal`: Use hand written OSPRay tasking system + - `Debug`: All tasks are run in serial (useful for debugging) + - In most cases, `TBB` remains the fastest option +- Added support for adaptive accumulation and stopping + - `ospRenderFrame` now returns an estimation of the variance in + the rendered image if the framebuffer was created with the + `OSP_FB_VARIANCE` channel + - If the renderer parameter `varianceThreshold` is set, + progressive refinement concentrates on regions of the image with + a variance higher than this threshold +- Added support for volumes with voxelType `ushort` (16-bit unsigned + integers) +- `OSPTexture2D` now supports sRGB formats -- actually most images are + stored in sRGB. As a consequence the API call `ospNewTexture2D()` + needed to change to accept the new `OSPTextureFormat` parameter. +- Similarly, OSPRay's framebuffer types now also distinguishes between + linear and sRGB 8-bit formats. The new types are `OSP_FB_NONE`, + `OSP_FB_RGBA8`, `OSP_FB_SRGBA`, and `OSP_FB_RGBA32F` +- Changed "scivis" renderer parameter defaults + - All shading (AO + shadows) must be explicitly enabled +- 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 + - Removes extra dependencies on internal Embree math types and + utility functions + - `ospray.h` header is now C99 compatible +- Removed loaders module, functionality remains inside of + `ospVolumeViewer` +- Many miscellaneous cleanups, bugfixes, and improvements: + - Fixed data distributed volume rendering bugs when using less + blocks than workers + - Fixes to CMake `find_package()` config + - Fix bug in `GhostBlockBrickVolume` when using `double`s + - Various robustness changes made in CMake to make it easier to + compile OSPRay + ### Changes in v0.9.1: - Volume rendering now integrated into the "scivis" renderer @@ -12,10 +55,10 @@ Version History infrastructure restored (volume rendering is known to still be broken) - New support for CPack built OSPRay binary redistributable packages -- Add support for HDRI lighting in path tracer -- Add `ospRemoveVolume()` API call -- Add ability to render a subsection of the full view into the entire - framebuffer in the perspective camera +- Added support for HDRI lighting in path tracer +- Added `ospRemoveVolume()` API call +- Added ability to render a subsection of the full view into the + entire framebuffer in the perspective camera - Many miscellaneous cleanups, bugfixes, and improvements: - The depthbuffer is now correctly populated by in the "scivis" renderer diff --git a/CMakeLists.txt b/CMakeLists.txt index f97d6cdf8b..bbb595f5e3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,17 +30,13 @@ ENDIF() SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/cmake) SET(OSPRAY_VERSION_MAJOR 0) -SET(OSPRAY_VERSION_MINOR 9) -SET(OSPRAY_VERSION_PATCH 1) +SET(OSPRAY_VERSION_MINOR 10) +SET(OSPRAY_VERSION_PATCH 0) SET(OSPRAY_VERSION ${OSPRAY_VERSION_MAJOR}.${OSPRAY_VERSION_MINOR}.${OSPRAY_VERSION_PATCH} ) SET(OSPRAY_SOVERSION 0) -MACRO(PRINT var) - MESSAGE("${var} = ${${var}}") -ENDMACRO() - SET(CONFIGURATION_TYPES "Debug;Release;RelWithDebInfo") IF (WIN32) IF (NOT OSPRAY_DEFAULT_CMAKE_CONFIGURATION_TYPES_SET) @@ -58,17 +54,41 @@ SET(OSPRAY_BINARY_DIR ${PROJECT_BINARY_DIR}) SET(LIBRARY_OUTPUT_PATH ${OSPRAY_BINARY_DIR}) SET(EXECUTABLE_OUTPUT_PATH ${OSPRAY_BINARY_DIR}) -# add experimental KNL/AVX512 build option - not fully supported, yet, so keep it hidden +############################################################## +# CMake modules and macro files +############################################################## + +INCLUDE(cmake/ospray.cmake) +INCLUDE(cmake/ispc.cmake) +INCLUDE(cmake/mpi.cmake) + +IF(NOT WIN32) + INCLUDE(cmake/doxygen.cmake) +ENDIF() + +OSPRAY_CONFIGURE_COMPILER() + +############################################################## +# OSPRay specific build options and configuration selection +############################################################## + +OPTION(OSPRAY_USE_EXTERNAL_EMBREE + "Use a pre-built Embree instead of the internally built version") + OPTION(OSPRAY_BUILD_ENABLE_KNL "Enable experimental 'Knights Landing' build?") MARK_AS_ADVANCED(OSPRAY_BUILD_ENABLE_KNL) -OPTION(OSPRAY_VOLUME_VOXELRANGE_IN_APP "Move 'voxelrange' computations to app?" OFF) +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.") + 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?") @@ -81,49 +101,35 @@ ELSE() SET_PROPERTY(CACHE OSPRAY_BUILD_ISA PROPERTY STRINGS ALL SSE AVX AVX2) ENDIF() -# make ospray target and compiler uppercase - we need this in some other parts of the build system +# make ISA target case-insensitive, used in configure_ospray() macro STRING(TOUPPER ${OSPRAY_BUILD_ISA} OSPRAY_BUILD_ISA) SET(OSPRAY_MIC ${OSPRAY_BUILD_MIC_SUPPORT}) SET(OSPRAY_MPI ${OSPRAY_BUILD_MPI_DEVICE}) -# Make OpenMP available to all apps/libraries/modules -FIND_PACKAGE(OpenMP QUIET) -IF (OPENMP_FOUND) - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") - SET(CMAKE_EXE_LINKER_FLAGS - "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}") -ENDIF() - ############################################################## -# create binary packages; before any INSTALL() invocation/definition +# create binary packages; before any INSTALL() invocation/definition ############################################################## INCLUDE(package) ############################################################## -# CMake modules +# the OSPRay 'common' library ############################################################## -INCLUDE(cmake/ospray.cmake) -INCLUDE(cmake/ispc.cmake) - -SET(OSPRAY_EMBREE_SOURCE_DIR ${PROJECT_SOURCE_DIR}/ospray/embree-v2.7.1) - - -INCLUDE(cmake/mpi.cmake) - -IF(NOT WIN32) - INCLUDE(cmake/doxygen.cmake) +INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}) +INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/ospray/include) +SET(OSPRAY_TARGET "intel64") +ADD_SUBDIRECTORY(common builddir/ospray_common/intel64) +IF (OSPRAY_MIC) + SET(OSPRAY_TARGET "mic") + ADD_SUBDIRECTORY(common builddir/ospray_common/mic) ENDIF() ############################################################## # the OSPRay library ############################################################## -INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}) -INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/ospray/include) SET(OSPRAY_TARGET "intel64") ADD_SUBDIRECTORY(ospray builddir/ospray/intel64) IF (OSPRAY_MIC) diff --git a/README.md b/README.md index 9c9e841628..b900753ea3 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ OSPRay ====== -This is release v0.9.1 of OSPRay. For changes and new -features see the [changelog](CHANGELOG.md). Also visit -http://www.ospray.org for more information. +This is release v0.10.0 of OSPRay. For changes and new features see the +[changelog](CHANGELOG.md). Also visit http://www.ospray.org for more +information. OSPRay Overview =============== @@ -56,7 +56,7 @@ branch should always point to the latest tested bugfix release. Prerequisites ------------- -OSPRay currently supports both Linux and Mac OS X (and experimentally +OSPRay currently supports both Linux and Mac OS X (and experimentally Windows). In addition, before you can build OSPRay you need the following prerequisites: @@ -106,7 +106,7 @@ Type the following to install the dependencies using `apt-get`: sudo apt-get install freeglut3-dev sudo apt-get install libqt4-dev -Under Mac OS\ X these dependencies can be installed using +Under Mac OS X these dependencies can be installed using [MacPorts](http://www.macports.org/): sudo port install cmake tbb freeglut qt4 @@ -161,7 +161,8 @@ Tutorial -------- A minimal working example demonstrating how to use OSPRay can be found -at `apps/ospTutorial.cpp`. On Linux build it in the build_directory with +at `apps/ospTutorial.cpp`^[A C99 version is available at +`apps/ospTutorial.c`.]. On Linux build it in the build_directory with g++ ../apps/ospTutorial.cpp -I ../ospray/include -I .. -I ../ospray/embree/common \ ./libospray.so -Wl,-rpath,. -o ospTutorial diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index c5c1fcfb12..1ba1c8e506 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -41,10 +41,14 @@ IF(NOT THIS_IS_MIC) ENDIF() IF(NOT WIN32) + # NOTE(jda) - Disable Qt based viewers when on OS X using ICC due to + # unresolved issues # qt-based viewer for geometry (and soon volumes) - OPTION(OSPRAY_APPS_QTVIEWER "Build ospQtViewer (Qt-based model viewer)" ON) - IF (OSPRAY_APPS_QTVIEWER) - ADD_SUBDIRECTORY(qtViewer) + 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() # stream line viewer for NASA Stream Line Demo @@ -61,14 +65,11 @@ IF(NOT THIS_IS_MIC) ENDIF() # volume viewer application - OPTION(OSPRAY_APPS_VOLUMEVIEWER "Build ospVolumeViewer application." ON) - IF(OSPRAY_APPS_VOLUMEVIEWER) - ADD_SUBDIRECTORY(volumeViewer) + 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() ENDIF() ENDIF(NOT WIN32) - - -# ADD_EXECUTABLE(test1 test1.cpp) -# TARGET_LINK_LIBRARIES(test1 ospray) - ENDIF() diff --git a/apps/common/widgets/glut3D.cpp b/apps/common/widgets/glut3D.cpp index 11f58a763c..a5af149fc8 100644 --- a/apps/common/widgets/glut3D.cpp +++ b/apps/common/widgets/glut3D.cpp @@ -32,6 +32,7 @@ # include # include // for usleep #endif +#include namespace ospray { @@ -39,10 +40,28 @@ namespace ospray { bool dumpScreensDuringAnimation = false; + FPSCounter::FPSCounter() + { + smooth_nom = 0.; + smooth_den = 0.; + frameStartTime = 0.; + } + + void FPSCounter::startRender() + { + frameStartTime = ospcommon::getSysTime(); + } + + void FPSCounter::doneRender() { + double seconds = ospcommon::getSysTime() - frameStartTime; + smooth_nom = smooth_nom * 0.8f + seconds; + smooth_den = smooth_den * 0.8f + 1.f; + } + /*! write given frame buffer to file, in PPM P6 format. */ void saveFrameBufferToFile(const char *fileName, - const uint32 *pixel, - const uint32 sizeX, const uint32 sizeY) + const uint32_t *pixel, + const uint32_t sizeX, const uint32_t sizeY) { FILE *file = fopen(fileName,"wb"); if (!file) { @@ -82,7 +101,7 @@ namespace ospray { // glut event handlers // ------------------------------------------------------------------ - void glut3dReshape(int32 x, int32 y) + void glut3dReshape(int32_t x, int32_t y) { if (Glut3DWidget::activeWindow) Glut3DWidget::activeWindow->reshape(vec2i(x,y)); @@ -98,12 +117,12 @@ namespace ospray { Glut3DWidget::activeWindow->display(); } - void glut3dKeyboard(unsigned char key, int32 x, int32 y) + void glut3dKeyboard(unsigned char key, int32_t x, int32_t y) { if (Glut3DWidget::activeWindow) Glut3DWidget::activeWindow->keypress(key,vec2i(x,y)); } - void glut3dSpecial(int32 key, int32 x, int32 y) + void glut3dSpecial(int32_t key, int32_t x, int32_t y) { if (Glut3DWidget::activeWindow) Glut3DWidget::activeWindow->specialkey(key,vec2i(x,y)); @@ -114,13 +133,13 @@ namespace ospray { if (Glut3DWidget::activeWindow) Glut3DWidget::activeWindow->idle(); } - void glut3dMotionFunc(int32 x, int32 y) + void glut3dMotionFunc(int32_t x, int32_t y) { if (Glut3DWidget::activeWindow) Glut3DWidget::activeWindow->motion(vec2i(x,y)); } - void glut3dMouseFunc(int32 whichButton, int32 released, int32 x, int32 y) + void glut3dMouseFunc(int32_t whichButton, int32_t released, int32_t x, int32_t y) { if (Glut3DWidget::activeWindow) Glut3DWidget::activeWindow->mouseButton(whichButton,released,vec2i(x,y)); @@ -138,7 +157,7 @@ namespace ospray { openingAngle(60.f*M_PI/360.f), modified(true) { - frame = AffineSpace3fa::translate(from) * AffineSpace3fa(embree::one); + frame = AffineSpace3fa::translate(from) * AffineSpace3fa(ospcommon::one); } void Glut3DWidget::ViewPort::snapUp() @@ -153,7 +172,7 @@ namespace ospray { // ------------------------------------------------------------------ // implementation of glut3d widget // ------------------------------------------------------------------ - void Glut3DWidget::mouseButton(int32 whichButton, bool released, const vec2i &pos) + void Glut3DWidget::mouseButton(int32_t whichButton, bool released, const vec2i &pos) { if (pos != currMousePos) @@ -279,7 +298,6 @@ namespace ospray { void Glut3DWidget::display() { if (frameBufferMode == Glut3DWidget::FRAMEBUFFER_UCHAR && ucharFB) { - //double before = getSysTime(); glDrawPixels(windowSize.x, windowSize.y, GL_RGBA, GL_UNSIGNED_BYTE, ucharFB); #ifndef _WIN32 if (animating && dumpScreensDuringAnimation) { @@ -313,7 +331,7 @@ namespace ospray { glutSwapBuffers(); } - void Glut3DWidget::drawPixels(const uint32 *framebuffer) + void Glut3DWidget::drawPixels(const uint32_t *framebuffer) { throw std::runtime_error("should not be used right now"); glDrawPixels(windowSize.x, windowSize.y, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer); @@ -347,10 +365,10 @@ namespace ospray { void Glut3DWidget::setWorldBounds(const box3f &worldBounds) { - vec3f center = embree::center(worldBounds); + vec3f center = ospcommon::center(worldBounds); vec3f diag = worldBounds.size(); diag = max(diag,vec3f(0.3f*length(diag))); - vec3f from = center - .75f*vec3f(-.6*diag.x,-1.2*diag.y,.8*diag.z); + vec3f from = center - .75f*vec3f(-.6*diag.x,-1.2f*diag.y,.8f*diag.z); vec3f dir = center - from; vec3f up = viewPort.up; @@ -405,7 +423,7 @@ namespace ospray { glutMainLoop(); } - void initGLUT(int32 *ac, const char **av) + void initGLUT(int32_t *ac, const char **av) { glutInit(ac, (char **) av); @@ -502,11 +520,11 @@ namespace ospray { // ------------------------------------------------------------------ InspectCenter::InspectCenter(Glut3DWidget *widget) : Manipulator(widget) - , pivot(center(widget->worldBounds)) + , pivot(ospcommon::center(widget->worldBounds)) {} void InspectCenter::keypress(Glut3DWidget *widget, - int32 key) + int32_t key) { switch(key) { case 'a': { @@ -547,7 +565,7 @@ namespace ospray { } void InspectCenter::specialkey(Glut3DWidget *widget, - int32 key) + int32_t key) { switch(key) { case GLUT_KEY_LEFT: { @@ -600,7 +618,7 @@ namespace ospray { vec2i delta_mouse = (to - from); AffineSpace3fa xfm = AffineSpace3fa::translate( widget->motionSpeed * dv * cam.frame.l.vz ) - * AffineSpace3fa::translate( -1.0 * widget->motionSpeed * du * cam.frame.l.vx ); + * AffineSpace3fa::translate( -1.0f * widget->motionSpeed * du * cam.frame.l.vx ); cam.frame = xfm * cam.frame; cam.from = xfmPoint(xfm, cam.from); @@ -617,7 +635,6 @@ namespace ospray { float dv = (to.y - from.y) * widget->rotateSpeed; vec2i delta_mouse = to - from; - // PRINT(delta_mouse); const vec3f pivot = cam.at; //center(widget->worldBounds); AffineSpace3fa xfm @@ -649,7 +666,7 @@ namespace ospray { */ void MoveMode::keypress(Glut3DWidget *widget, - int32 key) + int32_t key) { Glut3DWidget::ViewPort &cam = widget->viewPort; switch(key) { @@ -712,7 +729,7 @@ namespace ospray { vec2i delta_mouse = (to - from); AffineSpace3fa xfm = AffineSpace3fa::translate( widget->motionSpeed * dv * cam.frame.l.vz ) - * AffineSpace3fa::translate( -1.0 * widget->motionSpeed * du * cam.frame.l.vx ); + * AffineSpace3fa::translate( -1.0f * widget->motionSpeed * du * cam.frame.l.vx ); cam.frame = xfm * cam.frame; cam.from = xfmPoint(xfm, cam.from); @@ -742,11 +759,11 @@ namespace ospray { cam.modified = true; } - void Glut3DWidget::specialkey(int32 key, const vec2f where) + void Glut3DWidget::specialkey(int32_t key, const vec2i &where) { if (manipulator) manipulator->specialkey(this,key); } - void Glut3DWidget::keypress(char key, const vec2f where) + void Glut3DWidget::keypress(char key, const vec2i &where) { if (key == '!') { if (animating) { @@ -809,7 +826,7 @@ namespace ospray { - void Manipulator::keypress(Glut3DWidget *widget, const int32 key) + void Manipulator::keypress(Glut3DWidget *widget, const int32_t key) { switch(key) { case 27 /*ESC*/: @@ -818,7 +835,7 @@ namespace ospray { _exit(0); } }; - void Manipulator::specialkey(Glut3DWidget *widget, const int32 key) + void Manipulator::specialkey(Glut3DWidget *widget, const int32_t key) { }; diff --git a/apps/common/widgets/glut3D.h b/apps/common/widgets/glut3D.h index 272fd84c38..1cb7ac8b12 100644 --- a/apps/common/widgets/glut3D.h +++ b/apps/common/widgets/glut3D.h @@ -16,8 +16,9 @@ #pragma once -#include "ospray/common/OSPCommon.h" -#include /*embree*/"common/math/affinespace.h" +#include "common/common.h" +#include "common/box.h" +#include "common/AffineSpace.h" #ifdef __APPLE__ #include @@ -44,33 +45,27 @@ namespace ospray { //! dedicated namespace for 3D glut viewer widget namespace glut3D { + using namespace ospcommon; + /*! initialize everything GLUT-related */ - OSPRAY_GLUT3D_INTERFACE void initGLUT(int32 *ac, const char **av); + OSPRAY_GLUT3D_INTERFACE void initGLUT(int32_t *ac, const char **av); /*! switch over to GLUT for control flow. This functoin will not return */ OSPRAY_GLUT3D_INTERFACE void runGLUT(); - using embree::AffineSpace3fa; + using ospcommon::AffineSpace3fa; /*! helper class that allows for easily computing (smoothed) frame rate */ struct FPSCounter { + OSPRAY_GLUT3D_INTERFACE FPSCounter(); + OSPRAY_GLUT3D_INTERFACE void startRender(); + OSPRAY_GLUT3D_INTERFACE void doneRender(); + OSPRAY_GLUT3D_INTERFACE double getFPS() const { return smooth_den / smooth_nom; } + + private: double smooth_nom; double smooth_den; double frameStartTime; - - FPSCounter() - { - smooth_nom = 0.; - smooth_den = 0.; - frameStartTime = 0.; - } - OSPRAY_GLUT3D_INTERFACE void startRender() { frameStartTime = ospray::getSysTime(); } - OSPRAY_GLUT3D_INTERFACE void doneRender() { - double seconds = ospray::getSysTime() - frameStartTime; - smooth_nom = smooth_nom * 0.8f + seconds; - smooth_den = smooth_den * 0.8f + 1.f; - } - OSPRAY_GLUT3D_INTERFACE double getFPS() const { return smooth_den / smooth_nom; } }; @@ -83,23 +78,30 @@ namespace ospray { OSPRAY_GLUT3D_INTERFACE virtual void motion(Glut3DWidget *widget); // this is the fct that gets called when any mouse button got // pressed or released in the associated window - OSPRAY_GLUT3D_INTERFACE virtual void button(Glut3DWidget *widget, const vec2i &pos) {}; + OSPRAY_GLUT3D_INTERFACE virtual void button(Glut3DWidget *widget, + const vec2i &pos) {} /*! key press handler - override this fct to catch keyboard. */ - OSPRAY_GLUT3D_INTERFACE virtual void keypress(Glut3DWidget *widget, const int32 key); - OSPRAY_GLUT3D_INTERFACE virtual void specialkey(Glut3DWidget *widget, const int32 key); - OSPRAY_GLUT3D_INTERFACE Manipulator(Glut3DWidget *widget) : widget(widget) {}; + OSPRAY_GLUT3D_INTERFACE virtual void keypress(Glut3DWidget *widget, + const int32_t key); + OSPRAY_GLUT3D_INTERFACE virtual void specialkey(Glut3DWidget *widget, + const int32_t key); + OSPRAY_GLUT3D_INTERFACE Manipulator(Glut3DWidget *widget) + : widget(widget) {} protected: // helper functions called from the default 'motion' fct OSPRAY_GLUT3D_INTERFACE virtual void dragLeft(Glut3DWidget *widget, - const vec2i &to, const vec2i &from) - {}; + const vec2i &to, + const vec2i &from) + {} OSPRAY_GLUT3D_INTERFACE virtual void dragRight(Glut3DWidget *widget, - const vec2i &to, const vec2i &from) - {}; + const vec2i &to, + const vec2i &from) + {} OSPRAY_GLUT3D_INTERFACE virtual void dragMiddle(Glut3DWidget *widget, - const vec2i &to, const vec2i &from) - {}; + const vec2i &to, + const vec2i &from) + {} Glut3DWidget *widget; }; @@ -111,8 +113,8 @@ namespace ospray { const vec2i &to, const vec2i &from); virtual void dragMiddle(Glut3DWidget *widget, const vec2i &to, const vec2i &from); - virtual void specialkey(Glut3DWidget *widget, const int32 key); - virtual void keypress(Glut3DWidget *widget, int32 key); + virtual void specialkey(Glut3DWidget *widget, const int32_t key); + virtual void keypress(Glut3DWidget *widget, int32_t key); virtual void button(Glut3DWidget *widget, const vec2i &pos); InspectCenter(Glut3DWidget *widget); void rotate(float du, float dv); @@ -128,7 +130,7 @@ namespace ospray { const vec2i &to, const vec2i &from); virtual void dragMiddle(Glut3DWidget *widget, const vec2i &to, const vec2i &from); - virtual void keypress(Glut3DWidget *widget, int32 key); + virtual void keypress(Glut3DWidget *widget, int32_t key); virtual void button(Glut3DWidget *widget, const vec2i &pos) {} MoveMode(Glut3DWidget *widget) : Manipulator(widget) {} }; @@ -210,13 +212,17 @@ namespace ospray { /*! set window title */ OSPRAY_GLUT3D_INTERFACE void setTitle(const std::string &title) { setTitle(title.c_str()); } /*! set viewport to given values */ - OSPRAY_GLUT3D_INTERFACE void setViewPort(const vec3f from, const vec3f at, const vec3f up); + OSPRAY_GLUT3D_INTERFACE void setViewPort(const vec3f from, + const vec3f at, + const vec3f up); // ------------------------------------------------------------------ // event handling - override this to change this widgets behavior // to input events // ------------------------------------------------------------------ - OSPRAY_GLUT3D_INTERFACE virtual void mouseButton(int32 which, bool released, const vec2i &pos); + OSPRAY_GLUT3D_INTERFACE virtual void mouseButton(int32_t which, + bool released, + const vec2i &pos); OSPRAY_GLUT3D_INTERFACE virtual void motion(const vec2i &pos); // /*! mouse moved to this location, with given left/right/middle buttons pressed */ // virtual void mouseMotion(const vec2i &from, @@ -247,10 +253,12 @@ namespace ospray { /*! clear the frame buffer color and depth bits */ OSPRAY_GLUT3D_INTERFACE void clearPixels(); - /*! draw uint32 pixels into the GLUT window (assumes window and buffer dimensions are equal) */ - OSPRAY_GLUT3D_INTERFACE void drawPixels(const uint32 *framebuffer); + /*! draw uint32_t pixels into the GLUT window (assumes window and buffer + * dimensions are equal) */ + OSPRAY_GLUT3D_INTERFACE void drawPixels(const uint32_t *framebuffer); - /*! draw float4 pixels into the GLUT window (assumes window and buffer dimensions are equal) */ + /*! draw float4 pixels into the GLUT window (assumes window and buffer + * dimensions are equal) */ OSPRAY_GLUT3D_INTERFACE void drawPixels(const vec3fa *framebuffer); // ------------------------------------------------------------------ @@ -269,11 +277,11 @@ namespace ospray { vec2i lastMousePos; /*! last mouse screen position of mouse before current motion */ vec2i currMousePos; /*! current screen position of mouse */ - int64 lastButtonState, currButtonState, currModifiers; + int64_t lastButtonState, currButtonState, currModifiers; ViewPort viewPort; box3f worldBounds; /*!< world bounds, to automatically set viewPort lookat, mouse speed, etc */ - int32 windowID; + int32_t windowID; vec2i windowSize; /*! camera speed modifier - affects how many units the camera _moves_ with each unit on the screen */ @@ -293,20 +301,22 @@ namespace ospray { and deallocate the frame buffer pointer */ union { /*! uchar[4] RGBA-framebuffer, if applicable */ - uint32 *ucharFB; + uint32_t *ucharFB; /*! float[4] RGBA-framebuffer, if applicable */ vec3fa *floatFB; }; - friend void glut3dReshape(int32 x, int32 y); + friend void glut3dReshape(int32_t x, int32_t y); friend void glut3dDisplay(void); - friend void glut3dKeyboard(char key, int32 x, int32 y); + friend void glut3dKeyboard(char key, int32_t x, int32_t y); friend void glut3dIdle(void); - friend void glut3dMotionFunc(int32 x, int32 y); - friend void glut3dMouseFunc(int32 whichButton, int32 released, - int32 x, int32 y); - - OSPRAY_GLUT3D_INTERFACE virtual void keypress(char key, const vec2f where); - OSPRAY_GLUT3D_INTERFACE virtual void specialkey(int32 key, const vec2f where); + friend void glut3dMotionFunc(int32_t x, int32_t y); + friend void glut3dMouseFunc(int32_t whichButton, int32_t released, + int32_t x, int32_t y); + + OSPRAY_GLUT3D_INTERFACE virtual void keypress(char key, + const vec2i &where); + OSPRAY_GLUT3D_INTERFACE virtual void specialkey(int32_t key, + const vec2i &where); }; std::ostream &operator<<(std::ostream &o, const Glut3DWidget::ViewPort &cam); diff --git a/apps/common/xml/CMakeLists.txt b/apps/common/xml/CMakeLists.txt index eeda2bdb2e..1c2924f8f6 100644 --- a/apps/common/xml/CMakeLists.txt +++ b/apps/common/xml/CMakeLists.txt @@ -21,7 +21,7 @@ INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/ospray/include) ADD_LIBRARY(ospray_xml SHARED XML.cpp) -TARGET_LINK_LIBRARIES(ospray_xml ospray) +TARGET_LINK_LIBRARIES(ospray_xml ospray ospray_common) OSPRAY_SET_LIBRARY_VERSION(ospray_xml) INSTALL(TARGETS ospray_xml LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT lib diff --git a/apps/common/xml/XML.cpp b/apps/common/xml/XML.cpp index c0a839cd35..60c8337e2a 100644 --- a/apps/common/xml/XML.cpp +++ b/apps/common/xml/XML.cpp @@ -15,6 +15,7 @@ // ======================================================================== // #include "XML.h" +#include namespace ospray { namespace xml { @@ -22,7 +23,7 @@ namespace ospray { std::string toString(const float f) { std::stringstream ss; ss << f; return ss.str(); } - std::string toString(const vec3f &v) + std::string toString(const ospcommon::vec3f &v) { std::stringstream ss; ss << v.x << " " << v.y << " " << v.z; return ss.str(); } Node::~Node() diff --git a/apps/common/xml/XML.h b/apps/common/xml/XML.h index db536e7048..0ab4f56cce 100644 --- a/apps/common/xml/XML.h +++ b/apps/common/xml/XML.h @@ -16,10 +16,15 @@ #pragma once -// ospray -#include "ospray/common/OSPCommon.h" -// embree -#include "common/sys/filename.h" +// // ospray +// #include "ospray/common/OSPCommon.h" +// // embree +// #include "common/sys/filename.h" + +// ospcomon +#include "common/common.h" +#include "common/vec.h" +#include "common/FileName.h" // stl #include #include @@ -38,7 +43,7 @@ namespace ospray { namespace xml { struct Node; - using embree::FileName; + using ospcommon::FileName; struct XMLDoc; /*! 'prop'erties in xml nodes are the 'name="value"' inside the @@ -70,9 +75,19 @@ namespace ospray { /*! find properly with given name, and return as long ('l') int. return undefined if prop does not exist */ - inline size_t getPropl(const std::string &name) const - { return atol(getProp(name).c_str()); } - + inline size_t getPropl(const std::string &name, const size_t defaultValue = 0) const + { + const std::string prop = getProp(name); + if (prop == "") return defaultValue; else return atol(getProp(name).c_str()); + } + /*! find properly with given name, and return as long ('l') + int. return undefined if prop does not exist */ + inline float getPropf(const std::string &name, const float defaultValue = 0.f) const + { + const std::string prop = getProp(name); + if (prop == "") return defaultValue; else return atof(getProp(name).c_str()); + } + /*! name of the xml node (i.e., the thing that's in "....") */ std::string name; @@ -112,9 +127,9 @@ namespace ospray { /*! @{ */ //! \brief helper function(s) to convert data tyeps into strings - std::string toString(const int64 value); + std::string toString(const int64_t value); std::string toString(const float value); - std::string toString(const ospray::vec3f &value); + std::string toString(const ospcommon::vec3f &value); /*! @} */ /*! helper class for writing sg nodes in XML format */ diff --git a/apps/modelViewer/miniSG/importHBP.cpp b/apps/modelViewer/miniSG/importHBP.cpp index 10dd20f616..8e8f43eb42 100644 --- a/apps/modelViewer/miniSG/importHBP.cpp +++ b/apps/modelViewer/miniSG/importHBP.cpp @@ -24,7 +24,7 @@ namespace ospray { using std::endl; /*! import a HBP file, and add it to the specified model */ - void importHBP(Model &model, const embree::FileName &fileName) + void importHBP(Model &model, const ospcommon::FileName &fileName) { std::string vtxName = fileName.str()+".vtx"; std::string triName = fileName.str()+".tri"; diff --git a/apps/modelViewer/miniSG/importMSG.cpp b/apps/modelViewer/miniSG/importMSG.cpp index d236f20462..1287267ee3 100644 --- a/apps/modelViewer/miniSG/importMSG.cpp +++ b/apps/modelViewer/miniSG/importMSG.cpp @@ -23,7 +23,7 @@ namespace ospray { using std::endl; void importMSG(Model &model, - const embree::FileName &fileName) + const ospcommon::FileName &fileName) { error("importMSG: not implemented yet"); } diff --git a/apps/modelViewer/miniSG/importOBJ.cpp b/apps/modelViewer/miniSG/importOBJ.cpp index eb55fde47e..adf2f29b53 100644 --- a/apps/modelViewer/miniSG/importOBJ.cpp +++ b/apps/modelViewer/miniSG/importOBJ.cpp @@ -107,17 +107,17 @@ namespace ospray { std::map material; /*! Constructor. */ - OBJLoader(Model &model, const embree::FileName& fileName); + OBJLoader(Model &model, const ospcommon::FileName& fileName); /*! Destruction */ ~OBJLoader(); /*! Public methods. */ - void loadMTL(const embree::FileName& fileName); + void loadMTL(const ospcommon::FileName& fileName); private: - embree::FileName path; + ospcommon::FileName path; /*! Geometry buffer. */ std::vector v; @@ -136,10 +136,10 @@ namespace ospray { int fix_vn(int index); void flushFaceGroup(); Vertex getInt3(const char*& token); - uint32 getVertex(std::map& vertexMap, Mesh *mesh, const Vertex& i); + uint32_t getVertex(std::map& vertexMap, Mesh *mesh, const Vertex& i); }; - OBJLoader::OBJLoader(Model &model, const embree::FileName &fileName) + OBJLoader::OBJLoader(Model &model, const ospcommon::FileName &fileName) : model(model), curMaterial(NULL), path(fileName.path()) @@ -227,7 +227,7 @@ namespace ospray { } /* load material file */ - void OBJLoader::loadMTL(const embree::FileName &fileName) + void OBJLoader::loadMTL(const ospcommon::FileName &fileName) { std::ifstream cin; cin.open(fileName.c_str()); @@ -294,16 +294,16 @@ namespace ospray { if (!strncmp(token, "Ks", 2)) { parseSep(token += 2); cur->setParam("Ks", getVec3f(token)); continue; } if (!strncmp(token, "Tf", 2)) { parseSep(token += 2); cur->setParam("Tf", getVec3f(token)); continue; } - if (!strncmp(token, "map_d" , 5)) { parseSepOpt(token += 5); cur->setParam("map_d", loadTexture(path, std::string(token)),Material::Param::TEXTURE); continue; } - if (!strncmp(token, "map_Ns" , 6)) { parseSepOpt(token += 6); cur->setParam("map_Ns", loadTexture(path, std::string(token)),Material::Param::TEXTURE); continue; } + if (!strncmp(token, "map_d" , 5)) { parseSepOpt(token += 5); cur->setParam("map_d", loadTexture(path, std::string(token), true),Material::Param::TEXTURE); continue; } + if (!strncmp(token, "map_Ns" , 6)) { parseSepOpt(token += 6); cur->setParam("map_Ns", loadTexture(path, std::string(token), true),Material::Param::TEXTURE); continue; } if (!strncmp(token, "map_Ka" , 6)) { parseSepOpt(token += 6); cur->setParam("map_Ka", loadTexture(path, std::string(token)),Material::Param::TEXTURE); continue; } if (!strncmp(token, "map_Kd" , 6)) { parseSepOpt(token += 6); cur->setParam("map_Kd", loadTexture(path, std::string(token)),Material::Param::TEXTURE); continue; } 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)),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, "bumpMap" , 7)) { parseSepOpt(token += 7); cur->setParam("map_Bump", loadTexture(path, std::string(token)),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; } if (!strncmp(token, "color", 5)) { parseSep(token += 5); cur->setParam("color", getVec3f(token)); continue; } @@ -355,10 +355,10 @@ namespace ospray { return(v); } - uint32 OBJLoader::getVertex(std::map& vertexMap, + uint32_t OBJLoader::getVertex(std::map& vertexMap, Mesh *mesh, const Vertex& i) { - const std::map::iterator& entry = vertexMap.find(i); + const std::map::iterator& entry = vertexMap.find(i); if (entry != vertexMap.end()) return(entry->second); if (std::isnan(v[i.v].x) || std::isnan(v[i.v].y) || std::isnan(v[i.v].z)) @@ -389,7 +389,7 @@ namespace ospray { // std::vector &normals; // std::vector &texcoords; // std::vector &triangles; - std::map vertexMap; + std::map vertexMap; Mesh *mesh = new Mesh; model.mesh.push_back(mesh); model.instance.push_back(Instance(model.mesh.size()-1)); @@ -404,9 +404,9 @@ namespace ospray { /* triangulate the face with a triangle fan */ for (size_t k=2; k < face.size(); k++) { i1 = i2; i2 = face[k]; - int32 v0 = getVertex(vertexMap, mesh, i0); - int32 v1 = getVertex(vertexMap, mesh, i1); - int32 v2 = getVertex(vertexMap, mesh, i2); + int32_t v0 = getVertex(vertexMap, mesh, i0); + int32_t v1 = getVertex(vertexMap, mesh, i1); + int32_t v2 = getVertex(vertexMap, mesh, i2); if (v0 < 0 || v1 < 0 || v2 < 0) continue; Triangle tri; @@ -420,7 +420,7 @@ namespace ospray { } void importOBJ(Model &model, - const embree::FileName &fileName) + const ospcommon::FileName &fileName) { std::cout << "ospray::miniSG::importOBJ: importing from " << fileName << endl; OBJLoader loader(model,fileName); diff --git a/apps/modelViewer/miniSG/importRIVL.cpp b/apps/modelViewer/miniSG/importRIVL.cpp index 8e18223dfd..cefb0b30c7 100644 --- a/apps/modelViewer/miniSG/importRIVL.cpp +++ b/apps/modelViewer/miniSG/importRIVL.cpp @@ -21,12 +21,13 @@ #define O_LARGEFILE 0 #endif +#define WARN_ON_INCLUDING_OSPCOMMON 1 + // header -#include "ospray/common/Managed.h" -#include "ospray/common/Data.h" #include "miniSG.h" // stl #include +#include // // libxml #include "apps/common/xml/XML.h" // stdlib, for mmap @@ -52,7 +53,7 @@ namespace ospray { unsigned char *binBasePtr = NULL; /*! Base class for all scene graph node types */ - struct Node : public embree::RefCount + struct Node : public ospcommon::RefCount { virtual string toString() const { return "ospray::miniSG::Node"; } @@ -234,6 +235,7 @@ namespace ospray { txt.ptr->texData->channels = channels; txt.ptr->texData->depth = depth; + txt.ptr->texData->prefereLinear = true; txt.ptr->texData->width = width; txt.ptr->texData->height = height; if (channels == 4) { // RIVL bin stores alpha channel inverted, fix here @@ -337,31 +339,31 @@ namespace ospray { } else if (!childType.compare("int")) { //This *could* be a texture, handle it! if(childName.find("map_") == std::string::npos) { - mat->setParam(childName.c_str(), (int32)atol(s)); + mat->setParam(childName.c_str(), (int32_t)atol(s)); } else { - Texture2D* tex = mat->textures[(int32)atol(s)].ptr; + Texture2D* tex = mat->textures[(int32_t)atol(s)].ptr; mat->setParam(childName.c_str(), (void*)tex, Material::Param::TEXTURE); } } else if (!childType.compare("int2")) { - int32 x = atol(s); + int32_t x = atol(s); s = NEXT_TOK; - int32 y = atol(s); + int32_t y = atol(s); mat->setParam(childName.c_str(), vec2i(x,y)); } else if (!childType.compare("int3")) { - int32 x = atol(s); + int32_t x = atol(s); s = NEXT_TOK; - int32 y = atol(s); + int32_t y = atol(s); s = NEXT_TOK; - int32 z = atol(s); + int32_t z = atol(s); mat->setParam(childName.c_str(), vec3i(x,y,z)); } else if (!childType.compare("int4")) { - int32 x = atol(s); + int32_t x = atol(s); s = NEXT_TOK; - int32 y = atol(s); + int32_t y = atol(s); s = NEXT_TOK; - int32 z = atol(s); + int32_t z = atol(s); s = NEXT_TOK; - int32 w = atol(s); + int32_t w = atol(s); mat->setParam(childName.c_str(), vec4i(x,y,z,w)); } else { //error! @@ -650,7 +652,7 @@ namespace ospray { return node; } - void traverseSG(Model &model, Ref &node, const affine3f &xfm=embree::one) + void traverseSG(Model &model, Ref &node, const affine3f &xfm=ospcommon::one) { Group *g = dynamic_cast(node.ptr); if (g) { @@ -759,7 +761,7 @@ namespace ospray { } /*! import a wavefront OBJ file, and add it to the specified model */ - void importRIVL(Model &model, const embree::FileName &fileName) + void importRIVL(Model &model, const ospcommon::FileName &fileName) { nodeList.clear(); Ref sg = importRIVL(fileName); diff --git a/apps/modelViewer/miniSG/importSTL.cpp b/apps/modelViewer/miniSG/importSTL.cpp index c156356bbd..0f01588ecd 100644 --- a/apps/modelViewer/miniSG/importSTL.cpp +++ b/apps/modelViewer/miniSG/importSTL.cpp @@ -25,11 +25,11 @@ namespace ospray { struct STLTriangle { vec3f normal; vec3f v0, v1, v2; - uint16 attribute; + uint16_t attribute; }; /*! import a list of STL files */ - void importSTL(std::vector &animation, const embree::FileName &fileName) + void importSTL(std::vector &animation, const ospcommon::FileName &fileName) { FILE *file = fopen(fileName.c_str(),"rb"); if (!file) error("could not open input file"); @@ -47,15 +47,15 @@ namespace ospray { } void importSTL(Model &model, - const embree::FileName &fileName) + const ospcommon::FileName &fileName) { FILE *file = fopen(fileName.c_str(),"rb"); if (!file) error("could not open input file"); char header[80]; - int32 rc = fread(header,1,80,file); + int32_t rc = fread(header,1,80,file); if (rc < 80) error("could not read header"); - int32 numTriangles; + int32_t numTriangles; rc = fread(&numTriangles,sizeof(int),1,file); Assert(rc == 1 && "could not read num triangles from STL file"); cout << "miniSG::importSTL: #tris=" @@ -65,7 +65,7 @@ namespace ospray { miniSG::Triangle triangle; STLTriangle stlTri; - for (int32 i=0 ; i < numTriangles ; i++) { + for (int32_t i=0 ; i < numTriangles ; i++) { rc = fread(&stlTri.normal,sizeof(stlTri.normal),1,file); Assert(rc == 1 && "partial or broken STL file!?"); rc = fread(&stlTri.v0,sizeof(stlTri.v0),1,file); diff --git a/apps/modelViewer/miniSG/importTRI.cpp b/apps/modelViewer/miniSG/importTRI.cpp index 7a8184382b..c3d6bdf6ee 100644 --- a/apps/modelViewer/miniSG/importTRI.cpp +++ b/apps/modelViewer/miniSG/importTRI.cpp @@ -23,12 +23,12 @@ namespace ospray { using std::endl; void importTRI(Model &model, - const embree::FileName &fileName) + const ospcommon::FileName &fileName) { FILE *file = fopen(fileName.c_str(),"rb"); if (!file) error("could not open input file"); - int32 numVertices; + int32_t numVertices; fread(&numVertices,1,sizeof(numVertices),file); Mesh *mesh = new Mesh; diff --git a/apps/modelViewer/miniSG/importX3D.cpp b/apps/modelViewer/miniSG/importX3D.cpp index 4bf9289302..bb471eddfc 100644 --- a/apps/modelViewer/miniSG/importX3D.cpp +++ b/apps/modelViewer/miniSG/importX3D.cpp @@ -23,6 +23,7 @@ #include "apps/common/xml/XML.h" // std #include +#include namespace ospray { namespace miniSG { @@ -201,7 +202,7 @@ namespace ospray { continue; } if (node->name == "Transform") { - affine3f xfm = embree::one; + affine3f xfm = ospcommon::one; parseTransform(model,xfm,node); /* ignore */ continue; @@ -212,7 +213,7 @@ namespace ospray { /*! import a list of X3D files */ void importX3D(Model &model, - const embree::FileName &fileName) + const ospcommon::FileName &fileName) { xml::XMLDoc *doc = xml::readXML(fileName); assert(doc); diff --git a/apps/modelViewer/miniSG/importer.cpp b/apps/modelViewer/miniSG/importer.cpp index 66f8d10d40..0e5b54ce83 100644 --- a/apps/modelViewer/miniSG/importer.cpp +++ b/apps/modelViewer/miniSG/importer.cpp @@ -23,7 +23,7 @@ namespace ospray { : model(&model) { mesh = new Mesh; - mesh->bounds = embree::empty; + mesh->bounds = ospcommon::empty; } void ImportHelper::finalize() @@ -39,7 +39,7 @@ namespace ospray { } /*! find given vertex and return its ID, or add if it doesn't yet exist */ - uint32 ImportHelper::addVertex(const vec3f &position) + uint32_t ImportHelper::addVertex(const vec3f &position) { Assert(mesh); if (known_positions.find(position) == known_positions.end()) { diff --git a/apps/modelViewer/miniSG/importer.h b/apps/modelViewer/miniSG/importer.h index ff28c936c4..793bcb11bc 100644 --- a/apps/modelViewer/miniSG/importer.h +++ b/apps/modelViewer/miniSG/importer.h @@ -33,22 +33,22 @@ namespace ospray { Mesh *mesh; /*!< current mesh we're importing */ /*! to tell the ID of any known position in the mesh's list of vertex positions */ - std::map known_positions; + std::map known_positions; /*! to tell the ID of any known vtx normal in the mesh's list of vertex normals */ - std::map known_normals; + std::map known_normals; /*! to tell the ID of any known texcoord in the mesh's list of texcoords */ - std::map known_texcoords; + std::map known_texcoords; ImportHelper(Model &model, const std::string &name = ""); /*! find given vertex and return its ID, or add if it doesn't yet exist */ - uint32 addVertex(const vec3f &position); + uint32_t addVertex(const vec3f &position); /*! find given vertex and return its ID, or add if it doesn't yet exist */ - uint32 addVertex(const vec3f &position, const vec2f &texcoord); + uint32_t addVertex(const vec3f &position, const vec2f &texcoord); /*! find given vertex and return its ID, or add if it doesn't yet exist */ - uint32 addVertex(const vec3f &position, const vec3f &normal, const vec2f &texcoord); + uint32_t addVertex(const vec3f &position, const vec3f &normal, const vec2f &texcoord); /*! find given vertex and return its ID, or add if it doesn't yet exist */ - uint32 addVertex(const vec3f &position, const vec3f &normal); + uint32_t addVertex(const vec3f &position, const vec3f &normal); /*! add new triangle to the mesh. may discard the triangle if it is degenerated. */ void addTriangle(const miniSG::Triangle &triangle); diff --git a/apps/modelViewer/miniSG/miniSG.cpp b/apps/modelViewer/miniSG/miniSG.cpp index 6607aa55d9..4e4ac703e3 100644 --- a/apps/modelViewer/miniSG/miniSG.cpp +++ b/apps/modelViewer/miniSG/miniSG.cpp @@ -44,9 +44,9 @@ namespace ospray { // setParam( "Ka", vec3f(0.f) ); } - Texture2D *loadTexture(const std::string &path, const std::string &fileNameBase) + Texture2D *loadTexture(const std::string &path, const std::string &fileNameBase, const bool prefereLinear) { - const embree::FileName fileName = path+"/"+fileNameBase; + const FileName fileName = path+"/"+fileNameBase; static std::map textureCache; if (textureCache.find(fileName.str()) != textureCache.end()) @@ -111,6 +111,7 @@ namespace ospray { tex->height = height; tex->channels = 3; tex->depth = 1; + tex->prefereLinear = prefereLinear; tex->data = new unsigned char[width*height*3]; fread(tex->data,width*height*3,1,file); // flip in y, because OSPRay's textures have the origin at the lower left corner @@ -129,6 +130,7 @@ namespace ospray { tex->height = image.rows(); tex->channels = image.matte() ? 4 : 3; tex->depth = 4; + tex->prefereLinear = prefereLinear; float rcpMaxRGB = 1.0f/float(MaxRGB); const Magick::PixelPacket* pixels = image.getConstPixels(0,0,tex->width,tex->height); if (!pixels) { @@ -201,7 +203,7 @@ namespace ospray { return defaultVal; } - int32 Material::getParam(const char *name, int32 defaultVal) + int32_t Material::getParam(const char *name, int32_t defaultVal) { ParamMap::iterator it = params.find(name); if (it != params.end()) { @@ -246,7 +248,7 @@ namespace ospray { } - uint32 Material::getParam(const char *name, uint32 defaultVal) + uint32_t Material::getParam(const char *name, uint32_t defaultVal) { ParamMap::iterator it = params.find(name); if (it != params.end()) { @@ -338,7 +340,7 @@ namespace ospray { box3f Model::getBBox() { // this does not yet properly support instancing with transforms! - box3f bBox = embree::empty; + box3f bBox = ospcommon::empty; if (!instance.empty()) { std::vector meshBounds; for (int i=0;i #include namespace ospray { namespace miniSG { + using namespace ospcommon; + typedef ospcommon::AffineSpace3f affine3f; struct Camera : public RefCount { vec3f from, at, up; @@ -37,12 +45,13 @@ namespace ospray { int channels; //Number of color channels per pixel int depth; //Bytes per color channel + bool prefereLinear; //A linear texel format is preferred over sRGB int width; //Pixels per row int height; //Pixels per column void *data; //Pointer to binary texture data }; - Texture2D *loadTexture(const std::string &path, const std::string &fileName); + Texture2D *loadTexture(const std::string &path, const std::string &fileName, const bool prefereLinear = false); struct Material : public RefCount { struct Param : public RefCount { @@ -96,12 +105,12 @@ namespace ospray { void set(vec3f v) { clear(); type = FLOAT_3; f[0] = v.x; f[1] = v.y; f[2] = v.z; } void set(vec4f v) { clear(); type = FLOAT_3; f[0] = v.x; f[1] = v.y; f[2] = v.z; f[3] = v.w; } - void set(int32 v) { clear(); type = INT; i[0] = v; } + void set(int32_t v) { clear(); type = INT; i[0] = v; } void set(vec2i v) { clear(); type = INT_2; i[0] = v.x; i[1] = v.y; } void set(vec3i v) { clear(); type = INT_3; i[0] = v.x; i[1] = v.y; i[2] = v.z; } void set(vec4i v) { clear(); type = INT_3; i[0] = v.x; i[1] = v.y; i[2] = v.z; i[3] = v.w; } - void set(uint32 v) { clear(); type = UINT; i[0] = v; } + void set(uint32_t v) { clear(); type = UINT; i[0] = v; } void set(vec2ui v) { clear(); type = UINT_2; i[0] = v.x; i[1] = v.y; } void set(vec3ui v) { clear(); type = UINT_3; i[0] = v.x; i[1] = v.y; i[2] = v.z; } void set(vec4ui v) { clear(); type = UINT_3; i[0] = v.x; i[1] = v.y; i[2] = v.z; i[3] = v.w; } @@ -112,8 +121,8 @@ namespace ospray { } union { float f[4]; - int32 i[4]; - uint32 ui[4]; + int32_t i[4]; + uint32_t ui[4]; const char *s; void *ptr; }; @@ -130,12 +139,12 @@ namespace ospray { vec3f getParam(const char *name, vec3f defaultVal); vec4f getParam(const char *name, vec4f devaultVal); - int32 getParam(const char *name, int32 defaultVal); + int32_t getParam(const char *name, int32_t defaultVal); vec2i getParam(const char *name, vec2i defaultVal); vec3i getParam(const char *name, vec3i defaultVal); vec4i getParam(const char *name, vec4i defaultVal); - uint32 getParam(const char *name, uint32 defaultVal); + uint32_t getParam(const char *name, uint32_t defaultVal); vec2ui getParam(const char *name, vec2ui defaultVal); vec3ui getParam(const char *name, vec3ui defaultVal); vec4ui getParam(const char *name, vec4ui defaultVal); @@ -171,7 +180,7 @@ namespace ospray { }; struct Triangle { - uint32 v0, v1, v2; + uint32_t v0, v1, v2; }; /*! default triangle mesh layout */ @@ -196,7 +205,7 @@ namespace ospray { 'materialList'. Will eventually get merged into the foruth component of the triangle, but right now ospray/embree do not yet allow this ... */ - std::vector triangleMaterialId; + std::vector triangleMaterialId; box3f bounds; /*!< bounding box of all vertices */ @@ -204,19 +213,24 @@ namespace ospray { int size() const { return triangle.size(); } Ref material; box3f getBBox(); - Mesh() : bounds(embree::empty) {}; + Mesh() : bounds(ospcommon::empty) {}; }; struct Instance : public RefCount { + Instance() : meshID(0), xfm(ospcommon::one), ospGeometry(NULL) {} + Instance(int meshID, affine3f xfm=ospcommon::one) + : meshID(meshID), xfm(xfm), ospGeometry(NULL) + {}; + Instance(const Instance &o) + : meshID(o.meshID), xfm(o.xfm), ospGeometry(o.ospGeometry) + {} + affine3f xfm; int meshID; OSPGeometry ospGeometry; - - Instance(int meshID=0, affine3f xfm=embree::one) - : meshID(meshID), xfm(xfm), ospGeometry(NULL) - {}; }; + bool operator==(const Instance &a, const Instance &b); bool operator!=(const Instance &a, const Instance &b); @@ -237,28 +251,28 @@ namespace ospray { }; /*! import a wavefront OBJ file, and add it to the specified model */ - void importOBJ(Model &model, const embree::FileName &fileName); + void importOBJ(Model &model, const FileName &fileName); /*! import a HBP file, and add it to the specified model */ - void importHBP(Model &model, const embree::FileName &fileName); + void importHBP(Model &model, const FileName &fileName); /*! import a TRI file (format:vec3fa[3][numTris]), and add it to the specified model */ - void importTRI(Model &model, const embree::FileName &fileName); + void importTRI(Model &model, const FileName &fileName); /*! import a wavefront OBJ file, and add it to the specified model */ - void importRIVL(Model &model, const embree::FileName &fileName); + void importRIVL(Model &model, const FileName &fileName); /*! import a STL file, and add it to the specified model */ - void importSTL(Model &model, const embree::FileName &fileName); + void importSTL(Model &model, const FileName &fileName); /*! import a list of STL files */ - void importSTL(std::vector &animation, const embree::FileName &fileName); + void importSTL(std::vector &animation, const FileName &fileName); /*! import a list of X3D files */ - void importX3D(Model &model, const embree::FileName &fileName); + void importX3D(Model &model, const FileName &fileName); /*! import a MiniSG MSG file, and add it to the specified model */ - void importMSG(Model &model, const embree::FileName &fileName); + void importMSG(Model &model, const FileName &fileName); void error(const std::string &err); diff --git a/apps/modelViewer/modelViewer.cpp b/apps/modelViewer/modelViewer.cpp index 3c3249c4fb..80e22f0f79 100644 --- a/apps/modelViewer/modelViewer.cpp +++ b/apps/modelViewer/modelViewer.cpp @@ -14,6 +14,8 @@ // limitations under the License. // // ======================================================================== // +#define WARN_ON_INCLUDING_OSPCOMMON 1 + // viewer widget #include "apps/common/widgets/glut3D.h" // mini scene graph for loading the model @@ -23,8 +25,11 @@ // stl #include +#include namespace ospray { + using namespace ospcommon; + using std::cout; using std::endl; bool doShadows = 1; @@ -47,7 +52,7 @@ namespace ospray { int maxAccum = 64; int spp = 1; /*! number of samples per pixel */ int maxDepth = 2; // only set with home/end - unsigned int maxObjectsToConsider = (uint32)-1; + unsigned int maxObjectsToConsider = (uint32_t)-1; // if turned on, we'll put each triangle mesh into its own instance, no matter what bool forceInstancing = false; /*! if turned on we're showing the depth buffer rather than the (accum'ed) color buffer */ @@ -94,7 +99,7 @@ namespace ospray { // helper function to write the rendered image as PPM file void writePPM(const char *fileName, const int sizeX, const int sizeY, - const uint32 *pixel) + const uint32_t *pixel) { FILE *file = fopen(fileName, "wb"); fprintf(file, "P6\n%i %i\n255\n", sizeX, sizeY); @@ -140,7 +145,6 @@ namespace ospray { Assert(camera != NULL && "could not create camera"); ospSet3f(camera,"pos",-1,1,-1); ospSet3f(camera,"dir",+1,-1,+1); -// ospSet1f(camera,"fovy",120); ospCommit(camera); ospSetObject(renderer,"world",model); @@ -157,9 +161,10 @@ namespace ospray { Glut3DWidget::reshape(newSize); g_windowSize = newSize; if (fb) ospFreeFrameBuffer(fb); - fb = ospNewFrameBuffer((const osp::vec2i&)newSize,OSP_RGBA_I8,OSP_FB_COLOR|OSP_FB_DEPTH|OSP_FB_ACCUM); - ospSet1f(fb, "gamma", 2.2f); - ospCommit(fb); + fb = ospNewFrameBuffer((const osp::vec2i&)newSize, + OSP_FB_SRGBA, + OSP_FB_COLOR|OSP_FB_DEPTH| + OSP_FB_ACCUM|OSP_FB_VARIANCE); ospFrameBufferClear(fb,OSP_FB_ACCUM); /*! for now, let's just attach the pixel op to the _main_ frame @@ -169,7 +174,8 @@ namespace ospray { if (displayWall && displayWall->fb != fb) { PRINT(displayWall->size); displayWall->fb = ospNewFrameBuffer((const osp::vec2i&)displayWall->size, - OSP_RGBA_NONE,OSP_FB_COLOR|OSP_FB_DEPTH|OSP_FB_ACCUM); + OSP_FB_NONE,OSP_FB_COLOR| + OSP_FB_DEPTH|OSP_FB_ACCUM); ospFrameBufferClear(displayWall->fb,OSP_FB_ACCUM); if (displayWall->po == NULL) { displayWall->po = ospNewPixelOp("display_wall"); @@ -189,7 +195,7 @@ namespace ospray { forceRedraw(); } - void keypress(char key, const vec2f where) override + void keypress(char key, const vec2i &where) override { switch (key) { case 'R': @@ -219,7 +225,7 @@ namespace ospray { forceRedraw(); break; case '!': { - const uint32 * p = (uint32*)ospMapFrameBuffer(fb, OSP_FB_COLOR); + const uint32_t * p = (uint32_t*)ospMapFrameBuffer(fb, OSP_FB_COLOR); writePPM("ospmodelviewer.ppm", g_windowSize.x, g_windowSize.y, p); // ospUnmapFrameBuffer(fb,p); printf("#ospModelViewer: saved current frame to 'ospmodelviewer.ppm'\n"); @@ -265,7 +271,7 @@ namespace ospray { } } - void specialkey(int32 key, const vec2f where) override + void specialkey(int32_t key, const vec2i &where) override { switch(key) { case GLUT_KEY_PAGE_UP: @@ -295,7 +301,7 @@ namespace ospray { } } - void mouseButton(int32 whichButton, bool released, const vec2i &pos) override + void mouseButton(int32_t whichButton, bool released, const vec2i &pos) override { Glut3DWidget::mouseButton(whichButton, released, pos); if(currButtonState == (1<depth == 1) { - if( msgTex->channels == 3 ) type = OSP_UCHAR3; - if( msgTex->channels == 4 ) type = OSP_UCHAR4; + if( msgTex->channels == 1 ) type = OSP_TEXTURE_R8; + if( msgTex->channels == 3 ) + 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) { - if( msgTex->channels == 3 ) type = OSP_FLOAT3; - if( msgTex->channels == 4 ) type = OSP_FLOAT3A; + if( msgTex->channels == 1 ) type = OSP_TEXTURE_R32F; + if( msgTex->channels == 3 ) type = OSP_TEXTURE_RGB32F; + if( msgTex->channels == 4 ) type = OSP_TEXTURE_RGBA32F; } - OSPTexture2D ospTex = ospNewTexture2D( msgTex->width, - msgTex->height, + vec2i texSize(msgTex->width, msgTex->height); + OSPTexture2D ospTex = ospNewTexture2D( (osp::vec2i&)texSize, type, msgTex->data, 0); @@ -620,7 +630,7 @@ namespace ospray { } else if (av[i][0] == '-') { error("unknown commandline argument '"+arg+"'"); } else { - embree::FileName fn = arg; + FileName fn = arg; if (fn.ext() == "stl") { miniSG::importSTL(*msgModel,fn); } else if (fn.ext() == "msg") { @@ -678,6 +688,15 @@ namespace ospray { ospModel = ospNewModel(); ospRenderer = ospNewRenderer(rendererType.c_str()); + + // Set renderer defaults (if not using 'aoX' renderers) + if (rendererType[0] != 'a' && rendererType[1] != 'o') + { + ospSet1i(ospRenderer, "aoSamples", 1); + ospSet1i(ospRenderer, "shadowsEnabled", 1); + } + + // ospSet1f(ospRenderer, "varianceThreshold", 0.0002); if (!ospRenderer) throw std::runtime_error("could not create ospRenderer '"+rendererType+"'"); Assert(ospRenderer != NULL && "could not create ospRenderer"); @@ -714,17 +733,13 @@ namespace ospray { std::vector instanceModels; for (size_t i=0;imesh.size();i++) { - printf("Mesh %li/%li\n",i,msgModel->mesh.size()); Ref msgMesh = msgModel->mesh[i]; - // DBG(PRINT(msgMesh.ptr)); // create ospray mesh OSPGeometry ospMesh = g_alpha ? ospNewGeometry("alpha_aware_triangle_mesh") : ospNewGeometry("trianglemesh"); // check if we have to transform the vertices: if (doesInstancing == false && msgModel->instance[i] != miniSG::Instance(i)) { - // cout << "Transforming vertex array ..." << endl; - // PRINT(msgMesh->position.size()); for (size_t vID=0;vIDposition.size();vID++) { msgMesh->position[vID] = xfmPoint(msgModel->instance[i].xfm, msgMesh->position[vID]); diff --git a/apps/ospTutorial.c b/apps/ospTutorial.c new file mode 100644 index 0000000000..506c960e4d --- /dev/null +++ b/apps/ospTutorial.c @@ -0,0 +1,146 @@ +// ======================================================================== // +// 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. // +// ======================================================================== // + + +/* This is a small example tutorial how to use OSPRay in an application. + * + * On Linux build it in the build_directory with + * gcc -std=c99 ../apps/ospTutorial.c -I ../ospray/include -I .. -I ../ospray/embree/common ./libospray.so -Wl,-rpath,. -o ospTutorialC + * On Windows build it in the build_directory\$Configuration with + * cl ..\..\apps\ospTutorial.c /EHsc -I ..\..\ospray\include -I ..\.. -I ..\..\ospray\embree\common ospray.lib + */ + +#include +#include +#ifdef _WIN32 +# include +#else +# include +#endif +#include "ospray/ospray.h" + +// helper function to write the rendered image as PPM file +void writePPM(const char *fileName, + const osp_vec2i *size, + const uint32_t *pixel) +{ + FILE *file = fopen(fileName, "wb"); + fprintf(file, "P6\n%i %i\n255\n", size->x, size->y); + unsigned char *out = (unsigned char *)alloca(3*size->x); + for (int y = 0; y < size->y; y++) { + const unsigned char *in = (const unsigned char *)&pixel[(size->y-1-y)*size->x]; + for (int x = 0; x < size->x; x++) { + out[3*x + 0] = in[4*x + 0]; + out[3*x + 1] = in[4*x + 1]; + out[3*x + 2] = in[4*x +2 ]; + } + fwrite(out, 3*size->x, sizeof(char), file); + } + fprintf(file, "\n"); + fclose(file); +} + + +int main(int ac, const char **av) { + // image size + osp_vec2i imgSize; + imgSize.x = 1024; // width + imgSize.y = 768; // height + + // camera + float cam_pos[] = {0.f, 0.f, 0.f}; + float cam_up [] = {0.f, 1.f, 0.f}; + float cam_view [] = {0.1f, 0.f, 1.f}; + + // triangle mesh data + float vertex[] = { -1.0f, -1.0f, 3.0f, 0.f, + -1.0f, 1.0f, 3.0f, 0.f, + 1.0f, -1.0f, 3.0f, 0.f, + 0.1f, 0.1f, 0.3f, 0.f }; + float color[] = { 0.9f, 0.5f, 0.5f, 1.0f, + 0.8f, 0.8f, 0.8f, 1.0f, + 0.8f, 0.8f, 0.8f, 1.0f, + 0.5f, 0.9f, 0.5f, 1.0f }; + int32_t index[] = { 0, 1, 2, + 1, 2, 3 }; + + + // initialize OSPRay; OSPRay parses (and removes) its commandline parameters, e.g. "--osp:debug" + ospInit(&ac, av); + + // create and setup camera + OSPCamera camera = ospNewCamera("perspective"); + ospSetf(camera, "aspect", imgSize.x/(float)imgSize.y); + ospSet3fv(camera, "pos", cam_pos); + ospSet3fv(camera, "dir", cam_view); + ospSet3fv(camera, "up", cam_up); + ospCommit(camera); // commit each object to indicate modifications are done + + + // create and setup model and mesh + OSPGeometry mesh = ospNewGeometry("triangles"); + OSPData data = ospNewData(4, OSP_FLOAT3A, vertex, 0); // OSP_FLOAT3 format is also supported for vertex positions (currently not on MIC) + ospCommit(data); + ospSetData(mesh, "vertex", data); + + data = ospNewData(4, OSP_FLOAT4, color, 0); + ospCommit(data); + ospSetData(mesh, "vertex.color", data); + + data = ospNewData(2, OSP_INT3, index, 0); // OSP_INT4 format is also supported for triangle indices + ospCommit(data); + ospSetData(mesh, "index", data); + + ospCommit(mesh); + + + OSPModel world = ospNewModel(); + ospAddGeometry(world, mesh); + ospCommit(world); + + + // create and setup renderer + OSPRenderer renderer = ospNewRenderer("scivis"); // choose Scientific Visualization renderer + ospSet1f(renderer, "aoWeight", 1.0f); // with full Ambient Occlusion + ospSet1i(renderer, "aoSamples", 1); + ospSetObject(renderer, "model", world); + ospSetObject(renderer, "camera", camera); + ospCommit(renderer); + + + // create and setup framebuffer + OSPFrameBuffer framebuffer = ospNewFrameBuffer(&imgSize, OSP_FB_SRGBA, OSP_FB_COLOR | /*OSP_FB_DEPTH |*/ OSP_FB_ACCUM); + ospFrameBufferClear(framebuffer, OSP_FB_COLOR | OSP_FB_ACCUM); + + // render one frame + ospRenderFrame(framebuffer, renderer, OSP_FB_COLOR | OSP_FB_ACCUM); + + // access framebuffer and write its content as PPM file + const uint32_t * fb = (uint32_t*)ospMapFrameBuffer(framebuffer, OSP_FB_COLOR); + writePPM("firstFrameC.ppm", &imgSize, fb); + ospUnmapFrameBuffer(fb, framebuffer); + + + // render 10 more frames, which are accumulated to result in a better converged image + for (int frames = 0; frames < 10; frames++) + ospRenderFrame(framebuffer, renderer, OSP_FB_COLOR | OSP_FB_ACCUM); + + fb = (uint32_t*)ospMapFrameBuffer(framebuffer, OSP_FB_COLOR); + writePPM("accumulatedFrameC.ppm", &imgSize, fb); + ospUnmapFrameBuffer(fb, framebuffer); + + return 0; +} diff --git a/apps/ospTutorial.cpp b/apps/ospTutorial.cpp index 4afc2b6377..f9c7111ec0 100644 --- a/apps/ospTutorial.cpp +++ b/apps/ospTutorial.cpp @@ -115,13 +115,14 @@ int main(int ac, const char **av) { // create and setup renderer OSPRenderer renderer = ospNewRenderer("scivis"); // choose Scientific Visualization renderer ospSet1f(renderer, "aoWeight", 1.0f); // with full Ambient Occlusion + ospSet1i(renderer, "aoSamples", 1); ospSetObject(renderer, "model", world); ospSetObject(renderer, "camera", camera); ospCommit(renderer); // create and setup framebuffer - OSPFrameBuffer framebuffer = ospNewFrameBuffer(imgSize, OSP_RGBA_I8, OSP_FB_COLOR | /*OSP_FB_DEPTH |*/ OSP_FB_ACCUM); + OSPFrameBuffer framebuffer = ospNewFrameBuffer(imgSize, OSP_FB_SRGBA, OSP_FB_COLOR | /*OSP_FB_DEPTH |*/ OSP_FB_ACCUM); ospFrameBufferClear(framebuffer, OSP_FB_COLOR | OSP_FB_ACCUM); // render one frame diff --git a/apps/particleViewer/Model.cpp b/apps/particleViewer/Model.cpp index ca70f60810..cb9dbf5891 100644 --- a/apps/particleViewer/Model.cpp +++ b/apps/particleViewer/Model.cpp @@ -15,6 +15,8 @@ // ======================================================================== // #include "Model.h" +// stl +#include extern int yyparse(); extern void yyerror(const char* msg); @@ -31,14 +33,14 @@ namespace ospray { const int mx = 13*17*43; const int my = 11*29; const int mz = 7*23*63; - const uint32 g = (i * (3*5*127)+12312314); + const uint32_t g = (i * (3*5*127)+12312314); return vec3f((g % mx)*(1.f/(mx-1)), (g % my)*(1.f/(my-1)), (g % mz)*(1.f/(mz-1))); } /*! read given file with atom type definitions */ - void Model::readAtomTypeDefinitions(const embree::FileName &fn) + void Model::readAtomTypeDefinitions(const FileName &fn) { FILE *file = fopen(fn.str().c_str(),"r"); if (!file) { @@ -192,7 +194,7 @@ namespace ospray { box3f Model::getBBox() const { - box3f bbox = embree::empty; + box3f bbox = empty; for (int i=0;i #include namespace ospray { namespace particle { + using namespace ospcommon; struct Model { struct AtomType { @@ -49,7 +52,7 @@ namespace ospray { std::map *> attribute; /*! read given file with atom type definitions */ - void readAtomTypeDefinitions(const embree::FileName &fn); + void readAtomTypeDefinitions(const FileName &fn); int getAtomType(const std::string &name); diff --git a/apps/particleViewer/ParticleViewer.cpp b/apps/particleViewer/ParticleViewer.cpp index be68a946c1..0b9215c4c7 100644 --- a/apps/particleViewer/ParticleViewer.cpp +++ b/apps/particleViewer/ParticleViewer.cpp @@ -21,12 +21,12 @@ #include "apps/common/widgets/glut3D.h" // ospray, for rendering #include "ospray/ospray.h" -#include "common/parallel_for.h" +#include "common/tasking/parallel_for.h" // particle viewer #include "Model.h" #include "uintah.h" -// embree -#include "sys/filename.h" +// ospcommon +#include "common/FileName.h" namespace ospray { namespace particle { @@ -86,14 +86,12 @@ namespace ospray { ospCommit(renderer); }; - virtual void reshape(const ospray::vec2i &_newSize) + virtual void reshape(const ospcommon::vec2i &_newSize) { Glut3DWidget::reshape(_newSize); if (fb) ospFreeFrameBuffer(fb); const auto &newSize = reinterpret_cast(_newSize); - fb = ospNewFrameBuffer(newSize,OSP_RGBA_I8,OSP_FB_COLOR|OSP_FB_ACCUM); - ospSet1f(fb, "gamma", 2.2f); - ospCommit(fb); + fb = ospNewFrameBuffer(newSize, OSP_FB_SRGBA, OSP_FB_COLOR | OSP_FB_ACCUM); ospFrameBufferClear(fb,OSP_FB_ACCUM); accumID = 0; ospSetf(camera,"aspect",viewPort.aspect); @@ -102,7 +100,7 @@ namespace ospray { setTitle("OSPRay Particle Viewer"); } - virtual void keypress(char key, const vec2f where) + virtual void keypress(char key, const vec2i &where) { switch(key) { case 'Q': exit(0); @@ -169,7 +167,7 @@ namespace ospray { if (accumID < maxAccum) forceRedraw(); - ucharFB = (uint32 *) ospMapFrameBuffer(fb); + ucharFB = (uint32_t *) ospMapFrameBuffer(fb); frameBufferMode = Glut3DWidget::FRAMEBUFFER_UCHAR; Glut3DWidget::display(); @@ -226,17 +224,17 @@ namespace ospray { struct DeferredLoadJob { DeferredLoadJob(particle::Model *model, - const embree::FileName &xyzFileName, - const embree::FileName &defFileName) + const FileName &xyzFileName, + const FileName &defFileName) : model(model), xyzFileName(xyzFileName), defFileName(defFileName) {} //! the mode we still have to load particle::Model *model; //! file name of xyz file to be loaded into this model - embree::FileName xyzFileName; + FileName xyzFileName; //! name of atom type defintion file active when this xyz file was added - embree::FileName defFileName; + FileName defFileName; }; void ospParticleViewerMain(int &ac, const char **&av) @@ -245,7 +243,7 @@ namespace ospray { cout << "ospParticleViewer: starting to process cmdline arguments" << endl; std::vector deferredLoadingListXYZ; - embree::FileName defFileName = ""; + FileName defFileName = ""; for (int i=1;iloadXYZ(fn); - // std::pair loadJob(m,fn.str()); + // std::pair loadJob(m,fn.str()); deferredLoadingListXYZ.push_back(new DeferredLoadJob(m,fn,defFileName)); particleModel.push_back(m); } else if (fn.ext() == "xyz2") { @@ -299,8 +297,8 @@ namespace ospray { error("no input file specified"); parallel_for(deferredLoadingListXYZ.size(), [&](int i){ - embree::FileName defFileName = deferredLoadingListXYZ[i]->defFileName; - embree::FileName xyzFileName = deferredLoadingListXYZ[i]->xyzFileName; + FileName defFileName = deferredLoadingListXYZ[i]->defFileName; + FileName xyzFileName = deferredLoadingListXYZ[i]->xyzFileName; particle::Model *model = deferredLoadingListXYZ[i]->model; if (defFileName.str() != "") diff --git a/apps/particleViewer/uintah.cpp b/apps/particleViewer/uintah.cpp index 20deb6817e..62fa19e025 100644 --- a/apps/particleViewer/uintah.cpp +++ b/apps/particleViewer/uintah.cpp @@ -16,11 +16,12 @@ #undef NDEBUG -#include "ospray/common/OSPCommon.h" #include "apps/common/xml/XML.h" #include "Model.h" // embree -#include "common/sys/filename.h" +#include "common/FileName.h" +// std +#include namespace ospray { namespace particle { @@ -257,7 +258,7 @@ namespace ospray { void parse__Uintah_Datafile(Model *model, const std::string &fileName) { - std::string basePath = embree::FileName(fileName).path(); + std::string basePath = FileName(fileName).path(); xml::XMLDoc *doc = NULL; try { @@ -349,7 +350,7 @@ namespace ospray { assert(doc); assert(doc->child.size() == 1); assert(doc->child[0]->name == "Uintah_timestep"); - std::string basePath = embree::FileName(s).path(); + std::string basePath = FileName(s).path(); parse__Uintah_timestep(model, basePath, doc->child[0]); std::stringstream attrs; @@ -361,7 +362,7 @@ namespace ospray { std::cout << "#osp:mpm: read " << s << " : " << model->atom.size() << " particles (" << attrs.str() << ")" << std::endl; - box3f bounds = embree::empty; + box3f bounds = empty; for (int i=0;iatom.size();i++) { bounds.extend(model->atom[i].position); } diff --git a/apps/qtViewer/CMakeLists.txt b/apps/qtViewer/CMakeLists.txt index ce302c2d41..0ad957c3d9 100644 --- a/apps/qtViewer/CMakeLists.txt +++ b/apps/qtViewer/CMakeLists.txt @@ -16,9 +16,6 @@ CONFIGURE_OSPRAY() -#MESSAGE("EXTERNAL_EMBREE_DIR ${EXTERNAL_EMBREE_DIR}") -#MESSAGE("OSPRAY_EMBREE_SOURCE_DIR ${OSPRAY_EMBREE_SOURCE_DIR}") - INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/ospray/include) INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) @@ -59,7 +56,7 @@ QT4_WRAP_CPP(MOC_OUTFILES ${MOC_HEADERS}) ADD_EXECUTABLE(ospQtViewer ${SRCS} ${MOC_OUTFILES}) TARGET_LINK_LIBRARIES(ospQtViewer ${LIBS} - ospray_sg${OSPRAY_LIB_SUFFIX} + ospray_sg ${TBB_LIBRARY_MALLOC} ${TBB_LIBRARY} ) diff --git a/apps/qtViewer/FPSCounter.cpp b/apps/qtViewer/FPSCounter.cpp index e5a54477e4..df1e9a162c 100644 --- a/apps/qtViewer/FPSCounter.cpp +++ b/apps/qtViewer/FPSCounter.cpp @@ -28,12 +28,12 @@ namespace ospray { void FPSCounter::startRender() { - frameStartTime = ospray::getSysTime(); + frameStartTime = ospcommon::getSysTime(); } void FPSCounter::doneRender() { - double seconds = ospray::getSysTime() - frameStartTime; + double seconds = ospcommon::getSysTime() - frameStartTime; fps = 1./seconds; smooth_nom = smooth_nom * 0.8 + seconds; smooth_den = smooth_den * 0.8 + 1.; diff --git a/apps/qtViewer/ModelViewer.cpp b/apps/qtViewer/ModelViewer.cpp index 160761dbe3..99cb2e5fc5 100644 --- a/apps/qtViewer/ModelViewer.cpp +++ b/apps/qtViewer/ModelViewer.cpp @@ -17,9 +17,11 @@ #include "ModelViewer.h" #include "widgets/affineSpaceManipulator/HelperGeometry.h" #include "FPSCounter.h" - +// sg #include "sg/SceneGraph.h" #include "sg/Renderer.h" +// std +#include namespace ospray { namespace viewer { @@ -191,9 +193,18 @@ namespace ospray { // add combo box and stacked widget entries pageComboBox->addItem(tr(name.c_str())); + TransferFunction *xf = xferFuncs[i].ptr; + assert(xf); // create a transfer function editor for this transfer function node QOSPTransferFunctionEditor *xfEd - = new QOSPTransferFunctionEditor(xferFuncs[i]); + = new QOSPTransferFunctionEditor(xf); + const std::vector > &alpha = xf->getAlphaArray(); + if (!alpha.empty()) { + std::vector points; + for (int i=0;isetOpacityPoints(points); + } stackedWidget->addWidget(xfEd); connect(xfEd, SIGNAL(transferFunctionChanged()), this, SLOT(render())); @@ -388,8 +399,8 @@ namespace ospray { createTimeSlider(); createEditorWidgetStack(); - createLightManipulator(); createTransferFunctionEditor(); + createLightManipulator(); if (fullscreen) { setWindowState(windowState() | Qt::WindowFullScreen); diff --git a/apps/qtViewer/ModelViewer.h b/apps/qtViewer/ModelViewer.h index 780a29159f..5f6a8345cb 100644 --- a/apps/qtViewer/ModelViewer.h +++ b/apps/qtViewer/ModelViewer.h @@ -16,6 +16,8 @@ #pragma once +#define WARN_ON_INCLUDING_OSPCOMMON 1 + // widgets #include "widgets/affineSpaceManipulator/QAffineSpaceManipulator.h" #include "widgets/transferFunction/QTransferFunctionEditor.h" diff --git a/apps/qtViewer/main.cpp b/apps/qtViewer/main.cpp index 6fe649c9da..1507034cac 100644 --- a/apps/qtViewer/main.cpp +++ b/apps/qtViewer/main.cpp @@ -14,16 +14,14 @@ // limitations under the License. // // ======================================================================== // +// viewer +#include "ModelViewer.h" // ospray #include "ospray/ospray.h" // qt #include #include #include -// viewer -#include "ModelViewer.h" -// embree -#include "common/sys/filename.h" // scene graph #include "sg/module/Module.h" #include "sg/importer/Importer.h" @@ -33,7 +31,7 @@ namespace ospray { using std::cout; using std::endl; - static const std::string DEFAULT_INTEGRATOR_NAME = "ao2"; + static const std::string DEFAULT_INTEGRATOR_NAME = "scivis"; //ao2"; // static const std::string DEFAULT_INTEGRATOR_NAME = "eyeLight_geomID"; @@ -124,7 +122,7 @@ namespace ospray { throw std::runtime_error("#osp:qtv: unknown cmdline param '"+arg+"'"); } } else { - embree::FileName fn = arg; + FileName fn = arg; if (fn.ext() == "osp" || fn.ext() == "pkd") { world = sg::loadOSP(fn.str()); // } else if (fn.ext() == "atom") { diff --git a/apps/qtViewer/sg/CMakeLists.txt b/apps/qtViewer/sg/CMakeLists.txt index 47e3af4aa9..f52f6eb690 100644 --- a/apps/qtViewer/sg/CMakeLists.txt +++ b/apps/qtViewer/sg/CMakeLists.txt @@ -52,6 +52,7 @@ ADD_LIBRARY(ospray_sg STATIC ) TARGET_LINK_LIBRARIES(ospray_sg - ospray_xml ospray + ospray_common + ospray_xml ) diff --git a/apps/qtViewer/sg/Renderer.cpp b/apps/qtViewer/sg/Renderer.cpp index 306da2e9ed..f4d8c9fadb 100644 --- a/apps/qtViewer/sg/Renderer.cpp +++ b/apps/qtViewer/sg/Renderer.cpp @@ -54,6 +54,7 @@ namespace ospray { integrator->getOSPHandle(), OSP_FB_COLOR|OSP_FB_ACCUM); accumID++; + return 0; } @@ -70,7 +71,7 @@ namespace ospray { accumID = 0; // cout << "resetting accum" << endl; if (frameBuffer) - frameBuffer->clearAccum(); + frameBuffer->clear(); } } diff --git a/apps/qtViewer/sg/Renderer.h b/apps/qtViewer/sg/Renderer.h index 2041edf590..d3601b93b6 100644 --- a/apps/qtViewer/sg/Renderer.h +++ b/apps/qtViewer/sg/Renderer.h @@ -20,7 +20,7 @@ namespace ospray { namespace sg { - struct Renderer : public embree::RefCount { + struct Renderer : public RefCount { Renderer(); /*! re-start accumulation (for progressive rendering). make sure diff --git a/apps/qtViewer/sg/SceneGraph.cpp b/apps/qtViewer/sg/SceneGraph.cpp index 95a86edb2d..df050093cb 100644 --- a/apps/qtViewer/sg/SceneGraph.cpp +++ b/apps/qtViewer/sg/SceneGraph.cpp @@ -41,7 +41,7 @@ namespace ospray { template<> OSPDataType ParamT::getOSPDataType() const { return OSP_FLOAT4; } - template<> OSPDataType ParamT::getOSPDataType() const + template<> OSPDataType ParamT::getOSPDataType() const { return OSP_INT; } template<> OSPDataType ParamT::getOSPDataType() const { return OSP_INT2; } diff --git a/apps/qtViewer/sg/SceneGraph.h b/apps/qtViewer/sg/SceneGraph.h index c77ef80f46..392a91b7ad 100644 --- a/apps/qtViewer/sg/SceneGraph.h +++ b/apps/qtViewer/sg/SceneGraph.h @@ -18,7 +18,6 @@ #ifndef OSP_SG_INCLUDED #define OSP_SG_INCLUDED 1 - // std #include @@ -32,12 +31,12 @@ #include "sg/common/Data.h" #include "sg/common/FrameBuffer.h" -// embree -#include "common/sys/filename.h" +// ospcommon +#include "common/FileName.h" namespace ospray { namespace sg { - using embree::FileName; + using ospcommon::FileName; /*! \brief allows for adding semantical info to a model/scene graph. \note will not do anything by itself. */ diff --git a/apps/qtViewer/sg/common/Common.h b/apps/qtViewer/sg/common/Common.h index 87392ad578..e2bfa751c0 100644 --- a/apps/qtViewer/sg/common/Common.h +++ b/apps/qtViewer/sg/common/Common.h @@ -16,14 +16,31 @@ #pragma once +// use ospcommon vector types in ospray.h +#define OSPRAY_EXTERNAL_VECTOR_TYPES 1 +// ospcommon +#include "common/AffineSpace.h" + +namespace osp { + using ospcommon::vec2i; + using ospcommon::vec2f; + using ospcommon::vec3i; + using ospcommon::vec3f; + using ospcommon::vec4f; + using ospcommon::affine3f; +} + + // ospray API #include "ospray/ospray.h" -// ospray -#include "ospray/common/OSPCommon.h" // STL namespace ospray { namespace sg { + using namespace ospcommon; + + typedef AffineSpace3f affine3f; + typedef LinearSpace3f linear3f; #define THROW_SG_ERROR(where,err) \ throw std::runtime_error("in "+std::string(__PRETTY_FUNCTION__)+":"+std::string(err)); diff --git a/apps/qtViewer/sg/common/Data.h b/apps/qtViewer/sg/common/Data.h index 8e09718acb..97c62b6e3c 100644 --- a/apps/qtViewer/sg/common/Data.h +++ b/apps/qtViewer/sg/common/Data.h @@ -108,11 +108,11 @@ namespace ospray { virtual vec3fa get3fa(index_t idx) const { return this->base[idx]; } }; - struct DataArray1i : public DataArrayT { - DataArray1i(int32 *base, size_t size, bool mine=true) - : DataArrayT(base,size,mine) + struct DataArray1i : public DataArrayT { + DataArray1i(int32_t *base, size_t size, bool mine=true) + : DataArrayT(base,size,mine) {} - virtual int32 get1i(index_t idx) const { return this->base[idx]; } + virtual int32_t get1i(index_t idx) const { return this->base[idx]; } }; struct DataArray3i : public DataArrayT { diff --git a/apps/qtViewer/sg/common/FrameBuffer.h b/apps/qtViewer/sg/common/FrameBuffer.h index 9f3ee95084..0fa30621ed 100644 --- a/apps/qtViewer/sg/common/FrameBuffer.h +++ b/apps/qtViewer/sg/common/FrameBuffer.h @@ -65,9 +65,7 @@ namespace ospray { inline void FrameBuffer::createFB() { - ospFrameBuffer = ospNewFrameBuffer((const osp::vec2i&)size,OSP_RGBA_I8,OSP_FB_COLOR|OSP_FB_ACCUM); - ospSet1f(ospFrameBuffer, "gamma", 2.2f); - ospCommit(ospFrameBuffer); + ospFrameBuffer = ospNewFrameBuffer((const osp::vec2i&)size, OSP_FB_SRGBA, OSP_FB_COLOR | OSP_FB_ACCUM); } inline void FrameBuffer::destroyFB() diff --git a/apps/qtViewer/sg/common/Integrator.cpp b/apps/qtViewer/sg/common/Integrator.cpp index 055955422e..a1946e2e09 100644 --- a/apps/qtViewer/sg/common/Integrator.cpp +++ b/apps/qtViewer/sg/common/Integrator.cpp @@ -26,7 +26,15 @@ namespace ospray { { if (!ospRenderer) { ospRenderer = ospNewRenderer(type.c_str()); - if (!ospRenderer) + + // Set renderer defaults (if not using 'aoX' renderers) + if (type[0] != 'a' && type[1] != 'o') + { + ospSet1i(ospRenderer, "aoSamples", 1); + ospSet1i(ospRenderer, "shadowsEnabled", 1); + } + + if (!ospRenderer) throw std::runtime_error("#osp:sg:SceneGraph: could not create renderer (of type '"+type+"')"); } if (lastCommitted >= lastModified) return; diff --git a/apps/qtViewer/sg/common/Node.cpp b/apps/qtViewer/sg/common/Node.cpp index 2f3491b9e8..56585a0efb 100644 --- a/apps/qtViewer/sg/common/Node.cpp +++ b/apps/qtViewer/sg/common/Node.cpp @@ -36,5 +36,12 @@ namespace ospray { namedNodes[name] = node; } + void Node::setFromXML(const xml::Node *const node, + const unsigned char *binBasePtr) + { + throw std::runtime_error(toString()+":setFromXML() not implemented for XML node type " + +node->name); + }; + } } diff --git a/apps/qtViewer/sg/common/Node.h b/apps/qtViewer/sg/common/Node.h index 302bab08a4..eb7fa0fdaa 100644 --- a/apps/qtViewer/sg/common/Node.h +++ b/apps/qtViewer/sg/common/Node.h @@ -23,6 +23,8 @@ #include // xml #include "apps/common/xml/XML.h" +// ospcommon +#include "common/vec.h" namespace ospray { @@ -49,7 +51,7 @@ namespace ospray { \note This is only the abstract base class, actual instantiations are the in the 'ParamT' template. */ - struct Param : public embree::RefCount { + struct Param : public RefCount { /*! constructor. the passed name alwasys remains constant */ Param(const std::string &name) : name(name) {}; /*! return name of this parameter. the value is in the derived class */ @@ -79,7 +81,7 @@ namespace ospray { const affine3f xfm; //!< affine geometry transform matrix //! create a new context - RenderContext() : world(NULL), integrator(NULL), xfm(embree::one) {}; + RenderContext() : world(NULL), integrator(NULL), xfm(one) {}; //! create a new context with new transformation matrix RenderContext(const RenderContext &other, const affine3f &newXfm) @@ -88,7 +90,7 @@ namespace ospray { }; /*! \brief base node of all scene graph nodes */ - struct Node : public embree::RefCount + struct Node : public RefCount { Node() : lastModified(1), lastCommitted(0) {}; @@ -112,8 +114,8 @@ namespace ospray { existant) that contains additional binary data that the xml node fields may point into */ - virtual void setFromXML(const xml::Node *const node, const unsigned char *binBasePtr) - { throw std::runtime_error("setFromXML() not implemented for node type "+node->name); }; + virtual void setFromXML(const xml::Node *const node, + const unsigned char *binBasePtr); //! just for convenience; add a typed 'setParam' function template @@ -135,8 +137,8 @@ namespace ospray { This function can be used by the viewer(s) for calibrating camera motion, setting default camera position, etc. Nodes for which that does not apply can simpy return - box3f(embree::empty) */ - virtual box3f getBounds() { return box3f(embree::empty); }; + box3f(empty) */ + virtual box3f getBounds() { return box3f(empty); }; //! return when this node was last modified inline TimeStamp getLastModified() const { return lastModified; }; diff --git a/apps/qtViewer/sg/common/Serialization.h b/apps/qtViewer/sg/common/Serialization.h index 79b21967f6..1566a7a1ba 100644 --- a/apps/qtViewer/sg/common/Serialization.h +++ b/apps/qtViewer/sg/common/Serialization.h @@ -17,10 +17,16 @@ #pragma once #include "sg/common/Common.h" +// ospcommon +#include "common/RefCount.h" +#include "common/AffineSpace.h" +// std +#include namespace ospray { namespace sg { - + typedef ospcommon::AffineSpace3f affine3f; + /*! class one can use to serialize all nodes in the scene graph */ struct Serialization { typedef enum { @@ -34,14 +40,14 @@ namespace ospray { instantiation vector */ DONT_FOLLOW_INSTANCES } Mode; - struct Instantiation : public embree::RefCount { + struct Instantiation : public RefCount { Ref parentWorld; affine3f xfm; - Instantiation() : parentWorld(NULL), xfm(embree::one) {} + Instantiation() : parentWorld(NULL), xfm(one) {} }; /*! describes one object that we encountered */ - struct Object : public embree::RefCount { + struct Object : public RefCount { /*! the node itself */ Ref node; diff --git a/apps/qtViewer/sg/common/Texture2D.cpp b/apps/qtViewer/sg/common/Texture2D.cpp index d59a95599e..f94bbed5f1 100644 --- a/apps/qtViewer/sg/common/Texture2D.cpp +++ b/apps/qtViewer/sg/common/Texture2D.cpp @@ -23,7 +23,7 @@ namespace ospray { /*! \detailed if file does not exist, or cannot be loaded for some reason, return NULL. Multiple loads from the same file will return the *same* texture object */ - Ref Texture2D::load(const FileName &fileName) + Ref Texture2D::load(const FileName &fileName, const bool prefereLinear) { static std::map textureCache; if (textureCache.find(fileName.str()) != textureCache.end()) @@ -85,7 +85,7 @@ namespace ospray { tex = new Texture2D; tex->size = vec2i(width,height); - tex->texelType = OSP_UCHAR3; + 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); // flip in y, because OSPRay's textures have the origin at the lower left corner @@ -105,8 +105,7 @@ namespace ospray { { if (ospTexture) return; - ospTexture = ospNewTexture2D(size.x, - size.y, + ospTexture = ospNewTexture2D((osp::vec2i&)size, texelType, texel, 0); diff --git a/apps/qtViewer/sg/common/Texture2D.h b/apps/qtViewer/sg/common/Texture2D.h index cfea9acdbc..e1a76dae8c 100644 --- a/apps/qtViewer/sg/common/Texture2D.h +++ b/apps/qtViewer/sg/common/Texture2D.h @@ -18,12 +18,12 @@ // sg #include "sg/common/Node.h" -// embree -#include "common/sys/filename.h" +// ospcommon +#include "common/FileName.h" namespace ospray { namespace sg { - using embree::FileName; + using ospcommon::FileName; /*! \brief C++ wrapper for a 2D Texture */ struct Texture2D : public Node { @@ -34,7 +34,7 @@ namespace ospray { /*! \detailed if file does not exist, or cannot be loaded for some reason, return NULL. Multiple loads from the same file will return the *same* texture object */ - static Ref load(const FileName &fileName); + static Ref load(const FileName &fileName, const bool prefereLinear = false); virtual void render(RenderContext &ctx); //! texture size, in pixels @@ -42,7 +42,7 @@ namespace ospray { //! pixel data, in whatever format specified in 'texelType' void *texel; //! format of each texel - OSPDataType texelType; + OSPTextureFormat texelType; OSPTexture2D ospTexture; }; diff --git a/apps/qtViewer/sg/common/TimeStamp.h b/apps/qtViewer/sg/common/TimeStamp.h index cd06c7cac6..5c97757f78 100644 --- a/apps/qtViewer/sg/common/TimeStamp.h +++ b/apps/qtViewer/sg/common/TimeStamp.h @@ -17,6 +17,7 @@ #pragma once #include "sg/common/Common.h" +#include "common/intrinsics.h" namespace ospray { namespace sg { @@ -26,17 +27,17 @@ namespace ospray { node's last 'lastupdated' and /lastmodified' time stamps */ struct TimeStamp { //! \brief constructor - TimeStamp(uint64 t) : t(t) {}; + TimeStamp(uint64_t t) : t(t) {}; //! \brief returns global time(stamp) at time of calling - static inline TimeStamp now() { return ospray::rdtsc(); } + static inline TimeStamp now() { return ospcommon::rdtsc(); } - //! \brief Allows ot typecast to a uint64 (so times can be compared) - inline operator uint64 () const { return t; } + //! \brief Allows ot typecast to a uint64_t (so times can be compared) + inline operator uint64_t () const { return t; } private: - //! \brief the uint64 that stores the time value - uint64 t; + //! \brief the uint64_t that stores the time value + uint64_t t; }; } // ::ospray::sg diff --git a/apps/qtViewer/sg/common/TransferFunction.cpp b/apps/qtViewer/sg/common/TransferFunction.cpp index 7664bf597d..4e5e51a1dc 100644 --- a/apps/qtViewer/sg/common/TransferFunction.cpp +++ b/apps/qtViewer/sg/common/TransferFunction.cpp @@ -20,38 +20,88 @@ namespace ospray { namespace sg { + using std::cout; + using std::endl; - //! \brief Sets a new 'texture map' to be used for the color mapping + //! constructor + TransferFunction::TransferFunction() + : ospTransferFunction(NULL), + ospColorData(NULL), + ospAlphaData(NULL), + numSamples(128), + valueRange(0.f,1.f) + { + 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; } - this->colorArray = colorArray; + this->colorArray.clear(); + for (int i=0;icolorArray.push_back(std::pair(i,colorArray[i])); } //! \brief Sets a new 'texture map' to be used for the alpha mapping - void TransferFunction::setAlphaMap(const std::vector &alphaArray) + void TransferFunction::setAlphaMap(const std::vector &alphaArray) { if (ospAlphaData) { ospRelease(ospAlphaData); ospAlphaData = NULL; } - this->alphaArray = alphaArray; + this->alphaArray.clear(); + for (int i=0;ialphaArray.push_back(std::pair(alphaArray[i].x,alphaArray[i].y)); + } + + float TransferFunction::getInterpolatedAlphaValue(float x) + { + if (x <= alphaArray.front().first) + return alphaArray.front().second; + for (int i=1;i lastCommitted) { - lastCommitted = ospray::rdtsc(); + lastCommitted = rdtsc(); ospCommit(ospTransferFunction); } } @@ -64,21 +114,75 @@ namespace ospray { commit(); } + void TransferFunction::setFromXML(const xml::Node *const node, + const unsigned char *binBasePtr) + { + setDefaultValues(); + + const std::string name = node->getProp("name"); + if (name != "") + registerNamedNode(name,this); + + for (int ii = 0; ii != node->child.size(); ii++) { + const xml::Node *child = node->child[ii]; + // ------------------------------------------------------- + // colors + // ------------------------------------------------------- + if (child->name == "colors" || child->name == "color") { + colorArray.clear(); + char *cont = strdup(child->content.c_str()); + assert(cont); + + const char *c = strtok(cont,",\n"); + while (c) { + PRINT(c); + colorArray.push_back(std::pair(colorArray.size(),toVec3f(c))); + c = strtok(NULL,",\n"); + } + + free(cont); + } + + // ------------------------------------------------------- + // alpha + // ------------------------------------------------------- + if (child->name == "alphas" || child->name == "alpha") { + alphaArray.clear(); + char *cont = strdup(child->content.c_str()); + + assert(cont); + const char *c = strtok(cont,",\n"); + while (c) { + vec2f cp = toVec2f(c); + alphaArray.push_back(std::pair(cp.x,cp.y)); + c = strtok(NULL,",\n"); + } + + free(cont); + } + } + } + //! \brief Initialize this node's value from given corresponding XML node void TransferFunction::setDefaultValues() { + static float col[7][3] = {{0 , 0 , 0.562493 }, + {0 , 0 , 1 }, + {0 , 1 , 1 }, + {0.500008 , 1 , 0.500008 }, + {1 , 1 , 0 }, + {1 , 0 , 0 }, + {0.500008 , 0 , 0 }}; + colorArray.clear(); - colorArray.push_back(ospray::vec3f(0 , 0 , 0.562493 )); - colorArray.push_back(ospray::vec3f(0 , 0 , 1 )); - colorArray.push_back(ospray::vec3f(0 , 1 , 1 )); - colorArray.push_back(ospray::vec3f(0.500008 , 1 , 0.500008 )); - colorArray.push_back(ospray::vec3f(1 , 1 , 0 )); - colorArray.push_back(ospray::vec3f(1 , 0 , 0 )); - colorArray.push_back(ospray::vec3f(0.500008 , 0 , 0 )); - + for (int i=0;i<7;i++) + colorArray.push_back(std::pair(i,vec3f(col[i][0],col[i][1],col[i][2]))); + alphaArray.clear(); - for (int i=0;i(0.f,0.f)); + alphaArray.push_back(std::pair(1.f,1.f)); + // for (int i=0;i(i,1.f)); //i/float(colorArray.size()-1)); } OSP_REGISTER_SG_NODE(TransferFunction) diff --git a/apps/qtViewer/sg/common/TransferFunction.h b/apps/qtViewer/sg/common/TransferFunction.h index f96feaa72d..f484dcfcf1 100644 --- a/apps/qtViewer/sg/common/TransferFunction.h +++ b/apps/qtViewer/sg/common/TransferFunction.h @@ -25,9 +25,10 @@ namespace ospray { uniformly spaced color and alpha values between which the value will be linearly interpolated (similar to a 1D texture for each) */ - struct TransferFunction : public sg::Node { - - TransferFunction() : ospTransferFunction(NULL), ospColorData(NULL), ospAlphaData(NULL) { setDefaultValues(); } + struct TransferFunction : public sg::Node + { + //! constructor + TransferFunction(); //! \brief initialize color and alpha arrays to 'some' useful values void setDefaultValues(); @@ -39,27 +40,42 @@ namespace ospray { virtual void render(RenderContext &ctx); //! \brief Initialize this node's value from given corresponding XML node - virtual void setFromXML(const xml::Node *const node) {} + virtual void setFromXML(const xml::Node *const node, + const unsigned char *binBasePtr); virtual void commit(); - /*! set a new color map array */ + void setValueRange(const vec2f &range); + + // /*! set a new color map array (using array of uniformly samples colors) */ void setColorMap(const std::vector &colorArray); - /*! set a new alpha map array */ - void setAlphaMap(const std::vector &alphaArray); + /*! set a new alpha map array - x coordinate is point pos, y is point alpha value */ + void setAlphaMap(const std::vector &alphaArray); + + const std::vector > &getAlphaArray() const + { return alphaArray; } + + float getInterpolatedAlphaValue(float x); /*! 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 */ + it to ospray obejcts that need a reference to the ospray + version of this xf */ OSPTransferFunction getOSPHandle() const { return ospTransferFunction; }; protected: OSPTransferFunction ospTransferFunction; OSPData ospColorData; OSPData ospAlphaData; + vec2f valueRange; + // number of samples we'll use in the colordata and alphadata arrays + int numSamples; - std::vector colorArray; - std::vector alphaArray; - }; - + // array of (x,color(x)) color samples; the first and last x + // determine the range of x'es, all values will be resampled + // uniformly into this range. samples must be sorted by x + // coordinate, and must span a non-empty range of x coordinates + std::vector > colorArray; + // array of (x,alpha(x)) opacity samples; otherwise same as colorArray + std::vector > alphaArray; + }; } // ::ospray::sg } // ::ospray diff --git a/apps/qtViewer/sg/common/World.cpp b/apps/qtViewer/sg/common/World.cpp index ac5935fbf6..fd4d1626a7 100644 --- a/apps/qtViewer/sg/common/World.cpp +++ b/apps/qtViewer/sg/common/World.cpp @@ -21,7 +21,7 @@ namespace ospray { box3f World::getBounds() { - box3f bounds = embree::empty; + box3f bounds = empty; for (int i=0;igetBounds()); return bounds; @@ -46,7 +46,7 @@ namespace ospray { if (ospModel) throw std::runtime_error("World::ospModel alrady exists!?"); ospModel = ospNewModel(); - affine3f xfm = embree::one; + 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 46bf4c2db9..fbaf4b0083 100644 --- a/apps/qtViewer/sg/geometry/Spheres.cpp +++ b/apps/qtViewer/sg/geometry/Spheres.cpp @@ -38,7 +38,7 @@ namespace ospray { box3f Spheres::getBounds() { - box3f bounds = embree::empty; + box3f bounds = empty; for (size_t i=0;igetPropl("num"); size_t ofs = node->getPropl("ofs"); float rad = atof(node->getProp("radius").c_str()); + PRINT(num); PRINT(rad); Spheres::Sphere s(vec3f(0.f),rad,0); @@ -78,9 +79,9 @@ namespace ospray { sphere.push_back(s); } } else { + const vec3f *in = (const vec3f*)(binBasePtr+ofs); for (int i=0;i > materialList; - std::vector materialIDs; + std::vector materialIDs; // to allow memory-mapping triangle arrays (or in general, // sharing data with an application) we use data arrays, not std::vector's diff --git a/apps/qtViewer/sg/importer/ImportOBJ.cpp b/apps/qtViewer/sg/importer/ImportOBJ.cpp index 82be8e4aac..f43fa4699b 100644 --- a/apps/qtViewer/sg/importer/ImportOBJ.cpp +++ b/apps/qtViewer/sg/importer/ImportOBJ.cpp @@ -16,6 +16,8 @@ #undef NDEBUG +#define WARN_INCLUDE_EMBREE_FILENAME 1 + // O_LARGEFILE is a GNU extension. #ifdef __APPLE__ #define O_LARGEFILE 0 @@ -33,8 +35,8 @@ namespace ospray { using std::cout; using std::endl; - Ref loadTexture(const std::string &path, const std::string &fileName) - { return Texture2D::load(path+"/"+fileName); } + Ref loadTexture(const std::string &path, const std::string &fileName, const bool prefereLinear = false) + { return Texture2D::load(path+"/"+fileName, prefereLinear); } /*! Three-index vertex, indexing start at 0, -1 means invalid vertex. */ struct Vertex { @@ -108,17 +110,17 @@ namespace ospray { std::map material; /*! Constructor. */ - OBJLoader(World *world, const embree::FileName& fileName); + OBJLoader(World *world, const FileName& fileName); /*! Destruction */ ~OBJLoader(); /*! Public methods. */ - void loadMTL(const embree::FileName& fileName); + void loadMTL(const FileName& fileName); private: - embree::FileName path; + FileName path; /*! Geometry buffer. */ std::vector v; @@ -137,10 +139,10 @@ namespace ospray { int fix_vn(int index); void flushFaceGroup(); Vertex getInt3(const char*& token); - uint32 getVertex(std::map& vertexMap, TriangleMesh *mesh, const Vertex& i); + uint32_t getVertex(std::map& vertexMap, TriangleMesh *mesh, const Vertex& i); }; - OBJLoader::OBJLoader(World *world, const embree::FileName &fileName) + OBJLoader::OBJLoader(World *world, const FileName &fileName) : world(world), curMaterial(NULL), path(fileName.path()) @@ -228,7 +230,7 @@ namespace ospray { } /* load material file */ - void OBJLoader::loadMTL(const embree::FileName &fileName) + void OBJLoader::loadMTL(const FileName &fileName) { std::ifstream cin; cin.open(fileName.c_str()); @@ -291,16 +293,16 @@ namespace ospray { if (!strncmp(token, "Ks", 2)) { parseSep(token += 2); cur->setParam("Ks", getVec3f(token)); continue; } if (!strncmp(token, "Tf", 2)) { parseSep(token += 2); cur->setParam("Tf", getVec3f(token)); continue; } - if (!strncmp(token, "map_d" , 5)) { parseSepOpt(token += 5); cur->setParam("map_d", loadTexture(path, std::string(token))); continue; } - if (!strncmp(token, "map_Ns" , 6)) { parseSepOpt(token += 6); cur->setParam("map_Ns", loadTexture(path, std::string(token))); continue; } + if (!strncmp(token, "map_d" , 5)) { parseSepOpt(token += 5); cur->setParam("map_d", loadTexture(path, std::string(token), true)); continue; } + if (!strncmp(token, "map_Ns" , 6)) { parseSepOpt(token += 6); cur->setParam("map_Ns", loadTexture(path, std::string(token), true)); continue; } if (!strncmp(token, "map_Ka" , 6)) { parseSepOpt(token += 6); cur->setParam("map_Ka", loadTexture(path, std::string(token))); continue; } if (!strncmp(token, "map_Kd" , 6)) { parseSepOpt(token += 6); cur->setParam("map_Kd", loadTexture(path, std::string(token))); continue; } 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))); continue; } + if (!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))); 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; } if (!strncmp(token, "color", 5)) { parseSep(token += 5); cur->setParam("color", getVec3f(token)); continue; } @@ -352,10 +354,10 @@ namespace ospray { return(v); } - uint32 OBJLoader::getVertex(std::map& vertexMap, + uint32_t OBJLoader::getVertex(std::map& vertexMap, TriangleMesh *mesh, const Vertex& i) { - const std::map::iterator& entry = vertexMap.find(i); + const std::map::iterator& entry = vertexMap.find(i); if (entry != vertexMap.end()) return(entry->second); if (std::isnan(v[i.v].x) || std::isnan(v[i.v].y) || std::isnan(v[i.v].z)) @@ -381,7 +383,7 @@ namespace ospray { { if (curGroup.empty()) return; - std::map vertexMap; + std::map vertexMap; TriangleMesh *mesh = new TriangleMesh; mesh->vertex = new DataVector3f; mesh->normal = new DataVector3f; @@ -399,16 +401,16 @@ namespace ospray { /* triangulate the face with a triangle fan */ for (size_t k=2; k < face.size(); k++) { i1 = i2; i2 = face[k]; - int32 v0 = getVertex(vertexMap, mesh, i0); - int32 v1 = getVertex(vertexMap, mesh, i1); - int32 v2 = getVertex(vertexMap, mesh, i2); + int32_t v0 = getVertex(vertexMap, mesh, i0); + int32_t v1 = getVertex(vertexMap, mesh, i1); + int32_t v2 = getVertex(vertexMap, mesh, i2); if (v0 < 0 || v1 < 0 || v2 < 0) continue; vec3i tri(v0,v1,v2); mesh->index.cast()->push_back(tri); //Vec3i(v0, v1, v2)); } - } + } curGroup.clear(); } diff --git a/apps/qtViewer/sg/importer/ImportOSP.cpp b/apps/qtViewer/sg/importer/ImportOSP.cpp index 463253f2f0..ca0aa58d20 100644 --- a/apps/qtViewer/sg/importer/ImportOSP.cpp +++ b/apps/qtViewer/sg/importer/ImportOSP.cpp @@ -32,9 +32,6 @@ #include // xml #include "apps/common/xml/XML.h" -#include "ospray/common/Library.h" -// embree stuff -#include "common/sys/library.h" namespace ospray { namespace sg { @@ -104,7 +101,7 @@ namespace ospray { return true; } if (node->name == "int") { - target->addParam(new ParamT(name,atoi(node->content.c_str()))); + target->addParam(new ParamT(name,atoi(node->content.c_str()))); return true; } if (node->name == "float") { diff --git a/apps/qtViewer/sg/importer/ImportRIVL.cpp b/apps/qtViewer/sg/importer/ImportRIVL.cpp index 8ba12b725b..e83c07013b 100644 --- a/apps/qtViewer/sg/importer/ImportRIVL.cpp +++ b/apps/qtViewer/sg/importer/ImportRIVL.cpp @@ -21,6 +21,8 @@ #define O_LARGEFILE 0 #endif +#define WARN_ON_INCLUDING_OSPCOMMON 1 + #include "SceneGraph.h" #include "sg/common/Texture2D.h" #include "sg/geometry/TriangleMesh.h" @@ -83,10 +85,15 @@ namespace ospray { assert(channels != size_t(-1) && "Channel count not properly parsed for Texture2D nodes"); assert(depth != size_t(-1) && "Depth not properly parsed for Texture2D nodes"); - if (channels == 4 && depth == 1) txt.ptr->texelType = OSP_UCHAR4; - else if (channels == 3 && depth == 1) txt.ptr->texelType = OSP_UCHAR3; - else if (channels == 4) txt.ptr->texelType = OSP_FLOAT3A; - else if (channels == 3) txt.ptr->texelType = OSP_FLOAT3; + txt.ptr->texelType = OSP_TEXTURE_R8; + if (channels == 4 && depth == 1) + txt.ptr->texelType = OSP_TEXTURE_RGBA8; + else if (channels == 3 && depth == 1) + txt.ptr->texelType = OSP_TEXTURE_RGB8; + else if (channels == 4) + txt.ptr->texelType = OSP_TEXTURE_RGBA32F; + else if (channels == 3) + txt.ptr->texelType = OSP_TEXTURE_RGB32F; txt.ptr->size = vec2i(width, height); @@ -193,28 +200,28 @@ namespace ospray { float w = atof(s); mat->setParam(childName, vec4f(x,y,z,w)); } else if (!childType.compare("int")) { - mat->setParam(childName, (int32)atol(s)); + mat->setParam(childName, (int32_t)atol(s)); } else if (!childType.compare("int2")) { - int32 x = atol(s); + int32_t x = atol(s); s = NEXT_TOK; - int32 y = atol(s); + int32_t y = atol(s); // mat->setParam(childName.c_str(), vec2i(x,y)); mat->setParam(childName, vec2i(x,y)); } else if (!childType.compare("int3")) { - int32 x = atol(s); + int32_t x = atol(s); s = NEXT_TOK; - int32 y = atol(s); + int32_t y = atol(s); s = NEXT_TOK; - int32 z = atol(s); + int32_t z = atol(s); mat->setParam(childName, vec3i(x,y,z)); } else if (!childType.compare("int4")) { - int32 x = atol(s); + int32_t x = atol(s); s = NEXT_TOK; - int32 y = atol(s); + int32_t y = atol(s); s = NEXT_TOK; - int32 z = atol(s); + int32_t z = atol(s); s = NEXT_TOK; - int32 w = atol(s); + int32_t w = atol(s); mat->setParam(childName, vec4i(x,y,z,w)); } else { //error! diff --git a/apps/qtViewer/sg/importer/Importer.h b/apps/qtViewer/sg/importer/Importer.h index c6794909ed..0c7f4e3eca 100644 --- a/apps/qtViewer/sg/importer/Importer.h +++ b/apps/qtViewer/sg/importer/Importer.h @@ -18,8 +18,7 @@ // ospray::sg #include "../common/World.h" -// embree -#include "common/sys/filename.h" +#include "common/FileName.h" /*! \file sg/module/Importer.h Defines the interface for writing file importers for the ospray::sg */ @@ -27,8 +26,6 @@ namespace ospray { namespace sg { - using embree::FileName; - struct ImportState { Ref world; // std::vector searchPaths; diff --git a/apps/qtViewer/sg/module/Module.cpp b/apps/qtViewer/sg/module/Module.cpp index 03efe4294a..2821b54fbf 100644 --- a/apps/qtViewer/sg/module/Module.cpp +++ b/apps/qtViewer/sg/module/Module.cpp @@ -18,7 +18,9 @@ #include "Module.h" #include "../common/RuntimeError.h" // ospray -#include "ospray/common/Library.h" +#include "common/common.h" +// std +#include /*! \file sg/module/Module.cpp Defines the interface for writing ospray::sg modules */ @@ -38,8 +40,8 @@ namespace ospray { const std::string libName = "ospray_sg_"+moduleName; const std::string symName = "ospray_sg_"+moduleName+"_init"; - ospray::loadLibrary(libName); - void *sym = ospray::getSymbol(symName); + ospcommon::loadLibrary(libName); + void *sym = ospcommon::getSymbol(symName); if (!sym) throw sg::RuntimeError("could not load module '"+moduleName+"' (symbol '"+symName+"' not found)"); diff --git a/apps/qtViewer/sg/volume/Volume.cpp b/apps/qtViewer/sg/volume/Volume.cpp index 7b432561c0..9539697d5e 100644 --- a/apps/qtViewer/sg/volume/Volume.cpp +++ b/apps/qtViewer/sg/volume/Volume.cpp @@ -30,6 +30,13 @@ namespace ospray { /*! \brief returns a std::string with the c++ name of this class */ std::string Volume::toString() const { return "ospray::sg::Volume"; } + + void Volume::serialize(sg::Serialization::State &state) + { + Node::serialize(state); + if (transferFunction) + transferFunction->serialize(state); + } // ======================================================= // structured volume class @@ -193,9 +200,9 @@ namespace ospray { } delete[] slice; } else { - uint8 *slice = new uint8[nPerSlice]; + uint8_t *slice = new uint8_t[nPerSlice]; for (int z=0;zgetProp("baseName"); firstSliceID = node->getPropl("firstSliceID"); numSlices = node->getPropl("numSlices"); - if (voxelType != "uint8") - throw std::runtime_error("unknown StackedRawSlices.voxelType (currently only supporting 'uint8')"); + if (voxelType != "uint8_t") + throw std::runtime_error("unknown StackedRawSlices.voxelType (currently only supporting 'uint8_t')"); if (!transferFunction) setTransferFunction(new TransferFunction); @@ -280,7 +287,7 @@ namespace ospray { ospSetString(volume,"voxelType",voxelType.c_str()); ospSetVec3i(volume,"dimensions",(const osp::vec3i&)dimensions); size_t nPerSlice = dimensions.x*dimensions.y; - uint8 *slice = new uint8[nPerSlice]; + uint8_t *slice = new uint8_t[nPerSlice]; for (int sliceID=0;sliceIDserialize(state); - } + virtual void serialize(sg::Serialization::State &state); static bool useDataDistributedVolume; @@ -125,8 +116,8 @@ namespace ospray { SG_NODE_DECLARE_MEMBER(vec2i,sliceResolution,SliceResolution); /*! base path name for the slices, in "printf format" (e.g., "/mydir/slice%04i.raw") */ SG_NODE_DECLARE_MEMBER(std::string,baseName,BaseName); - SG_NODE_DECLARE_MEMBER(int32,firstSliceID,FirstSliceID); - SG_NODE_DECLARE_MEMBER(int32,numSlices,numSlices); + SG_NODE_DECLARE_MEMBER(int32_t,firstSliceID,FirstSliceID); + SG_NODE_DECLARE_MEMBER(int32_t,numSlices,numSlices); SG_NODE_DECLARE_MEMBER(std::string,voxelType,ScalarType); //! actual dimensions after the data is loaded in - to be computed from sliceResolutiona nd numSlices diff --git a/apps/qtViewer/widgets/affineSpaceManipulator/HelperGeometry.cpp b/apps/qtViewer/widgets/affineSpaceManipulator/HelperGeometry.cpp index 9b1b089e19..b088292027 100644 --- a/apps/qtViewer/widgets/affineSpaceManipulator/HelperGeometry.cpp +++ b/apps/qtViewer/widgets/affineSpaceManipulator/HelperGeometry.cpp @@ -41,7 +41,7 @@ namespace ospray { void CoordFrameGeometry::makeArrow(Mesh &mesh,const vec3f &axis) { mesh.color = axis; - affine3f xfm = embree::frame(axis); + affine3f xfm = frame(axis); std::swap(xfm.l.vx,xfm.l.vz); Quad quad; for (int i=0;i namespace ospray { namespace viewer { + using namespace sg; //! \brief Helper class for storing tessellated geometry (with //! single color per mesh); that can be used to store 3D geometry diff --git a/apps/qtViewer/widgets/affineSpaceManipulator/QAffineSpaceManipulator.cpp b/apps/qtViewer/widgets/affineSpaceManipulator/QAffineSpaceManipulator.cpp index 7013d6968b..31644b839b 100644 --- a/apps/qtViewer/widgets/affineSpaceManipulator/QAffineSpaceManipulator.cpp +++ b/apps/qtViewer/widgets/affineSpaceManipulator/QAffineSpaceManipulator.cpp @@ -54,7 +54,7 @@ namespace ospray { : sourcePoint(0,-4,0), targetPoint(0,0,0), upVector(0,1,0), - orientation(embree::one) + orientation(ospcommon::one) {} void QAffineSpaceManipulator::ReferenceFrame::snapUp() @@ -344,7 +344,7 @@ namespace ospray { glBegin(GL_TRIANGLES); for (int i=0;i #include namespace ospray { namespace viewer { + using namespace ospcommon; + typedef LinearSpace3f linear3f; + // ================================================================== //! \brief A QT Widget that allows mouse manipulation of a reference /*! The Widget works by keeping and manipulating a reference frame diff --git a/apps/qtViewer/widgets/lightManipulator/QLightManipulator.cpp b/apps/qtViewer/widgets/lightManipulator/QLightManipulator.cpp index 582906fda3..3749808b56 100644 --- a/apps/qtViewer/widgets/lightManipulator/QLightManipulator.cpp +++ b/apps/qtViewer/widgets/lightManipulator/QLightManipulator.cpp @@ -16,7 +16,9 @@ // viewer #include "QLightManipulator.h" +// std #include +#include namespace ospray { namespace viewer { diff --git a/apps/qtViewer/widgets/lightManipulator/QLightManipulator.h b/apps/qtViewer/widgets/lightManipulator/QLightManipulator.h index d557887909..4f239e2552 100644 --- a/apps/qtViewer/widgets/lightManipulator/QLightManipulator.h +++ b/apps/qtViewer/widgets/lightManipulator/QLightManipulator.h @@ -16,17 +16,20 @@ #pragma once -// ospray interna -#include "ospray/common/OSPCommon.h" +#include "sg/SceneGraph.h" // ospray public api #include "ospray/ospray.h" // qt #include //sg #include "sg/Renderer.h" +// ospcomon +#include "common/common.h" namespace ospray { namespace viewer { + using namespace ospcommon; + // ================================================================== //! \brief A QT Widget that allows mouse manipulation of a reference /*! The Widget works by keeping and manipulating a reference frame @@ -54,8 +57,8 @@ namespace ospray { // ================================================================== struct LightInfo { OSPLight ospLight; - ospray::vec3f color; - ospray::vec3f direction; + vec3f color; + vec3f direction; float intensity; }; @@ -102,7 +105,7 @@ namespace ospray { QPushButton *applyButton; private: - ospray::vec3f upVector; + vec3f upVector; }; } } diff --git a/apps/qtViewer/widgets/transferFunction/QTransferFunctionEditor.cpp b/apps/qtViewer/widgets/transferFunction/QTransferFunctionEditor.cpp index 9870b89ef0..f99fae09f2 100644 --- a/apps/qtViewer/widgets/transferFunction/QTransferFunctionEditor.cpp +++ b/apps/qtViewer/widgets/transferFunction/QTransferFunctionEditor.cpp @@ -1,6 +1,7 @@ // ======================================================================== // // 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 // @@ -25,7 +26,7 @@ namespace ospray { float QTransferFunctionAlphaEditor::pointPixelRadius = 8.; float QTransferFunctionAlphaEditor::linePixelWidth = 2.; - bool comparePointsByX(const ospray::vec2f &i, const ospray::vec2f &j) + bool comparePointsByX(const ospcommon::vec2f &i, const ospcommon::vec2f &j) { return (i.x < j.x); } @@ -40,9 +41,8 @@ namespace ospray { colorMapImage.fill(QColor::fromRgbF(1,1,1,1).rgb()); // default transfer function points - // points.push_back(ospray::vec2f(0.,1.)); - points.push_back(ospray::vec2f(0.,0.)); - points.push_back(ospray::vec2f(1.,1.)); + points.push_back(ospcommon::vec2f(0.,0.)); + points.push_back(ospcommon::vec2f(1.,1.)); } void QTransferFunctionAlphaEditor::setColorMapImage(const QImage &image) @@ -109,7 +109,7 @@ namespace ospray { if(selectedPointIndex == -1) { // no point selected, create a new one - ospray::vec2f newPoint = widgetPointToPoint(widgetClickPoint); + ospcommon::vec2f newPoint = widgetPointToPoint(widgetClickPoint); // insert into points vector and sort ascending by x points.push_back(newPoint); @@ -151,7 +151,6 @@ namespace ospray { // trigger repaint repaint(); - PING; // emit signal emit transferFunctionChanged(); } @@ -177,7 +176,7 @@ namespace ospray { return; QPointF widgetMousePoint = event->posF(); - ospray::vec2f mousePoint = widgetPointToPoint(widgetMousePoint); + ospcommon::vec2f mousePoint = widgetPointToPoint(widgetMousePoint); // clamp x value if(selectedPointIndex == 0) { @@ -204,14 +203,14 @@ namespace ospray { emit transferFunctionChanged(); } - QPointF QTransferFunctionAlphaEditor::pointToWidgetPoint(const ospray::vec2f &point) + QPointF QTransferFunctionAlphaEditor::pointToWidgetPoint(const ospcommon::vec2f &point) { return QPointF(point.x * float(width()), (1.f - point.y) * float(height())); } - ospray::vec2f QTransferFunctionAlphaEditor::widgetPointToPoint(const QPointF &widgetPoint) + ospcommon::vec2f QTransferFunctionAlphaEditor::widgetPointToPoint(const QPointF &widgetPoint) { - return ospray::vec2f(float(widgetPoint.x()) / float(width()), + return ospcommon::vec2f(float(widgetPoint.x()) / float(width()), 1.f - float(widgetPoint.y()) / float(height())); } @@ -227,27 +226,27 @@ namespace ospray { return -1; } - float QTransferFunctionAlphaEditor::getInterpolatedValue(float x) - { - // boundary cases - if(x <= 0.) - return points[0].y; + // float QTransferFunctionAlphaEditor::getInterpolatedValue(float x) + // { + // // boundary cases + // if(x <= 0.) + // return points[0].y; - if(x >= 1.) - return points[points.size()-1].y; - - // we could make this more efficient... - for(unsigned int i=0; i= 1.) + // return points[points.size()-1].y; + + // // we could make this more efficient... + // for(unsigned int i=0; i colors; + std::vector colors; // jet colors.clear(); - colors.push_back(ospray::vec3f(0 , 0 , 0.562493 )); - colors.push_back(ospray::vec3f(0 , 0 , 1 )); - colors.push_back(ospray::vec3f(0 , 1 , 1 )); - colors.push_back(ospray::vec3f(0.500008 , 1 , 0.500008 )); - colors.push_back(ospray::vec3f(1 , 1 , 0 )); - colors.push_back(ospray::vec3f(1 , 0 , 0 )); - colors.push_back(ospray::vec3f(0.500008 , 0 , 0 )); + colors.push_back(ospcommon::vec3f(0 , 0 , 0.562493 )); + colors.push_back(ospcommon::vec3f(0 , 0 , 1 )); + colors.push_back(ospcommon::vec3f(0 , 1 , 1 )); + colors.push_back(ospcommon::vec3f(0.500008 , 1 , 0.500008 )); + colors.push_back(ospcommon::vec3f(1 , 1 , 0 )); + colors.push_back(ospcommon::vec3f(1 , 0 , 0 )); + colors.push_back(ospcommon::vec3f(0.500008 , 0 , 0 )); addColorMap(new ColorMap("Jet", colors)); // ice / fire colors.clear(); - colors.push_back(ospray::vec3f(0 , 0 , 0 )); - colors.push_back(ospray::vec3f(0 , 0.120394 , 0.302678 )); - colors.push_back(ospray::vec3f(0 , 0.216587 , 0.524575 )); - colors.push_back(ospray::vec3f(0.0552529 , 0.345022 , 0.659495 )); - colors.push_back(ospray::vec3f(0.128054 , 0.492592 , 0.720287 )); - colors.push_back(ospray::vec3f(0.188952 , 0.641306 , 0.792096 )); - colors.push_back(ospray::vec3f(0.327672 , 0.784939 , 0.873426 )); - colors.push_back(ospray::vec3f(0.60824 , 0.892164 , 0.935546 )); - colors.push_back(ospray::vec3f(0.881376 , 0.912184 , 0.818097 )); - colors.push_back(ospray::vec3f(0.9514 , 0.835615 , 0.449271 )); - colors.push_back(ospray::vec3f(0.904479 , 0.690486 , 0 )); - colors.push_back(ospray::vec3f(0.854063 , 0.510857 , 0 )); - colors.push_back(ospray::vec3f(0.777096 , 0.330175 , 0.000885023 )); - colors.push_back(ospray::vec3f(0.672862 , 0.139086 , 0.00270085 )); - colors.push_back(ospray::vec3f(0.508812 , 0 , 0 )); - colors.push_back(ospray::vec3f(0.299413 , 0.000366217 , 0.000549325 )); - colors.push_back(ospray::vec3f(0.0157473 , 0.00332647 , 0 )); + colors.push_back(ospcommon::vec3f(0 , 0 , 0 )); + colors.push_back(ospcommon::vec3f(0 , 0.120394 , 0.302678 )); + colors.push_back(ospcommon::vec3f(0 , 0.216587 , 0.524575 )); + colors.push_back(ospcommon::vec3f(0.0552529 , 0.345022 , 0.659495 )); + colors.push_back(ospcommon::vec3f(0.128054 , 0.492592 , 0.720287 )); + colors.push_back(ospcommon::vec3f(0.188952 , 0.641306 , 0.792096 )); + colors.push_back(ospcommon::vec3f(0.327672 , 0.784939 , 0.873426 )); + colors.push_back(ospcommon::vec3f(0.60824 , 0.892164 , 0.935546 )); + colors.push_back(ospcommon::vec3f(0.881376 , 0.912184 , 0.818097 )); + colors.push_back(ospcommon::vec3f(0.9514 , 0.835615 , 0.449271 )); + colors.push_back(ospcommon::vec3f(0.904479 , 0.690486 , 0 )); + colors.push_back(ospcommon::vec3f(0.854063 , 0.510857 , 0 )); + colors.push_back(ospcommon::vec3f(0.777096 , 0.330175 , 0.000885023 )); + colors.push_back(ospcommon::vec3f(0.672862 , 0.139086 , 0.00270085 )); + colors.push_back(ospcommon::vec3f(0.508812 , 0 , 0 )); + colors.push_back(ospcommon::vec3f(0.299413 , 0.000366217 , 0.000549325 )); + colors.push_back(ospcommon::vec3f(0.0157473 , 0.00332647 , 0 )); addColorMap(new ColorMap("Ice / Fire", colors)); // cool to warm colors.clear(); - colors.push_back(ospray::vec3f(0.231373 , 0.298039 , 0.752941 )); - colors.push_back(ospray::vec3f(0.865003 , 0.865003 , 0.865003 )); - colors.push_back(ospray::vec3f(0.705882 , 0.0156863 , 0.14902 )); + colors.push_back(ospcommon::vec3f(0.231373 , 0.298039 , 0.752941 )); + colors.push_back(ospcommon::vec3f(0.865003 , 0.865003 , 0.865003 )); + colors.push_back(ospcommon::vec3f(0.705882 , 0.0156863 , 0.14902 )); addColorMap(new ColorMap("Cool to Warm", colors)); // blue to red rainbow colors.clear(); - colors.push_back(ospray::vec3f(0 , 0 , 1 )); - colors.push_back(ospray::vec3f(1 , 0 , 0 )); + colors.push_back(ospcommon::vec3f(0 , 0 , 1 )); + colors.push_back(ospcommon::vec3f(1 , 0 , 0 )); addColorMap(new ColorMap("Blue to Red Rainbow", colors)); // grayscale colors.clear(); - colors.push_back(ospray::vec3f(0.)); - colors.push_back(ospray::vec3f(1.)); + colors.push_back(ospcommon::vec3f(0.)); + colors.push_back(ospcommon::vec3f(1.)); addColorMap(new ColorMap("Grayscale", colors)); } @@ -362,17 +361,6 @@ namespace ospray { updateAlphaMap(); } - // void QTransferFunctionEditor::transferFunctionChanged() - // { - // PING; - // } - // void QTransferFunctionAlphaEditor::transferFunctionChanged() - // { - // PING; - // } - - - void QTransferFunctionEditor::selectColorMap(int index) { activeColorMap = colorMaps[index]; @@ -384,7 +372,7 @@ namespace ospray { } QTransferFunctionEditor::ColorMap::ColorMap(const std::string &name, - const std::vector &colors) + const std::vector &colors) : name(name), colors(colors) {} @@ -407,24 +395,25 @@ namespace ospray { void QOSPTransferFunctionEditor::updateColorMap() { - // PING; sgNode->setColorMap(activeColorMap->getColors()); sgNode->commit(); } + const std::vector &QTransferFunctionAlphaEditor::getPoints() const + { + return points; + } + + void QTransferFunctionAlphaEditor::setPoints(const std::vector &points) + { + this->points = points; + } + + void QOSPTransferFunctionEditor::updateAlphaMap() { - // PING; - const int numAlphas = 256; - std::vector alphas; - for (int i=0;igetInterpolatedValue(i/float(numAlphas-1))); - - // PING; - sgNode->setAlphaMap(alphas); - // PING; + sgNode->setAlphaMap(transferFunctionAlphaEditor->getPoints()); sgNode->commit(); - // PING; } } // ::ospray::viewer diff --git a/apps/qtViewer/widgets/transferFunction/QTransferFunctionEditor.h b/apps/qtViewer/widgets/transferFunction/QTransferFunctionEditor.h index 4eb7e377c9..7552e56f01 100644 --- a/apps/qtViewer/widgets/transferFunction/QTransferFunctionEditor.h +++ b/apps/qtViewer/widgets/transferFunction/QTransferFunctionEditor.h @@ -16,18 +16,20 @@ #pragma once -// ospray +// scene graph +#include "sg/SceneGraph.h" +// ospray, PUBLIC #include // stl #include #include // qt #include -// scene graph -#include "sg/SceneGraph.h" +// ospcommon namespace ospray { namespace viewer { + using namespace ospcommon; /*! the editor widget to edit a transfer function's alpha values. This will show the current color map as a background @@ -43,15 +45,15 @@ namespace ospray { /*! set background image for a given color map */ void setColorMapImage(const QImage &image); - + const std::vector &getPoints() const; + void setPoints(const std::vector &points); signals: void transferFunctionChanged(); - public: - // get y value based on linear interpolation of the points values for x in [0, 1] - float getInterpolatedValue(float x); + // // get y value based on linear interpolation of the points values for x in [0, 1] + // float getInterpolatedValue(float x); protected: @@ -63,10 +65,10 @@ namespace ospray { //! @} // transform normalized coordinates to widget coordinates - QPointF pointToWidgetPoint(const ospray::vec2f &point); + QPointF pointToWidgetPoint(const ospcommon::vec2f &point); // transform widget coordinates to normalized coordinates - ospray::vec2f widgetPointToPoint(const QPointF &widgetPoint); + ospcommon::vec2f widgetPointToPoint(const QPointF &widgetPoint); // get the index of the selected point based on the clicked point in widget coordinates // returns -1 if no selected point @@ -77,7 +79,7 @@ namespace ospray { //! the points that define the transfer function, in normalize //! coordinates ([0,0], [1,1]) - std::vector points; + std::vector points; //! currently selected point int selectedPointIndex; @@ -101,7 +103,7 @@ namespace ospray { public: //! construct a new color map from given colors - ColorMap(const std::string &name, const std::vector &colors); + ColorMap(const std::string &name, const std::vector &colors); //! return the name of this color map inline std::string getName() const { return name; }; @@ -112,12 +114,12 @@ namespace ospray { //! query function that returns the current color map (to be //! used in a scene graph node, for example - std::vector getColors() const { return colors; }; + std::vector getColors() const { return colors; }; protected: const std::string name; - const std::vector colors; + const std::vector colors; }; public: @@ -126,6 +128,8 @@ namespace ospray { // add a new color map to the list of selectable color maps void addColorMap(const ColorMap *colorMap); + void setOpacityPoints(const std::vector &points) + { transferFunctionAlphaEditor->setPoints(points); } signals: void transferFunctionChanged(); diff --git a/apps/streamLineViewer/StreamLineViewer.cpp b/apps/streamLineViewer/StreamLineViewer.cpp index 9f8b78fe67..ad10fffd29 100644 --- a/apps/streamLineViewer/StreamLineViewer.cpp +++ b/apps/streamLineViewer/StreamLineViewer.cpp @@ -20,13 +20,14 @@ // ospray, for rendering #include "ospray/ospray.h" // embree -#include "common/sys/filename.h" +#include "common/FileName.h" // xml #include "apps/common/xml/XML.h" namespace ospray { using std::cout; using std::endl; + using namespace ospcommon; const char *rendererType = "raycast_eyelight"; bool doShadows = 1; @@ -75,7 +76,7 @@ namespace ospray { else return vec3f(lerpf(f, .5f,1.f,vec3f(0,1,0),vec3f(1,0,0))); } - void parseSV(const embree::FileName &fn) + void parseSV(const FileName &fn) { FILE *file = fopen(fn.str().c_str(),"rb"); if (!file) return; @@ -94,7 +95,7 @@ namespace ospray { box3f getBounds() const { - box3f bounds = embree::empty; + box3f bounds = empty; for (int i=0;i filePoints; @@ -199,7 +200,7 @@ namespace ospray { fclose(file); } - void parse(const embree::FileName &fn) + void parse(const FileName &fn) { if (fn.ext() == "pnt") parsePNT(fn); @@ -218,7 +219,7 @@ namespace ospray { } box3f getBounds() const { - box3f bounds = embree::empty; + box3f bounds = empty; for (int i=0;i cylinders[3]; box3f bounds; - void parse(const embree::FileName &fn) + void parse(const FileName &fn) { std::vector filePoints; FILE *file = fopen(fn.c_str(),"r"); Assert(file); - bounds = embree::empty; + bounds = empty; for (char line[10000]; fgets(line,10000,file) && !feof(file); ) { if (line[0] == '#') continue; @@ -580,18 +581,16 @@ namespace ospray { ospCommit(renderer); }; - virtual void reshape(const ospray::vec2i &newSize) + virtual void reshape(const vec2i &newSize) { Glut3DWidget::reshape(newSize); if (fb) ospFreeFrameBuffer(fb); - fb = ospNewFrameBuffer((const osp::vec2i&)newSize,OSP_RGBA_I8,OSP_FB_COLOR|OSP_FB_ACCUM); - ospSet1f(fb, "gamma", 2.2f); - ospCommit(fb); + fb = ospNewFrameBuffer((const osp::vec2i&)newSize, OSP_FB_SRGBA, OSP_FB_COLOR | OSP_FB_ACCUM); ospSetf(camera,"aspect",viewPort.aspect); ospCommit(camera); } - virtual void keypress(char key, const vec2f where) + virtual void keypress(char key, const vec2i where) { switch (key) { case 'S': @@ -602,7 +601,7 @@ namespace ospray { ospFrameBufferClear(fb,OSP_FB_ACCUM); break; default: - Glut3DWidget::keypress(key,where); + Glut3DWidget::keypress(key, where); } } virtual void display() @@ -658,7 +657,7 @@ namespace ospray { for (int i=1;i - -namespace ospray { - - using namespace std; - - volatile size_t sum = 0; - volatile int nextFreeID = 0; - volatile bool done = 0; - double timeToRun = 1.f; - embree::MutexSys mutex; - embree::BarrierSys barrier; - - struct MyThread : public Thread { - MyThread(int numThreads) - { - } - - virtual void run() - { - mutex.lock(); - int myID = nextFreeID++; -#ifdef __LINUX__ - printf("ID no %i runs on core %i\n",myID,sched_getcpu()); -#endif - mutex.unlock(); - - barrier.wait(); - double t0 = getSysTime(); - int lastPing = 0; - while (1) { - barrier.wait(); - if (done) { - break; - } - mutex.lock(); - sum += 1; - mutex.unlock(); - barrier.wait(); - - double t1 = getSysTime(); - - if (myID == 0) { - int numSecs = int(t1-t0); - if (numSecs > lastPing) { - printf("after t=%5.fs: num ops =%8li, that's %f ops/sec\n", - t1-t0,sum,sum/(t1-t0)); - lastPing = numSecs; - } - } - if (myID == 0 && (t1 - t0) >= timeToRun) - done = true; - } - - if (myID == 0) - cout << "total number of OPs: " << sum << endl; - } - - }; - - int numThreads = 10; - int firstThreadID = 1; - - extern "C" int main(int ac, char **av) - { -#ifdef __LINUX__ - printf("main thread runs on core %i\n",sched_getcpu()); -#endif - printf("address of global variables is %li\n",(long)&sum); - - for (int i=1;istart(firstThreadID+i); - } - - while (1) { - sleep(1); - if (done) break; - } - - - for (int i=0;ijoin(); - return 0; - } - -} diff --git a/apps/testMC.cpp b/apps/testMC.cpp deleted file mode 100644 index d85a86bf6c..0000000000 --- a/apps/testMC.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "testMC.h" -#include - -#include "testMC_ispc.h" - -namespace ospray { - float sqr(float f) { return f*f; } - - Field *createTestField(const vec3i &size) - { - Field *field = new Field(size); - for (int z=0;zset(vec3i(x,y,z),f); - } - return field; - } - - void testMC(int ac, const char **av) - { - ospInit(&ac,av); - Field *field = createTestField(vec3i(256)); - field->ie = ispc::createField(field->size.x,field->size.y,field->size.z,field->voxel); - ispc::marchingCubes(field->ie,0.4f); - } -} - -int main(int ac, const char **av) -{ - ospray::testMC(ac,av); -} - - diff --git a/apps/volumeViewer/CMakeLists.txt b/apps/volumeViewer/CMakeLists.txt index baf2bde4f0..1c329fe7b0 100644 --- a/apps/volumeViewer/CMakeLists.txt +++ b/apps/volumeViewer/CMakeLists.txt @@ -14,10 +14,6 @@ ## limitations under the License. ## ## ======================================================================== ## -IF (NOT OSPRAY_MODULE_LOADERS) - message(FATAL_ERROR "The 'loaders' module must be enabled to build the 'ospVolumeViewer' application.") -ENDIF (NOT OSPRAY_MODULE_LOADERS) - IF (NOT OSPRAY_MODULE_OPENGL_UTIL) message(FATAL_ERROR "The 'OpenGL util' module must be enabled to build the 'ospVolumeViewer' application.") ENDIF (NOT OSPRAY_MODULE_OPENGL_UTIL) @@ -25,8 +21,10 @@ ENDIF (NOT OSPRAY_MODULE_OPENGL_UTIL) INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/ospray/include) # setup dependencies -SET(LIBS ${LIBS} ospray ospray_module_loaders) -SET(LIBS ${LIBS} ospray ospray_module_opengl_util) +SET(LIBS ${LIBS} ospray) +SET(LIBS ${LIBS} ospray_common) +SET(LIBS ${LIBS} ospray_module_loaders) +SET(LIBS ${LIBS} ospray_module_opengl_util) # link optional loaders-based modules if built IF (OSPRAY_MODULE_SEISMIC) @@ -76,6 +74,7 @@ SET(MOC_HEADERS QT4_WRAP_CPP(MOC_OUTFILES ${MOC_HEADERS}) +ADD_SUBDIRECTORY(loaders) ADD_EXECUTABLE(ospVolumeViewer ${SRCS} ${MOC_OUTFILES}) TARGET_LINK_LIBRARIES(ospVolumeViewer ${LIBS}) INSTALL(TARGETS ospVolumeViewer diff --git a/apps/volumeViewer/ColorMap.cpp b/apps/volumeViewer/ColorMap.cpp index 22042086ae..90d67b439d 100644 --- a/apps/volumeViewer/ColorMap.cpp +++ b/apps/volumeViewer/ColorMap.cpp @@ -16,7 +16,7 @@ #include "ColorMap.h" -ColorMap::ColorMap(std::string name, std::vector colors) +ColorMap::ColorMap(std::string name, std::vector colors) { this->name = name; this->colors = colors; @@ -27,7 +27,7 @@ std::string ColorMap::getName() return name; } -std::vector ColorMap::getColors() +std::vector ColorMap::getColors() { return colors; } diff --git a/apps/volumeViewer/ColorMap.h b/apps/volumeViewer/ColorMap.h index 0601ac6fae..e0d63b3d93 100644 --- a/apps/volumeViewer/ColorMap.h +++ b/apps/volumeViewer/ColorMap.h @@ -16,8 +16,11 @@ #pragma once +// ospray public #include -#include "ospray/common/OSPCommon.h" +// ospcommon +#include "common/vec.h" +// std #include #include #include @@ -26,15 +29,15 @@ class ColorMap { public: - ColorMap(std::string name, std::vector colors); + ColorMap(std::string name, std::vector colors); std::string getName(); - std::vector getColors(); + std::vector getColors(); QImage getImage(); protected: std::string name; - std::vector colors; + std::vector colors; }; diff --git a/apps/volumeViewer/IsosurfaceEditor.cpp b/apps/volumeViewer/IsosurfaceEditor.cpp index 0c6781fad5..61b7088c6a 100644 --- a/apps/volumeViewer/IsosurfaceEditor.cpp +++ b/apps/volumeViewer/IsosurfaceEditor.cpp @@ -29,7 +29,7 @@ IsosurfaceEditor::IsosurfaceEditor() connect(addIsovalueButton, SIGNAL(clicked()), this, SLOT(addIsovalue())); } -void IsosurfaceEditor::setDataValueRange(ospray::vec2f dataValueRange) +void IsosurfaceEditor::setDataValueRange(ospcommon::vec2f dataValueRange) { this->dataValueRange = dataValueRange; diff --git a/apps/volumeViewer/IsosurfaceEditor.h b/apps/volumeViewer/IsosurfaceEditor.h index b110aca1d7..a044a4708e 100644 --- a/apps/volumeViewer/IsosurfaceEditor.h +++ b/apps/volumeViewer/IsosurfaceEditor.h @@ -17,7 +17,7 @@ #pragma once #include -#include "ospray/common/OSPCommon.h" +#include "common/vec.h" #include #include @@ -37,7 +37,7 @@ Q_OBJECT public slots: - void setDataValueRange(ospray::vec2f dataValueRange); + void setDataValueRange(ospcommon::vec2f dataValueRange); void apply(); @@ -47,7 +47,7 @@ protected slots: protected: - ospray::vec2f dataValueRange; + ospcommon::vec2f dataValueRange; QVBoxLayout layout; diff --git a/apps/volumeViewer/IsovalueWidget.cpp b/apps/volumeViewer/IsovalueWidget.cpp index 4ce63c46c9..ca2293233e 100644 --- a/apps/volumeViewer/IsovalueWidget.cpp +++ b/apps/volumeViewer/IsovalueWidget.cpp @@ -44,7 +44,7 @@ IsovalueWidget::IsovalueWidget(IsosurfaceEditor *isosurfaceEditor) : dataRangeSe connect(this, SIGNAL(isovalueChanged()), isosurfaceEditor, SLOT(apply())); } -void IsovalueWidget::setDataValueRange(ospray::vec2f dataValueRange) +void IsovalueWidget::setDataValueRange(ospcommon::vec2f dataValueRange) { this->dataValueRange = dataValueRange; diff --git a/apps/volumeViewer/IsovalueWidget.h b/apps/volumeViewer/IsovalueWidget.h index 0ee4bd221f..96a8c8b8ee 100644 --- a/apps/volumeViewer/IsovalueWidget.h +++ b/apps/volumeViewer/IsovalueWidget.h @@ -17,7 +17,7 @@ #pragma once #include -#include "ospray/common/OSPCommon.h" +#include "common/vec.h" #include class IsosurfaceEditor; @@ -33,7 +33,7 @@ Q_OBJECT bool getIsovalueEnabled() { return isovalueCheckBox.isChecked(); } float getIsovalue() { return isovalueSpinBox.value(); } - void setDataValueRange(ospray::vec2f dataValueRange); + void setDataValueRange(ospcommon::vec2f dataValueRange); signals: @@ -45,7 +45,7 @@ protected slots: protected: - ospray::vec2f dataValueRange; + ospcommon::vec2f dataValueRange; //! Indicates if the data value range has been set; we don't automatically set the isovalue after the first time it's set. bool dataRangeSet; diff --git a/apps/volumeViewer/OpenGLAnnotationRenderer.cpp b/apps/volumeViewer/OpenGLAnnotationRenderer.cpp index 51f4bc39b1..990e210740 100644 --- a/apps/volumeViewer/OpenGLAnnotationRenderer.cpp +++ b/apps/volumeViewer/OpenGLAnnotationRenderer.cpp @@ -29,9 +29,9 @@ void OpenGLAnnotationRenderer::render() glEnable(GL_DEPTH_TEST); // render volume bounding box - ospray::box3f boundingBox = volumeViewer->getBoundingBox(); + ospcommon::box3f boundingBox = volumeViewer->getBoundingBox(); - ospray::vec3f size(boundingBox.upper - boundingBox.lower); + ospcommon::vec3f size(boundingBox.upper - boundingBox.lower); glPushMatrix(); glTranslatef(boundingBox.lower.x, boundingBox.lower.y, boundingBox.lower.z); diff --git a/apps/volumeViewer/PreferencesDialog.cpp b/apps/volumeViewer/PreferencesDialog.cpp index 2835169af4..b3dc2b1014 100644 --- a/apps/volumeViewer/PreferencesDialog.cpp +++ b/apps/volumeViewer/PreferencesDialog.cpp @@ -17,7 +17,7 @@ #include "VolumeViewer.h" #include "PreferencesDialog.h" -PreferencesDialog::PreferencesDialog(VolumeViewer *volumeViewer, ospray::box3f boundingBox) : QDialog(volumeViewer), volumeViewer(volumeViewer) +PreferencesDialog::PreferencesDialog(VolumeViewer *volumeViewer, ospcommon::box3f boundingBox) : QDialog(volumeViewer), volumeViewer(volumeViewer) { setWindowTitle("Preferences"); @@ -91,12 +91,12 @@ PreferencesDialog::PreferencesDialog(VolumeViewer *volumeViewer, ospray::box3f b void PreferencesDialog::updateVolumeClippingBox() { - ospray::vec3f lower(volumeClippingBoxSpinBoxes[0]->value(), + ospcommon::vec3f lower(volumeClippingBoxSpinBoxes[0]->value(), volumeClippingBoxSpinBoxes[1]->value(), volumeClippingBoxSpinBoxes[2]->value()); - ospray::vec3f upper(volumeClippingBoxSpinBoxes[3]->value(), + ospcommon::vec3f upper(volumeClippingBoxSpinBoxes[3]->value(), volumeClippingBoxSpinBoxes[4]->value(), volumeClippingBoxSpinBoxes[5]->value()); - volumeViewer->setVolumeClippingBox(ospray::box3f(lower, upper)); + volumeViewer->setVolumeClippingBox(ospcommon::box3f(lower, upper)); } diff --git a/apps/volumeViewer/PreferencesDialog.h b/apps/volumeViewer/PreferencesDialog.h index 180ee27603..3e8611174e 100644 --- a/apps/volumeViewer/PreferencesDialog.h +++ b/apps/volumeViewer/PreferencesDialog.h @@ -17,7 +17,7 @@ #pragma once #include -#include "ospray/common/OSPCommon.h" +#include "common/box.h" #include #include @@ -29,7 +29,7 @@ Q_OBJECT public: - PreferencesDialog(VolumeViewer *volumeViewer, ospray::box3f boundingBox); + PreferencesDialog(VolumeViewer *volumeViewer, ospcommon::box3f boundingBox); protected slots: diff --git a/apps/volumeViewer/ProbeWidget.cpp b/apps/volumeViewer/ProbeWidget.cpp index 24aaf7b6d8..341c97f771 100644 --- a/apps/volumeViewer/ProbeWidget.cpp +++ b/apps/volumeViewer/ProbeWidget.cpp @@ -24,7 +24,7 @@ #include #endif -ProbeCoordinateWidget::ProbeCoordinateWidget(const std::string &label, ospray::vec2f range) : range(range) +ProbeCoordinateWidget::ProbeCoordinateWidget(const std::string &label, ospcommon::vec2f range) : range(range) { QHBoxLayout *layout = new QHBoxLayout(); setLayout(layout); @@ -89,9 +89,9 @@ ProbeWidget::ProbeWidget(VolumeViewer *volumeViewer) : volumeViewer(volumeViewer coordinatesGroupBox->setLayout(coordinatesLayout); connect(this, SIGNAL(enabled(bool)), coordinatesGroupBox, SLOT(setEnabled(bool))); - probeCoordinateWidgets.push_back(new ProbeCoordinateWidget("x", ospray::vec2f(boundingBox.lower.x, boundingBox.upper.x))); - probeCoordinateWidgets.push_back(new ProbeCoordinateWidget("y", ospray::vec2f(boundingBox.lower.y, boundingBox.upper.y))); - probeCoordinateWidgets.push_back(new ProbeCoordinateWidget("z", ospray::vec2f(boundingBox.lower.z, boundingBox.upper.z))); + probeCoordinateWidgets.push_back(new ProbeCoordinateWidget("x", ospcommon::vec2f(boundingBox.lower.x, boundingBox.upper.x))); + probeCoordinateWidgets.push_back(new ProbeCoordinateWidget("y", ospcommon::vec2f(boundingBox.lower.y, boundingBox.upper.y))); + probeCoordinateWidgets.push_back(new ProbeCoordinateWidget("z", ospcommon::vec2f(boundingBox.lower.z, boundingBox.upper.z))); for (int i=0; i<3; i++) { coordinatesLayout->addWidget(probeCoordinateWidgets[i]); @@ -132,12 +132,12 @@ void ProbeWidget::updateProbe() return; } - coordinate = ospray::vec3f(probeCoordinateWidgets[0]->getValue(), probeCoordinateWidgets[1]->getValue(), probeCoordinateWidgets[2]->getValue()); + coordinate = osp::vec3f{probeCoordinateWidgets[0]->getValue(), probeCoordinateWidgets[1]->getValue(), probeCoordinateWidgets[2]->getValue()}; if (volume) { float *results = NULL; - ospSampleVolume(&results, volume, (osp::vec3f*)&coordinate, 1); + ospSampleVolume(&results, volume, coordinate, 1); if (!results) std::cout << "error calling ospSampleVolume()" << std::endl; diff --git a/apps/volumeViewer/ProbeWidget.h b/apps/volumeViewer/ProbeWidget.h index d48f3a0926..f5e550abb3 100644 --- a/apps/volumeViewer/ProbeWidget.h +++ b/apps/volumeViewer/ProbeWidget.h @@ -17,7 +17,7 @@ #pragma once #include -#include "ospray/common/OSPCommon.h" +#include "common/box.h" #include #include @@ -30,7 +30,7 @@ Q_OBJECT public: - ProbeCoordinateWidget(const std::string &label, ospray::vec2f range); + ProbeCoordinateWidget(const std::string &label, ospcommon::vec2f range); float getValue() { return spinBox.value(); } @@ -44,7 +44,7 @@ protected slots: protected: - ospray::vec2f range; + ospcommon::vec2f range; QSlider slider; QDoubleSpinBox spinBox; @@ -80,7 +80,7 @@ public slots: QOSPRayWindow *osprayWindow; //! Bounding box to consider. - ospray::box3f boundingBox; + ospcommon::box3f boundingBox; //! Active volume to probe. OSPVolume volume; @@ -89,7 +89,7 @@ public slots: bool isEnabled; //! The probe coordinate. - ospray::vec3f coordinate; + osp::vec3f coordinate; // UI elements. std::vector probeCoordinateWidgets; diff --git a/apps/volumeViewer/QOSPRayWindow.cpp b/apps/volumeViewer/QOSPRayWindow.cpp index 5a40c98537..3e54c39a7b 100644 --- a/apps/volumeViewer/QOSPRayWindow.cpp +++ b/apps/volumeViewer/QOSPRayWindow.cpp @@ -105,7 +105,7 @@ void QOSPRayWindow::setBenchmarkParameters(int benchmarkWarmUpFrames, int benchm this->benchmarkFrames = benchmarkFrames; } -void QOSPRayWindow::setWorldBounds(const ospray::box3f &worldBounds) +void QOSPRayWindow::setWorldBounds(const ospcommon::box3f &worldBounds) { this->worldBounds = worldBounds; @@ -131,7 +131,7 @@ void QOSPRayWindow::paintGL() // update OSPRay camera if viewport has been modified if(viewport.modified) { - const ospray::vec3f dir = viewport.at - viewport.from; + const ospcommon::vec3f dir = viewport.at - viewport.from; ospSetVec3f(camera,"pos" ,(const osp::vec3f&)viewport.from); ospSetVec3f(camera,"dir" ,(const osp::vec3f&)dir); ospSetVec3f(camera,"up", (const osp::vec3f&)viewport.up); @@ -216,17 +216,13 @@ void QOSPRayWindow::paintGL() void QOSPRayWindow::resizeGL(int width, int height) { - windowSize = ospray::vec2i(width, height); + windowSize = ospcommon::vec2i(width, height); // reallocate OSPRay framebuffer for new size if(frameBuffer) ospFreeFrameBuffer(frameBuffer); - frameBuffer = ospNewFrameBuffer((const osp::vec2i&)windowSize, OSP_RGBA_I8, OSP_FB_COLOR | OSP_FB_ACCUM); - - // set gamma correction - ospSet1f(frameBuffer, "gamma", 1.0f); - ospCommit(frameBuffer); + frameBuffer = ospNewFrameBuffer((const osp::vec2i&)windowSize, OSP_FB_SRGBA, OSP_FB_COLOR | OSP_FB_ACCUM); resetAccumulationBuffer(); @@ -313,12 +309,12 @@ void QOSPRayWindow::mouseMoveEvent(QMouseEvent * event) void QOSPRayWindow::rotateCenter(float du, float dv) { - const ospray::vec3f pivot = viewport.at; + const ospcommon::vec3f pivot = viewport.at; - ospray::affine3f xfm = ospray::affine3f::translate(pivot) - * ospray::affine3f::rotate(viewport.frame.l.vx, -dv) - * ospray::affine3f::rotate(viewport.frame.l.vz, -du) - * ospray::affine3f::translate(-pivot); + ospcommon::affine3f xfm = ospcommon::affine3f::translate(pivot) + * ospcommon::affine3f::rotate(viewport.frame.l.vx, -dv) + * ospcommon::affine3f::rotate(viewport.frame.l.vz, -du) + * ospcommon::affine3f::translate(-pivot); viewport.frame = xfm * viewport.frame; viewport.from = xfmPoint(xfm, viewport.from); @@ -330,8 +326,8 @@ void QOSPRayWindow::rotateCenter(float du, float dv) void QOSPRayWindow::strafe(float du, float dv) { - ospray::affine3f xfm = ospray::affine3f::translate(dv * viewport.frame.l.vz) - * ospray::affine3f::translate(-du * viewport.frame.l.vx); + ospcommon::affine3f xfm = ospcommon::affine3f::translate(dv * viewport.frame.l.vz) + * ospcommon::affine3f::translate(-du * viewport.frame.l.vx); viewport.frame = xfm * viewport.frame; viewport.from = xfmPoint(xfm, viewport.from); @@ -344,7 +340,7 @@ void QOSPRayWindow::strafe(float du, float dv) void QOSPRayWindow::renderGL() { // setup OpenGL state to match OSPRay view - const ospray::vec3f bgColor = ospray::vec3f(1.f); + const ospcommon::vec3f bgColor = ospcommon::vec3f(1.f); glClearColor(bgColor.x, bgColor.y, bgColor.z, 1.f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); diff --git a/apps/volumeViewer/QOSPRayWindow.h b/apps/volumeViewer/QOSPRayWindow.h index 691413eceb..5ebe855d51 100644 --- a/apps/volumeViewer/QOSPRayWindow.h +++ b/apps/volumeViewer/QOSPRayWindow.h @@ -16,8 +16,11 @@ #pragma once +// ospray public #include -#include "ospray/common/OSPCommon.h" +// ospcommon +#include "common/AffineSpace.h" +// qt #include #include @@ -30,12 +33,12 @@ struct Viewport fovY(60.f), modified(true) { - frame = ospray::affine3f::translate(from) * ospray::affine3f(embree::one); + frame = ospcommon::affine3f::translate(from) * ospcommon::affine3f(ospcommon::one); } - ospray::vec3f from; - ospray::vec3f at; - ospray::vec3f up; + ospcommon::vec3f from; + ospcommon::vec3f at; + ospcommon::vec3f up; /*! aspect ratio (width / height) */ float aspect; @@ -49,10 +52,10 @@ struct Viewport /*! camera frame in which the Y axis is the depth axis, and X and Z axes are parallel to the screen X and Y axis. The frame itself remains normalized. */ - ospray::affine3f frame; + ospcommon::affine3f frame; /*! set up vector */ - void setUp(const ospray::vec3f &vec) + void setUp(const ospcommon::vec3f &vec) { up = vec; snapUp(); @@ -87,7 +90,7 @@ Q_OBJECT void setRenderingEnabled(bool renderingEnabled); void setRotationRate(float rotationRate); void setBenchmarkParameters(int benchmarkWarmUpFrames, int benchmarkFrames); - virtual void setWorldBounds(const ospray::box3f &worldBounds); + virtual void setWorldBounds(const ospcommon::box3f &worldBounds); Viewport * getViewport() { return &viewport; } @@ -150,9 +153,9 @@ Q_OBJECT /*! Timer to measure elapsed time over a single frame. */ QTime renderFrameTimer; - ospray::vec2i windowSize; + ospcommon::vec2i windowSize; Viewport viewport; - ospray::box3f worldBounds; + ospcommon::box3f worldBounds; QPoint lastMousePosition; OSPFrameBuffer frameBuffer; diff --git a/apps/volumeViewer/SliceEditor.cpp b/apps/volumeViewer/SliceEditor.cpp index ecdc12ecba..f7da6beeea 100644 --- a/apps/volumeViewer/SliceEditor.cpp +++ b/apps/volumeViewer/SliceEditor.cpp @@ -17,7 +17,8 @@ #include "SliceEditor.h" #include -SliceEditor::SliceEditor(ospray::box3f boundingBox) : boundingBox(boundingBox) +SliceEditor::SliceEditor(ospcommon::box3f boundingBox) + : boundingBox(boundingBox) { // Setup UI elements. layout.setSizeConstraint(QLayout::SetMinimumSize); diff --git a/apps/volumeViewer/SliceEditor.h b/apps/volumeViewer/SliceEditor.h index bc47e70fb1..d9ed334182 100644 --- a/apps/volumeViewer/SliceEditor.h +++ b/apps/volumeViewer/SliceEditor.h @@ -29,7 +29,7 @@ Q_OBJECT public: - SliceEditor(ospray::box3f boundingBox); + SliceEditor(ospcommon::box3f boundingBox); signals: @@ -44,7 +44,7 @@ public slots: protected: //! Bounding box of the volume. - ospray::box3f boundingBox; + ospcommon::box3f boundingBox; //! UI elements. QVBoxLayout layout; diff --git a/apps/volumeViewer/SliceWidget.cpp b/apps/volumeViewer/SliceWidget.cpp index 1db5f8e801..98538ba459 100644 --- a/apps/volumeViewer/SliceWidget.cpp +++ b/apps/volumeViewer/SliceWidget.cpp @@ -17,12 +17,12 @@ #include "SliceWidget.h" #include "SliceEditor.h" -SliceWidget::SliceWidget(SliceEditor *sliceEditor, ospray::box3f boundingBox) +SliceWidget::SliceWidget(SliceEditor *sliceEditor, ospcommon::box3f boundingBox) : boundingBox(boundingBox), originSliderAnimationDirection(1) { // Check parameters. - if(ospray::volume(boundingBox) <= 0.f) + if(ospcommon::volume(boundingBox) <= 0.f) throw std::runtime_error("invalid volume bounds"); // Setup UI elements. @@ -164,8 +164,8 @@ SliceParameters SliceWidget::getSliceParameters() SliceParameters sliceParameters; // Get the origin and normal values. - sliceParameters.origin = ospray::vec3f(float(originXSpinBox.value()), float(originYSpinBox.value()), float(originZSpinBox.value())); - sliceParameters.normal = ospray::vec3f(float(normalXSpinBox.value()), float(normalYSpinBox.value()), float(normalZSpinBox.value())); + sliceParameters.origin = ospcommon::vec3f(float(originXSpinBox.value()), float(originYSpinBox.value()), float(originZSpinBox.value())); + sliceParameters.normal = ospcommon::vec3f(float(normalXSpinBox.value()), float(normalYSpinBox.value()), float(normalZSpinBox.value())); return sliceParameters; } @@ -258,15 +258,15 @@ void SliceWidget::originSliderValueChanged(int value) { float sliderPosition = float(value) / float(originSlider.maximum() - originSlider.minimum()); // Get origin and (normalized) normal vectors. - ospray::vec3f origin(originXSpinBox.value(), originYSpinBox.value(), originZSpinBox.value()); - ospray::vec3f normal = normalize(ospray::vec3f(normalXSpinBox.value(), normalYSpinBox.value(), normalZSpinBox.value())); + ospcommon::vec3f origin(originXSpinBox.value(), originYSpinBox.value(), originZSpinBox.value()); + ospcommon::vec3f normal = normalize(ospcommon::vec3f(normalXSpinBox.value(), normalYSpinBox.value(), normalZSpinBox.value())); // Compute allowed range along normal for the volume bounds. - ospray::vec3f upper(normal.x >= 0.f ? boundingBox.upper.x : boundingBox.lower.x, + ospcommon::vec3f upper(normal.x >= 0.f ? boundingBox.upper.x : boundingBox.lower.x, normal.y >= 0.f ? boundingBox.upper.y : boundingBox.lower.y, normal.z >= 0.f ? boundingBox.upper.z : boundingBox.lower.z); - ospray::vec3f lower(normal.x >= 0.f ? boundingBox.lower.x : boundingBox.upper.x, + ospcommon::vec3f lower(normal.x >= 0.f ? boundingBox.lower.x : boundingBox.upper.x, normal.y >= 0.f ? boundingBox.lower.y : boundingBox.upper.y, normal.z >= 0.f ? boundingBox.lower.z : boundingBox.upper.z); @@ -281,7 +281,7 @@ void SliceWidget::originSliderValueChanged(int value) { t = std::max(std::min(t, tMax-epsilon), tMin+epsilon); // Compute updated origin, clamped within the volume bounds. - ospray::vec3f updatedOrigin = clamp(origin + t*normal, boundingBox.lower, boundingBox.upper); + ospcommon::vec3f updatedOrigin = clamp(origin + t*normal, boundingBox.lower, boundingBox.upper); // Finally, set the new origin value. originXSpinBox.setValue(updatedOrigin.x); diff --git a/apps/volumeViewer/SliceWidget.h b/apps/volumeViewer/SliceWidget.h index d636c898a9..1551a1c05e 100644 --- a/apps/volumeViewer/SliceWidget.h +++ b/apps/volumeViewer/SliceWidget.h @@ -17,13 +17,13 @@ #pragma once #include -#include "ospray/common/OSPCommon.h" +#include "common/box.h" #include struct SliceParameters { - ospray::vec3f origin; - ospray::vec3f normal; + ospcommon::vec3f origin; + ospcommon::vec3f normal; }; class SliceEditor; @@ -35,7 +35,7 @@ Q_OBJECT public: - SliceWidget(SliceEditor *sliceEditor, ospray::box3f boundingBox); + SliceWidget(SliceEditor *sliceEditor, ospcommon::box3f boundingBox); ~SliceWidget(); SliceParameters getSliceParameters(); @@ -60,7 +60,7 @@ protected slots: protected: //! Bounding box of the volume. - ospray::box3f boundingBox; + ospcommon::box3f boundingBox; //! UI elements. QDoubleSpinBox originXSpinBox; diff --git a/apps/volumeViewer/TransferFunctionEditor.cpp b/apps/volumeViewer/TransferFunctionEditor.cpp index cb13e57c66..bffa02c2ad 100644 --- a/apps/volumeViewer/TransferFunctionEditor.cpp +++ b/apps/volumeViewer/TransferFunctionEditor.cpp @@ -149,12 +149,12 @@ void TransferFunctionEditor::load(std::string filename) // Update transfer function state. Update values of the UI elements directly to signal appropriate slots. colorMapComboBox.setCurrentIndex(colorMapIndex); - setDataValueRange(ospray::vec2f(dataValueMin, dataValueMax), true); + setDataValueRange(ospcommon::vec2f(dataValueMin, dataValueMax), true); opacityValuesWidget.setPoints(points); opacityScalingSlider.setValue(opacityScalingIndex); } -void TransferFunctionEditor::setDataValueRange(ospray::vec2f dataValueRange, bool force) +void TransferFunctionEditor::setDataValueRange(ospcommon::vec2f dataValueRange, bool force) { // Only update widget values the first time. if(dataRangeSet && !force) @@ -232,7 +232,7 @@ void TransferFunctionEditor::save() void TransferFunctionEditor::setColorMapIndex(int index) { // Set transfer function color properties for this color map. - std::vector colors = colorMaps[index].getColors(); + std::vector colors = colorMaps[index].getColors(); OSPData colorsData = ospNewData(colors.size(), OSP_FLOAT3, colors.data()); ospSetData(transferFunction, "colors", colorsData); @@ -262,56 +262,56 @@ void TransferFunctionEditor::loadColorMaps() { // Color maps based on ParaView default color maps. - std::vector colors; + std::vector colors; // Jet. colors.clear(); - colors.push_back(ospray::vec3f(0 , 0 , 0.562493 )); - colors.push_back(ospray::vec3f(0 , 0 , 1 )); - colors.push_back(ospray::vec3f(0 , 1 , 1 )); - colors.push_back(ospray::vec3f(0.500008 , 1 , 0.500008 )); - colors.push_back(ospray::vec3f(1 , 1 , 0 )); - colors.push_back(ospray::vec3f(1 , 0 , 0 )); - colors.push_back(ospray::vec3f(0.500008 , 0 , 0 )); + colors.push_back(ospcommon::vec3f(0 , 0 , 0.562493 )); + colors.push_back(ospcommon::vec3f(0 , 0 , 1 )); + colors.push_back(ospcommon::vec3f(0 , 1 , 1 )); + colors.push_back(ospcommon::vec3f(0.500008 , 1 , 0.500008 )); + colors.push_back(ospcommon::vec3f(1 , 1 , 0 )); + colors.push_back(ospcommon::vec3f(1 , 0 , 0 )); + colors.push_back(ospcommon::vec3f(0.500008 , 0 , 0 )); colorMaps.push_back(ColorMap("Jet", colors)); // Ice / fire. colors.clear(); - colors.push_back(ospray::vec3f(0 , 0 , 0 )); - colors.push_back(ospray::vec3f(0 , 0.120394 , 0.302678 )); - colors.push_back(ospray::vec3f(0 , 0.216587 , 0.524575 )); - colors.push_back(ospray::vec3f(0.0552529 , 0.345022 , 0.659495 )); - colors.push_back(ospray::vec3f(0.128054 , 0.492592 , 0.720287 )); - colors.push_back(ospray::vec3f(0.188952 , 0.641306 , 0.792096 )); - colors.push_back(ospray::vec3f(0.327672 , 0.784939 , 0.873426 )); - colors.push_back(ospray::vec3f(0.60824 , 0.892164 , 0.935546 )); - colors.push_back(ospray::vec3f(0.881376 , 0.912184 , 0.818097 )); - colors.push_back(ospray::vec3f(0.9514 , 0.835615 , 0.449271 )); - colors.push_back(ospray::vec3f(0.904479 , 0.690486 , 0 )); - colors.push_back(ospray::vec3f(0.854063 , 0.510857 , 0 )); - colors.push_back(ospray::vec3f(0.777096 , 0.330175 , 0.000885023 )); - colors.push_back(ospray::vec3f(0.672862 , 0.139086 , 0.00270085 )); - colors.push_back(ospray::vec3f(0.508812 , 0 , 0 )); - colors.push_back(ospray::vec3f(0.299413 , 0.000366217 , 0.000549325 )); - colors.push_back(ospray::vec3f(0.0157473 , 0.00332647 , 0 )); + colors.push_back(ospcommon::vec3f(0 , 0 , 0 )); + colors.push_back(ospcommon::vec3f(0 , 0.120394 , 0.302678 )); + colors.push_back(ospcommon::vec3f(0 , 0.216587 , 0.524575 )); + colors.push_back(ospcommon::vec3f(0.0552529 , 0.345022 , 0.659495 )); + colors.push_back(ospcommon::vec3f(0.128054 , 0.492592 , 0.720287 )); + colors.push_back(ospcommon::vec3f(0.188952 , 0.641306 , 0.792096 )); + colors.push_back(ospcommon::vec3f(0.327672 , 0.784939 , 0.873426 )); + colors.push_back(ospcommon::vec3f(0.60824 , 0.892164 , 0.935546 )); + colors.push_back(ospcommon::vec3f(0.881376 , 0.912184 , 0.818097 )); + colors.push_back(ospcommon::vec3f(0.9514 , 0.835615 , 0.449271 )); + colors.push_back(ospcommon::vec3f(0.904479 , 0.690486 , 0 )); + colors.push_back(ospcommon::vec3f(0.854063 , 0.510857 , 0 )); + colors.push_back(ospcommon::vec3f(0.777096 , 0.330175 , 0.000885023 )); + colors.push_back(ospcommon::vec3f(0.672862 , 0.139086 , 0.00270085 )); + colors.push_back(ospcommon::vec3f(0.508812 , 0 , 0 )); + colors.push_back(ospcommon::vec3f(0.299413 , 0.000366217 , 0.000549325 )); + colors.push_back(ospcommon::vec3f(0.0157473 , 0.00332647 , 0 )); colorMaps.push_back(ColorMap("Ice / Fire", colors)); // Cool to warm. colors.clear(); - colors.push_back(ospray::vec3f(0.231373 , 0.298039 , 0.752941 )); - colors.push_back(ospray::vec3f(0.865003 , 0.865003 , 0.865003 )); - colors.push_back(ospray::vec3f(0.705882 , 0.0156863 , 0.14902 )); + colors.push_back(ospcommon::vec3f(0.231373 , 0.298039 , 0.752941 )); + colors.push_back(ospcommon::vec3f(0.865003 , 0.865003 , 0.865003 )); + colors.push_back(ospcommon::vec3f(0.705882 , 0.0156863 , 0.14902 )); colorMaps.push_back(ColorMap("Cool to Warm", colors)); // Blue to red rainbow. colors.clear(); - colors.push_back(ospray::vec3f(0 , 0 , 1 )); - colors.push_back(ospray::vec3f(1 , 0 , 0 )); + colors.push_back(ospcommon::vec3f(0 , 0 , 1 )); + colors.push_back(ospcommon::vec3f(1 , 0 , 0 )); colorMaps.push_back(ColorMap("Blue to Red Rainbow", colors)); // Grayscale. colors.clear(); - colors.push_back(ospray::vec3f(0.)); - colors.push_back(ospray::vec3f(1.)); + colors.push_back(ospcommon::vec3f(0.)); + colors.push_back(ospcommon::vec3f(1.)); colorMaps.push_back(ColorMap("Grayscale", colors)); } diff --git a/apps/volumeViewer/TransferFunctionEditor.h b/apps/volumeViewer/TransferFunctionEditor.h index 45d9f93763..145e52b7f5 100644 --- a/apps/volumeViewer/TransferFunctionEditor.h +++ b/apps/volumeViewer/TransferFunctionEditor.h @@ -41,7 +41,7 @@ public slots: void load(std::string filename = std::string()); //! Set the data value range for the transfer function editor. - void setDataValueRange(ospray::vec2f dataValueRange, bool force=false); + void setDataValueRange(ospcommon::vec2f dataValueRange, bool force=false); //! Slot called to update transfer function opacity values based on widget values. void updateOpacityValues(); diff --git a/apps/volumeViewer/VolumeViewer.cpp b/apps/volumeViewer/VolumeViewer.cpp index 2b13cff80c..b4a045d24c 100644 --- a/apps/volumeViewer/VolumeViewer.cpp +++ b/apps/volumeViewer/VolumeViewer.cpp @@ -14,11 +14,11 @@ // limitations under the License. // // ======================================================================== // -#include "ospray/common/OSPCommon.h" -#include "VolumeViewer.h" #include -#include "modules/loaders/ObjectFile.h" -#include "modules/loaders/TriangleMeshFile.h" +// own +#include "VolumeViewer.h" +#include "loaders/ObjectFile.h" +#include "loaders/TriangleMeshFile.h" #include "TransferFunctionEditor.h" #include "IsosurfaceEditor.h" #include "LightEditor.h" @@ -40,7 +40,7 @@ VolumeViewer::VolumeViewer(const std::vector &objectFileFilenames, : objectFileFilenames(objectFileFilenames), modelIndex(0), ownModelPerObject(ownModelPerObject), - boundingBox(ospray::vec3f(0.f), ospray::vec3f(1.f)), + boundingBox(ospcommon::vec3f(0.f), ospcommon::vec3f(1.f)), renderer(NULL), rendererInitialized(false), transferFunction(NULL), @@ -77,7 +77,7 @@ VolumeViewer::VolumeViewer(const std::vector &objectFileFilenames, show(); } -ospray::box3f VolumeViewer::getBoundingBox() +ospcommon::box3f VolumeViewer::getBoundingBox() { return boundingBox; } @@ -102,7 +102,7 @@ void VolumeViewer::setModel(size_t index) rendererInitialized = true; // Update transfer function and isosurface editor data value range with the voxel range of the current model's first volume. - ospray::vec2f voxelRange(0.f); + ospcommon::vec2f voxelRange(0.f); OSPVolume volume = modelStates[index].volumes[0]; #ifdef OSPRAY_VOLUME_VOXELRANGE_IN_APP voxelRange = VolumeFile::voxelRangeOf[volume]; @@ -110,7 +110,7 @@ void VolumeViewer::setModel(size_t index) ospGetVec2f(modelStates[index].volumes[0], "voxelRange", (osp::vec2f*)&voxelRange); #endif - if(voxelRange != ospray::vec2f(0.f)) { + if(voxelRange != ospcommon::vec2f(0.f)) { transferFunctionEditor->setDataValueRange(voxelRange); isosurfaceEditor->setDataValueRange(voxelRange); } @@ -210,7 +210,7 @@ void VolumeViewer::addGeometry(std::string filename) ospAddGeometry(modelInstance, triangleMesh); ospCommit(modelInstance); - ospray::affine3f xfm = embree::one; + ospcommon::affine3f xfm = ospcommon::one; OSPGeometry triangleMeshInstance = ospNewInstance(modelInstance, (osp::affine3f&)xfm); ospCommit(triangleMeshInstance); @@ -310,7 +310,7 @@ void VolumeViewer::setSamplingRate(double value) render(); } -void VolumeViewer::setVolumeClippingBox(ospray::box3f value) +void VolumeViewer::setVolumeClippingBox(ospcommon::box3f value) { for(size_t i=0; i sliceParameters) { // Provide the slices to OSPRay as the coefficients (a,b,c,d) of the plane equation ax + by + cz + d = 0. - std::vector planes; + std::vector planes; for(size_t i=0; i @@ -55,7 +55,7 @@ Q_OBJECT std::string writeFramesFilename); //! Get the volume bounding box. - ospray::box3f getBoundingBox(); + ospcommon::box3f getBoundingBox(); //! Get the OSPRay output window. QOSPRayWindow *getWindow(); @@ -111,7 +111,7 @@ public slots: void setSamplingRate(double value); //! Set volume clipping box on all volumes. - void setVolumeClippingBox(ospray::box3f value); + void setVolumeClippingBox(ospcommon::box3f value); //! Set slices on all volumes. void setSlices(std::vector sliceParameters); @@ -132,7 +132,7 @@ public slots: size_t modelIndex; //! Bounding box of the (first) volume. - ospray::box3f boundingBox; + ospcommon::box3f boundingBox; //! OSPRay renderer. OSPRenderer renderer; diff --git a/modules/loaders/CMakeLists.txt b/apps/volumeViewer/loaders/CMakeLists.txt similarity index 93% rename from modules/loaders/CMakeLists.txt rename to apps/volumeViewer/loaders/CMakeLists.txt index 6b6929103f..10545ab8c3 100644 --- a/modules/loaders/CMakeLists.txt +++ b/apps/volumeViewer/loaders/CMakeLists.txt @@ -14,11 +14,9 @@ ## limitations under the License. ## ## ======================================================================== ## -OPTION(OSPRAY_MODULE_LOADERS "Build loaders for common file types." ON) - CONFIGURE_OSPRAY() -IF(NOT THIS_IS_MIC AND OSPRAY_MODULE_LOADERS) +IF(NOT THIS_IS_MIC) INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/ospray) INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/ospray/include) diff --git a/modules/loaders/OSPObjectFile.cpp b/apps/volumeViewer/loaders/OSPObjectFile.cpp similarity index 98% rename from modules/loaders/OSPObjectFile.cpp rename to apps/volumeViewer/loaders/OSPObjectFile.cpp index f2aa15a008..75445f528b 100644 --- a/modules/loaders/OSPObjectFile.cpp +++ b/apps/volumeViewer/loaders/OSPObjectFile.cpp @@ -14,13 +14,16 @@ // limitations under the License. // // ======================================================================== // -#include "ospray/common/OSPCommon.h" +// our own +#include "OSPObjectFile.h" +#include "TriangleMeshFile.h" +#include "VolumeFile.h" +// ospcommon +#include "common/common.h" +// std #include #include #include -#include "modules/loaders/OSPObjectFile.h" -#include "modules/loaders/TriangleMeshFile.h" -#include "modules/loaders/VolumeFile.h" OSPObject *OSPObjectFile::importObjects() { diff --git a/modules/loaders/OSPObjectFile.h b/apps/volumeViewer/loaders/OSPObjectFile.h similarity index 96% rename from modules/loaders/OSPObjectFile.h rename to apps/volumeViewer/loaders/OSPObjectFile.h index 8f46b4c877..1f1fe03444 100644 --- a/modules/loaders/OSPObjectFile.h +++ b/apps/volumeViewer/loaders/OSPObjectFile.h @@ -16,9 +16,9 @@ #pragma once -#include "modules/loaders/RawVolumeFile.h" -#include "modules/loaders/ObjectFile.h" -#include "modules/loaders/TinyXML2.h" +#include "RawVolumeFile.h" +#include "ObjectFile.h" +#include "TinyXML2.h" // stl #include diff --git a/modules/loaders/ObjectFile.cpp b/apps/volumeViewer/loaders/ObjectFile.cpp similarity index 93% rename from modules/loaders/ObjectFile.cpp rename to apps/volumeViewer/loaders/ObjectFile.cpp index 05980aeccd..9402d748e1 100644 --- a/modules/loaders/ObjectFile.cpp +++ b/apps/volumeViewer/loaders/ObjectFile.cpp @@ -15,8 +15,8 @@ // ======================================================================== // #include -#include "ospray/common/Library.h" -#include "modules/loaders/ObjectFile.h" +#include "common/common.h" +#include "ObjectFile.h" OSPObject *ObjectFile::importObjects(const std::string &filename) { @@ -40,7 +40,7 @@ OSPObject *ObjectFile::importObjects(const std::string &filename) std::string creationFunctionName = "ospray_import_object_file_" + std::string(type); // Look for the named function. - symbolRegistry[type] = (creationFunctionPointer) ospray::getSymbol(creationFunctionName); + symbolRegistry[type] = (creationFunctionPointer) ospcommon::getSymbol(creationFunctionName); // The named function may not be found if the requested subtype is not known. if (!symbolRegistry[type]) std::cerr << " ospray_module_loaders::ObjectFile WARNING: unrecognized file type '" + type + "'." << std::endl; diff --git a/modules/loaders/ObjectFile.h b/apps/volumeViewer/loaders/ObjectFile.h similarity index 98% rename from modules/loaders/ObjectFile.h rename to apps/volumeViewer/loaders/ObjectFile.h index 28f12cab7b..5de368bfe6 100644 --- a/modules/loaders/ObjectFile.h +++ b/apps/volumeViewer/loaders/ObjectFile.h @@ -17,8 +17,9 @@ #pragma once #include +#include #include -#include "ospray/include/ospray/ospray.h" +#include "ospray/ospray.h" //! \brief Define a function to create an instance of the InternalClass //! associated with ExternalName. diff --git a/modules/loaders/PLYTriangleMeshFile.cpp b/apps/volumeViewer/loaders/PLYTriangleMeshFile.cpp similarity index 92% rename from modules/loaders/PLYTriangleMeshFile.cpp rename to apps/volumeViewer/loaders/PLYTriangleMeshFile.cpp index 2943f3c58e..3dfca58b7b 100644 --- a/modules/loaders/PLYTriangleMeshFile.cpp +++ b/apps/volumeViewer/loaders/PLYTriangleMeshFile.cpp @@ -29,7 +29,7 @@ bool startsWith(const std::string &haystack, const std::string &needle) PLYTriangleMeshFile::PLYTriangleMeshFile(const std::string &filename) : filename(filename), - scale(ospray::vec3f(1.f)), + scale(ospcommon::vec3f(1.f)), verbose(true) { } @@ -181,16 +181,16 @@ bool PLYTriangleMeshFile::parse() } // Add to vertices vector with scaling applied. - vertices.push_back(scale * ospray::vec3fa(vertexProperties[xIndex], vertexProperties[yIndex], vertexProperties[zIndex])); + vertices.push_back(scale * ospcommon::vec3fa(vertexProperties[xIndex], vertexProperties[yIndex], vertexProperties[zIndex])); // Vertex normals will be computed later. - vertexNormals.push_back(ospray::vec3fa(0.f)); + vertexNormals.push_back(ospcommon::vec3fa(0.f)); // Use vertex colors if we have them; otherwise default to white (note that the volume renderer currently requires a color for every vertex). if(haveVertexColors) - vertexColors.push_back(1.f/255.f * ospray::vec4f(vertexProperties[rIndex], vertexProperties[gIndex], vertexProperties[bIndex], vertexProperties[aIndex])); + vertexColors.push_back(1.f/255.f * ospcommon::vec4f(vertexProperties[rIndex], vertexProperties[gIndex], vertexProperties[bIndex], vertexProperties[aIndex])); else - vertexColors.push_back(ospray::vec4f(1.f)); + vertexColors.push_back(ospcommon::vec4f(1.f)); } // Read the face data. @@ -200,14 +200,14 @@ bool PLYTriangleMeshFile::parse() in >> count; exitOnCondition(count != 3, "only triangle faces are supported."); - ospray::vec3i triangle; + ospcommon::vec3i triangle; in >> triangle.x >> triangle.y >> triangle.z; exitOnCondition(!in.good(), "error reading face data."); triangles.push_back(triangle); // Add vertex normal contributions. - ospray::vec3fa triangleNormal = cross(vertices[triangle.y] - vertices[triangle.x], vertices[triangle.z] - vertices[triangle.x]); + ospcommon::vec3fa triangleNormal = cross(vertices[triangle.y] - vertices[triangle.x], vertices[triangle.z] - vertices[triangle.x]); vertexNormals[triangle.x] += triangleNormal; vertexNormals[triangle.y] += triangleNormal; vertexNormals[triangle.z] += triangleNormal; diff --git a/modules/loaders/PLYTriangleMeshFile.h b/apps/volumeViewer/loaders/PLYTriangleMeshFile.h similarity index 87% rename from modules/loaders/PLYTriangleMeshFile.h rename to apps/volumeViewer/loaders/PLYTriangleMeshFile.h index 818e2bdaef..65ee6299b8 100644 --- a/modules/loaders/PLYTriangleMeshFile.h +++ b/apps/volumeViewer/loaders/PLYTriangleMeshFile.h @@ -16,9 +16,13 @@ #pragma once -#include "ospray/common/OSPCommon.h" +// ospcommon +#include "common/vec.h" +// std #include -#include "modules/loaders/TriangleMeshFile.h" +#include +// own +#include "TriangleMeshFile.h" //! \brief A concrete implementation of the TriangleMeshFile class //! for reading triangle data stored in the PLY file format on disk. @@ -44,22 +48,22 @@ class PLYTriangleMeshFile : public TriangleMeshFile { std::string filename; //! Scaling for vertex coordinates. - ospray::vec3f scale; + ospcommon::vec3f scale; //! Verbose logging. bool verbose; //! Vertices. - std::vector vertices; + std::vector vertices; //! Vertex colors. - std::vector vertexColors; + std::vector vertexColors; //! Vertex normals. - std::vector vertexNormals; + std::vector vertexNormals; //! Triangle definitions. - std::vector triangles; + std::vector triangles; //! Parse the file, determining the vertices, vertex colors, and triangles. bool parse(); diff --git a/modules/loaders/README.txt b/apps/volumeViewer/loaders/README.txt similarity index 100% rename from modules/loaders/README.txt rename to apps/volumeViewer/loaders/README.txt diff --git a/modules/loaders/RMVolumeFile.cpp b/apps/volumeViewer/loaders/RMVolumeFile.cpp similarity index 90% rename from modules/loaders/RMVolumeFile.cpp rename to apps/volumeViewer/loaders/RMVolumeFile.cpp index cac58a3fb7..7b934de23d 100644 --- a/modules/loaders/RMVolumeFile.cpp +++ b/apps/volumeViewer/loaders/RMVolumeFile.cpp @@ -14,21 +14,21 @@ // limitations under the License. // // ======================================================================== // +#include "RMVolumeFile.h" +// ospcommon +#include "common/sysinfo.h" +// std:: #include #include -#include "modules/loaders/RMVolumeFile.h" -#include "ospray/common/OSPCommon.h" -#include "common/sys/sysinfo.h" -#include "common/sys/thread.h" #ifdef __LINUX__ # include #endif #include - +#include struct RMLoaderThreads { OSPVolume volume; - embree::MutexSys mutex; + std::mutex mutex; int nextBlockID; int nextPinID; int numThreads; @@ -36,7 +36,7 @@ struct RMLoaderThreads { pthread_t *thread; std::string inFilesDir; bool useGZip; - ospray::vec2f voxelRange; + ospcommon::vec2f voxelRange; struct Block { uint8_t voxel[256*256*128]; }; @@ -112,7 +112,7 @@ struct RMLoaderThreads { { mutex.lock(); int threadID = nextPinID++; - embree::setAffinity(threadID); + // embree::setAffinity(threadID); mutex.unlock(); Block *block = new Block; @@ -140,12 +140,12 @@ struct RMLoaderThreads { for (int i=0;i<5;i++) printf("[%i]",block->voxel[i]); #endif - ospray::vec3i region_lo(I*256,J*256,K*128); - ospray::vec3i region_sz(256,256,128); + ospcommon::vec3i region_lo(I*256,J*256,K*128); + ospcommon::vec3i region_sz(256,256,128); ospSetRegion(volume,block->voxel,(osp::vec3i&)region_lo,(osp::vec3i&)region_sz); mutex.unlock(); - ospray::vec2f blockRange(block->voxel[0]); + ospcommon::vec2f blockRange(block->voxel[0]); extendVoxelRange(blockRange,&block->voxel[0],256*256*128); #ifdef OSPRAY_VOLUME_VOXELRANGE_IN_APP @@ -166,21 +166,21 @@ struct RMLoaderThreads { OSPVolume RMVolumeFile::importVolume(OSPVolume volume) { // Update the provided dimensions of the volume for the subvolume specified. - ospray::vec3i dims(2048,2048,1920); + ospcommon::vec3i dims(2048,2048,1920); ospSetVec3i(volume, "dimensions", (osp::vec3i&)dims); ospSetString(volume,"voxelType", "uchar"); #ifdef __LINUX__ - int numThreads = embree::getNumberOfLogicalThreads(); //20; + int numThreads = ospcommon::getNumberOfLogicalThreads(); //20; #else int numThreads = 1; #endif - double t0 = ospray::getSysTime(); + double t0 = ospcommon::getSysTime(); RMLoaderThreads(volume,fileName,numThreads); - double t1 = ospray::getSysTime(); + double t1 = ospcommon::getSysTime(); std::cout << "done loading " << fileName << ", needed " << (t1-t0) << " seconds" << std::endl; diff --git a/modules/loaders/RMVolumeFile.h b/apps/volumeViewer/loaders/RMVolumeFile.h similarity index 97% rename from modules/loaders/RMVolumeFile.h rename to apps/volumeViewer/loaders/RMVolumeFile.h index 993fcbe995..32f9d48f49 100644 --- a/modules/loaders/RMVolumeFile.h +++ b/apps/volumeViewer/loaders/RMVolumeFile.h @@ -17,7 +17,7 @@ #pragma once #include -#include "modules/loaders/VolumeFile.h" +#include "VolumeFile.h" //! \brief specific importer for the LLNL "RM" (Richtmyer-Meshkov) instability files /*! Note this exists only for a specific demo */ diff --git a/modules/loaders/RawVolumeFile.cpp b/apps/volumeViewer/loaders/RawVolumeFile.cpp similarity index 88% rename from modules/loaders/RawVolumeFile.cpp rename to apps/volumeViewer/loaders/RawVolumeFile.cpp index ce695a12ba..b17dd3a360 100644 --- a/modules/loaders/RawVolumeFile.cpp +++ b/apps/volumeViewer/loaders/RawVolumeFile.cpp @@ -14,18 +14,20 @@ // limitations under the License. // // ======================================================================== // -#include "modules/loaders/RawVolumeFile.h" +#include "RawVolumeFile.h" + #include #include -#include "modules/loaders/RawVolumeFile.h" -#include "common/sys/filename.h" +#include "common/FileName.h" + +using ospcommon::FileName; OSPVolume RawVolumeFile::importVolume(OSPVolume volume) { // Look for the volume data file at the given path. FILE *file = NULL; - embree::FileName fn = filename; + FileName fn = filename; bool gzipped = fn.ext() == "gz"; if (gzipped) { std::string cmd = "/usr/bin/gunzip -c "+filename; @@ -41,7 +43,7 @@ OSPVolume RawVolumeFile::importVolume(OSPVolume volume) ospGeti(volume, "filename offset", &offset); fseek(file, offset, SEEK_SET); // Volume dimensions. - ospray::vec3i volumeDimensions; + ospcommon::vec3i volumeDimensions; exitOnCondition(!ospGetVec3i(volume, "dimensions", &(osp::vec3i&)volumeDimensions), @@ -57,6 +59,8 @@ OSPVolume RawVolumeFile::importVolume(OSPVolume volume) if (strcmp(voxelType, "uchar") == 0) voxelSize = sizeof(unsigned char); + else if (strcmp(voxelType, "ushort") == 0) + voxelSize = sizeof(uint16_t); else if (strcmp(voxelType, "float") == 0) voxelSize = sizeof(float); else if (strcmp(voxelType, "double") == 0) @@ -68,20 +72,20 @@ OSPVolume RawVolumeFile::importVolume(OSPVolume volume) // Subvolume params: subvolumeOffsets, subvolumeDimensions, subvolumeSteps. // The subvolume defaults to full dimensions (allowing for just subsampling, // for example). - ospray::vec3i subvolumeOffsets = ospray::vec3i(0); + ospcommon::vec3i subvolumeOffsets = ospcommon::vec3i(0); ospGetVec3i(volume, "subvolumeOffsets", (osp::vec3i*)&subvolumeOffsets); exitOnCondition(reduce_min(subvolumeOffsets) < 0 || reduce_max(subvolumeOffsets - volumeDimensions) >= 0, "invalid subvolume offsets"); - ospray::vec3i subvolumeDimensions = volumeDimensions - subvolumeOffsets; + ospcommon::vec3i subvolumeDimensions = volumeDimensions - subvolumeOffsets; ospGetVec3i(volume, "subvolumeDimensions", (osp::vec3i*)&subvolumeDimensions); exitOnCondition(reduce_min(subvolumeDimensions) < 1 || reduce_max(subvolumeDimensions - (volumeDimensions - subvolumeOffsets)) > 0, "invalid subvolume dimension(s) specified"); - ospray::vec3i subvolumeSteps = ospray::vec3i(1); + ospcommon::vec3i subvolumeSteps = ospcommon::vec3i(1); ospGetVec3i(volume, "subvolumeSteps", (osp::vec3i*)&subvolumeSteps); exitOnCondition(reduce_min(subvolumeSteps) < 1 || reduce_max(subvolumeSteps - @@ -92,7 +96,7 @@ OSPVolume RawVolumeFile::importVolume(OSPVolume volume) // The dimensions of the volume to be imported; this will be changed if a // subvolume is specified. - ospray::vec3i importVolumeDimensions = volumeDimensions; + ospcommon::vec3i importVolumeDimensions = volumeDimensions; if (reduce_max(subvolumeOffsets) > 0 || subvolumeDimensions != volumeDimensions || @@ -108,7 +112,7 @@ OSPVolume RawVolumeFile::importVolume(OSPVolume volume) (subvolumeDimensions.y % subvolumeSteps.y != 0); int zdim = subvolumeDimensions.z / subvolumeSteps.z + (subvolumeDimensions.z % subvolumeSteps.z != 0); - importVolumeDimensions = ospray::vec3i(xdim, ydim, zdim); + importVolumeDimensions = ospcommon::vec3i(xdim, ydim, zdim); // Range check. exitOnCondition(reduce_min(importVolumeDimensions) <= 0, @@ -119,7 +123,7 @@ OSPVolume RawVolumeFile::importVolume(OSPVolume volume) } #ifdef OSPRAY_VOLUME_VOXELRANGE_IN_APP -ospray::vec2f voxelRange(+std::numeric_limits::infinity(), +ospcommon::vec2f voxelRange(+std::numeric_limits::infinity(), -std::numeric_limits::infinity()); #endif @@ -156,6 +160,11 @@ ospray::vec2f voxelRange(+std::numeric_limits::infinity(), (unsigned char *)voxelData, volumeDimensions.x*volumeDimensions.y); } + else if (strcmp(voxelType, "ushort") == 0) { + extendVoxelRange(voxelRange, + (uint16_t *)voxelData, + volumeDimensions.x*volumeDimensions.y); + } else if (strcmp(voxelType, "float") == 0) { extendVoxelRange(voxelRange, (float *)voxelData, @@ -172,8 +181,8 @@ ospray::vec2f voxelRange(+std::numeric_limits::infinity(), #endif - ospray::vec3i region_lo(0, 0, z); - ospray::vec3i region_sz(volumeDimensions.x, + ospcommon::vec3i region_lo(0, 0, z); + ospcommon::vec3i region_sz(volumeDimensions.x, volumeDimensions.y, slicesToRead); // Copy the voxels into the volume. @@ -182,9 +191,9 @@ ospray::vec2f voxelRange(+std::numeric_limits::infinity(), (osp::vec3i&)region_lo, (osp::vec3i&)region_sz); - std::cerr << "volume load: " - << float(z) / float(volumeDimensions.z) * 100. << " %" - << std::endl; + // std::cerr << "volume load: " + // << float(z) / float(volumeDimensions.z) * 100. << " %" + // << std::endl; } // Clean up. @@ -237,10 +246,10 @@ ospray::vec2f voxelRange(+std::numeric_limits::infinity(), } // Copy subvolume row into the volume. - ospray::vec3i region_lo(0, + ospcommon::vec3i region_lo(0, (i2 - subvolumeOffsets.y) / subvolumeSteps.y, (i3 - subvolumeOffsets.z) / subvolumeSteps.z); - ospray::vec3i region_sz(importVolumeDimensions.x, 1, 1); + ospcommon::vec3i region_sz(importVolumeDimensions.x, 1, 1); ospSetRegion(volume, &subvolumeRowData[0], (osp::vec3i&)region_lo, diff --git a/modules/loaders/RawVolumeFile.h b/apps/volumeViewer/loaders/RawVolumeFile.h similarity index 96% rename from modules/loaders/RawVolumeFile.h rename to apps/volumeViewer/loaders/RawVolumeFile.h index cb9c908cce..969c3c35f2 100644 --- a/modules/loaders/RawVolumeFile.h +++ b/apps/volumeViewer/loaders/RawVolumeFile.h @@ -16,9 +16,10 @@ #pragma once -#include "ospray/common/OSPCommon.h" +// own +#include "VolumeFile.h" +// std #include -#include "modules/loaders/VolumeFile.h" //! \brief A concrete implementation of the VolumeFile class for reading //! voxel data stored in a file on disk as a single monolithic brick, diff --git a/modules/loaders/SymbolRegistry.cpp b/apps/volumeViewer/loaders/SymbolRegistry.cpp similarity index 89% rename from modules/loaders/SymbolRegistry.cpp rename to apps/volumeViewer/loaders/SymbolRegistry.cpp index 591f6f395b..f4072ceb46 100644 --- a/modules/loaders/SymbolRegistry.cpp +++ b/apps/volumeViewer/loaders/SymbolRegistry.cpp @@ -14,10 +14,10 @@ // limitations under the License. // // ======================================================================== // -#include "modules/loaders/OSPObjectFile.h" -#include "modules/loaders/RawVolumeFile.h" -#include "modules/loaders/RMVolumeFile.h" -#include "modules/loaders/PLYTriangleMeshFile.h" +#include "OSPObjectFile.h" +#include "RawVolumeFile.h" +#include "RMVolumeFile.h" +#include "PLYTriangleMeshFile.h" // Loader for XML object files. OSP_REGISTER_OBJECT_FILE(OSPObjectFile, osp); diff --git a/modules/loaders/TinyXML2.cpp b/apps/volumeViewer/loaders/TinyXML2.cpp similarity index 100% rename from modules/loaders/TinyXML2.cpp rename to apps/volumeViewer/loaders/TinyXML2.cpp diff --git a/modules/loaders/TinyXML2.h b/apps/volumeViewer/loaders/TinyXML2.h similarity index 100% rename from modules/loaders/TinyXML2.h rename to apps/volumeViewer/loaders/TinyXML2.h diff --git a/modules/loaders/TriangleMeshFile.cpp b/apps/volumeViewer/loaders/TriangleMeshFile.cpp similarity index 95% rename from modules/loaders/TriangleMeshFile.cpp rename to apps/volumeViewer/loaders/TriangleMeshFile.cpp index 2a9d79c8fa..7175cf748a 100644 --- a/modules/loaders/TriangleMeshFile.cpp +++ b/apps/volumeViewer/loaders/TriangleMeshFile.cpp @@ -14,9 +14,9 @@ // limitations under the License. // // ======================================================================== // +#include "TriangleMeshFile.h" #include -#include "ospray/common/Library.h" -#include "modules/loaders/TriangleMeshFile.h" +#include "common/common.h" OSPGeometry TriangleMeshFile::importTriangleMesh(const std::string &filename, OSPGeometry triangleMesh) @@ -41,7 +41,7 @@ OSPGeometry TriangleMeshFile::importTriangleMesh(const std::string &filename, std::string creationFunctionName = "ospray_import_trianglemesh_file_" + std::string(type); // Look for the named function. - symbolRegistry[type] = (creationFunctionPointer) ospray::getSymbol(creationFunctionName); + symbolRegistry[type] = (creationFunctionPointer) ospcommon::getSymbol(creationFunctionName); // The named function may not be found if the requested subtype is not known. if (!symbolRegistry[type]) std::cerr << " ospray_module_loaders::TriangleMeshFile WARNING: unrecognized file type '" + type + "'." << std::endl; diff --git a/modules/loaders/TriangleMeshFile.h b/apps/volumeViewer/loaders/TriangleMeshFile.h similarity index 100% rename from modules/loaders/TriangleMeshFile.h rename to apps/volumeViewer/loaders/TriangleMeshFile.h diff --git a/modules/loaders/VolumeFile.cpp b/apps/volumeViewer/loaders/VolumeFile.cpp similarity index 92% rename from modules/loaders/VolumeFile.cpp rename to apps/volumeViewer/loaders/VolumeFile.cpp index e703e6096d..80815e8307 100644 --- a/modules/loaders/VolumeFile.cpp +++ b/apps/volumeViewer/loaders/VolumeFile.cpp @@ -14,9 +14,8 @@ // limitations under the License. // // ======================================================================== // +#include "VolumeFile.h" #include -#include "ospray/common/Library.h" -#include "modules/loaders/VolumeFile.h" OSPVolume VolumeFile::importVolume(const std::string &filename, OSPVolume volume) { @@ -40,7 +39,7 @@ OSPVolume VolumeFile::importVolume(const std::string &filename, OSPVolume volume std::string creationFunctionName = "ospray_import_volume_file_" + std::string(type); // Look for the named function. - symbolRegistry[type] = (creationFunctionPointer) ospray::getSymbol(creationFunctionName); + symbolRegistry[type] = (creationFunctionPointer) ospcommon::getSymbol(creationFunctionName); // The named function may not be found of the requested subtype is not known. if (!symbolRegistry[type]) std::cerr << " ospray_module_loaders::VolumeFile WARNING: unrecognized file type '" + type + "'." << std::endl; @@ -50,6 +49,6 @@ OSPVolume VolumeFile::importVolume(const std::string &filename, OSPVolume volume } #ifdef OSPRAY_VOLUME_VOXELRANGE_IN_APP -std::map VolumeFile::voxelRangeOf; +std::map VolumeFile::voxelRangeOf; #endif diff --git a/modules/loaders/VolumeFile.h b/apps/volumeViewer/loaders/VolumeFile.h similarity index 94% rename from modules/loaders/VolumeFile.h rename to apps/volumeViewer/loaders/VolumeFile.h index 8a4f5baf64..cf9b71cc27 100644 --- a/modules/loaders/VolumeFile.h +++ b/apps/volumeViewer/loaders/VolumeFile.h @@ -16,12 +16,17 @@ #pragma once +// ospcommon +#include "common/common.h" +#include "common/vec.h" +// ospray public +#include "ospray/include/ospray/ospray.h" +// std #include #include -#include "ospray/include/ospray/ospray.h" -#include "ospray/common/OSPCommon.h" //stl #include +#include //! \brief Define a function to create an instance of the InternalClass //! associated with ExternalName. @@ -38,7 +43,7 @@ /*! helper function to help build voxel ranges during parsing */ template -inline void extendVoxelRange(ospray::vec2f &voxelRange, const T *voxel, size_t num) +inline void extendVoxelRange(ospcommon::vec2f &voxelRange, const T *voxel, size_t num) { for (size_t i=0;i voxelRangeOf; + static std::map voxelRangeOf; #endif //! Print an error message. diff --git a/apps/volumeViewer/main.cpp b/apps/volumeViewer/main.cpp index 718b1d6db7..64dbb2c430 100644 --- a/apps/volumeViewer/main.cpp +++ b/apps/volumeViewer/main.cpp @@ -14,14 +14,17 @@ // limitations under the License. // // ======================================================================== // +// own #include "VolumeViewer.h" +#include "TransferFunctionEditor.h" +// ospray public +#include "ospray/ospray.h" +// std #include -#include #include #include -#include "VolumeViewer.h" -#include "TransferFunctionEditor.h" -#include "ospray/include/ospray/ospray.h" +// qt +#include int main(int argc, char *argv[]) { @@ -73,8 +76,8 @@ int main(int argc, char *argv[]) int benchmarkFrames = 0; int viewSizeWidth = 0; int viewSizeHeight = 0; - ospray::vec3f viewUp(0.f); - ospray::vec3f viewAt(0.f), viewFrom(0.f); + ospcommon::vec3f viewUp(0.f); + ospcommon::vec3f viewAt(0.f), viewFrom(0.f); bool showFrameRate = false; bool fullScreen = false; bool ownModelPerObject = false; @@ -200,7 +203,7 @@ int main(int argc, char *argv[]) if (i + 1 >= argc) throw std::runtime_error("missing argument"); std::string moduleName = argv[++i]; std::cout << "loading module '" << moduleName << "'." << std::endl; - error_t error = ospLoadModule(moduleName.c_str()); + int error = ospLoadModule(moduleName.c_str()); if(error != 0) { std::ostringstream ss; @@ -260,7 +263,7 @@ int main(int argc, char *argv[]) // Set the view up vector if specified. - if(viewUp != ospray::vec3f(0.f)) { + if(viewUp != ospcommon::vec3f(0.f)) { volumeViewer->getWindow()->getViewport()->setUp(viewUp); volumeViewer->getWindow()->resetAccumulationBuffer(); } diff --git a/cmake/FindTBB.cmake b/cmake/FindTBB.cmake index 1def6b352e..4c716ae743 100644 --- a/cmake/FindTBB.cmake +++ b/cmake/FindTBB.cmake @@ -50,6 +50,8 @@ IF (WIN32) HINTS ${TBB_ROOT} PATHS ${PROJECT_SOURCE_DIR}/tbb + ${PROJECT_SOURCE_DIR}/../tbb + "${PROGRAMFILES32}/IntelSWTools/compilers_and_libraries/windows/tbb" "${PROGRAMFILES32}/Intel/Composer XE/tbb" "${PROGRAMFILES32}/Intel/compilers_and_libraries/windows/tbb" ) @@ -188,5 +190,7 @@ IF (WIN32) 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? - INSTALL(PROGRAMS ${TBB_LIBRARIES_MIC} DESTINATION ${CMAKE_INSTALL_LIBDIR}/mic COMPONENT lib_mic) + 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/build_embree.cmake b/cmake/build_embree.cmake index 7abafd2d6b..c650962301 100644 --- a/cmake/build_embree.cmake +++ b/cmake/build_embree.cmake @@ -38,10 +38,10 @@ set(RTCORE_ENABLE_RAYSTREAM_LOGGER OFF CACHE INTERNAL "" FORCE) set(RTCORE_IGNORE_INVALID_RAYS OFF CACHE INTERNAL "" FORCE) set(RTCORE_RAY_PACKETS ON CACHE INTERNAL "" FORCE) -if (USE_TBB) +if (OSPRAY_TASKING_TBB) set(RTCORE_TASKING_SYSTEM TBB CACHE INTERNAL "" FORCE) else () - set(RTCORE_TASKING_SYSTEM Internal CACHE INTERNAL "" FORCE) + set(RTCORE_TASKING_SYSTEM INTERNAL CACHE INTERNAL "" FORCE) endif () if (OSPRAY_MIC) diff --git a/cmake/clang.cmake b/cmake/clang.cmake index 74dcf92166..40eb261e56 100644 --- a/cmake/clang.cmake +++ b/cmake/clang.cmake @@ -18,10 +18,12 @@ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -fno-strict-aliasing -Wno-narrowin SET(CMAKE_CXX_FLAGS_DEBUG "-DDEBUG -g -O0 -Wstrict-aliasing=1") SET(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG -O3 -Wstrict-aliasing=1") SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-DNDEBUG -g -O3 -Wstrict-aliasing=1") +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99") IF (APPLE) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.7 -stdlib=libc++") -ENDIF (APPLE) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.7") # we only use MacOSX 10.7 features + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") # link against C++11 stdlib +ENDIF() # these flags apply ONLY to how embree is built; the rest of the ospray C++ code is ISA-agnostic SET(OSPRAY_ARCH_SSE3 "-msse3") diff --git a/cmake/gcc.cmake b/cmake/gcc.cmake index 33807374e4..3db539b7e7 100644 --- a/cmake/gcc.cmake +++ b/cmake/gcc.cmake @@ -18,10 +18,12 @@ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -fno-strict-aliasing -std=c++11 - SET(CMAKE_CXX_FLAGS_DEBUG "-DDEBUG -g -Wstrict-aliasing=1") SET(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG -O3 -Wstrict-aliasing=1 -ffast-math ") SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-DNDEBUG -g -O3 -Wstrict-aliasing=1 -ffast-math ") +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99") IF (APPLE) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.7") -ENDIF (APPLE) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.7") # we only use MacOSX 10.7 features + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") # link against C++11 stdlib +ENDIF() # these flags apply ONLY to how embree is built; the rest of the ospray C++ code is ISA-agnostic SET(OSPRAY_ARCH_SSE3 "-msse3") diff --git a/cmake/glut.cmake b/cmake/glut.cmake index c572b451d0..fed7e4b1b6 100644 --- a/cmake/glut.cmake +++ b/cmake/glut.cmake @@ -67,7 +67,16 @@ ELSE() ) FIND_LIBRARY(GLUT_LIBRARIES NAMES libglut.so PATHS $ENV{TACC_FREEGLUT_LIB}) IF (NOT GLUT_LIBRARIES) - MESSAGE(FATAL_ERROR "Could not find GLUT library, even after trying additional search dirs") + MESSAGE(FATAL_ERROR "Could not find GLUT library, even after trying" + " additional search dirs." + " Please disable the following to build without GLUT:" + "\n" + " OSPRAY_APPS_MODELVIEWER," + " OSPRAY_APPS_PARTICLEVIEWER," + " OSPRAY_APPS_QTVIEWER," + " OSPRAY_APPS_STREAMLINEVIEWER," + " OSPRAY_MODULE_TACHYON" + "\n") ELSE() SET(GLUT_FOUND ON) ENDIF() diff --git a/cmake/icc.cmake b/cmake/icc.cmake index db31511fa2..a92eb9ed15 100644 --- a/cmake/icc.cmake +++ b/cmake/icc.cmake @@ -19,11 +19,13 @@ SET(CMAKE_CXX_FLAGS_DEBUG "-DDEBUG -g") SET(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG -O3") #SET(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG -O3 -no-ansi-alias -restrict -fp-model fast -fimf-precision=low -no-prec-div -no-prec-sqrt -fma -no-inline-max-total-size -inline-factor=200 ") SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-DNDEBUG -g -O3 -no-ansi-alias -restrict -fp-model fast -fimf-precision=low -no-prec-div -no-prec-sqrt -fma -no-inline-max-total-size -inline-factor=200") +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99") IF (APPLE) SET (CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS_INIT} -dynamiclib) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.7") -ENDIF (APPLE) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.7") # we only use MacOSX 10.7 features + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") # link against C++11 stdlib +ENDIF() # these flags apply ONLY to how embree is built; the rest of the ospray C++ code is ISA-agnostic SET(OSPRAY_ARCH_SSE3 "-xsse3") diff --git a/cmake/ispc.cmake b/cmake/ispc.cmake index d8d1920315..41ce36ec1f 100644 --- a/cmake/ispc.cmake +++ b/cmake/ispc.cmake @@ -29,11 +29,18 @@ IF (NOT ISPC_EXECUTABLE) SET(ISPC_DIR_SUFFIX "osx") ELSEIF(WIN32) SET(ISPC_DIR_SUFFIX "windows") + IF (MSVC14) + LIST(APPEND ISPC_DIR_SUFFIX "windows-vs2015") + ELSE() + LIST(APPEND ISPC_DIR_SUFFIX "windows-vs2013") + ENDIF() ELSE() SET(ISPC_DIR_SUFFIX "linux") ENDIF() FOREACH(ver ${ISPC_VERSION_WORKING}) - LIST(APPEND ISPC_DIR_HINT ${PROJECT_SOURCE_DIR}/../ispc-v${ver}-${ISPC_DIR_SUFFIX}) + FOREACH(suffix ${ISPC_DIR_SUFFIX}) + LIST(APPEND ISPC_DIR_HINT ${PROJECT_SOURCE_DIR}/../ispc-v${ver}-${suffix}) + ENDFOREACH() ENDFOREACH() FIND_PROGRAM(ISPC_EXECUTABLE ispc PATHS ${ISPC_DIR_HINT} DOC "Path to the ISPC executable.") @@ -66,10 +73,9 @@ IF(NOT ISPC_VERSION) ENDIF() # warn about recommended ISPC version on KNC -IF (OSPRAY_MIC AND NOT ISPC_VERSION VERSION_EQUAL ISPC_VERSION_RECOMMENDED_KNC - AND NOT OSPRAY_WARNED_KNC_ISPC_VERSION) - MESSAGE("Warning: use of ISPC v${ISPC_VERSION_RECOMMENDED_KNC} is recommended on KNC.") - SET(OSPRAY_WARNED_KNC_ISPC_VERSION ON CACHE INTERNAL "Warned about recommended ISPC version with KNC.") +IF (OSPRAY_MIC AND NOT ISPC_VERSION VERSION_EQUAL ISPC_VERSION_RECOMMENDED_KNC) + OSPRAY_WARN_ONCE(KNC_ISPC_VERSION + "Use of ISPC v${ISPC_VERSION_RECOMMENDED_KNC} is recommended on KNC.") ENDIF() GET_FILENAME_COMPONENT(ISPC_DIR ${ISPC_EXECUTABLE} PATH) @@ -92,7 +98,12 @@ MACRO (OSPRAY_ISPC_COMPILE) IF (THIS_IS_MIC) SET(ISPC_TARGET_EXT .cpp) SET(ISPC_TARGET_ARGS generic-16) - SET(ISPC_ADDITIONAL_ARGS ${ISPC_ADDITIONAL_ARGS} --opt=force-aligned-memory --emit-c++ --c++-include-file=${PROJECT_SOURCE_DIR}/ospray/common/ISPC_KNC_Backend.h ) + SET(ISPC_ADDITIONAL_ARGS + ${ISPC_ADDITIONAL_ARGS} + --opt=force-aligned-memory + --emit-c++ + --c++-include-file=${PROJECT_SOURCE_DIR}/ospray/common/ISPC_KNC_Backend.h + ) ELSE() SET(ISPC_TARGET_EXT ${CMAKE_CXX_OUTPUT_EXTENSION}) STRING(REPLACE ";" "," ISPC_TARGET_ARGS "${ISPC_TARGETS}") @@ -122,6 +133,10 @@ MACRO (OSPRAY_ISPC_COMPILE) SET(ISPC_ADDITIONAL_ARGS ${ISPC_ADDITIONAL_ARGS} --pic) ENDIF() + IF (NOT OSPRAY_DEBUG_BUILD) + SET(ISPC_ADDITIONAL_ARGS ${ISPC_ADDITIONAL_ARGS} --opt=disable-assertions) + ENDIF() + SET(ISPC_OBJECTS "") FOREACH(src ${ARGN}) diff --git a/cmake/mpi.cmake b/cmake/mpi.cmake index 3aecbe6a0f..26eaaf164e 100644 --- a/cmake/mpi.cmake +++ b/cmake/mpi.cmake @@ -14,54 +14,45 @@ ## limitations under the License. ## ## ======================================================================== ## -IF (OSPRAY_MPI) - SET(OSPRAY_MPI_DISTRIBUTED ON) # sets this define in OSPConfig.h +MACRO(CONFIGURE_MPI) - MACRO(CONFIGURE_MPI) + IF (WIN32) # FindMPI does not find Intel MPI on Windows, we need to help here + FIND_PACKAGE(MPI) - IF (WIN32) # FindMPI does not find Intel MPI on Windows, we need to help here - FIND_PACKAGE(MPI) - - # need to strip quotes, otherwise CMake treats it as relative path - STRING(REGEX REPLACE "^\"|\"$" "" MPI_CXX_INCLUDE_PATH ${MPI_CXX_INCLUDE_PATH}) + # need to strip quotes, otherwise CMake treats it as relative path + STRING(REGEX REPLACE "^\"|\"$" "" MPI_CXX_INCLUDE_PATH ${MPI_CXX_INCLUDE_PATH}) - IF (NOT MPI_CXX_FOUND) - # try again, hinting the compiler wrappers - SET(MPI_CXX_COMPILER mpicxx.bat) - SET(MPI_C_COMPILER mpicc.bat) - FIND_PACKAGE(MPI) + IF (NOT MPI_CXX_FOUND) + # try again, hinting the compiler wrappers + SET(MPI_CXX_COMPILER mpicxx.bat) + SET(MPI_C_COMPILER mpicc.bat) + FIND_PACKAGE(MPI) - IF (NOT MPI_CXX_LIBRARIES) - SET(MPI_LIB_PATH ${MPI_CXX_INCLUDE_PATH}\\..\\lib) + IF (NOT MPI_CXX_LIBRARIES) + SET(MPI_LIB_PATH ${MPI_CXX_INCLUDE_PATH}\\..\\lib) - SET(MPI_LIB "MPI_LIB-NOTFOUND" CACHE FILEPATH "Cleared" FORCE) - FIND_LIBRARY(MPI_LIB NAMES impi HINTS ${MPI_LIB_PATH}) - SET(MPI_C_LIB ${MPI_LIB}) - SET(MPI_C_LIBRARIES ${MPI_LIB} CACHE STRING "MPI C libraries to link against" FORCE) + SET(MPI_LIB "MPI_LIB-NOTFOUND" CACHE FILEPATH "Cleared" FORCE) + FIND_LIBRARY(MPI_LIB NAMES impi HINTS ${MPI_LIB_PATH}) + SET(MPI_C_LIB ${MPI_LIB}) + SET(MPI_C_LIBRARIES ${MPI_LIB} CACHE STRING "MPI C libraries to link against" FORCE) - SET(MPI_LIB "MPI_LIB-NOTFOUND" CACHE FILEPATH "Cleared" FORCE) - FIND_LIBRARY(MPI_LIB NAMES impicxx HINTS ${MPI_LIB_PATH}) - SET(MPI_CXX_LIBRARIES ${MPI_C_LIB} ${MPI_LIB} CACHE STRING "MPI CXX libraries to link against" FORCE) - SET(MPI_LIB "MPI_LIB-NOTFOUND" CACHE INTERNAL "Scratch variable for MPI lib detection" FORCE) - ENDIF() - ENDIF() - ELSE() - FIND_PACKAGE(MPI REQUIRED) - IF(MPI_CXX_FOUND) - GET_FILENAME_COMPONENT(DIR ${MPI_LIBRARY} PATH) - SET(MPI_LIBRARY_MIC ${DIR}/../../mic/lib/libmpi.so CACHE FILEPATH "") + SET(MPI_LIB "MPI_LIB-NOTFOUND" CACHE FILEPATH "Cleared" FORCE) + FIND_LIBRARY(MPI_LIB NAMES impicxx HINTS ${MPI_LIB_PATH}) + SET(MPI_CXX_LIBRARIES ${MPI_C_LIB} ${MPI_LIB} CACHE STRING "MPI CXX libraries to link against" FORCE) + SET(MPI_LIB "MPI_LIB-NOTFOUND" CACHE INTERNAL "Scratch variable for MPI lib detection" FORCE) ENDIF() ENDIF() + ELSE() + FIND_PACKAGE(MPI REQUIRED) + IF(MPI_CXX_FOUND) + GET_FILENAME_COMPONENT(DIR ${MPI_LIBRARY} PATH) + SET(MPI_LIBRARY_MIC ${DIR}/../../mic/lib/libmpi.so CACHE FILEPATH "") + ENDIF() + ENDIF() - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MPI_CXX_COMPILE_FLAGS}") - SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${MPI_CXX_LINK_FLAGS}") - - INCLUDE_DIRECTORIES(SYSTEM ${MPI_CXX_INCLUDE_PATH}) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MPI_CXX_COMPILE_FLAGS}") + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${MPI_CXX_LINK_FLAGS}") - ENDMACRO() + INCLUDE_DIRECTORIES(SYSTEM ${MPI_CXX_INCLUDE_PATH}) -ELSE() - MACRO(CONFIGURE_MPI) - # nothing to do w/o mpi mode - ENDMACRO() -ENDIF() +ENDMACRO() diff --git a/cmake/ospray.cmake b/cmake/ospray.cmake index 169cd7b812..33ab05e8bc 100644 --- a/cmake/ospray.cmake +++ b/cmake/ospray.cmake @@ -30,22 +30,50 @@ 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}}") +ENDMACRO() + +## Macro to print a warning message that only appears once ## +MACRO(OSPRAY_WARN_ONCE identifier message) + SET(INTERNAL_WARNING "OSPRAY_WARNED_${identifier}") + IF(NOT ${INTERNAL_WARNING}) + MESSAGE(WARNING ${message}) + SET(${INTERNAL_WARNING} ON CACHE INTERNAL "Warned about '${message}'") + ENDIF() +ENDMACRO() + +## Macro check for compiler support of ISA ## +MACRO(OSPRAY_CHECK_COMPILER_SUPPORT ISA) + IF (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.") + SET(OSPRAY_EMBREE_ENABLE_${ISA} false) + 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) - # Embree common include directories; others may be added depending on build target. - # this section could be sooo much cleaner if embree only used - # fully-qualified include names... - SET(EMBREE_INCLUDE_DIRECTORIES - ${OSPRAY_EMBREE_SOURCE_DIR}/ - ${OSPRAY_EMBREE_SOURCE_DIR}/include - ${OSPRAY_EMBREE_SOURCE_DIR}/common - ${OSPRAY_EMBREE_SOURCE_DIR}/ - ${OSPRAY_EMBREE_SOURCE_DIR}/kernels - ) + 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() IF (OSPRAY_TARGET STREQUAL "mic") SET(OSPRAY_EXE_SUFFIX ".mic") @@ -56,9 +84,6 @@ MACRO(CONFIGURE_OSPRAY) SET(__XEON__ OFF) INCLUDE(${PROJECT_SOURCE_DIR}/cmake/icc_xeonphi.cmake) - # additional Embree include directory - LIST(APPEND EMBREE_INCLUDE_DIRECTORIES ${OSPRAY_EMBREE_SOURCE_DIR}/kernels/xeonphi) - SET(OSPRAY_TARGET_MIC ON PARENT_SCOPE) ELSE() SET(OSPRAY_EXE_SUFFIX "") @@ -66,21 +91,16 @@ MACRO(CONFIGURE_OSPRAY) SET(OSPRAY_ISPC_SUFFIX ".o") SET(THIS_IS_MIC OFF) SET(__XEON__ ON) - IF (${CMAKE_CXX_COMPILER_ID} STREQUAL "Intel") + IF (OSPRAY_COMPILER_ICC) INCLUDE(${PROJECT_SOURCE_DIR}/cmake/icc.cmake) - ELSEIF (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") + ELSEIF (OSPRAY_COMPILER_GCC) INCLUDE(${PROJECT_SOURCE_DIR}/cmake/gcc.cmake) - ELSEIF (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang") + ELSEIF (OSPRAY_COMPILER_CLANG) INCLUDE(${PROJECT_SOURCE_DIR}/cmake/clang.cmake) - ELSEIF (${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") + ELSEIF (OSPRAY_COMPILER_MSVC) INCLUDE(${PROJECT_SOURCE_DIR}/cmake/msvc.cmake) - ELSE() - MESSAGE(FATAL_ERROR "Unsupported compiler specified: '${CMAKE_CXX_COMPILER_ID}'") ENDIF() - # additional Embree include directory - LIST(APPEND EMBREE_INCLUDE_DIRECTORIES ${OSPRAY_EMBREE_SOURCE_DIR}/kernels/xeon) - SET(OSPRAY_EMBREE_ENABLE_AVX512 false) IF (OSPRAY_BUILD_ISA STREQUAL "ALL") # ------------------------------------------------------------------ @@ -150,42 +170,21 @@ MACRO(CONFIGURE_OSPRAY) ENDIF() - IF (OSPRAY_EMBREE_ENABLE_AVX AND NOT OSPRAY_COMPILER_SUPPORTS_AVX) - IF (NOT OSPRAY_WARNED_MISSING_AVX) - MESSAGE("Warning: Need at least version ${GCC_VERSION_REQUIRED_AVX} of gcc for AVX. Disabling AVX.\nTo compile for AVX, please switch to either 'ICC'-compiler, or upgrade your gcc version.") - SET(OSPRAY_WARNED_MISSING_AVX ON CACHE INTERNAL "Warned about missing AVX support.") - ENDIF() - SET(OSPRAY_EMBREE_ENABLE_AVX false) - ENDIF() - - IF (OSPRAY_EMBREE_ENABLE_AVX2 AND NOT OSPRAY_COMPILER_SUPPORTS_AVX2) - IF (NOT OSPRAY_WARNED_MISSING_AVX2) - MESSAGE("Warning: Need at least version ${GCC_VERSION_REQUIRED_AVX2} of gcc for AVX2. Disabling AVX2.\nTo compile for AVX2, please switch to either 'ICC'-compiler, or upgrade your gcc version.") - SET(OSPRAY_WARNED_MISSING_AVX2 ON CACHE INTERNAL "Warned about missing AVX2 support.") - ENDIF() - SET(OSPRAY_EMBREE_ENABLE_AVX2 false) - ENDIF() - - IF (OSPRAY_EMBREE_ENABLE_AVX512 AND NOT OSPRAY_COMPILER_SUPPORTS_AVX512) - IF (NOT OSPRAY_WARNED_MISSING_AVX2) - MESSAGE("Warning: Need at least version ${GCC_VERSION_REQUIRED_AVX512} of gcc for AVX512. Disabling AVX512.\nTo compile for AVX512, please switch to either 'ICC'-compiler, or upgrade your gcc version.") - SET(OSPRAY_WARNED_MISSING_AVX512 ON CACHE INTERNAL "Warned about missing AVX512 support.") - ENDIF() - SET(OSPRAY_EMBREE_ENABLE_AVX512 false) - ENDIF() + OSPRAY_CHECK_COMPILER_SUPPORT(AVX) + OSPRAY_CHECK_COMPILER_SUPPORT(AVX2) + OSPRAY_CHECK_COMPILER_SUPPORT(AVX512) IF (THIS_IS_MIC) - # whether to build in MIC/xeon phi support - SET(OSPRAY_BUILD_COI_DEVICE OFF CACHE BOOL "Build COI Device for OSPRay's MIC support?") + OPTION(OSPRAY_BUILD_COI_DEVICE "Build COI Device for OSPRay's MIC support?" ON) ENDIF() INCLUDE(${PROJECT_SOURCE_DIR}/cmake/ispc.cmake) INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}) - INCLUDE_DIRECTORIES(${EMBREE_INCLUDE_DIRECTORIES}) + INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/ospray/include) INCLUDE_DIRECTORIES_ISPC(${PROJECT_SOURCE_DIR}) - INCLUDE_DIRECTORIES_ISPC(${EMBREE_INCLUDE_DIRECTORIES}) + INCLUDE_DIRECTORIES_ISPC(${PROJECT_SOURCE_DIR}/ospray/include) # for auto-generated cmakeconfig etc INCLUDE_DIRECTORIES(${PROJECT_BINARY_DIR}) @@ -193,7 +192,6 @@ MACRO(CONFIGURE_OSPRAY) ENDMACRO() - ## Target creation macros ## MACRO(OSPRAY_ADD_EXECUTABLE name) @@ -286,3 +284,148 @@ MACRO(OSPRAY_SET_LIBRARY_VERSION _name) SET_TARGET_PROPERTIES(${name} PROPERTIES VERSION ${OSPRAY_VERSION} SOVERSION ${OSPRAY_SOVERSION}) ENDMACRO() + +## Compiler configuration macro ## + +MACRO(OSPRAY_CONFIGURE_COMPILER) + # enable ability for users to force a compiler using the pre-0.8.3 method + 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() + + 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) + 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) + 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) + 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 ) + ELSE() + MESSAGE(FATAL_ERROR + "Unsupported compiler specified: '${CMAKE_CXX_COMPILER_ID}'") + ENDIF() +ENDMACRO() + +## Tasking system configuration macro ## + +MACRO(OSPRAY_CONFIGURE_TASKING_SYSTEM) + # ------------------------------------------------------- + # Setup tasking system build configuration + # ------------------------------------------------------- + + # NOTE(jda) - Notice that this implies that OSPRAY_CONFIGURE_COMPILER() has + # been called before this macro! + IF(OSPRAY_COMPILER_ICC) + SET(CILK_STRING "Cilk") + ENDIF() + + # NOTE(jda) - Always default to TBB, at least until Cilk is *exactly* the same + # as TBB... + #IF(${CMAKE_CXX_COMPILER_ID} STREQUAL "Intel") + # SET(TASKING_DEFAULT ${CILK_STRING}) + #ELSE() + SET(TASKING_DEFAULT TBB) + #ENDIF() + + SET(OSPRAY_TASKING_SYSTEM ${TASKING_DEFAULT} CACHE STRING + "Per-node thread tasking system [TBB,OpenMP,Cilk,Internal,Debug]") + + SET_PROPERTY(CACHE OSPRAY_TASKING_SYSTEM PROPERTY + STRINGS TBB ${CILK_STRING} OpenMP Internal Debug) + MARK_AS_ADVANCED(OSPRAY_TASKING_SYSTEM) + + # NOTE(jda) - Make the OSPRAY_TASKING_SYSTEM build option case-insensitive + STRING(TOUPPER ${OSPRAY_TASKING_SYSTEM} OSPRAY_TASKING_SYSTEM_ID) + + SET(OSPRAY_TASKING_TBB FALSE) + SET(OSPRAY_TASKING_CILK FALSE) + SET(OSPRAY_TASKING_OPENMP FALSE) + SET(OSPRAY_TASKING_INTERNAL FALSE) + SET(OSPRAY_TASKING_DEBUG FALSE) + + IF(${OSPRAY_TASKING_SYSTEM_ID} STREQUAL "TBB") + SET(OSPRAY_TASKING_TBB TRUE) + ELSEIF(${OSPRAY_TASKING_SYSTEM_ID} STREQUAL "CILK") + SET(OSPRAY_TASKING_CILK TRUE) + ELSEIF(${OSPRAY_TASKING_SYSTEM_ID} STREQUAL "OPENMP") + SET(OSPRAY_TASKING_OPENMP TRUE) + ELSEIF(${OSPRAY_TASKING_SYSTEM_ID} STREQUAL "INTERNAL") + SET(OSPRAY_TASKING_INTERNAL TRUE) + ELSE() + SET(OSPRAY_TASKING_DEBUG TRUE) + ENDIF() + + UNSET(TASKING_SYSTEM_LIBS) + UNSET(TASKING_SYSTEM_LIBS_MIC) + + IF(OSPRAY_TASKING_TBB) + FIND_PACKAGE(TBB REQUIRED) + ADD_DEFINITIONS(-DOSPRAY_TASKING_TBB) + INCLUDE_DIRECTORIES(${TBB_INCLUDE_DIRS}) + SET(TASKING_SYSTEM_LIBS ${TBB_LIBRARIES}) + SET(TASKING_SYSTEM_LIBS_MIC ${TBB_LIBRARIES_MIC}) + ELSE(OSPRAY_TASKING_TBB) + UNSET(TBB_INCLUDE_DIR CACHE) + UNSET(TBB_LIBRARY CACHE) + UNSET(TBB_LIBRARY_DEBUG CACHE) + UNSET(TBB_LIBRARY_MALLOC CACHE) + UNSET(TBB_LIBRARY_MALLOC_DEBUG CACHE) + UNSET(TBB_INCLUDE_DIR_MIC CACHE) + UNSET(TBB_LIBRARY_MIC CACHE) + UNSET(TBB_LIBRARY_MALLOC_MIC CACHE) + IF(OSPRAY_TASKING_OPENMP) + FIND_PACKAGE(OpenMP) + IF (OPENMP_FOUND) + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") + SET(CMAKE_EXE_LINKER_FLAGS + "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}") + ADD_DEFINITIONS(-DOSPRAY_TASKING_OMP) + ENDIF() + ELSEIF(OSPRAY_TASKING_CILK) + ADD_DEFINITIONS(-DOSPRAY_TASKING_CILK) + ELSEIF(OSPRAY_TASKING_INTERNAL) + ADD_DEFINITIONS(-DOSPRAY_TASKING_INTERNAL) + ELSE()#Debug + # Do nothing, will fall back to scalar code (useful for debugging) + ENDIF() + ENDIF(OSPRAY_TASKING_TBB) +ENDMACRO() diff --git a/cmake/ospray_cmake_config/osprayConfig.cmake.in b/cmake/ospray_cmake_config/osprayConfig.cmake.in index dc3c5a3679..75e96c1652 100644 --- a/cmake/ospray_cmake_config/osprayConfig.cmake.in +++ b/cmake/ospray_cmake_config/osprayConfig.cmake.in @@ -18,9 +18,9 @@ # unsets all public (designed to be used externally) variables and reports # error message at priority depending upon [REQUIRED/QUIET/] argument. macro(OSPRAY_REPORT_NOT_FOUND REASON_MSG) - UNSET(OSPRAY_FOUND) - UNSET(OSPRAY_INCLUDE_DIRS) - UNSET(OSPRAY_LIBRARIES) + unset(OSPRAY_FOUND) + unset(OSPRAY_INCLUDE_DIRS) + unset(OSPRAY_LIBRARIES) # Reset the CMake module path to its state when this script was called. set(CMAKE_MODULE_PATH ${CALLERS_CMAKE_MODULE_PATH}) @@ -66,7 +66,7 @@ if(WIN32) ) else(WIN32) get_filename_component(CURRENT_ROOT_INSTALL_DIR - ${CURRENT_CONFIG_INSTALL_DIR}/../../ ABSOLUTE + ${CURRENT_CONFIG_INSTALL_DIR}/../../../ ABSOLUTE ) endif(WIN32) @@ -96,11 +96,21 @@ endif(NOT EXISTS ${OSPRAY_INCLUDE_DIR}/ospray/version.h) set(OSPRAY_INCLUDE_DIRS ${OSPRAY_INCLUDE_DIR} ${OSPRAY_INCLUDE_DIR}/ospray - ${OSPRAY_INCLUDE_DIR}/ospray/embree-v2.7.1 - ${OSPRAY_INCLUDE_DIR}/ospray/embree-v2.7.1/common ) +############################################################################### +# 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_USE_EXTERNAL_EMBREE @OSPRAY_USE_EXTERNAL_EMBREE@) + + ############################################################################### # ospray dependencies @@ -113,7 +123,7 @@ set(OSPRAY_CURRENT_ROOT_INSTALL_DIR ${CURRENT_ROOT_INSTALL_DIR}) # any ospray dependencies. A list of libs should be constructed # and added to the OSPRAY_LIBRARIES variable below. -if (@USE_TBB@) +if (OSPRAY_TASKING_TBB) # Find tbb find_package(TBB) if(":${TBB_LIBRARY}" STREQUAL ":") @@ -123,10 +133,25 @@ if (@USE_TBB@) message(STATUS "Found required OSPRay dependency: TBB in ${TBB_INCLUDE_DIRS}") endif() - add_definitions(-DOSPRAY_USE_TBB) + add_definitions(-DOSPRAY_TASKING_TBB) list(APPEND OSPRAY_DEPENDENCIES ${TBB_LIBRARIES}) endif() +if (OSPRAY_TASKING_CILK) + add_definitions(-DOSPRAY_TASKING_CILK) +endif() + +if(OSPRAY_USE_EXTERNAL_EMBREE) + # Find existing Embree on the machine + find_package(embree @REQUIRED_MINIMUM_EMBREE@ REQUIRED) +else() + if (APPLE) + set(EMBREE_LIBRARY ${CURRENT_ROOT_INSTALL_DIR}/@CMAKE_INSTALL_LIBDIR@/${CMAKE_SHARED_LIBRARY_PREFIX}embree.2${CMAKE_SHARED_LIBRARY_SUFFIX}) + else() + set(EMBREE_LIBRARY ${CURRENT_ROOT_INSTALL_DIR}/@CMAKE_INSTALL_LIBDIR@/${CMAKE_SHARED_LIBRARY_PREFIX}embree${CMAKE_SHARED_LIBRARY_SUFFIX}.2) + endif() +endif() + # Restore state set(CMAKE_CURRENT_LIST_DIR ${OSPRAY_CMAKE_CURRENT_LIST_DIR}) set(CURRENT_CONFIG_INSTALL_DIR ${OSPRAY_CURRENT_CONFIG_INSTALL_DIR}) @@ -170,8 +195,9 @@ set(OSPRAY_LIBRARIES ${OSPRAY_DEPENDENCIES} #ospray# NOTE(jda) - target disabled (see above) #ospray_embree# NOTE(jda) - target disabled (see above) - ${CMAKE_CURRENT_LIST_DIR}/../../lib/${CMAKE_SHARED_LIBRARY_PREFIX}embree${CMAKE_SHARED_LIBRARY_SUFFIX} - ${CMAKE_CURRENT_LIST_DIR}/../../lib/${CMAKE_SHARED_LIBRARY_PREFIX}ospray${CMAKE_SHARED_LIBRARY_SUFFIX} + ${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} ) # Reset CMake module path to its state when this script was called. diff --git a/cmake/package.cmake b/cmake/package.cmake index 9133727a4c..09d8d66385 100644 --- a/cmake/package.cmake +++ b/cmake/package.cmake @@ -16,18 +16,12 @@ INCLUDE(GNUInstallDirs) -IF (NOT OSPRAY_ZIP_MODE AND NOT WIN32 AND NOT APPLE) - SET(CMAKE_INSTALL_BINDIR ${CMAKE_INSTALL_BINDIR}/ospray) - SET(CMAKE_INSTALL_FULL_BINDIR ${CMAKE_INSTALL_FULL_BINDIR}/ospray) -ENDIF() - -SET(CMAKE_INSTALL_NAME_DIR ${CMAKE_INSTALL_FULL_LIBDIR}) - IF (OSPRAY_ZIP_MODE) # in tgz / zip let's have relative RPath SET(CMAKE_SKIP_INSTALL_RPATH OFF) IF (APPLE) - SET(CMAKE_INSTALL_RPATH "@executable_path:@executable_path/../lib") + SET(CMAKE_MACOSX_RPATH ON) + SET(CMAKE_INSTALL_RPATH "@executable_path/" "@executable_path/../lib") ELSE() SET(CMAKE_INSTALL_RPATH "\$ORIGIN:\$ORIGIN/../lib") # on per target basis: @@ -35,8 +29,14 @@ IF (OSPRAY_ZIP_MODE) #SET_TARGET_PROPERTIES(libs INSTALL_RPATH "$ORIGIN") ENDIF() ELSE() - # we do not want any RPath for installed binaries - SET(CMAKE_SKIP_INSTALL_RPATH ON) + SET(CMAKE_INSTALL_NAME_DIR ${CMAKE_INSTALL_FULL_LIBDIR}) + IF (APPLE) + # use RPath on OSX + SET(CMAKE_SKIP_INSTALL_RPATH OFF) + ELSE() + # we do not want any RPath for installed binaries + SET(CMAKE_SKIP_INSTALL_RPATH ON) + ENDIF() ENDIF() ############################################################## @@ -48,8 +48,6 @@ INSTALL(DIRECTORY ${PROJECT_SOURCE_DIR}/ospray/include/ospray COMPONENT devel FILES_MATCHING PATTERN "*.h" ) -# OSPDataType.h is included by ospray.h, should eventually move to include/ospray as well -INSTALL(FILES ${PROJECT_SOURCE_DIR}/ospray/common/OSPDataType.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/ospray COMPONENT devel) ############################################################## # install documentation @@ -60,10 +58,10 @@ INSTALL(FILES ${PROJECT_SOURCE_DIR}/CHANGELOG.md DESTINATION ${CMAKE_INSTALL_DOC INSTALL(FILES ${PROJECT_SOURCE_DIR}/README.md DESTINATION ${CMAKE_INSTALL_DOCDIR} COMPONENT lib) #INSTALL(FILES ${PROJECT_SOURCE_DIR}/readme.pdf DESTINATION ${CMAKE_INSTALL_DOCDIR} COMPONENT lib) -SET(CPACK_NSIS_MENU_LINKS ${CPACK_NSIS_MENU_LINKS} "${CMAKE_INSTALL_DOCDIR}/LICENSE.txt" "LICENSE") -SET(CPACK_NSIS_MENU_LINKS ${CPACK_NSIS_MENU_LINKS} "${CMAKE_INSTALL_DOCDIR}/CHANGELOG.txt" "CHANGELOG") -SET(CPACK_NSIS_MENU_LINKS ${CPACK_NSIS_MENU_LINKS} "${CMAKE_INSTALL_DOCDIR}/README.md" "README.md") -#SET(CPACK_NSIS_MENU_LINKS ${CPACK_NSIS_MENU_LINKS} "${CMAKE_INSTALL_DOCDIR}/readme.pdf" "readme.pdf") +LIST(APPEND CPACK_NSIS_MENU_LINKS "${CMAKE_INSTALL_DOCDIR}/LICENSE.txt" "LICENSE") +LIST(APPEND CPACK_NSIS_MENU_LINKS "${CMAKE_INSTALL_DOCDIR}/CHANGELOG.md" "CHANGELOG") +LIST(APPEND CPACK_NSIS_MENU_LINKS "${CMAKE_INSTALL_DOCDIR}/README.md" "README.md") +#LIST(APPEND CPACK_NSIS_MENU_LINKS "${CMAKE_INSTALL_DOCDIR}/readme.pdf" "readme.pdf") ############################################################## # CPack specific stuff @@ -140,8 +138,8 @@ IF(WIN32) # MacOSX specific settings ELSEIF(APPLE) - FILE(COPY ${PROJECT_SOURCE_DIR}/README.md DESTINATION ${PROJECT_BINARY_DIR}/README.txt) - SET(CPACK_RESOURCE_FILE_README ${PROJECT_BINARY_DIR}/README.txt) + CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/README.md ${PROJECT_BINARY_DIR}/ReadMe.txt COPYONLY) + SET(CPACK_RESOURCE_FILE_README ${PROJECT_BINARY_DIR}/ReadMe.txt) IF (OSPRAY_ZIP_MODE) SET(CPACK_GENERATOR TGZ) @@ -164,6 +162,21 @@ ELSE() SET(CPACK_GENERATOR TGZ) SET(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}.x86_64.linux") ELSE() + OSPRAY_CONFIGURE_TASKING_SYSTEM()# NOTE(jda) - OSPRAY_TASKING_SYSTEM wasn't visible + IF(${OSPRAY_TASKING_SYSTEM} STREQUAL "TBB") + SET(TBB_REQ "tbb >= 3.0") + ENDIF() + IF(CMAKE_VERSION VERSION_LESS "3.4.0") + OSPRAY_WARN_ONCE(RPM_PACKAGING "You need at least v3.4.0 of CMake for generating RPMs") + SET(CPACK_RPM_PACKAGE_REQUIRES ${TBB_REQ}) + ELSE() + # needs to use COMPONENT names in original capitalization (i.e. lowercase) + SET(CPACK_RPM_lib_PACKAGE_REQUIRES ${TBB_REQ}) + SET(CPACK_RPM_lib_mic_PACKAGE_REQUIRES "ospray-lib = ${OSPRAY_VERSION}") + SET(CPACK_RPM_apps_PACKAGE_REQUIRES "ospray-lib >= ${OSPRAY_VERSION}, qt = 4") + SET(CPACK_RPM_devel_PACKAGE_REQUIRES "ospray-lib = ${OSPRAY_VERSION}") + #SET(CPACK_RPM_PACKAGE_DEBUG ON) + ENDIF() SET(CPACK_GENERATOR RPM) SET(CPACK_RPM_PACKAGE_RELEASE 1) # scripts/release_linux.sh assumes "1" SET(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}-${CPACK_RPM_PACKAGE_RELEASE}.x86_64") diff --git a/common/AffineSpace.h b/common/AffineSpace.h new file mode 100644 index 0000000000..47cecd8184 --- /dev/null +++ b/common/AffineSpace.h @@ -0,0 +1,160 @@ +// ======================================================================== // +// 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 "LinearSpace.h" +#include "box.h" + +namespace ospcommon { + +#define VectorT typename L::Vector +#define ScalarT typename L::Vector::Scalar + + //////////////////////////////////////////////////////////////////////////////// + // Affine Space + //////////////////////////////////////////////////////////////////////////////// + + template + struct AffineSpaceT + { + L l; /*< linear part of affine space */ + VectorT p; /*< affine part of affine space */ + + //////////////////////////////////////////////////////////////////////////////// + // Constructors, Assignment, Cast, Copy Operations + //////////////////////////////////////////////////////////////////////////////// + + inline AffineSpaceT ( ) { } + inline AffineSpaceT ( const AffineSpaceT& other ) { l = other.l; p = other.p; } + inline AffineSpaceT ( const L & other ) { l = other ; p = VectorT(zero); } + inline AffineSpaceT& operator=( const AffineSpaceT& other ) { l = other.l; p = other.p; return *this; } + + inline AffineSpaceT( const VectorT& vx, const VectorT& vy, const VectorT& vz, const VectorT& p ) : l(vx,vy,vz), p(p) {} + inline AffineSpaceT( const L& l, const VectorT& p ) : l(l), p(p) {} + + template inline AffineSpaceT( const AffineSpaceT& s ) : l(s.l), p(s.p) {} + + //////////////////////////////////////////////////////////////////////////////// + // Constants + //////////////////////////////////////////////////////////////////////////////// + + inline AffineSpaceT( ZeroTy ) : l(zero), p(zero) {} + inline AffineSpaceT( OneTy ) : l(one), p(zero) {} + + /*! return matrix for scaling */ + static inline AffineSpaceT scale(const VectorT& s) { return L::scale(s); } + + /*! return matrix for translation */ + static inline AffineSpaceT translate(const VectorT& p) { return AffineSpaceT(one,p); } + + /*! return matrix for rotation, only in 2D */ + static inline AffineSpaceT rotate(const ScalarT& r) { return L::rotate(r); } + + /*! return matrix for rotation around arbitrary point (2D) or axis (3D) */ + static inline AffineSpaceT rotate(const VectorT& u, const ScalarT& r) { return L::rotate(u,r); } + + /*! return matrix for rotation around arbitrary axis and point, only in 3D */ + static inline AffineSpaceT rotate(const VectorT& p, const VectorT& u, const ScalarT& r) { return translate(+p) * rotate(u,r) * translate(-p); } + + /*! return matrix for looking at given point, only in 3D */ + static inline AffineSpaceT lookat(const VectorT& eye, const VectorT& point, const VectorT& up) { + VectorT Z = normalize(point-eye); + VectorT U = normalize(cross(up,Z)); + VectorT V = normalize(cross(Z,U)); + return AffineSpaceT(L(U,V,Z),eye); + } + + }; + + //////////////////////////////////////////////////////////////////////////////// + // Unary Operators + //////////////////////////////////////////////////////////////////////////////// + + template inline AffineSpaceT operator -( const AffineSpaceT& a ) { return AffineSpaceT(-a.l,-a.p); } + template inline AffineSpaceT operator +( const AffineSpaceT& a ) { return AffineSpaceT(+a.l,+a.p); } + template inline AffineSpaceT rcp( const AffineSpaceT& a ) { L il = rcp(a.l); return AffineSpaceT(il,-(il*a.p)); } + + //////////////////////////////////////////////////////////////////////////////// + // Binary Operators + //////////////////////////////////////////////////////////////////////////////// + + template inline const AffineSpaceT operator +( const AffineSpaceT& a, const AffineSpaceT& b ) { return AffineSpaceT(a.l+b.l,a.p+b.p); } + template inline const AffineSpaceT operator -( const AffineSpaceT& a, const AffineSpaceT& b ) { return AffineSpaceT(a.l-b.l,a.p-b.p); } + + template inline const AffineSpaceT operator *( const ScalarT & a, const AffineSpaceT& b ) { return AffineSpaceT(a*b.l,a*b.p); } + template inline const AffineSpaceT operator *( const AffineSpaceT& a, const AffineSpaceT& b ) { return AffineSpaceT(a.l*b.l,a.l*b.p+a.p); } + template inline const AffineSpaceT operator /( const AffineSpaceT& a, const AffineSpaceT& b ) { return a * rcp(b); } + template inline const AffineSpaceT operator /( const AffineSpaceT& a, const ScalarT & b ) { return a * rcp(b); } + + template inline AffineSpaceT& operator *=( AffineSpaceT& a, const AffineSpaceT& b ) { return a = a * b; } + template inline AffineSpaceT& operator *=( AffineSpaceT& a, const ScalarT & b ) { return a = a * b; } + template inline AffineSpaceT& operator /=( AffineSpaceT& a, const AffineSpaceT& b ) { return a = a / b; } + template inline AffineSpaceT& operator /=( AffineSpaceT& a, const ScalarT & b ) { return a = a / b; } + + template inline const VectorT xfmPoint (const AffineSpaceT& m, const VectorT& p) { return madd(VectorT(p.x),m.l.vx,madd(VectorT(p.y),m.l.vy,madd(VectorT(p.z),m.l.vz,m.p))); } + template inline const VectorT xfmVector(const AffineSpaceT& m, const VectorT& v) { return xfmVector(m.l,v); } + template inline const VectorT xfmNormal(const AffineSpaceT& m, const VectorT& n) { return xfmNormal(m.l,n); } + + inline const box3fa xfmBounds(const AffineSpaceT >& m, const box3fa& b) + { + box3fa dst = empty; + const vec3fa p0(b.lower.x,b.lower.y,b.lower.z); dst.extend(xfmPoint(m,p0)); + const vec3fa p1(b.lower.x,b.lower.y,b.upper.z); dst.extend(xfmPoint(m,p1)); + const vec3fa p2(b.lower.x,b.upper.y,b.lower.z); dst.extend(xfmPoint(m,p2)); + const vec3fa p3(b.lower.x,b.upper.y,b.upper.z); dst.extend(xfmPoint(m,p3)); + const vec3fa p4(b.upper.x,b.lower.y,b.lower.z); dst.extend(xfmPoint(m,p4)); + const vec3fa p5(b.upper.x,b.lower.y,b.upper.z); dst.extend(xfmPoint(m,p5)); + const vec3fa p6(b.upper.x,b.upper.y,b.lower.z); dst.extend(xfmPoint(m,p6)); + const vec3fa p7(b.upper.x,b.upper.y,b.upper.z); dst.extend(xfmPoint(m,p7)); + return dst; + } + + //////////////////////////////////////////////////////////////////////////////// + /// Comparison Operators + //////////////////////////////////////////////////////////////////////////////// + + template inline bool operator ==( const AffineSpaceT& a, const AffineSpaceT& b ) { return a.l == b.l && a.p == b.p; } + template inline bool operator !=( const AffineSpaceT& a, const AffineSpaceT& b ) { return a.l != b.l || a.p != b.p; } + + //////////////////////////////////////////////////////////////////////////////// + // Output Operators + //////////////////////////////////////////////////////////////////////////////// + + template static std::ostream& operator<<(std::ostream& cout, const AffineSpaceT& m) { + return cout << "{ l = " << m.l << ", p = " << m.p << " }"; + } + + //////////////////////////////////////////////////////////////////////////////// + // Template Instantiations + //////////////////////////////////////////////////////////////////////////////// + + typedef AffineSpaceT AffineSpace2f; + typedef AffineSpaceT AffineSpace3f; + typedef AffineSpaceT AffineSpace3fa; + typedef AffineSpaceT OrthonormalSpace3f; + + typedef AffineSpace2f affine2f; + typedef AffineSpace3f affine3f; + + //////////////////////////////////////////////////////////////////////////////// + /*! Template Specialization for 2D: return matrix for rotation around point (rotation around arbitrarty vector is not meaningful in 2D) */ + template<> inline AffineSpace2f AffineSpace2f::rotate(const vec2f& p, const float& r) { return translate(+p) * AffineSpace2f(LinearSpace2f::rotate(r)) * translate(-p); } + +#undef VectorT +#undef ScalarT + +} // ::ospcommon diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt new file mode 100644 index 0000000000..40db5afebe --- /dev/null +++ b/common/CMakeLists.txt @@ -0,0 +1,52 @@ +## ======================================================================== ## +## 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. ## +## ======================================================================== ## + +CONFIGURE_OSPRAY() + +SET(CMAKE_THREAD_PREFER_PTHREAD TRUE) +FIND_PACKAGE(Threads REQUIRED) + +OSPRAY_ADD_LIBRARY(ospray_common SHARED + common.cpp + FileName.cpp + sysinfo.cpp + malloc.cpp + library.cpp + thread.cpp + vec.cpp + + AffineSpace.h + box.h + constants.h + intrinsics.h + LinearSpace.h + math.h + platform.h + Quaternion.h + RefCount.h + vec.h +) + +OSPRAY_LIBRARY_LINK_LIBRARIES(ospray_common + ${CMAKE_THREAD_LIBS_INIT} + ${CMAKE_DL_LIBS} +) +IF (WIN32) + OSPRAY_LIBRARY_LINK_LIBRARIES(ospray_common ws2_32) +ENDIF() + +OSPRAY_SET_LIBRARY_VERSION(ospray_common) +OSPRAY_INSTALL_LIBRARY(ospray_common) diff --git a/common/FileName.cpp b/common/FileName.cpp new file mode 100644 index 0000000000..16f6d5003f --- /dev/null +++ b/common/FileName.cpp @@ -0,0 +1,151 @@ +// ======================================================================== // +// 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. // +// ======================================================================== // + +#include "FileName.h" +#include "sysinfo.h" + +namespace ospcommon +{ +#ifdef _WIN32 + const char path_sep = '\\'; +#else + const char path_sep = '/'; +#endif + + /*! create an empty filename */ + FileName::FileName () {} + + /*! create a valid filename from a string */ + FileName::FileName (const char* in) { + filename = in; + for (size_t i=0; i struct LinearSpace2 + { + typedef T Vector; + typedef typename T::scalar_t Scalar; + + /*! default matrix constructor */ + inline LinearSpace2 ( ) {} + inline LinearSpace2 ( const LinearSpace2& other ) { vx = other.vx; vy = other.vy; } + inline LinearSpace2& operator=( const LinearSpace2& other ) { vx = other.vx; vy = other.vy; return *this; } + + template inline LinearSpace2( const LinearSpace2& s ) : vx(s.vx), vy(s.vy) {} + + /*! matrix construction from column vectors */ + inline LinearSpace2(const Vector& vx, const Vector& vy) + : vx(vx), vy(vy) {} + + /*! matrix construction from row mayor data */ + inline LinearSpace2(const Scalar& m00, const Scalar& m01, + const Scalar& m10, const Scalar& m11) + : vx(m00,m10), vy(m01,m11) {} + + /*! compute the determinant of the matrix */ + inline const Scalar det() const { return vx.x*vy.y - vx.y*vy.x; } + + /*! compute adjoint matrix */ + inline const LinearSpace2 adjoint() const { return LinearSpace2(vy.y,-vy.x,-vx.y,vx.x); } + + /*! compute inverse matrix */ + inline const LinearSpace2 inverse() const { return adjoint()/det(); } + + /*! compute transposed matrix */ + inline const LinearSpace2 transposed() const { return LinearSpace2(vx.x,vx.y,vy.x,vy.y); } + + /*! returns first row of matrix */ + inline const Vector row0() const { return Vector(vx.x,vy.x); } + + /*! returns second row of matrix */ + inline const Vector row1() const { return Vector(vx.y,vy.y); } + + //////////////////////////////////////////////////////////////////////////////// + /// Constants + //////////////////////////////////////////////////////////////////////////////// + + inline LinearSpace2( ZeroTy ) : vx(zero), vy(zero) {} + inline LinearSpace2( OneTy ) : vx(one, zero), vy(zero, one) {} + + /*! return matrix for scaling */ + static inline LinearSpace2 scale(const Vector& s) { + return LinearSpace2(s.x, 0, + 0 , s.y); + } + + /*! return matrix for rotation */ + static inline LinearSpace2 rotate(const Scalar& r) { + Scalar s = sin(r), c = cos(r); + return LinearSpace2(c, -s, + s, c); + } + + /*! return closest orthogonal matrix (i.e. a general rotation including reflection) */ + LinearSpace2 orthogonal() const { + LinearSpace2 m = *this; + + // mirrored? + Scalar mirror(one); + if (m.det() < Scalar(zero)) { + m.vx = -m.vx; + mirror = -mirror; + } + + // rotation + for (int i = 0; i < 99; i++) { + const LinearSpace2 m_next = 0.5 * (m + m.transposed().inverse()); + const LinearSpace2 d = m_next - m; + m = m_next; + // norm^2 of difference small enough? + if (max(dot(d.vx, d.vx), dot(d.vy, d.vy)) < 1e-8) + break; + } + + // rotation * mirror_x + return LinearSpace2(mirror*m.vx, m.vy); + } + + public: + + /*! the column vectors of the matrix */ + Vector vx,vy; + }; + + //////////////////////////////////////////////////////////////////////////////// + // Unary Operators + //////////////////////////////////////////////////////////////////////////////// + + template inline LinearSpace2 operator -( const LinearSpace2& a ) { return LinearSpace2(-a.vx,-a.vy); } + template inline LinearSpace2 operator +( const LinearSpace2& a ) { return LinearSpace2(+a.vx,+a.vy); } + template inline LinearSpace2 rcp ( const LinearSpace2& a ) { return a.inverse(); } + + //////////////////////////////////////////////////////////////////////////////// + // Binary Operators + //////////////////////////////////////////////////////////////////////////////// + + template inline LinearSpace2 operator +( const LinearSpace2& a, const LinearSpace2& b ) { return LinearSpace2(a.vx+b.vx,a.vy+b.vy); } + template inline LinearSpace2 operator -( const LinearSpace2& a, const LinearSpace2& b ) { return LinearSpace2(a.vx-b.vx,a.vy-b.vy); } + + template inline LinearSpace2 operator*(const typename T::Scalar & a, const LinearSpace2& b) { return LinearSpace2(a*b.vx, a*b.vy); } + template inline T operator*(const LinearSpace2& a, const T & b) { return b.x*a.vx + b.y*a.vy; } + template inline LinearSpace2 operator*(const LinearSpace2& a, const LinearSpace2& b) { return LinearSpace2(a*b.vx, a*b.vy); } + + template inline LinearSpace2 operator/(const LinearSpace2& a, const typename T::Scalar & b) { return LinearSpace2(a.vx/b, a.vy/b); } + template inline LinearSpace2 operator/(const LinearSpace2& a, const LinearSpace2& b) { return a * rcp(b); } + + template inline LinearSpace2& operator *=( LinearSpace2& a, const LinearSpace2& b ) { return a = a * b; } + template inline LinearSpace2& operator /=( LinearSpace2& a, const LinearSpace2& b ) { return a = a / b; } + + //////////////////////////////////////////////////////////////////////////////// + /// Comparison Operators + //////////////////////////////////////////////////////////////////////////////// + + template inline bool operator ==( const LinearSpace2& a, const LinearSpace2& b ) { return a.vx == b.vx && a.vy == b.vy; } + template inline bool operator !=( const LinearSpace2& a, const LinearSpace2& b ) { return a.vx != b.vx || a.vy != b.vy; } + + //////////////////////////////////////////////////////////////////////////////// + /// Output Operators + //////////////////////////////////////////////////////////////////////////////// + + template static std::ostream& operator<<(std::ostream& cout, const LinearSpace2& m) { + return cout << "{ vx = " << m.vx << ", vy = " << m.vy << "}"; + } + + //////////////////////////////////////////////////////////////////////////////// + /// 3D Linear Transform (3x3 Matrix) + //////////////////////////////////////////////////////////////////////////////// + + template struct LinearSpace3 + { + typedef T Vector; + typedef typename T::scalar_t Scalar; + + /*! default matrix constructor */ + inline LinearSpace3 ( ) {} + inline LinearSpace3 ( const LinearSpace3& other ) { vx = other.vx; vy = other.vy; vz = other.vz; } + inline LinearSpace3& operator=( const LinearSpace3& other ) { vx = other.vx; vy = other.vy; vz = other.vz; return *this; } + + template inline LinearSpace3( const LinearSpace3& s ) : vx(s.vx), vy(s.vy), vz(s.vz) {} + + /*! matrix construction from column vectors */ + inline LinearSpace3(const Vector& vx, const Vector& vy, const Vector& vz) + : vx(vx), vy(vy), vz(vz) {} + + /*! construction from quaternion */ + inline LinearSpace3( const QuaternionT& q ) + : vx((q.r*q.r + q.i*q.i - q.j*q.j - q.k*q.k), 2.0f*(q.i*q.j + q.r*q.k), 2.0f*(q.i*q.k - q.r*q.j)) + , vy(2.0f*(q.i*q.j - q.r*q.k), (q.r*q.r - q.i*q.i + q.j*q.j - q.k*q.k), 2.0f*(q.j*q.k + q.r*q.i)) + , vz(2.0f*(q.i*q.k + q.r*q.j), 2.0f*(q.j*q.k - q.r*q.i), (q.r*q.r - q.i*q.i - q.j*q.j + q.k*q.k)) {} + + /*! matrix construction from row mayor data */ + inline LinearSpace3(const Scalar& m00, const Scalar& m01, const Scalar& m02, + const Scalar& m10, const Scalar& m11, const Scalar& m12, + const Scalar& m20, const Scalar& m21, const Scalar& m22) + : vx(m00,m10,m20), vy(m01,m11,m21), vz(m02,m12,m22) {} + + /*! compute the determinant of the matrix */ + inline const Scalar det() const { return dot(vx,cross(vy,vz)); } + + /*! compute adjoint matrix */ + inline const LinearSpace3 adjoint() const { return LinearSpace3(cross(vy,vz),cross(vz,vx),cross(vx,vy)).transposed(); } + + /*! compute inverse matrix */ + inline const LinearSpace3 inverse() const { return adjoint()/det(); } + + /*! compute transposed matrix */ + inline const LinearSpace3 transposed() const { return LinearSpace3(vx.x,vx.y,vx.z,vy.x,vy.y,vy.z,vz.x,vz.y,vz.z); } + + /*! returns first row of matrix */ + inline const Vector row0() const { return Vector(vx.x,vy.x,vz.x); } + + /*! returns second row of matrix */ + inline const Vector row1() const { return Vector(vx.y,vy.y,vz.y); } + + /*! returns third row of matrix */ + inline const Vector row2() const { return Vector(vx.z,vy.z,vz.z); } + + //////////////////////////////////////////////////////////////////////////////// + /// Constants + //////////////////////////////////////////////////////////////////////////////// + + inline LinearSpace3( ZeroTy ) : vx(zero), vy(zero), vz(zero) {} + inline LinearSpace3( OneTy ) : vx(one, zero, zero), vy(zero, one, zero), vz(zero, zero, one) {} + + /*! return matrix for scaling */ + static inline LinearSpace3 scale(const Vector& s) { + return LinearSpace3(s.x, 0, 0, + 0 , s.y, 0, + 0 , 0, s.z); + } + + /*! return matrix for rotation around arbitrary axis */ + static inline LinearSpace3 rotate(const Vector& _u, const Scalar& r) { + Vector u = normalize(_u); + Scalar s = sin(r), c = cos(r); + return LinearSpace3(u.x*u.x+(1-u.x*u.x)*c, u.x*u.y*(1-c)-u.z*s, u.x*u.z*(1-c)+u.y*s, + u.x*u.y*(1-c)+u.z*s, u.y*u.y+(1-u.y*u.y)*c, u.y*u.z*(1-c)-u.x*s, + u.x*u.z*(1-c)-u.y*s, u.y*u.z*(1-c)+u.x*s, u.z*u.z+(1-u.z*u.z)*c); + } + + public: + + /*! the column vectors of the matrix */ + Vector vx,vy,vz; + }; + + //////////////////////////////////////////////////////////////////////////////// + // Unary Operators + //////////////////////////////////////////////////////////////////////////////// + + template inline LinearSpace3 operator -( const LinearSpace3& a ) { return LinearSpace3(-a.vx,-a.vy,-a.vz); } + template inline LinearSpace3 operator +( const LinearSpace3& a ) { return LinearSpace3(+a.vx,+a.vy,+a.vz); } + template inline LinearSpace3 rcp ( const LinearSpace3& a ) { return a.inverse(); } + + /* constructs a coordinate frame form a normalized normal */ + template inline LinearSpace3 frame(const T& N) + { + const T dx0 = cross(T(one,zero,zero),N); + const T dx1 = cross(T(zero,one,zero),N); + const T dx = normalize(select(dot(dx0,dx0) > dot(dx1,dx1),dx0,dx1)); + const T dy = normalize(cross(N,dx)); + return LinearSpace3(dx,dy,N); + } + + /* constructs a coordinate frame from a normal and approximate x-direction */ + template inline LinearSpace3 frame(const T& N, const T& dxi) + { + if (abs(dot(dxi,N)) > 0.99f) return frame(N); // fallback in case N and dxi are very parallel + const T dx = normalize(cross(dxi,N)); + const T dy = normalize(cross(N,dx)); + return LinearSpace3(dx,dy,N); + } + + /* clamps linear space to range -1 to +1 */ + template inline LinearSpace3 clamp(const LinearSpace3& space) { + return LinearSpace3(clamp(space.vx,T(-1.0f),T(1.0f)), + clamp(space.vy,T(-1.0f),T(1.0f)), + clamp(space.vz,T(-1.0f),T(1.0f))); + } + + //////////////////////////////////////////////////////////////////////////////// + // Binary Operators + //////////////////////////////////////////////////////////////////////////////// + + template inline LinearSpace3 operator +( const LinearSpace3& a, const LinearSpace3& b ) { return LinearSpace3(a.vx+b.vx,a.vy+b.vy,a.vz+b.vz); } + template inline LinearSpace3 operator -( const LinearSpace3& a, const LinearSpace3& b ) { return LinearSpace3(a.vx-b.vx,a.vy-b.vy,a.vz-b.vz); } + + template inline LinearSpace3 operator*(const typename T::Scalar & a, const LinearSpace3& b) { return LinearSpace3(a*b.vx, a*b.vy, a*b.vz); } + template inline T operator*(const LinearSpace3& a, const T & b) { return b.x*a.vx + b.y*a.vy + b.z*a.vz; } + template inline LinearSpace3 operator*(const LinearSpace3& a, const LinearSpace3& b) { return LinearSpace3(a*b.vx, a*b.vy, a*b.vz); } + + template inline LinearSpace3 operator/(const LinearSpace3& a, const typename T::Scalar & b) { return LinearSpace3(a.vx/b, a.vy/b, a.vz/b); } + template inline LinearSpace3 operator/(const LinearSpace3& a, const LinearSpace3& b) { return a * rcp(b); } + + template inline LinearSpace3& operator *=( LinearSpace3& a, const LinearSpace3& b ) { return a = a * b; } + template inline LinearSpace3& operator /=( LinearSpace3& a, const LinearSpace3& b ) { return a = a / b; } + + template inline T xfmPoint (const LinearSpace3& s, const T & a) { return madd(T(a.x),s.vx,madd(T(a.y),s.vy,T(a.z)*s.vz)); } + template inline T xfmVector(const LinearSpace3& s, const T & a) { return madd(T(a.x),s.vx,madd(T(a.y),s.vy,T(a.z)*s.vz)); } + template inline T xfmNormal(const LinearSpace3& s, const T & a) { return xfmVector(s.inverse().transposed(),a); } + + //////////////////////////////////////////////////////////////////////////////// + /// Comparison Operators + //////////////////////////////////////////////////////////////////////////////// + + template inline bool operator ==( const LinearSpace3& a, const LinearSpace3& b ) { return a.vx == b.vx && a.vy == b.vy && a.vz == b.vz; } + template inline bool operator !=( const LinearSpace3& a, const LinearSpace3& b ) { return a.vx != b.vx || a.vy != b.vy || a.vz != b.vz; } + + //////////////////////////////////////////////////////////////////////////////// + /// Output Operators + //////////////////////////////////////////////////////////////////////////////// + + template static std::ostream& operator<<(std::ostream& cout, const LinearSpace3& m) { + return cout << "{ vx = " << m.vx << ", vy = " << m.vy << ", vz = " << m.vz << "}"; + } + + /*! Shortcuts for common linear spaces. */ + typedef LinearSpace2 LinearSpace2f; + typedef LinearSpace3 LinearSpace3f; + typedef LinearSpace3 LinearSpace3fa; + + typedef LinearSpace2f linear2f; + typedef LinearSpace3f linear3f; +} // ::ospcommon diff --git a/common/Quaternion.h b/common/Quaternion.h new file mode 100644 index 0000000000..d1d130f163 --- /dev/null +++ b/common/Quaternion.h @@ -0,0 +1,209 @@ +// ======================================================================== // +// 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 "vec.h" + +namespace ospcommon +{ + //////////////////////////////////////////////////////////////// + // Quaternion Struct + //////////////////////////////////////////////////////////////// + + template + struct QuaternionT + { + typedef vec_t Vector; + + //////////////////////////////////////////////////////////////////////////////// + /// Construction + //////////////////////////////////////////////////////////////////////////////// + + __forceinline QuaternionT ( void ) { } + __forceinline QuaternionT ( const QuaternionT& other ) { r = other.r; i = other.i; j = other.j; k = other.k; } + __forceinline QuaternionT& operator=( const QuaternionT& other ) { r = other.r; i = other.i; j = other.j; k = other.k; return *this; } + + __forceinline QuaternionT( const T& r ) : r(r), i(zero), j(zero), k(zero) {} + __forceinline explicit QuaternionT( const Vector& v ) : r(zero), i(v.x), j(v.y), k(v.z) {} + __forceinline QuaternionT( const T& r, const T& i, const T& j, const T& k ) : r(r), i(i), j(j), k(k) {} + __forceinline QuaternionT( const T& r, const Vector& v ) : r(r), i(v.x), j(v.y), k(v.z) {} + + __inline QuaternionT( const Vector& vx, const Vector& vy, const Vector& vz ); + __inline QuaternionT( const T& yaw, const T& pitch, const T& roll ); + + //////////////////////////////////////////////////////////////////////////////// + /// Constants + //////////////////////////////////////////////////////////////////////////////// + + __forceinline QuaternionT( ZeroTy ) : r(zero), i(zero), j(zero), k(zero) {} + __forceinline QuaternionT( OneTy ) : r( one), i(zero), j(zero), k(zero) {} + + /*! return quaternion for rotation around arbitrary axis */ + static __forceinline QuaternionT rotate(const Vector& u, const T& r) { + return QuaternionT(cos(T(0.5)*r),sin(T(0.5)*r)*normalize(u)); + } + + /*! returns the rotation axis of the quaternion as a vector */ + __forceinline const Vector v( ) const { return Vector(i, j, k); } + + public: + T r, i, j, k; + }; + + template __forceinline QuaternionT operator *( const T & a, const QuaternionT& b ) { return QuaternionT(a * b.r, a * b.i, a * b.j, a * b.k); } + template __forceinline QuaternionT operator *( const QuaternionT& a, const T & b ) { return QuaternionT(a.r * b, a.i * b, a.j * b, a.k * b); } + + //////////////////////////////////////////////////////////////// + // Unary Operators + //////////////////////////////////////////////////////////////// + + template __forceinline QuaternionT operator +( const QuaternionT& a ) { return QuaternionT(+a.r, +a.i, +a.j, +a.k); } + template __forceinline QuaternionT operator -( const QuaternionT& a ) { return QuaternionT(-a.r, -a.i, -a.j, -a.k); } + template __forceinline QuaternionT conj ( const QuaternionT& a ) { return QuaternionT(a.r, -a.i, -a.j, -a.k); } + template __forceinline T abs ( const QuaternionT& a ) { return sqrt(a.r*a.r + a.i*a.i + a.j*a.j + a.k*a.k); } + template __forceinline QuaternionT rcp ( const QuaternionT& a ) { return conj(a)*rcp(a.r*a.r + a.i*a.i + a.j*a.j + a.k*a.k); } + template __forceinline QuaternionT normalize ( const QuaternionT& a ) { return a*rsqrt(a.r*a.r + a.i*a.i + a.j*a.j + a.k*a.k); } + + //////////////////////////////////////////////////////////////// + // Binary Operators + //////////////////////////////////////////////////////////////// + + template __forceinline QuaternionT operator +( const T & a, const QuaternionT& b ) { return QuaternionT(a + b.r, b.i, b.j, b.k); } + template __forceinline QuaternionT operator +( const QuaternionT& a, const T & b ) { return QuaternionT(a.r + b, a.i, a.j, a.k); } + template __forceinline QuaternionT operator +( const QuaternionT& a, const QuaternionT& b ) { return QuaternionT(a.r + b.r, a.i + b.i, a.j + b.j, a.k + b.k); } + template __forceinline QuaternionT operator -( const T & a, const QuaternionT& b ) { return QuaternionT(a - b.r, -b.i, -b.j, -b.k); } + template __forceinline QuaternionT operator -( const QuaternionT& a, const T & b ) { return QuaternionT(a.r - b, a.i, a.j, a.k); } + template __forceinline QuaternionT operator -( const QuaternionT& a, const QuaternionT& b ) { return QuaternionT(a.r - b.r, a.i - b.i, a.j - b.j, a.k - b.k); } + + template __forceinline typename QuaternionT::Vector operator *( const QuaternionT& a, const typename QuaternionT::Vector & b ) { return (a*QuaternionT(b)*conj(a)).v(); } + template __forceinline QuaternionT operator *( const QuaternionT& a, const QuaternionT& b ) { + return QuaternionT(a.r*b.r - a.i*b.i - a.j*b.j - a.k*b.k, + a.r*b.i + a.i*b.r + a.j*b.k - a.k*b.j, + a.r*b.j - a.i*b.k + a.j*b.r + a.k*b.i, + a.r*b.k + a.i*b.j - a.j*b.i + a.k*b.r); + } + template __forceinline QuaternionT operator /( const T & a, const QuaternionT& b ) { return a*rcp(b); } + template __forceinline QuaternionT operator /( const QuaternionT& a, const T & b ) { return a*rcp(b); } + template __forceinline QuaternionT operator /( const QuaternionT& a, const QuaternionT& b ) { return a*rcp(b); } + + template __forceinline QuaternionT& operator +=( QuaternionT& a, const T & b ) { return a = a+b; } + template __forceinline QuaternionT& operator +=( QuaternionT& a, const QuaternionT& b ) { return a = a+b; } + template __forceinline QuaternionT& operator -=( QuaternionT& a, const T & b ) { return a = a-b; } + template __forceinline QuaternionT& operator -=( QuaternionT& a, const QuaternionT& b ) { return a = a-b; } + template __forceinline QuaternionT& operator *=( QuaternionT& a, const T & b ) { return a = a*b; } + template __forceinline QuaternionT& operator *=( QuaternionT& a, const QuaternionT& b ) { return a = a*b; } + template __forceinline QuaternionT& operator /=( QuaternionT& a, const T & b ) { return a = a*rcp(b); } + template __forceinline QuaternionT& operator /=( QuaternionT& a, const QuaternionT& b ) { return a = a*rcp(b); } + + template __forceinline typename QuaternionT::Vector + xfmPoint ( const QuaternionT& a, + const typename QuaternionT::Vector& b ) + { return (a*QuaternionT(b)*conj(a)).v(); } + + template __forceinline typename QuaternionT::Vector + xfmQuaternion( const QuaternionT& a, + const typename QuaternionT::Vector& b ) + { return (a*QuaternionT(b)*conj(a)).v(); } + + + template __forceinline typename QuaternionT::Vector + xfmNormal( const QuaternionT& a, + const typename QuaternionT::Vector& b ) + { return (a*QuaternionT(b)*conj(a)).v(); } + + //////////////////////////////////////////////////////////////////////////////// + /// Comparison Operators + //////////////////////////////////////////////////////////////////////////////// + + template __forceinline bool operator ==( const QuaternionT& a, const QuaternionT& b ) { return a.r == b.r && a.i == b.i && a.j == b.j && a.k == b.k; } + + template __forceinline bool operator !=( const QuaternionT& a, const QuaternionT& b ) { return a.r != b.r || a.i != b.i || a.j != b.j || a.k != b.k; } + + + //////////////////////////////////////////////////////////////////////////////// + /// Orientation Functions + //////////////////////////////////////////////////////////////////////////////// + + template + QuaternionT::QuaternionT(const typename QuaternionT::Vector& vx, + const typename QuaternionT::Vector& vy, + const typename QuaternionT::Vector& vz ) + { + if ( vx.x + vy.y + vz.z >= T(zero) ) + { + const T t = T(one) + (vx.x + vy.y + vz.z); + const T s = rsqrt(t)*T(0.5f); + r = t*s; + i = (vy.z - vz.y)*s; + j = (vz.x - vx.z)*s; + k = (vx.y - vy.x)*s; + } + else if ( vx.x >= max(vy.y, vz.z) ) + { + const T t = (T(one) + vx.x) - (vy.y + vz.z); + const T s = rsqrt(t)*T(0.5f); + r = (vy.z - vz.y)*s; + i = t*s; + j = (vx.y + vy.x)*s; + k = (vz.x + vx.z)*s; + } + else if ( vy.y >= vz.z ) // if ( vy.y >= max(vz.z, vx.x) ) + { + const T t = (T(one) + vy.y) - (vz.z + vx.x); + const T s = rsqrt(t)*T(0.5f); + r = (vz.x - vx.z)*s; + i = (vx.y + vy.x)*s; + j = t*s; + k = (vy.z + vz.y)*s; + } + else //if ( vz.z >= max(vy.y, vx.x) ) + { + const T t = (T(one) + vz.z) - (vx.x + vy.y); + const T s = rsqrt(t)*T(0.5f); + r = (vx.y - vy.x)*s; + i = (vz.x + vx.z)*s; + j = (vy.z + vz.y)*s; + k = t*s; + } + } + + template QuaternionT::QuaternionT( const T& yaw, const T& pitch, const T& roll ) + { + const T cya = cos(yaw *T(0.5f)); + const T cpi = cos(pitch*T(0.5f)); + const T cro = cos(roll *T(0.5f)); + const T sya = sin(yaw *T(0.5f)); + const T spi = sin(pitch*T(0.5f)); + const T sro = sin(roll *T(0.5f)); + r = cro*cya*cpi + sro*sya*spi; + i = cro*cya*spi + sro*sya*cpi; + j = cro*sya*cpi - sro*cya*spi; + k = sro*cya*cpi - cro*sya*spi; + } + + //////////////////////////////////////////////////////////////////////////////// + /// Output Operators + //////////////////////////////////////////////////////////////////////////////// + + template static std::ostream& operator<<(std::ostream& cout, const QuaternionT& q) { + return cout << "{ r = " << q.r << ", i = " << q.i << ", j = " << q.j << ", k = " << q.k << " }"; + } + + /*! default template instantiations */ + typedef QuaternionT Quaternion3f; + typedef QuaternionT Quaternion3d; +} diff --git a/common/RefCount.h b/common/RefCount.h new file mode 100644 index 0000000000..e446879688 --- /dev/null +++ b/common/RefCount.h @@ -0,0 +1,134 @@ +// ======================================================================== // +// 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 "platform.h" +#include // c++11 ... + +/*! iw: TODO: move to c++11-style refcoutned object instead of this + homebrewed one */ +namespace ospcommon +{ +#if defined(__X86_64__) || defined(__MIC__) + typedef long long atomic_init_t; +#else + typedef int atomic_init_t; +#endif + typedef std::atomic atomic_t; + + static struct NullTy { + } null MAYBE_UNUSED; + + class RefCount + { + public: + inline RefCount(atomic_init_t val = 0) : refCounter(val) {} + 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!"); } + /*! 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; } + + 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) {} + __forceinline Ref( const Ref& input ) : ptr(input.ptr) { if ( ptr ) ptr->refInc(); } + + __forceinline Ref( Type* const input ) : ptr(input) { + if ( ptr ) + ptr->refInc(); + } + + __forceinline ~Ref( void ) { + if (ptr) ptr->refDec(); + } + + __forceinline Ref& operator= ( const Ref& input ) + { + if ( input.ptr ) input.ptr->refInc(); + if (ptr) ptr->refDec(); + *(Type**)&ptr = input.ptr; + return *this; + } + + __forceinline Ref& operator= ( Type* const input ) + { + if ( input ) input->refInc(); + if (ptr) ptr->refDec(); + *(Type**)&ptr = input; + return *this; + } + + __forceinline Ref& operator= ( NullTy ) { + if (ptr) ptr->refDec(); + *(Type**)&ptr = nullptr; + return *this; + } + + __forceinline operator bool( void ) const { return ptr != nullptr; } + + __forceinline const Type& operator *( void ) const { return *ptr; } + __forceinline Type& operator *( void ) { return *ptr; } + __forceinline const Type* operator ->( void ) const { return ptr; } + __forceinline Type* operator ->( void ) { return ptr; } + + template + __forceinline Ref cast() { return Ref(static_cast(ptr)); } + template + __forceinline const Ref cast() const { return Ref(static_cast(ptr)); } + + template + __forceinline Ref dynamicCast() { return Ref(dynamic_cast(ptr)); } + template + __forceinline const Ref dynamicCast() const { return Ref(dynamic_cast(ptr)); } + }; + + template __forceinline bool operator < ( const Ref& a, const Ref& b ) { return a.ptr < b.ptr ; } + + template __forceinline bool operator ==( const Ref& a, NullTy ) { return a.ptr == nullptr ; } + template __forceinline bool operator ==( NullTy , const Ref& b ) { return nullptr == b.ptr ; } + template __forceinline bool operator ==( const Ref& a, const Ref& b ) { return a.ptr == b.ptr ; } + + template __forceinline bool operator !=( const Ref& a, NullTy ) { return a.ptr != nullptr ; } + template __forceinline bool operator !=( NullTy , const Ref& b ) { return nullptr != b.ptr ; } + template __forceinline bool operator !=( const Ref& a, const Ref& b ) { return a.ptr != b.ptr ; } +} diff --git a/common/bak.vec.h b/common/bak.vec.h new file mode 100644 index 0000000000..e77a4b6ae3 --- /dev/null +++ b/common/bak.vec.h @@ -0,0 +1,136 @@ +// ======================================================================== // +// 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/common/box.h b/common/box.h new file mode 100644 index 0000000000..8659980e1d --- /dev/null +++ b/common/box.h @@ -0,0 +1,101 @@ +// ======================================================================== // +// 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 "vec.h" + +namespace ospcommon { + + /*! over over scalar type T and N dimensions */ + template + struct box_t { + typedef T scalar_t; + typedef typename ospcommon::vec_t vec_t; + + inline box_t() {} + inline box_t( EmptyTy ) : lower(pos_inf), upper(neg_inf) {} + inline box_t(const box_t &o) : lower(o.lower), upper(o.upper) {} + inline box_t(const vec_t &lower, const vec_t &upper) : lower(lower), upper(upper) {} + + inline vec_t size() const { return upper - lower; } + inline void extend(const vec_t &v) { lower=min(lower,v); upper=max(upper,v); } + inline void extend(const box_t &b) { lower=min(lower,b.lower); upper=max(upper,b.upper); } + + /*! returns the center of the box (not valid for empty boxes) */ + inline vec_t center() const { return 0.5f * (lower+upper); } + inline bool empty() const { return anyLessThan(upper,lower); } + + inline bool contains(const vec_t &vec) const + { return !anyLessThan(vec,lower) && !anyLessThan(upper,vec); } + + inline box_t &operator=(const box_t &o) + { lower = o.lower; upper = o.upper; return *this; } + + vec_t lower, upper; + }; + + template + inline scalar_t area(const box_t &b) { return b.size().product(); } + + /*! return the volume of the 3D box - undefined for empty boxes */ + template + inline scalar_t volume(const box_t &b) { return b.size().product(); } + + + /*! compute the intersection of two boxes */ + template + inline box_t intersectionOf(const box_t &a, const box_t &b) + { return box_t(max(a.lower,b.lower), min(a.upper,b.upper)); } + + template + inline bool disjoint(const box_t &a, const box_t &b) + { return anyLessThen(a.upper,b.lower) || anyLessThan(b.lower,a.upper); } + + + /*! returns the center of the box (not valid for empty boxes) */ + template + inline vec_t center(const box_t &b) + { return b.center(); } + + // ------------------------------------------------------- + // comparison operator + // ------------------------------------------------------- + template + inline bool operator==(const box_t &a, const box_t &b) + { return a.lower == b.lower && a.upper == b.upper; } + template + inline bool operator!=(const box_t &a, const box_t &b) + { return !(a == b); } + + // ------------------------------------------------------- + // output operator + // ------------------------------------------------------- + template + std::ostream &operator<<(std::ostream &o, const box_t &b) + { o << "[" << b.lower <<":"< box2i; + typedef box_t box3i; + typedef box_t box3f; + typedef box_t box3fa; + // typedef box_t box2i; + + // this is just a renaming - in some cases the code reads cleaner if + // we're talking about 'regions' than about boxes + typedef box2i region2i; +} // ::ospcommon diff --git a/common/common.cpp b/common/common.cpp new file mode 100644 index 0000000000..55ed80e703 --- /dev/null +++ b/common/common.cpp @@ -0,0 +1,75 @@ +// ======================================================================== // +// 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. // +// ======================================================================== // + +#include "common.h" +#include "sysinfo.h" +#include "library.h" + +// std +#include +#ifdef _WIN32 +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include // for GetSystemTime +#else +# include +# include +# include +#endif + +namespace ospcommon { + + /*! return system time in seconds */ + double getSysTime() { +#ifdef _WIN32 + SYSTEMTIME tp; GetSystemTime(&tp); + return double(tp.wSecond) + double(tp.wMilliseconds) / 1E3; +#else + struct timeval tp; gettimeofday(&tp,NULL); + return double(tp.tv_sec) + double(tp.tv_usec)/1E6; +#endif + } + + void removeArgs(int &ac, char **&av, int where, int howMany) + { + for (int i=where+howMany;iadd(name); + } + + void *getSymbol(const std::string& name) + { + return LibraryRepository::getInstance()->getSymbol(name); + } + +} // ::ospcommon + diff --git a/common/common.h b/common/common.h new file mode 100644 index 0000000000..e6d9646f6d --- /dev/null +++ b/common/common.h @@ -0,0 +1,101 @@ +// ======================================================================== // +// 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 "platform.h" +// c runtime +#include +// std +#include + +#ifdef _WIN32 +// ----------- windows only ----------- +typedef unsigned long long id_t; +# ifndef _USE_MATH_DEFINES +# define _USE_MATH_DEFINES +# endif +# include +# include +# ifdef _M_X64 +typedef long long ssize_t; +# else +typedef int ssize_t; +# endif +#else +// ----------- NOT windows ----------- +# include "unistd.h" +#endif + +#include + +#ifdef _WIN32 +# ifdef ospray_common_EXPORTS +# define OSPCOMMON_INTERFACE __declspec(dllexport) +# else +# define OSPCOMMON_INTERFACE __declspec(dllimport) +# endif +#else +# define OSPCOMMON_INTERFACE +#endif + +#ifdef NDEBUG +# define Assert(expr) /* nothing */ +# define Assert2(expr,expl) /* nothing */ +# define AssertError(errMsg) /* nothing */ +#else +# define Assert(expr) \ + ((void)((expr) ? 0 : ((void)ospcommon::doAssertion(__FILE__, __LINE__, #expr, NULL), 0))) +# define Assert2(expr,expl) \ + ((void)((expr) ? 0 : ((void)ospcommon::doAssertion(__FILE__, __LINE__, #expr, expl), 0))) +# define AssertError(errMsg) \ + doAssertion(__FILE__,__LINE__, (errMsg), NULL) +#endif + +#ifdef _WIN32 +#define __PRETTY_FUNCTION__ __FUNCSIG__ +#endif +#define NOTIMPLEMENTED throw std::runtime_error(std::string(__PRETTY_FUNCTION__)+": not implemented..."); + +namespace ospcommon { + + /*! return system time in seconds */ + OSPCOMMON_INTERFACE double getSysTime(); + OSPCOMMON_INTERFACE void doAssertion(const char *file, int line, const char *expr, const char *expl); + /*! remove specified num arguments from an ac/av arglist */ + OSPCOMMON_INTERFACE void removeArgs(int &ac, char **&av, int where, int howMany); + OSPCOMMON_INTERFACE void loadLibrary(const std::string &name); + OSPCOMMON_INTERFACE void *getSymbol(const std::string &name); + + /*! added pretty-print function for large numbers, printing 10000000 as "10M" instead */ + inline std::string prettyNumber(const size_t s) { + double val = s; + char result[100]; + if (val >= 1e12f) { + sprintf(result,"%.1fT",val/1e12f); + } else if (val >= 1e9f) { + sprintf(result,"%.1fG",val/1e9f); + } else if (val >= 1e6f) { + sprintf(result,"%.1fM",val/1e6f); + } else if (val >= 1e3f) { + sprintf(result,"%.1fK",val/1e3f); + } else { + sprintf(result,"%lu",s); + } + return result; + } + +} // ::ospcommon diff --git a/common/constants.h b/common/constants.h new file mode 100644 index 0000000000..f77d53db81 --- /dev/null +++ b/common/constants.h @@ -0,0 +1,168 @@ +// ======================================================================== // +// 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 "platform.h" +#include + +#ifndef _USE_MATH_DEFINES +# define _USE_MATH_DEFINES +#endif +#include // using cmath causes issues under Windows +#include + +namespace ospcommon +{ + static const float one_over_255 = 1.0f/255.0f; + static const float min_rcp_input = 1E-18f; // for abs(x) >= min_rcp_input the newton raphson rcp calculation does not fail + + /* we consider floating point numbers in that range as valid input numbers */ + static float FLT_LARGE = 1.844E18f; + + static struct TrueTy { + __forceinline operator bool( ) const { return true; } + } True MAYBE_UNUSED; + + static struct FalseTy { + __forceinline operator bool( ) const { return false; } + } False MAYBE_UNUSED; + + static struct ZeroTy + { + __forceinline operator double ( ) const { return 0; } + __forceinline operator float ( ) const { return 0; } + __forceinline operator long long( ) const { return 0; } + __forceinline operator unsigned long long( ) const { return 0; } + __forceinline operator long ( ) const { return 0; } + __forceinline operator unsigned long ( ) const { return 0; } + __forceinline operator int ( ) const { return 0; } + __forceinline operator unsigned int ( ) const { return 0; } + __forceinline operator short ( ) const { return 0; } + __forceinline operator unsigned short ( ) const { return 0; } + __forceinline operator char ( ) const { return 0; } + __forceinline operator unsigned char ( ) const { return 0; } + } zero MAYBE_UNUSED; + + static struct OneTy + { + __forceinline operator double ( ) const { return 1; } + __forceinline operator float ( ) const { return 1; } + __forceinline operator long long( ) const { return 1; } + __forceinline operator unsigned long long( ) const { return 1; } + __forceinline operator long ( ) const { return 1; } + __forceinline operator unsigned long ( ) const { return 1; } + __forceinline operator int ( ) const { return 1; } + __forceinline operator unsigned int ( ) const { return 1; } + __forceinline operator short ( ) const { return 1; } + __forceinline operator unsigned short ( ) const { return 1; } + __forceinline operator char ( ) const { return 1; } + __forceinline operator unsigned char ( ) const { return 1; } + } one MAYBE_UNUSED; + + static struct NegInfTy + { + __forceinline operator double ( ) const { return -std::numeric_limits::infinity(); } + __forceinline operator float ( ) const { return -std::numeric_limits::infinity(); } + __forceinline operator long long( ) const { return std::numeric_limits::min(); } + __forceinline operator unsigned long long( ) const { return std::numeric_limits::min(); } + __forceinline operator long ( ) const { return std::numeric_limits::min(); } + __forceinline operator unsigned long ( ) const { return std::numeric_limits::min(); } + __forceinline operator int ( ) const { return std::numeric_limits::min(); } + __forceinline operator unsigned int ( ) const { return std::numeric_limits::min(); } + __forceinline operator short ( ) const { return std::numeric_limits::min(); } + __forceinline operator unsigned short ( ) const { return std::numeric_limits::min(); } + __forceinline operator char ( ) const { return std::numeric_limits::min(); } + __forceinline operator unsigned char ( ) const { return std::numeric_limits::min(); } + + } neg_inf MAYBE_UNUSED; + + static struct PosInfTy + { + __forceinline operator double ( ) const { return std::numeric_limits::infinity(); } + __forceinline operator float ( ) const { return std::numeric_limits::infinity(); } + __forceinline operator long long( ) const { return std::numeric_limits::max(); } + __forceinline operator unsigned long long( ) const { return std::numeric_limits::max(); } + __forceinline operator long ( ) const { return std::numeric_limits::max(); } + __forceinline operator unsigned long ( ) const { return std::numeric_limits::max(); } + __forceinline operator int ( ) const { return std::numeric_limits::max(); } + __forceinline operator unsigned int ( ) const { return std::numeric_limits::max(); } + __forceinline operator short ( ) const { return std::numeric_limits::max(); } + __forceinline operator unsigned short ( ) const { return std::numeric_limits::max(); } + __forceinline operator char ( ) const { return std::numeric_limits::max(); } + __forceinline operator unsigned char ( ) const { return std::numeric_limits::max(); } + } inf MAYBE_UNUSED, pos_inf MAYBE_UNUSED; + + static struct NaNTy + { + __forceinline operator double( ) const { return std::numeric_limits::quiet_NaN(); } + __forceinline operator float ( ) const { return std::numeric_limits::quiet_NaN(); } + } nan MAYBE_UNUSED; + + static struct UlpTy + { + __forceinline operator double( ) const { return std::numeric_limits::epsilon(); } + __forceinline operator float ( ) const { return std::numeric_limits::epsilon(); } + } ulp MAYBE_UNUSED; + + static struct PiTy + { + __forceinline operator double( ) const { return M_PI; } + __forceinline operator float ( ) const { return M_PI; } + } pi MAYBE_UNUSED; + + static struct OneOverPiTy + { + __forceinline operator double( ) const { return M_1_PI; } + __forceinline operator float ( ) const { return M_1_PI; } + } one_over_pi MAYBE_UNUSED; + + static struct TwoPiTy + { + __forceinline operator double( ) const { return 2.0*M_PI; } + __forceinline operator float ( ) const { return 2.0*M_PI; } + } two_pi MAYBE_UNUSED; + + static struct OneOverTwoPiTy + { + __forceinline operator double( ) const { return 0.5*M_1_PI; } + __forceinline operator float ( ) const { return 0.5*M_1_PI; } + } one_over_two_pi MAYBE_UNUSED; + + static struct FourPiTy + { + __forceinline operator double( ) const { return 4.0*M_PI; } + __forceinline operator float ( ) const { return 4.0*M_PI; } + } four_pi MAYBE_UNUSED; + + static struct OneOverFourPiTy + { + __forceinline operator double( ) const { return 0.25*M_1_PI; } + __forceinline operator float ( ) const { return 0.25*M_1_PI; } + } one_over_four_pi MAYBE_UNUSED; + + static struct StepTy { + } step MAYBE_UNUSED; + + static struct ReverseStepTy { + } reverse_step MAYBE_UNUSED; + + static struct EmptyTy { + } empty MAYBE_UNUSED; + + static struct FullTy { + } full MAYBE_UNUSED; +} diff --git a/common/intrinsics.h b/common/intrinsics.h new file mode 100644 index 0000000000..1ced7ac03d --- /dev/null +++ b/common/intrinsics.h @@ -0,0 +1,863 @@ +// ======================================================================== // +// 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 "platform.h" + +#ifdef _WIN32 +#include +#endif + +#if defined(__SSE__) +#include +#endif + +#if defined(__SSE2__) +#include +#endif + +#if defined(__SSE3__) +#include +#endif + +#if defined(__SSSE3__) +#include +#endif + +#if defined (__SSE4_1__) +#include +#endif + +#if defined (__SSE4_2__) +#include +#endif + +#if defined(__AVX__) || defined(__MIC__) +#include +#endif + +#if defined(__BMI__) && defined(__GNUC__) + #if !defined(_tzcnt_u32) + #define _tzcnt_u32 __tzcnt_u32 + #endif + #if !defined(_tzcnt_u64) + #define _tzcnt_u64 __tzcnt_u64 + #endif +#endif + +#if defined(__LZCNT__) + #if !defined(_lzcnt_u32) + #define _lzcnt_u32 __lzcnt32 + #endif + #if !defined(_lzcnt_u64) + #define _lzcnt_u64 __lzcnt64 + #endif +#endif + +#if defined(__MIC__) +# include +#endif + +#ifdef _WIN32 +# define NOMINMAX +# include +#endif + +/* normally defined in pmmintrin.h, but we always need this */ +#if !defined(_MM_SET_DENORMALS_ZERO_MODE) +#define _MM_DENORMALS_ZERO_ON (0x0040) +#define _MM_DENORMALS_ZERO_OFF (0x0000) +#define _MM_DENORMALS_ZERO_MASK (0x0040) +#define _MM_SET_DENORMALS_ZERO_MODE(x) (_mm_setcsr((_mm_getcsr() & ~_MM_DENORMALS_ZERO_MASK) | (x))) +#endif + +namespace ospcommon +{ + +//////////////////////////////////////////////////////////////////////////////// +/// Windows Platform +//////////////////////////////////////////////////////////////////////////////// + +#ifdef _WIN32 + + __forceinline size_t read_tsc() + { + LARGE_INTEGER li; + QueryPerformanceCounter(&li); + return li.QuadPart; + } + +#if defined(__SSE4_2__) + + __forceinline int __popcnt(int in) { + return _mm_popcnt_u32(in); + } + + __forceinline unsigned __popcnt(unsigned in) { + return _mm_popcnt_u32(in); + } + +#if defined(__X86_64__) + __forceinline size_t __popcnt(size_t in) { + return _mm_popcnt_u64(in); + } +#endif + +#endif + + __forceinline int __bsf(int v) { +#if defined(__AVX2__) + return _tzcnt_u32(v); +#else + unsigned long r = 0; _BitScanForward(&r,v); return r; +#endif + } + + __forceinline unsigned __bsf(unsigned v) { +#if defined(__AVX2__) + return _tzcnt_u32(v); +#else + unsigned long r = 0; _BitScanForward(&r,v); return r; +#endif + } + +#if defined(__X86_64__) + __forceinline size_t __bsf(size_t v) { +#if defined(__AVX2__) + return _tzcnt_u64(v); +#else + unsigned long r = 0; _BitScanForward64(&r,v); return r; +#endif + } +#endif + + __forceinline int __bscf(int& v) + { + int i = __bsf(v); + v &= v-1; + return i; + } + + __forceinline unsigned __bscf(unsigned& v) + { + unsigned i = __bsf(v); + v &= v-1; + return i; + } + +#if defined(__X86_64__) + __forceinline size_t __bscf(size_t& v) + { + size_t i = __bsf(v); + v &= v-1; + return i; + } +#endif + + __forceinline int __bsr(int v) { +#if defined(__AVX2__) + return _lzcnt_u32(v); +#else + unsigned long r = 0; _BitScanReverse(&r,v); return r; +#endif + } + + __forceinline unsigned __bsr(unsigned v) { +#if defined(__AVX2__) + return _lzcnt_u32(v); +#else + unsigned long r = 0; _BitScanReverse(&r,v); return r; +#endif + } + +#if defined(__X86_64__) + __forceinline size_t __bsr(size_t v) { +#if defined(__AVX2__) + return _lzcnt_u64(v); +#else + unsigned long r = 0; _BitScanReverse64(&r,v); return r; +#endif + } +#endif + + __forceinline int lzcnt(const int x) + { +#if defined(__AVX2__) + return _lzcnt_u32(x); +#else + if (unlikely(x == 0)) return 32; + return 31 - __bsr(x); +#endif + } + + __forceinline int __btc(int v, int i) { + long r = v; _bittestandcomplement(&r,i); return r; + } + + __forceinline int __bts(int v, int i) { + long r = v; _bittestandset(&r,i); return r; + } + + __forceinline int __btr(int v, int i) { + long r = v; _bittestandreset(&r,i); return r; + } + +#if defined(__X86_64__) + + __forceinline size_t __btc(size_t v, size_t i) { + size_t r = v; _bittestandcomplement64((__int64*)&r,i); return r; + } + + __forceinline size_t __bts(size_t v, size_t i) { + __int64 r = v; _bittestandset64(&r,i); return r; + } + + __forceinline size_t __btr(size_t v, size_t i) { + __int64 r = v; _bittestandreset64(&r,i); return r; + } + +#endif + +// typedef int16_t atomic16_t; + +// __forceinline int16_t atomic_add(volatile int16_t* p, const int16_t v) { +// return _InterlockedExchangeAdd16((volatile short*)p,v); +// } + +// __forceinline int16_t atomic_sub(volatile int16_t* p, const int16_t v) { +// return _InterlockedExchangeAdd16((volatile short*)p,-v); +// } + +// __forceinline int16_t atomic_xchg(volatile int16_t *p, int16_t v) { +// return _InterlockedExchange16((volatile short*)p, v); +// } + +// __forceinline int16_t atomic_cmpxchg(volatile int16_t* p, const int16_t c, const int16_t v) { +// return _InterlockedCompareExchange16((volatile short*)p,v,c); +// } + +// __forceinline int16_t atomic_and(volatile int16_t* p, const int16_t v) { +// return _InterlockedAnd16((volatile short*)p,v); +// } + +// __forceinline int16_t atomic_or(volatile int16_t* p, const int16_t v) { +// return _InterlockedOr16((volatile short*)p,v); +// } + +// typedef int32_t atomic32_t; + +// __forceinline int32_t atomic_add(volatile int32_t* p, const int32_t v) { +// return _InterlockedExchangeAdd((volatile long*)p,v); +// } + +// __forceinline int32_t atomic_sub(volatile int32_t* p, const int32_t v) { +// return _InterlockedExchangeAdd((volatile long*)p,-v); +// } + +// __forceinline int32_t atomic_xchg(volatile int32_t *p, int32_t v) { +// return _InterlockedExchange((volatile long*)p, v); +// } + +// __forceinline int32_t atomic_cmpxchg(volatile int32_t* p, const int32_t c, const int32_t v) { +// return _InterlockedCompareExchange((volatile long*)p,v,c); +// } + +// __forceinline int32_t atomic_and(volatile int32_t* p, const int32_t v) { +// return _InterlockedAnd((volatile long*)p,v); +// } + +// __forceinline int32_t atomic_or(volatile int32_t* p, const int32_t v) { +// return _InterlockedOr((volatile long*)p,v); +// } + +// #if defined(__X86_64__) + +// typedef int64_t atomic64_t; + +// __forceinline int64_t atomic_add(volatile int64_t* m, const int64_t v) { +// return _InterlockedExchangeAdd64(m,v); +// } + +// __forceinline int64_t atomic_sub(volatile int64_t* m, const int64_t v) { +// return _InterlockedExchangeAdd64(m,-v); +// } + +// __forceinline int64_t atomic_xchg(volatile int64_t *p, int64_t v) { +// return _InterlockedExchange64((volatile long long *)p, v); +// } + +// __forceinline int64_t atomic_cmpxchg(volatile int64_t* m, const int64_t c, const int64_t v) { +// return _InterlockedCompareExchange64(m,v,c); +// } + +// __forceinline int64_t atomic_and(volatile int64_t* p, const int64_t v) { +// return _InterlockedAnd64((volatile int64_t*)p,v); +// } + +// __forceinline int64_t atomic_or(volatile int64_t* p, const int64_t v) { +// return _InterlockedOr64((volatile int64_t*)p,v); +// } + +// #endif + +//////////////////////////////////////////////////////////////////////////////// +/// Unix Platform +//////////////////////////////////////////////////////////////////////////////// + +#else + +#if defined(__i386__) && defined(__PIC__) + + __forceinline void __cpuid(int out[4], int op) + { + asm volatile ("xchg{l}\t{%%}ebx, %1\n\t" + "cpuid\n\t" + "xchg{l}\t{%%}ebx, %1\n\t" + : "=a"(out[0]), "=r"(out[1]), "=c"(out[2]), "=d"(out[3]) + : "0"(op)); + } + + __forceinline void __cpuid_count(int out[4], int op1, int op2) + { + asm volatile ("xchg{l}\t{%%}ebx, %1\n\t" + "cpuid\n\t" + "xchg{l}\t{%%}ebx, %1\n\t" + : "=a" (out[0]), "=r" (out[1]), "=c" (out[2]), "=d" (out[3]) + : "0" (op1), "2" (op2)); + } + +#else + + __forceinline void __cpuid(int out[4], int op) { + asm volatile ("cpuid" : "=a"(out[0]), "=b"(out[1]), "=c"(out[2]), "=d"(out[3]) : "a"(op)); + } + + __forceinline void __cpuid_count(int out[4], int op1, int op2) { + asm volatile ("cpuid" : "=a"(out[0]), "=b"(out[1]), "=c"(out[2]), "=d"(out[3]) : "a"(op1), "c"(op2)); + } + +#endif + + __forceinline uint64_t read_tsc() { + uint32_t high,low; + asm volatile ("rdtsc" : "=d"(high), "=a"(low)); + return (((uint64_t)high) << 32) + (uint64_t)low; + } + +#if !defined(__MIC__) + +#if defined(__SSE4_2__) + __forceinline unsigned int __popcnt(unsigned int in) { + int r = 0; asm ("popcnt %1,%0" : "=r"(r) : "r"(in)); return r; + } +#endif + + __forceinline int __bsf(int v) { +#if defined(__AVX2__) + return _tzcnt_u32(v); +#else + int r = 0; asm ("bsf %1,%0" : "=r"(r) : "r"(v)); return r; +#endif + } + + __forceinline unsigned __bsf(unsigned v) + { +#if defined(__AVX2__) + return _tzcnt_u32(v); +#else + unsigned r = 0; asm ("bsf %1,%0" : "=r"(r) : "r"(v)); return r; +#endif + } + + __forceinline size_t __bsf(size_t v) { +#if defined(__AVX2__) +#if defined(__X86_64__) + return _tzcnt_u64(v); +#else + return _tzcnt_u32(v); +#endif +#else + size_t r = 0; asm ("bsf %1,%0" : "=r"(r) : "r"(v)); return r; +#endif + } + + __forceinline int __bscf(int& v) + { + int i = __bsf(v); + v &= v-1; + return i; + } + + __forceinline unsigned int __bscf(unsigned int& v) + { + unsigned int i = __bsf(v); + v &= v-1; + return i; + } + + __forceinline size_t __bscf(size_t& v) + { + size_t i = __bsf(v); + v &= v-1; + return i; + } + + __forceinline int __bsr(int v) { +#if defined(__AVX2__) + return 31 - _lzcnt_u32(v); +#else + int r = 0; asm ("bsr %1,%0" : "=r"(r) : "r"(v)); return r; +#endif + } + + __forceinline unsigned __bsr(unsigned v) { +#if defined(__AVX2__) + return 31 - _lzcnt_u32(v); +#else + unsigned r = 0; asm ("bsr %1,%0" : "=r"(r) : "r"(v)); return r; +#endif + } + + __forceinline size_t __bsr(size_t v) { +#if defined(__AVX2__) +#if defined(__X86_64__) + return 63 - _lzcnt_u64(v); +#else + return 31 - _lzcnt_u32(v); +#endif +#else + size_t r = 0; asm ("bsr %1,%0" : "=r"(r) : "r"(v)); return r; +#endif + } + + __forceinline int lzcnt(const int x) + { +#if defined(__AVX2__) + return _lzcnt_u32(x); +#else + if (unlikely(x == 0)) return 32; + return 31 - __bsr(x); +#endif + } + + __forceinline size_t __blsr(size_t v) { +#if defined(__AVX2__) +#if defined(__INTEL_COMPILER) + return _blsr_u64(v); +#else + return __blsr_u64(v); +#endif +#else + return v & (v-1); +#endif + } + + __forceinline int __btc(int v, int i) { + int r = 0; asm ("btc %1,%0" : "=r"(r) : "r"(i), "0"(v) : "flags" ); return r; + } + + __forceinline int __bts(int v, int i) { + int r = 0; asm ("bts %1,%0" : "=r"(r) : "r"(i), "0"(v) : "flags"); return r; + } + + __forceinline int __btr(int v, int i) { + int r = 0; asm ("btr %1,%0" : "=r"(r) : "r"(i), "0"(v) : "flags"); return r; + } + + __forceinline size_t __btc(size_t v, size_t i) { + size_t r = 0; asm ("btc %1,%0" : "=r"(r) : "r"(i), "0"(v) : "flags" ); return r; + } + + __forceinline size_t __bts(size_t v, size_t i) { + size_t r = 0; asm ("bts %1,%0" : "=r"(r) : "r"(i), "0"(v) : "flags"); return r; + } + + __forceinline size_t __btr(size_t v, size_t i) { + size_t r = 0; asm ("btr %1,%0" : "=r"(r) : "r"(i), "0"(v) : "flags"); return r; + } + +#else + + static const unsigned int BITSCAN_NO_BIT_SET_32 = 32; + static const size_t BITSCAN_NO_BIT_SET_64 = 64; + + __forceinline unsigned int clz(const unsigned int x) { + return _lzcnt_u32(x); + } + + __forceinline size_t clz(const size_t x) { + return _lzcnt_u64(x); + } + + __forceinline unsigned int bitscan(unsigned int v) { + return _mm_tzcnt_32(v); + } + + __forceinline size_t bitscan64(size_t v) { + return _mm_tzcnt_64(v); + } + + __forceinline unsigned int bitscan(const int index, const unsigned int v) { + return _mm_tzcnti_32(index,v); + }; + + __forceinline size_t bitscan64(const ssize_t index, const size_t v) { + return _mm_tzcnti_64(index,v); + }; + + __forceinline int __popcnt(int v) { + return _mm_countbits_32(v); + } + + __forceinline unsigned int __popcnt(unsigned int v) { + return _mm_countbits_32(v); + } + + __forceinline unsigned int countbits(unsigned int v) { + return _mm_countbits_32(v); + }; + + __forceinline size_t __popcnt(size_t v) { + return _mm_countbits_64(v); + } + + __forceinline size_t countbits64(size_t v) { + return _mm_countbits_64(v); + }; + + __forceinline int __bsf(int v) { + return bitscan(v); + } + + __forceinline unsigned int __bsf(unsigned int v) { + return bitscan(v); + } + + __forceinline size_t __bsf(size_t v) { + return bitscan(v); + } + + __forceinline size_t __btc(size_t v, size_t i) { + return v ^ (size_t(1) << i); + } + + __forceinline unsigned int __bsr(unsigned int v) { + return 31 - _lzcnt_u32(v); + } + + __forceinline size_t __bsr(size_t v) { + return 63 - _lzcnt_u64(v); + } + +#endif + +// typedef int8_t atomic8_t; + +// __forceinline int8_t atomic_add( int8_t volatile* value, int8_t input ) { +// return __sync_fetch_and_add(value, input); +// } + +// __forceinline int8_t atomic_sub( int8_t volatile* value, int8_t input ) { +// return __sync_fetch_and_add(value, -input); +// } + +// __forceinline int8_t atomic_xchg( int8_t volatile* value, int8_t input ) { +// return __sync_lock_test_and_set(value, input); +// } + +// __forceinline int8_t atomic_cmpxchg( int8_t volatile* value, int8_t comparand, const int8_t input ) { +// return __sync_val_compare_and_swap(value, comparand, input); +// } + +// typedef int16_t atomic16_t; + +// __forceinline int16_t atomic_add( int16_t volatile* value, int16_t input ) { +// return __sync_fetch_and_add(value, input); +// } + +// __forceinline int16_t atomic_sub( int16_t volatile* value, int16_t input ) { +// return __sync_fetch_and_add(value, -input); +// } + +// __forceinline int16_t atomic_xchg( int16_t volatile* value, int16_t input ) { +// return __sync_lock_test_and_set(value, input); +// } + +// __forceinline int16_t atomic_cmpxchg( int16_t volatile* value, int16_t comparand, const int16_t input ) { +// return __sync_val_compare_and_swap(value, comparand, input); +// } + +// typedef int32_t atomic32_t; + +// __forceinline int32_t atomic_add( int32_t volatile* value, int32_t input ) { +// return __sync_fetch_and_add(value, input); +// } + +// __forceinline int32_t atomic_sub( int32_t volatile* value, int32_t input ) { +// return __sync_fetch_and_add(value, -input); +// } + +// __forceinline int32_t atomic_xchg( int32_t volatile* value, int32_t input ) { +// return __sync_lock_test_and_set(value, input); +// } + +// __forceinline int32_t atomic_cmpxchg( int32_t volatile* value, int32_t comparand, const int32_t input ) { +// return __sync_val_compare_and_swap(value, comparand, input); +// } + +// __forceinline int32_t atomic_or(int32_t volatile* value, int32_t input) { +// return __sync_fetch_and_or(value, input); +// } + +// __forceinline int32_t atomic_and(int32_t volatile* value, int32_t input) { +// return __sync_fetch_and_and(value, input); +// } + +// #if defined(__X86_64__) + +// typedef int64_t atomic64_t; + +// __forceinline int64_t atomic_add( int64_t volatile* value, int64_t input ) { +// return __sync_fetch_and_add(value, input); +// } + +// __forceinline int64_t atomic_sub( int64_t volatile* value, int64_t input ) { +// return __sync_fetch_and_add(value, -input); +// } + +// __forceinline int64_t atomic_xchg( int64_t volatile* value, int64_t input ) { +// return __sync_lock_test_and_set(value, input); +// } + +// __forceinline int64_t atomic_cmpxchg( int64_t volatile* value, int64_t comparand, const int64_t input) { +// return __sync_val_compare_and_swap(value, comparand, input); +// } + +// __forceinline int64_t atomic_or(int64_t volatile* value, int64_t input) { +// return __sync_fetch_and_or(value, input); +// } + +// __forceinline int64_t atomic_and(int64_t volatile* value, int64_t input) { +// return __sync_fetch_and_and(value, input); +// } + +// #endif + +#endif + +//////////////////////////////////////////////////////////////////////////////// +/// All Platforms +//////////////////////////////////////////////////////////////////////////////// + +// #if defined(__X86_64__) +// typedef atomic64_t atomic_t; +// #else +// typedef atomic32_t atomic_t; +// #endif + +// #if defined(__X86_64__) + +// template +// __forceinline T* atomic_xchg_ptr( T* volatile* value, const T* input) +// { return (T*)atomic_xchg((int64_t*)value,(int64_t)input); } + +// template +// __forceinline T* atomic_cmpxchg_ptr( T* volatile* value, T* comparand, const T* input ) +// { return (T*)atomic_cmpxchg((int64_t*)value,(int64_t)comparand,(int64_t)input); } + +// #else + +// template +// __forceinline T* atomic_xchg_ptr( T* volatile* value, const T* input) +// { return (T*)atomic_xchg((int32_t*)value,(int32_t)input); } + +// template +// __forceinline T* atomic_cmpxchg_ptr( T* volatile* value, T* comparand, const T* input ) +// { return (T*)atomic_cmpxchg((int32_t*)value,(int32_t)comparand,(int32_t)input); } + +// #endif + +// __forceinline void atomic_min_f32(volatile float *__restrict__ ptr, const float b) +// { +// const int int_b = *(int*)&b; +// while (1) +// { +// float a = *ptr; +// if (a <= b) break; +// const int int_a = *(int*)&a; +// const int result = atomic_cmpxchg((int*)ptr,int_a,int_b); +// if (result == int_a) break; +// } +// } + +// __forceinline void atomic_max_f32(volatile float *__restrict__ ptr, const float b) +// { +// const int int_b = *(int*)&b; +// while (1) +// { +// float a = *ptr; +// if (a >= b) break; +// const int int_a = *(int*)&a; +// const int result = atomic_cmpxchg((int*)ptr,int_a,int_b); +// if (result == int_a) break; +// } +// } + +// __forceinline void atomic_min_i32(volatile int *__restrict__ ptr, const int b) +// { +// while (1) +// { +// int a = *ptr; +// if (a <= b) break; +// const int int_a = *(int*)&a; +// const int result = atomic_cmpxchg((int*)ptr,int_a,b); +// if (result == int_a) break; +// } +// } + +// __forceinline void atomic_max_i32(volatile int *__restrict__ ptr, const int b) +// { +// while (1) +// { +// int a = *ptr; +// if (a >= b) break; +// const int int_a = *(int*)&a; +// const int result = atomic_cmpxchg((int*)ptr,int_a,b); +// if (result == int_a) break; +// } +// } + +// __forceinline void atomic_min_ui32(volatile unsigned int *__restrict__ ptr, const unsigned int b) +// { +// while (1) +// { +// unsigned int a = *ptr; +// if (a <= b) break; +// const unsigned int int_a = *(unsigned int*)&a; +// const unsigned int result = atomic_cmpxchg((int*)ptr,int_a,b); +// if (result == int_a) break; +// } +// } + +// __forceinline void atomic_max_ui32(volatile unsigned int *__restrict__ ptr, const unsigned int b) +// { +// while (1) +// { +// unsigned int a = *ptr; +// if (a >= b) break; +// const unsigned int int_a = *(unsigned int*)&a; +// const unsigned int result = atomic_cmpxchg((int*)ptr,int_a,b); +// if (result == int_a) break; +// } +// } + +// __forceinline void atomic_add_f32(volatile float *__restrict__ ptr, const float b) +// { +// while (1) +// { +// float a = *ptr; +// float ab = a + b; +// const int int_a = *(int*)&a; +// const int int_ab = *(int*)&ab; +// const int result = atomic_cmpxchg((int*)ptr,int_a,int_ab); +// if (result == int_a) break; +// } +// } + + __forceinline uint64_t rdtsc() + { +#if !defined(__MIC__) + int dummy[4]; + __cpuid(dummy,0); + uint64_t clock = read_tsc(); + __cpuid(dummy,0); + return clock; +#else + return read_tsc(); +#endif + } + +// #if defined(__MIC__) +// __forceinline void __pause_cpu (const unsigned int cycles = 1024) { +// _mm_delay_32(cycles); +// } +// #else +// __forceinline void __pause_cpu (const int cycles = 0) { +// for (size_t i=0; i<8; i++) +// _mm_pause(); +// } +// #endif + +// __forceinline void __pause_cpu_expfalloff(unsigned int &cycles, const unsigned int max_cycles) +// { +// __pause_cpu(cycles); +// cycles += cycles; +// if (cycles > max_cycles) +// cycles = max_cycles; +// } + +// /* prefetches */ +// __forceinline void prefetchL1 (const void* ptr) { _mm_prefetch((const char*)ptr,_MM_HINT_T0); } +// __forceinline void prefetchL2 (const void* ptr) { _mm_prefetch((const char*)ptr,_MM_HINT_T1); } +// __forceinline void prefetchL3 (const void* ptr) { _mm_prefetch((const char*)ptr,_MM_HINT_T2); } +// __forceinline void prefetchNTA(const void* ptr) { _mm_prefetch((const char*)ptr,_MM_HINT_NTA); } +// __forceinline void prefetchEX (const void* ptr) { +// #if defined(__INTEL_COMPILER) +// _mm_prefetch((const char*)ptr,_MM_HINT_ET0); +// #else +// _mm_prefetch((const char*)ptr,_MM_HINT_T0); +// #endif +// } + +// __forceinline void prefetchL1EX(const void* ptr) { +// #if defined(__MIC__) +// _mm_prefetch((const char*)ptr,_MM_HINT_ET0); +// #else +// prefetchEX(ptr); +// #endif +// } + +// __forceinline void prefetchL2EX(const void* ptr) { +// #if defined(__MIC__) +// _mm_prefetch((const char*)ptr,_MM_HINT_ET2); +// #else +// prefetchEX(ptr); +// #endif +// } + +// #if defined(__MIC__) +// __forceinline void evictL1(const void * __restrict__ m) { +// _mm_clevict(m,_MM_HINT_T0); +// } + +// __forceinline void evictL2(const void * __restrict__ m) { +// _mm_clevict(m,_MM_HINT_T1); +// } +// #endif + +// /* compiler memory barriers */ +// #if defined(__GNUC__) || defined(__clang__) +// # define __memory_barrier() asm volatile("" ::: "memory") +// #elif defined(__MIC__) +// #define __memory_barrier() +// #elif defined(__INTEL_COMPILER) +// //#define __memory_barrier() __memory_barrier() +// #elif defined(_MSC_VER) +// # define __memory_barrier() _ReadWriteBarrier() +// #endif + +} diff --git a/common/library.cpp b/common/library.cpp new file mode 100644 index 0000000000..1359b1c3c0 --- /dev/null +++ b/common/library.cpp @@ -0,0 +1,127 @@ +// ======================================================================== // +// 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. // +// ======================================================================== // + +#include "library.h" +#include "FileName.h" +#include "sysinfo.h" + +// std +#ifdef _WIN32 +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +#else +# include +# include +#endif + + +namespace ospcommon { + + Library::Library(const std::string& name) + { +#ifdef OSPRAY_TARGET_MIC + std::string file = name+"_mic"; +#else + std::string file = name; +#endif +#ifdef _WIN32 + std::string fullName = file+".dll"; + FileName executable = getExecutableFileName(); + lib = LoadLibrary((executable.path() + fullName).c_str()); +#else +#if defined(__MACOSX__) + std::string fullName = "lib"+file+".dylib"; +#else + std::string fullName = "lib"+file+".so"; +#endif + lib = dlopen(fullName.c_str(), RTLD_NOW); + if (!lib) { + FileName executable = getExecutableFileName(); + lib = dlopen((executable.path() + fullName).c_str(), RTLD_NOW); + } +#endif + + if (lib == NULL) + throw std::runtime_error("could not open module lib "+name); + } + + Library::Library(void* const lib) : lib(lib) {}; + + void* Library::getSymbol(const std::string& sym) const + { +#ifdef _WIN32 + return GetProcAddress((HMODULE)lib, sym.c_str()); +#else + return dlsym(lib, sym.c_str()); +#endif + } + + + LibraryRepository* LibraryRepository::instance = NULL; + + LibraryRepository* LibraryRepository::getInstance() + { + if (instance == NULL) + instance = new LibraryRepository; + + return instance; + } + + void LibraryRepository::add(const std::string& name) + { + if (repo.find(name) != repo.end()) + return; // lib already loaded. + + repo[name] = new Library(name); + } + + void* LibraryRepository::getSymbol(const std::string& name) const + { + void *sym = NULL; + for (auto lib = repo.cbegin(); sym == NULL && lib != repo.end(); ++lib) + sym = lib->second->getSymbol(name); + + return sym; + } + + LibraryRepository::LibraryRepository() + { + // already populate the repo with "virtual" libs, representing the default OSPRay core lib +#ifdef _WIN32 + // look in exe (i.e. when OSPRay is linked statically into the application) + repo["exedefault"] = new Library(GetModuleHandle(0)); + + // look in ospray.dll (i.e. when linked dynamically) +#if 0 + // we cannot get a function from ospray.dll, because this would create a + // cyclic dependency between ospray.dll and ospray_common.dll + + // only works when ospray_common is liked statically into ospray + const void * functionInOSPRayDLL = ospcommon::getSymbol; + // get handle to current dll via a known function + MEMORY_BASIC_INFORMATION mbi; + VirtualQuery(functionInOSPRayDLL, &mbi, sizeof(mbi)); + repo["dlldefault"] = new Library(mbi.AllocationBase); +#else + repo["ospray"] = new Library(std::string("ospray")); +#endif +#else + repo["ospray"] = new Library(RTLD_DEFAULT); +#endif + } +} diff --git a/ospray/texture/Texture.h b/common/library.h similarity index 59% rename from ospray/texture/Texture.h rename to common/library.h index 952eeac354..c76b017701 100644 --- a/ospray/texture/Texture.h +++ b/common/library.h @@ -14,18 +14,43 @@ // limitations under the License. // // ======================================================================== // -#pragma once +#include "common.h" +// std +#include +#include -#include "ospray/common/Managed.h" +namespace ospcommon { -namespace ospray { + class Library + { + public: + /* opens a shared library */ + Library(const std::string& name); + + /* returns address of a symbol from the library */ + void* getSymbol(const std::string& sym) const; + + private: + Library(void* const lib); + void *lib; + friend class LibraryRepository; + }; - /*! \brief implements the basic abstraction for anything that is a 'texture' */ - struct Texture : public ManagedObject + class LibraryRepository { - //! \brief common function to help printf-debugging - /*! Every derived class should overrride this! */ - virtual std::string toString() const { return "ospray::Texture"; } + public: + static LibraryRepository* getInstance(); + + /* add a library to the repo */ + void add(const std::string& name); + + /* returns address of a symbol from any library in the repo */ + void* getSymbol(const std::string& sym) const; + + private: + static LibraryRepository* instance; + LibraryRepository(); + std::map repo; }; +} -} // ::ospray diff --git a/common/malloc.cpp b/common/malloc.cpp new file mode 100644 index 0000000000..32e766b648 --- /dev/null +++ b/common/malloc.cpp @@ -0,0 +1,191 @@ +// ======================================================================== // +// 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. // +// ======================================================================== // + +#include "malloc.h" +#include "intrinsics.h" +#if defined(TASKING_TBB) +# define __TBB_NO_IMPLICIT_LINKAGE 1 +# include "tbb/scalable_allocator.h" +#endif + +//////////////////////////////////////////////////////////////////////////////// +/// Windows Platform +//////////////////////////////////////////////////////////////////////////////// + +#ifdef _WIN32 + +#define WIN32_LEAN_AND_MEAN +#include +#include + +namespace embree +{ + void* os_malloc(size_t bytes, const int additional_flags) + { + int flags = MEM_COMMIT|MEM_RESERVE|additional_flags; + char* ptr = (char*) VirtualAlloc(NULL,bytes,flags,PAGE_READWRITE); + if (ptr == NULL) throw std::bad_alloc(); + return ptr; + } + + void* os_reserve(size_t bytes) + { + char* ptr = (char*) VirtualAlloc(NULL,bytes,MEM_RESERVE,PAGE_READWRITE); + if (ptr == NULL) throw std::bad_alloc(); + return ptr; + } + + void os_commit (void* ptr, size_t bytes) { + VirtualAlloc(ptr,bytes,MEM_COMMIT,PAGE_READWRITE); + } + + size_t os_shrink(void* ptr, size_t bytesNew, size_t bytesOld) + { + size_t pageSize = 4096; + bytesNew = (bytesNew+pageSize-1) & ~(pageSize-1); + assert(bytesNew <= bytesOld); + if (bytesNew < bytesOld) + VirtualFree((char*)ptr+bytesNew,bytesOld-bytesNew,MEM_DECOMMIT); + return bytesNew; + } + + void os_free(void* ptr, size_t bytes) { + if (bytes == 0) return; + VirtualFree(ptr,0,MEM_RELEASE); + } +} +#endif + +//////////////////////////////////////////////////////////////////////////////// +/// Unix Platform +//////////////////////////////////////////////////////////////////////////////// + +#if defined(__UNIX__) + +#include +#include +#include +#include + +#if defined(__MIC__) +#define USE_HUGE_PAGES 1 +#else +#define USE_HUGE_PAGES 0 +#endif + +namespace ospcommon +{ + void* os_malloc(size_t bytes, const int additional_flags) + { + int flags = MAP_PRIVATE | MAP_ANON | additional_flags; +#if USE_HUGE_PAGES + if (bytes > 16*4096) { + flags |= MAP_HUGETLB; + bytes = (bytes+2*1024*1024-1)&ssize_t(-2*1024*1024); + } else { + bytes = (bytes+4095)&ssize_t(-4096); + } +#endif +#if __MIC__ + flags |= MAP_POPULATE; +#endif + char* ptr = (char*) mmap(0, bytes, PROT_READ | PROT_WRITE, flags, -1, 0); + if (ptr == NULL || ptr == MAP_FAILED) throw std::bad_alloc(); + return ptr; + } + + void* os_reserve(size_t bytes) + { + int flags = MAP_PRIVATE | MAP_ANON | MAP_NORESERVE; +#if USE_HUGE_PAGES + if (bytes > 16*4096) { + flags |= MAP_HUGETLB; + bytes = (bytes+2*1024*1024-1)&ssize_t(-2*1024*1024); + } else { + bytes = (bytes+4095)&ssize_t(-4096); + } +#endif +#if __MIC__ + flags |= MAP_POPULATE; +#endif + + char* ptr = (char*) mmap(0, bytes, PROT_READ | PROT_WRITE, flags, -1, 0); + if (ptr == NULL || ptr == MAP_FAILED) throw std::bad_alloc(); + return ptr; + } + + void os_commit (void* ptr, size_t bytes) { + } + + size_t os_shrink(void* ptr, size_t bytesNew, size_t bytesOld) + { + size_t pageSize = 4096; +#if USE_HUGE_PAGES + if (bytesOld > 16*4096) pageSize = 2*1024*1024; +#endif + bytesNew = (bytesNew+pageSize-1) & ~(pageSize-1); + assert(bytesNew <= bytesOld); + if (bytesNew < bytesOld) + if (munmap((char*)ptr+bytesNew,bytesOld-bytesNew) == -1) + throw std::bad_alloc(); + + return bytesNew; + } + + void os_free(void* ptr, size_t bytes) + { + if (bytes == 0) + return; + +#if USE_HUGE_PAGES + if (bytes > 16*4096) { + bytes = (bytes+2*1024*1024-1)&ssize_t(-2*1024*1024); + } else { + bytes = (bytes+4095)&ssize_t(-4096); + } +#endif + if (munmap(ptr,bytes) == -1) + throw std::bad_alloc(); + } +} + +#endif + +//////////////////////////////////////////////////////////////////////////////// +/// All Platforms +//////////////////////////////////////////////////////////////////////////////// + +namespace ospcommon +{ + void* alignedMalloc(size_t size, size_t align) + { + assert((align & (align-1)) == 0); +//#if defined(TASKING_TBB) // FIXME: have to disable this for now as the TBB allocator itself seems to access some uninitialized value when using valgrind +// return scalable_aligned_malloc(size,align); +//#else + return _mm_malloc(size,align); +//#endif + } + + void alignedFree(void* ptr) + { +//#if defined(TASKING_TBB) +// scalable_aligned_free(ptr); +//#else + _mm_free(ptr); +//#endif + } +} diff --git a/common/malloc.h b/common/malloc.h new file mode 100644 index 0000000000..55c50d8aa0 --- /dev/null +++ b/common/malloc.h @@ -0,0 +1,124 @@ +// ======================================================================== // +// 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.h" + +namespace ospcommon +{ +#define ALIGN_PTR(ptr,alignment) \ + ((((size_t)ptr)+alignment-1)&((size_t)-(ssize_t)alignment)) + + +// #define ALIGNED_STRUCT \ +// void* operator new(size_t size) { return alignedMalloc(size); } \ +// void operator delete(void* ptr) { alignedFree(ptr); } \ +// void* operator new[](size_t size) { return alignedMalloc(size); } \ +// void operator delete[](void* ptr) { alignedFree(ptr); } \ + +// #define ALIGNED_STRUCT_(align) \ +// void* operator new(size_t size) { return alignedMalloc(size,align); } \ +// void operator delete(void* ptr) { alignedFree(ptr); } \ +// void* operator new[](size_t size) { return alignedMalloc(size,align); } \ +// void operator delete[](void* ptr) { alignedFree(ptr); } \ + +// #define ALIGNED_CLASS \ +// public: \ +// ALIGNED_STRUCT \ +// private: + +// #define ALIGNED_CLASS_(align) \ +// public: \ +// ALIGNED_STRUCT_(align) \ +// private: + + /*! aligned allocation */ + OSPCOMMON_INTERFACE void* alignedMalloc(size_t size, size_t align = 64); + OSPCOMMON_INTERFACE void alignedFree(void* ptr); + + // /*! alloca that returns aligned data */ + // template + // __forceinline T* aligned_alloca(size_t elements, const size_t alignment = 64) { + // return (T*)ALIGN_PTR(alloca(elements * sizeof(T) + alignment),alignment); + // } + + // /*! allocator that performs aligned allocations */ + // template + // struct aligned_allocator + // { + // typedef T value_type; + // typedef T* pointer; + // typedef const T* const_pointer; + // typedef T& reference; + // typedef const T& const_reference; + // typedef std::size_t size_type; + // typedef std::ptrdiff_t difference_type; + + // __forceinline pointer allocate( size_type n ) { + // return (pointer) alignedMalloc(n*sizeof(value_type),alignment); + // } + + // __forceinline void deallocate( pointer p, size_type n ) { + // return alignedFree(p); + // } + + // __forceinline void construct( pointer p, const_reference val ) { + // new (p) T(val); + // } + + // __forceinline void destroy( pointer p ) { + // p->~T(); + // } + // }; + + // /*! allocates pages directly from OS */ + // void* os_malloc (size_t bytes, const int additional_flags = 0); + // void* os_reserve(size_t bytes); + // void os_commit (void* ptr, size_t bytes); + // size_t os_shrink (void* ptr, size_t bytesNew, size_t bytesOld); + // void os_free (void* ptr, size_t bytes); + + // /*! allocator that performs OS allocations */ + // template + // struct os_allocator + // { + // typedef T value_type; + // typedef T* pointer; + // typedef const T* const_pointer; + // typedef T& reference; + // typedef const T& const_reference; + // typedef std::size_t size_type; + // typedef std::ptrdiff_t difference_type; + + // __forceinline pointer allocate( size_type n ) { + // return (pointer) os_malloc(n*sizeof(value_type)); + // } + + // __forceinline void deallocate( pointer p, size_type n ) { + // return os_free(p,n*sizeof(value_type)); + // } + + // __forceinline void construct( pointer p, const_reference val ) { + // new (p) T(val); + // } + + // __forceinline void destroy( pointer p ) { + // p->~T(); + // } + // }; +} + diff --git a/common/math.h b/common/math.h new file mode 100644 index 0000000000..291d963232 --- /dev/null +++ b/common/math.h @@ -0,0 +1,308 @@ +// ======================================================================== // +// 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 "platform.h" +#include "constants.h" +#include + +#ifdef _WIN32 +#include +#if (__MSV_VER <= 1700) +namespace std +{ + __forceinline bool isinf ( const float x ) { return !_finite(x); } + __forceinline bool isnan ( const float x ) { return _isnan(x); } + __forceinline bool isfinite (const float x) { return _finite(x); } +} +#endif +#else +#include +#endif + +namespace ospcommon +{ + __forceinline bool isvalid ( const float& v ) { + return (v > -FLT_LARGE) & (v < +FLT_LARGE); + } + + __forceinline int cast_f2i(float f) { + union { float f; int i; } v; v.f = f; return v.i; + } + + __forceinline float cast_i2f(int i) { + union { float f; int i; } v; v.i = i; return v.f; + } + +#ifdef _WIN32 + __forceinline bool finite ( const float x ) { return _finite(x) != 0; } +#endif + + __forceinline float sign ( const float x ) { return x<0?-1.0f:1.0f; } + __forceinline float sqr ( const float x ) { return x*x; } + +#ifndef __MIC__ + __forceinline float rcp ( const float x ) + { + const __m128 a = _mm_set_ss(x); + const __m128 r = _mm_rcp_ps(a); +#if defined(__AVX2__) + return _mm_cvtss_f32(_mm_mul_ps(r,_mm_fnmadd_ps(r, a, _mm_set_ss(2.0f)))); +#else + return _mm_cvtss_f32(_mm_mul_ps(r,_mm_sub_ps(_mm_set_ss(2.0f), _mm_mul_ps(r, a)))); +#endif + } + + __forceinline float signmsk ( const float x ) { + return _mm_cvtss_f32(_mm_and_ps(_mm_set_ss(x),_mm_castsi128_ps(_mm_set1_epi32(0x80000000)))); + } + __forceinline float xorf( const float x, const float y ) { + return _mm_cvtss_f32(_mm_xor_ps(_mm_set_ss(x),_mm_set_ss(y))); + } + __forceinline float andf( const float x, const unsigned y ) { + return _mm_cvtss_f32(_mm_and_ps(_mm_set_ss(x),_mm_castsi128_ps(_mm_set1_epi32(y)))); + } + __forceinline float rsqrt( const float x ) { + const __m128 a = _mm_set_ss(x); + const __m128 r = _mm_rsqrt_ps(a); + const __m128 c = _mm_add_ps(_mm_mul_ps(_mm_set_ps(1.5f, 1.5f, 1.5f, 1.5f), r), + _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(a, _mm_set_ps(-0.5f, -0.5f, -0.5f, -0.5f)), r), _mm_mul_ps(r, r))); + return _mm_cvtss_f32(c); + } +#else + __forceinline float rcp ( const float x ) { return 1.0f/x; } + __forceinline float signmsk ( const float x ) { return cast_i2f(cast_f2i(x)&0x80000000); } + __forceinline float xorf( const float x, const float y ) { return cast_i2f(cast_f2i(x) ^ cast_f2i(y)); } + __forceinline float andf( const float x, const float y ) { return cast_i2f(cast_f2i(x) & cast_f2i(y)); } + __forceinline float rsqrt( const float x ) { return 1.0f/sqrtf(x); } +#endif + +#ifndef _WIN32 + __forceinline float abs ( const float x ) { return ::fabsf(x); } + __forceinline float acos ( const float x ) { return ::acosf (x); } + __forceinline float asin ( const float x ) { return ::asinf (x); } + __forceinline float atan ( const float x ) { return ::atanf (x); } + __forceinline float atan2( const float y, const float x ) { return ::atan2f(y, x); } + __forceinline float cos ( const float x ) { return ::cosf (x); } + __forceinline float cosh ( const float x ) { return ::coshf (x); } + __forceinline float exp ( const float x ) { return ::expf (x); } + __forceinline float fmod ( const float x, const float y ) { return ::fmodf (x, y); } + __forceinline float log ( const float x ) { return ::logf (x); } + __forceinline float log10( const float x ) { return ::log10f(x); } + __forceinline float pow ( const float x, const float y ) { return ::powf (x, y); } + __forceinline float sin ( const float x ) { return ::sinf (x); } + __forceinline float sinh ( const float x ) { return ::sinhf (x); } + __forceinline float sqrt ( const float x ) { return ::sqrtf (x); } + __forceinline float tan ( const float x ) { return ::tanf (x); } + __forceinline float tanh ( const float x ) { return ::tanhf (x); } + __forceinline float floor( const float x ) { return ::floorf (x); } + __forceinline float ceil ( const float x ) { return ::ceilf (x); } +#endif + __forceinline float frac ( const float x ) { return x-floor(x); } + + __forceinline double abs ( const double x ) { return ::fabs(x); } + __forceinline double sign ( const double x ) { return x<0?-1.0:1.0; } + __forceinline double acos ( const double x ) { return ::acos (x); } + __forceinline double asin ( const double x ) { return ::asin (x); } + __forceinline double atan ( const double x ) { return ::atan (x); } + __forceinline double atan2( const double y, const double x ) { return ::atan2(y, x); } + __forceinline double cos ( const double x ) { return ::cos (x); } + __forceinline double cosh ( const double x ) { return ::cosh (x); } + __forceinline double exp ( const double x ) { return ::exp (x); } + __forceinline double fmod ( const double x, const double y ) { return ::fmod (x, y); } + __forceinline double log ( const double x ) { return ::log (x); } + __forceinline double log10( const double x ) { return ::log10(x); } + __forceinline double pow ( const double x, const double y ) { return ::pow (x, y); } + __forceinline double rcp ( const double x ) { return 1.0/x; } + __forceinline double rsqrt( const double x ) { return 1.0/::sqrt(x); } + __forceinline double sin ( const double x ) { return ::sin (x); } + __forceinline double sinh ( const double x ) { return ::sinh (x); } + __forceinline double sqr ( const double x ) { return x*x; } + __forceinline double sqrt ( const double x ) { return ::sqrt (x); } + __forceinline double tan ( const double x ) { return ::tan (x); } + __forceinline double tanh ( const double x ) { return ::tanh (x); } + __forceinline double floor( const double x ) { return ::floor (x); } + __forceinline double ceil ( const double x ) { return ::ceil (x); } + +#if defined(__SSE4_1__) + __forceinline float mini(float a, float b) { + const __m128i ai = _mm_castps_si128(_mm_set_ss(a)); + const __m128i bi = _mm_castps_si128(_mm_set_ss(b)); + const __m128i ci = _mm_min_epi32(ai,bi); + return _mm_cvtss_f32(_mm_castsi128_ps(ci)); + } +#endif + +#if defined(__SSE4_1__) + __forceinline float maxi(float a, float b) { + const __m128i ai = _mm_castps_si128(_mm_set_ss(a)); + const __m128i bi = _mm_castps_si128(_mm_set_ss(b)); + const __m128i ci = _mm_max_epi32(ai,bi); + return _mm_cvtss_f32(_mm_castsi128_ps(ci)); + } +#endif + + __forceinline int min(int a, int b) { return a __forceinline T min(const T& a, const T& b, const T& c) { return min(min(a,b),c); } + template __forceinline T min(const T& a, const T& b, const T& c, const T& d) { return min(min(a,b),min(c,d)); } + template __forceinline T min(const T& a, const T& b, const T& c, const T& d, const T& e) { return min(min(min(a,b),min(c,d)),e); } + + __forceinline int max(int a, int b) { return a __forceinline T max(const T& a, const T& b, const T& c) { return max(max(a,b),c); } + template __forceinline T max(const T& a, const T& b, const T& c, const T& d) { return max(max(a,b),max(c,d)); } + template __forceinline T max(const T& a, const T& b, const T& c, const T& d, const T& e) { return max(max(max(a,b),max(c,d)),e); } + +#if defined(__MACOSX__) + __forceinline ssize_t min(ssize_t a, ssize_t b) { return a __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 sin2cos ( const T& x ) { return sqrt(max(T(zero),T(one)-x*x)); } + template __forceinline T cos2sin ( const T& x ) { return sin2cos(x); } + +#if defined(__AVX2__) + __forceinline float madd ( const float a, const float b, const float c) { return _mm_cvtss_f32(_mm_fmadd_ss(_mm_set_ss(a),_mm_set_ss(b),_mm_set_ss(c))); } + __forceinline float msub ( const float a, const float b, const float c) { return _mm_cvtss_f32(_mm_fmsub_ss(_mm_set_ss(a),_mm_set_ss(b),_mm_set_ss(c))); } + __forceinline float nmadd ( const float a, const float b, const float c) { return _mm_cvtss_f32(_mm_fnmadd_ss(_mm_set_ss(a),_mm_set_ss(b),_mm_set_ss(c))); } + __forceinline float nmsub ( const float a, const float b, const float c) { return _mm_cvtss_f32(_mm_fnmsub_ss(_mm_set_ss(a),_mm_set_ss(b),_mm_set_ss(c))); } +#else + __forceinline float madd ( const float a, const float b, const float c) { return a*b+c; } + __forceinline float msub ( const float a, const float b, const float c) { return a*b-c; } + __forceinline float nmadd ( const float a, const float b, const float c) { return -a*b+c;} + __forceinline float nmsub ( const float a, const float b, const float c) { return -a*b-c; } +#endif + + /*! random functions */ + template T random() { return T(0); } +#if defined(_WIN32) + template<> __forceinline int random() { return int(rand()) ^ (int(rand()) << 8) ^ (int(rand()) << 16); } + template<> __forceinline uint32_t random() { return uint32_t(rand()) ^ (uint32_t(rand()) << 8) ^ (uint32_t(rand()) << 16); } +#else + template<> __forceinline int random() { return int(rand()); } + template<> __forceinline uint32_t random() { return uint32_t(rand()) ^ (uint32_t(rand()) << 16); } +#endif + template<> __forceinline float random() { return rand()/float(RAND_MAX); } + template<> __forceinline double random() { return rand()/double(RAND_MAX); } + +#if _WIN32 + __forceinline double drand48() { + return double(rand())/double(RAND_MAX); + } + + __forceinline void srand48(long seed) { + return srand(seed); + } +#endif + + /*! selects */ + __forceinline bool select(bool s, bool t , bool f) { return s ? t : f; } + __forceinline int select(bool s, int t, int f) { return s ? t : f; } + __forceinline float select(bool s, float t, float f) { return s ? t : f; } + + template + __forceinline T lerp2(const float x0, const float x1, const float x2, const float x3,const T &u, const T &v) { + return (1.0f-u)*(1.0f-v)*x0 + u*(1.0f-v)*x1 + (1.0f-u)*v*x2 + u*v*x3; + } + + // ------------------------------------------------------- + // scalar functors we eventually define for vec's, too + // ------------------------------------------------------- + template + inline T divRoundUp(T a, T b) { return (a+b-1)/b; } + + /*! exchange */ + template __forceinline void xchg ( T& a, T& b ) { const T tmp = a; a = b; b = tmp; } + + /*! bit reverse operation */ + template + __forceinline T bitReverse(const T& vin) + { + T v = vin; + v = ((v >> 1) & 0x55555555) | ((v & 0x55555555) << 1); + v = ((v >> 2) & 0x33333333) | ((v & 0x33333333) << 2); + v = ((v >> 4) & 0x0F0F0F0F) | ((v & 0x0F0F0F0F) << 4); + v = ((v >> 8) & 0x00FF00FF) | ((v & 0x00FF00FF) << 8); + v = ( v >> 16 ) | ( v << 16); + return v; + } + + /*! bit interleave operation */ + template + __forceinline T bitInterleave(const T& xin, const T& yin, const T& zin) + { + T x = xin, y = yin, z = zin; + x = (x | (x << 16)) & 0x030000FF; + x = (x | (x << 8)) & 0x0300F00F; + x = (x | (x << 4)) & 0x030C30C3; + x = (x | (x << 2)) & 0x09249249; + + y = (y | (y << 16)) & 0x030000FF; + y = (y | (y << 8)) & 0x0300F00F; + y = (y | (y << 4)) & 0x030C30C3; + y = (y | (y << 2)) & 0x09249249; + + z = (z | (z << 16)) & 0x030000FF; + z = (z | (z << 8)) & 0x0300F00F; + z = (z | (z << 4)) & 0x030C30C3; + z = (z | (z << 2)) & 0x09249249; + + return x | (y << 1) | (z << 2); + } + + /*! bit interleave operation for 64bit data types*/ + template + __forceinline T bitInterleave64(const T& xin, const T& yin, const T& zin){ + T x = xin & 0x1fffff; + T y = yin & 0x1fffff; + T z = zin & 0x1fffff; + + x = (x | x << 32) & 0x1f00000000ffff; + x = (x | x << 16) & 0x1f0000ff0000ff; + x = (x | x << 8) & 0x100f00f00f00f00f; + x = (x | x << 4) & 0x10c30c30c30c30c3; + x = (x | x << 2) & 0x1249249249249249; + + y = (y | y << 32) & 0x1f00000000ffff; + y = (y | y << 16) & 0x1f0000ff0000ff; + y = (y | y << 8) & 0x100f00f00f00f00f; + y = (y | y << 4) & 0x10c30c30c30c30c3; + y = (y | y << 2) & 0x1249249249249249; + + z = (z | z << 32) & 0x1f00000000ffff; + z = (z | z << 16) & 0x1f0000ff0000ff; + z = (z | z << 8) & 0x100f00f00f00f00f; + z = (z | z << 4) & 0x10c30c30c30c30c3; + z = (z | z << 2) & 0x1249249249249249; + + return x | (y << 1) | (z << 2); + } +} diff --git a/common/platform.h b/common/platform.h new file mode 100644 index 0000000000..8c328c5a73 --- /dev/null +++ b/common/platform.h @@ -0,0 +1,335 @@ +// ======================================================================== // +// 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 + +#define _CRT_SECURE_NO_WARNINGS + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//////////////////////////////////////////////////////////////////////////////// +/// detect platform +//////////////////////////////////////////////////////////////////////////////// + +/* detect 32 or 64 platform */ +#if defined(__x86_64__) || defined(__ia64__) || defined(_M_X64) +#define __X86_64__ +#endif + +/* detect Linux platform */ +#if defined(linux) || defined(__linux__) || defined(__LINUX__) +# if !defined(__LINUX__) +# define __LINUX__ +# endif +# if !defined(__UNIX__) +# define __UNIX__ +# endif +#endif + +/* detect FreeBSD platform */ +#if defined(__FreeBSD__) || defined(__FREEBSD__) +# if !defined(__FREEBSD__) +# define __FREEBSD__ +# endif +# if !defined(__UNIX__) +# define __UNIX__ +# endif +#endif + +/* detect Windows 95/98/NT/2000/XP/Vista/7 platform */ +#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)) && !defined(__CYGWIN__) +# if !defined(__WIN32__) +# define __WIN32__ +# endif +#endif + +/* detect Cygwin platform */ +#if defined(__CYGWIN__) +# if !defined(__UNIX__) +# define __UNIX__ +# endif +#endif + +/* detect MAC OS X platform */ +#if defined(__APPLE__) || defined(MACOSX) || defined(__MACOSX__) +# if !defined(__MACOSX__) +# define __MACOSX__ +# endif +# if !defined(__UNIX__) +# define __UNIX__ +# endif +#endif + +/* try to detect other Unix systems */ +#if defined(__unix__) || defined (unix) || defined(__unix) || defined(_unix) +# if !defined(__UNIX__) +# define __UNIX__ +# endif +#endif + +#if defined (_DEBUG) +#define DEBUG +#endif + +//////////////////////////////////////////////////////////////////////////////// +/// ISA configuration +//////////////////////////////////////////////////////////////////////////////// + +#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__clang__) + #define __SSE__ + #define __SSE2__ +#endif + +#if defined(__WIN32__) && !defined(__clang__) +#if defined(CONFIG_SSE41) + #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) + #define __SSE3__ + #define __SSSE3__ + #define __SSE4_1__ + #endif +#endif +#if defined(CONFIG_SSE42) + #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) + #define __SSE3__ + #define __SSSE3__ + #define __SSE4_1__ + #define __SSE4_2__ + #endif +#endif +#if defined(CONFIG_AVX) + #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) + #define __SSE3__ + #define __SSSE3__ + #define __SSE4_1__ + #define __SSE4_2__ + #if !defined(__AVX__) + #define __AVX__ + #endif + #endif +#endif +#if defined(CONFIG_AVX2) + #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) + #define __SSE3__ + #define __SSSE3__ + #define __SSE4_1__ + #define __SSE4_2__ + #if !defined(__AVX__) + #define __AVX__ + #endif + #if !defined(__AVX2__) + #define __AVX2__ + #endif + #endif +#endif +#if defined(CONFIG_AVX512) + #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) + #define __SSE3__ + #define __SSSE3__ + #define __SSE4_1__ + #define __SSE4_2__ + #if !defined(__AVX__) + #define __AVX__ + #endif + #if !defined(__AVX2__) + #define __AVX2__ + #endif + #if !defined(__AVX512F__) + #define __AVX512F__ + #endif + #endif +#endif + +#endif + +//////////////////////////////////////////////////////////////////////////////// +/// Makros +//////////////////////////////////////////////////////////////////////////////// + +#ifdef __WIN32__ +#undef __noinline +#define __noinline __declspec(noinline) +//#define __forceinline __forceinline +//#define __restrict __restrict +#if defined(__INTEL_COMPILER) +#define __restrict__ __restrict +#else +#define __restrict__ //__restrict // causes issues with MSVC +#endif +#define __thread __declspec(thread) +#define __aligned(...) __declspec(align(__VA_ARGS__)) +//#define __FUNCTION__ __FUNCTION__ +#define debugbreak() __debugbreak() + +#else +#undef __noinline +#undef __forceinline +#define __noinline __attribute__((noinline)) +#define __forceinline inline __attribute__((always_inline)) +//#define __restrict __restrict +//#define __thread __thread +#define __aligned(...) __attribute__((aligned(__VA_ARGS__))) +#define __FUNCTION__ __PRETTY_FUNCTION__ +#define debugbreak() asm ("int $3") +#endif + +#ifdef __GNUC__ + #define MAYBE_UNUSED __attribute__((used)) +#else + #define MAYBE_UNUSED +#endif + +#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) +#define likely(expr) (expr) +#define unlikely(expr) (expr) +#else +#define likely(expr) __builtin_expect((bool)(expr),true ) +#define unlikely(expr) __builtin_expect((bool)(expr),false) +#endif + +//////////////////////////////////////////////////////////////////////////////// +/// Error handling and debugging +//////////////////////////////////////////////////////////////////////////////// + +/* debug printing macros */ +#define STRING(x) #x +#define TOSTRING(x) STRING(x) +#define PING std::cout << __FILE__ << " (" << __LINE__ << "): " << __FUNCTION__ << std::endl +#define PRINT(x) std::cout << STRING(x) << " = " << (x) << std::endl +#define PRINT2(x,y) std::cout << STRING(x) << " = " << (x) << ", " << STRING(y) << " = " << (y) << std::endl +#define PRINT3(x,y,z) std::cout << STRING(x) << " = " << (x) << ", " << STRING(y) << " = " << (y) << ", " << STRING(z) << " = " << (z) << std::endl +#define PRINT4(x,y,z,w) std::cout << STRING(x) << " = " << (x) << ", " << STRING(y) << " = " << (y) << ", " << STRING(z) << " = " << (z) << ", " << STRING(w) << " = " << (w) << std::endl + +#define THROW_RUNTIME_ERROR(str) \ + throw std::runtime_error(std::string(__FILE__) + " (" + std::to_string((long long)__LINE__) + "): " + std::string(str)); + +#if defined(__MIC__) +#define FATAL(x) { std::cerr << "Error in " << __FUNCTION__ << " : " << x << std::endl << std::flush; exit(1); } +#define WARNING(x) std::cerr << "Warning:" << std::string(x) << std::endl +#else +#define FATAL(x) THROW_RUNTIME_ERROR(x) +#define WARNING(x) std::cerr << "Warning:" << std::string(x) << std::endl +#endif + +#define NOT_IMPLEMENTED FATAL(std::string(__FUNCTION__) + " not implemented") + +//////////////////////////////////////////////////////////////////////////////// +/// Basic Types +//////////////////////////////////////////////////////////////////////////////// + +/* default floating-point type */ +typedef float real; + +/* windows does not have ssize_t */ +#if defined(__WIN32__) +#if defined(__X86_64__) +typedef int64_t ssize_t; +#else +typedef int32_t ssize_t; +#endif +#endif + +//////////////////////////////////////////////////////////////////////////////// +/// Disable some compiler warnings +//////////////////////////////////////////////////////////////////////////////// + +#if defined(__INTEL_COMPILER) +#pragma warning(disable:265 ) // floating-point operation result is out of range +#pragma warning(disable:383 ) // value copied to temporary, reference to temporary used +#pragma warning(disable:869 ) // parameter was never referenced +#pragma warning(disable:981 ) // operands are evaluated in unspecified order +#pragma warning(disable:1418) // external function definition with no prior declaration +#pragma warning(disable:1419) // external declaration in primary source file +#pragma warning(disable:1572) // floating-point equality and inequality comparisons are unreliable +#pragma warning(disable:94 ) // the size of an array must be greater than zero +#pragma warning(disable:1599) // declaration hides parameter +#pragma warning(disable:424 ) // extra ";" ignored +#pragma warning(disable:2196) // routine is both "inline" and "noinline" +#pragma warning(disable:177 ) // label was declared but never referenced +#pragma warning(disable:114 ) // function was referenced but not defined +#endif + +#if defined(_MSC_VER) +#pragma warning(disable:4200) // nonstandard extension used : zero-sized array in struct/union +#pragma warning(disable:4800) // forcing value to bool 'true' or 'false' (performance warning) +#pragma warning(disable:4267) // '=' : conversion from 'size_t' to 'unsigned long', possible loss of data +#pragma warning(disable:4244) // 'argument' : conversion from 'ssize_t' to 'unsigned int', possible loss of data +#pragma warning(disable:4355) // 'this' : used in base member initializer list +#pragma warning(disable:391 ) // '<=' : signed / unsigned mismatch +#pragma warning(disable:4018) // '<' : signed / unsigned mismatch +#pragma warning(disable:4305) // 'initializing' : truncation from 'double' to 'float' +#pragma warning(disable:4068) // unknown pragma +#pragma warning(disable:4146) // unary minus operator applied to unsigned type, result still unsigned +#pragma warning(disable:4838) // conversion from 'unsigned int' to 'const int' requires a narrowing conversion) +#pragma warning(disable:4227) // anachronism used : qualifiers on reference are ignored +#endif + +#if defined(__clang__) && !defined(__INTEL_COMPILER) +#pragma clang diagnostic ignored "-Wunknown-pragmas" +#pragma clang diagnostic ignored "-Wunused-variable" +#pragma clang diagnostic ignored "-Wreorder" +#pragma clang diagnostic ignored "-Wmicrosoft" +#pragma clang diagnostic ignored "-Wunused-private-field" +#pragma clang diagnostic ignored "-Wunused-local-typedef" +#pragma clang diagnostic ignored "-Wunused-function" +#endif + +//////////////////////////////////////////////////////////////////////////////// +/// Some macros for static profiling +//////////////////////////////////////////////////////////////////////////////// + +#if defined (__GNUC__) +#define IACA_SSC_MARK( MARK_ID ) \ +__asm__ __volatile__ ( \ + "\n\t movl $"#MARK_ID", %%ebx" \ + "\n\t .byte 0x64, 0x67, 0x90" \ + : : : "memory" ); + +#define IACA_UD_BYTES __asm__ __volatile__ ("\n\t .byte 0x0F, 0x0B"); + +#else +#define IACA_UD_BYTES {__asm _emit 0x0F \ + __asm _emit 0x0B} + +#define IACA_SSC_MARK(x) {__asm mov ebx, x\ + __asm _emit 0x64 \ + __asm _emit 0x67 \ + __asm _emit 0x90 } + +#define IACA_VC64_START __writegsbyte(111, 111); +#define IACA_VC64_END __writegsbyte(222, 222); + +#endif + +#define IACA_START {IACA_UD_BYTES \ + IACA_SSC_MARK(111)} +#define IACA_END {IACA_SSC_MARK(222) \ + IACA_UD_BYTES} + +namespace ospcommon { + +} + diff --git a/common/sysinfo.cpp b/common/sysinfo.cpp new file mode 100644 index 0000000000..44a23029d4 --- /dev/null +++ b/common/sysinfo.cpp @@ -0,0 +1,515 @@ +// ======================================================================== // +// 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. // +// ======================================================================== // + +#include "sysinfo.h" +//#include "string.h" +#include "intrinsics.h" +#include + +//////////////////////////////////////////////////////////////////////////////// +/// All Platforms +//////////////////////////////////////////////////////////////////////////////// + +namespace ospcommon +{ + std::string to_string(long long l) + { + std::stringstream ss; + ss << l; + return ss.str(); + } + + std::string getPlatformName() + { +#if defined(__LINUX__) && !defined(__X86_64__) + return "Linux (32bit)"; +#elif defined(__LINUX__) && defined(__X86_64__) + return "Linux (64bit)"; +#elif defined(__FREEBSD__) && !defined(__X86_64__) + return "FreeBSD (32bit)"; +#elif defined(__FREEBSD__) && defined(__X86_64__) + return "FreeBSD (64bit)"; +#elif defined(__CYGWIN__) && !defined(__X86_64__) + return "Cygwin (32bit)"; +#elif defined(__CYGWIN__) && defined(__X86_64__) + return "Cygwin (64bit)"; +#elif defined(__WIN32__) && !defined(__X86_64__) + return "Windows (32bit)"; +#elif defined(__WIN32__) && defined(__X86_64__) + return "Windows (64bit)"; +#elif defined(__MACOSX__) && !defined(__X86_64__) + return "Mac OS X (32bit)"; +#elif defined(__MACOSX__) && defined(__X86_64__) + return "Mac OS X (64bit)"; +#elif defined(__UNIX__) && !defined(__X86_64__) + return "Unix (32bit)"; +#elif defined(__UNIX__) && defined(__X86_64__) + return "Unix (64bit)"; +#else + return "Unknown"; +#endif + } + + std::string getCompilerName() + { +#if defined(__INTEL_COMPILER) + int icc_mayor = __INTEL_COMPILER / 100 % 100; + int icc_minor = __INTEL_COMPILER % 100; + std::string version = "Intel Compiler "; + version += ospcommon::to_string((long long)icc_mayor); + version += "." + ospcommon::to_string((long long)icc_minor); +#if defined(__INTEL_COMPILER_UPDATE) + version += "." + ospcommon::to_string((long long)__INTEL_COMPILER_UPDATE); +#endif + return version; +#elif defined(__clang__) + return "CLANG " __clang_version__; +#elif defined (__GNUC__) + return "GCC " __VERSION__; +#elif defined(_MSC_VER) + std::string version = ospcommon::to_string((long long)_MSC_FULL_VER); + version.insert(4,"."); + version.insert(9,"."); + version.insert(2,"."); + return "Visual C++ Compiler " + version; +#else + return "Unknown Compiler"; +#endif + } + + std::string getCPUVendor() + { + int cpuinfo[4]; + __cpuid (cpuinfo, 0); + int name[4]; + name[0] = cpuinfo[1]; + name[1] = cpuinfo[3]; + name[2] = cpuinfo[2]; + name[3] = 0; + return (char*)name; + } + + CPUModel getCPUModel() + { + int out[4]; + __cpuid(out, 0); + if (out[0] < 1) return CPU_UNKNOWN; + __cpuid(out, 1); + int family = ((out[0] >> 8) & 0x0F) + ((out[0] >> 20) & 0xFF); + int model = ((out[0] >> 4) & 0x0F) | ((out[0] >> 12) & 0xF0); + if (family == 11) return CPU_KNC; + if (family != 6) return CPU_UNKNOWN; // earlier than P6 + if (model == 0x0E) return CPU_CORE1; // Core 1 + if (model == 0x0F) return CPU_CORE2; // Core 2, 65 nm + if (model == 0x16) return CPU_CORE2; // Core 2, 65 nm Celeron + if (model == 0x17) return CPU_CORE2; // Core 2, 45 nm + if (model == 0x1A) return CPU_CORE_NEHALEM; // Core i7, Nehalem + if (model == 0x1E) return CPU_CORE_NEHALEM; // Core i7 + if (model == 0x1F) return CPU_CORE_NEHALEM; // Core i7 + if (model == 0x2C) return CPU_CORE_NEHALEM; // Core i7, Xeon + if (model == 0x2E) return CPU_CORE_NEHALEM; // Core i7, Xeon + if (model == 0x2A) return CPU_CORE_SANDYBRIDGE; // Core i7, SandyBridge + if (model == 0x2D) return CPU_CORE_SANDYBRIDGE; // Core i7, SandyBridge + if (model == 0x45) return CPU_HASWELL; // Haswell + if (model == 0x3C) return CPU_HASWELL; // Haswell + return CPU_UNKNOWN; + } + + std::string stringOfCPUModel(CPUModel model) + { + switch (model) { + case CPU_KNC : return "Knights Corner"; + case CPU_CORE1 : return "Core1"; + case CPU_CORE2 : return "Core2"; + case CPU_CORE_NEHALEM : return "Nehalem"; + case CPU_CORE_SANDYBRIDGE: return "SandyBridge"; + case CPU_HASWELL : return "Haswell"; + default : return "Unknown CPU"; + } + } + + /* constants to access destination registers of CPUID instruction */ + static const int EAX = 0; + static const int EBX = 1; + static const int ECX = 2; + static const int EDX = 3; + + /* cpuid[eax=0].ecx */ + static const int CPU_FEATURE_BIT_SSE3 = 1 << 0; + static const int CPU_FEATURE_BIT_SSSE3 = 1 << 9; + static const int CPU_FEATURE_BIT_FMA3 = 1 << 12; + static const int CPU_FEATURE_BIT_SSE4_1 = 1 << 19; + static const int CPU_FEATURE_BIT_SSE4_2 = 1 << 20; + static const int CPU_FEATURE_BIT_MOVBE = 1 << 22; + static const int CPU_FEATURE_BIT_POPCNT = 1 << 23; + static const int CPU_FEATURE_BIT_XSAVE = 1 << 26; + static const int CPU_FEATURE_BIT_OXSAVE = 1 << 27; + static const int CPU_FEATURE_BIT_AVX = 1 << 28; + static const int CPU_FEATURE_BIT_F16C = 1 << 29; + static const int CPU_FEATURE_BIT_RDRAND = 1 << 30; + + /* cpuid[eax=1].edx */ + static const int CPU_FEATURE_BIT_SSE = 1 << 25; + static const int CPU_FEATURE_BIT_SSE2 = 1 << 26; + + /* cpuid[eax=0x80000001].ecx */ + static const int CPU_FEATURE_BIT_LZCNT = 1 << 5; + + /* cpuid[eax=7,ecx=0].ebx */ + static const int CPU_FEATURE_BIT_BMI1 = 1 << 3; + static const int CPU_FEATURE_BIT_AVX2 = 1 << 5; + static const int CPU_FEATURE_BIT_BMI2 = 1 << 8; + static const int CPU_FEATURE_BIT_AVX512F = 1 << 16; // AVX512F (foundation) + static const int CPU_FEATURE_BIT_AVX512DQ = 1 << 17; // AVX512DQ + static const int CPU_FEATURE_BIT_AVX512PF = 1 << 26; // AVX512PF (prefetch) + static const int CPU_FEATURE_BIT_AVX512ER = 1 << 27; // AVX512ER (exponential and reciprocal) + static const int CPU_FEATURE_BIT_AVX512CD = 1 << 28; // AVX512CD (conflict detection) + static const int CPU_FEATURE_BIT_AVX512BW = 1 << 30; // AVX512BW + static const int CPU_FEATURE_BIT_AVX512VL = 1 << 31; // AVX512VL (EVEX.128 and EVEX.256 AVX512 instructions) + static const int CPU_FEATURE_BIT_AVX512IFMA = 1 << 21; // AVX512IFMA + + /* cpuid[eax=7,ecx=0].ecx */ + static const int CPU_FEATURE_BIT_AVX512VBMI = 1 << 1; // AVX512VBMI + + __noinline int64_t get_xcr0() + { +#ifdef _WIN32 + int64_t xcr0 = 0; // int64_t is workaround for compiler bug under VS2013, Win32 +#if defined(__INTEL_COMPILER) + xcr0 = _xgetbv(0); +#elif (defined(_MSC_VER) && (_MSC_FULL_VER >= 160040219)) // min VS2010 SP1 compiler is required + xcr0 = _xgetbv(0); +#else +#pragma message ("WARNING: AVX not supported by your compiler.") + xcr0 = 0; +#endif + return xcr0; + +#else + + int xcr0 = 0; +#if defined(__INTEL_COMPILER) + __asm__ ("xgetbv" : "=a" (xcr0) : "c" (0) : "%edx" ); +#elif ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) && (!defined(__MACOSX__) || defined(__TARGET_AVX__) || defined(__TARGET_AVX2__)) + __asm__ ("xgetbv" : "=a" (xcr0) : "c" (0) : "%edx" ); +#elif ((__clang_major__ > 3) || (__clang_major__ == 3 && __clang_minor__ >= 1)) + __asm__ ("xgetbv" : "=a" (xcr0) : "c" (0) : "%edx" ); +#else +#pragma message ("WARNING: AVX not supported by your compiler.") + xcr0 = 0; +#endif + return xcr0; +#endif + } + + int getCPUFeatures() + { + /* cache CPU features access */ + static int cpu_features = 0; + if (cpu_features) + return cpu_features; + + /* get number of CPUID leaves */ + int cpuid_leaf0[4]; + __cpuid(cpuid_leaf0, 0x00000000); + unsigned nIds = cpuid_leaf0[EAX]; + + /* get number of extended CPUID leaves */ + int cpuid_leafe[4]; + __cpuid(cpuid_leafe, 0x80000000); + unsigned nExIds = cpuid_leafe[EAX]; + + /* get CPUID leaves for EAX = 1,7, and 0x80000001 */ + int cpuid_leaf_1[4] = { 0,0,0,0 }; + int cpuid_leaf_7[4] = { 0,0,0,0 }; + int cpuid_leaf_e1[4] = { 0,0,0,0 }; + if (nIds >= 1) __cpuid (cpuid_leaf_1,0x00000001); +#if _WIN32 +#if _MSC_VER && (_MSC_FULL_VER < 160040219) +#else + if (nIds >= 7) __cpuidex(cpuid_leaf_7,0x00000007,0); +#endif +#else + if (nIds >= 7) __cpuid_count(cpuid_leaf_7,0x00000007,0); +#endif + if (nExIds >= 0x80000001) __cpuid(cpuid_leaf_e1,0x80000001); + + /* detect if OS saves XMM, YMM, and ZMM states */ + bool xmm_enabled = true; + bool ymm_enabled = false; + bool zmm_enabled = false; + if (cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_OXSAVE) { + int64_t xcr0 = get_xcr0(); + xmm_enabled = ((xcr0 & 0x02) == 0x02); /* check if xmm are enabled in XCR0 */ + ymm_enabled = xmm_enabled && ((xcr0 & 0x04) == 0x04); /* check if ymm state are enabled in XCR0 */ + zmm_enabled = ymm_enabled && ((xcr0 & 0xE0) == 0xE0); /* check if OPMASK state, upper 256-bit of ZMM0-ZMM15 and ZMM16-ZMM31 state are enabled in XCR0 */ + } + + if (xmm_enabled && cpuid_leaf_1[EDX] & CPU_FEATURE_BIT_SSE ) cpu_features |= CPU_FEATURE_SSE; + if (xmm_enabled && cpuid_leaf_1[EDX] & CPU_FEATURE_BIT_SSE2 ) cpu_features |= CPU_FEATURE_SSE2; + if (xmm_enabled && cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_SSE3 ) cpu_features |= CPU_FEATURE_SSE3; + if (xmm_enabled && cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_SSSE3 ) cpu_features |= CPU_FEATURE_SSSE3; + if (xmm_enabled && cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_SSE4_1) cpu_features |= CPU_FEATURE_SSE41; + if (xmm_enabled && cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_SSE4_2) cpu_features |= CPU_FEATURE_SSE42; + if ( cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_POPCNT) cpu_features |= CPU_FEATURE_POPCNT; + if (ymm_enabled && cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_AVX ) cpu_features |= CPU_FEATURE_AVX; + if (xmm_enabled && cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_F16C ) cpu_features |= CPU_FEATURE_F16C; + if ( cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_RDRAND) cpu_features |= CPU_FEATURE_RDRAND; + if (ymm_enabled && cpuid_leaf_7[EBX] & CPU_FEATURE_BIT_AVX2 ) cpu_features |= CPU_FEATURE_AVX2; + if (ymm_enabled && cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_FMA3 ) cpu_features |= CPU_FEATURE_FMA3; + if (cpuid_leaf_e1[ECX] & CPU_FEATURE_BIT_LZCNT) cpu_features |= CPU_FEATURE_LZCNT; + if (cpuid_leaf_7 [EBX] & CPU_FEATURE_BIT_BMI1 ) cpu_features |= CPU_FEATURE_BMI1; + if (cpuid_leaf_7 [EBX] & CPU_FEATURE_BIT_BMI2 ) cpu_features |= CPU_FEATURE_BMI2; + + if (zmm_enabled && cpuid_leaf_7[EBX] & CPU_FEATURE_BIT_AVX512F ) cpu_features |= CPU_FEATURE_AVX512F; + if (zmm_enabled && cpuid_leaf_7[EBX] & CPU_FEATURE_BIT_AVX512DQ) cpu_features |= CPU_FEATURE_AVX512DQ; + if (zmm_enabled && cpuid_leaf_7[EBX] & CPU_FEATURE_BIT_AVX512PF) cpu_features |= CPU_FEATURE_AVX512PF; + if (zmm_enabled && cpuid_leaf_7[EBX] & CPU_FEATURE_BIT_AVX512ER) cpu_features |= CPU_FEATURE_AVX512ER; + if (zmm_enabled && cpuid_leaf_7[EBX] & CPU_FEATURE_BIT_AVX512CD) cpu_features |= CPU_FEATURE_AVX512CD; + if (zmm_enabled && cpuid_leaf_7[EBX] & CPU_FEATURE_BIT_AVX512BW) cpu_features |= CPU_FEATURE_AVX512BW; + if (zmm_enabled && cpuid_leaf_7[EBX] & CPU_FEATURE_BIT_AVX512IFMA) cpu_features |= CPU_FEATURE_AVX512IFMA; + if (ymm_enabled && cpuid_leaf_7[EBX] & CPU_FEATURE_BIT_AVX512VL) cpu_features |= CPU_FEATURE_AVX512VL; // on purpose ymm_enabled! + if (zmm_enabled && cpuid_leaf_7[ECX] & CPU_FEATURE_BIT_AVX512VBMI) cpu_features |= CPU_FEATURE_AVX512VBMI; + +#if defined(__MIC__) + cpu_features |= CPU_FEATURE_KNC; +#endif + return cpu_features; + } + + std::string stringOfCPUFeatures(int features) + { + std::string str; + if (features & CPU_FEATURE_SSE ) str += "SSE "; + if (features & CPU_FEATURE_SSE2 ) str += "SSE2 "; + if (features & CPU_FEATURE_SSE3 ) str += "SSE3 "; + if (features & CPU_FEATURE_SSSE3 ) str += "SSSE3 "; + if (features & CPU_FEATURE_SSE41 ) str += "SSE41 "; + if (features & CPU_FEATURE_SSE42 ) str += "SSE42 "; + if (features & CPU_FEATURE_POPCNT) str += "POPCNT "; + if (features & CPU_FEATURE_AVX ) str += "AVX "; + if (features & CPU_FEATURE_F16C ) str += "F16C "; + if (features & CPU_FEATURE_RDRAND) str += "RDRAND "; + if (features & CPU_FEATURE_AVX2 ) str += "AVX2 "; + if (features & CPU_FEATURE_FMA3 ) str += "FMA3 "; + if (features & CPU_FEATURE_LZCNT ) str += "LZCNT "; + if (features & CPU_FEATURE_BMI1 ) str += "BMI1 "; + if (features & CPU_FEATURE_BMI2 ) str += "BMI2 "; + if (features & CPU_FEATURE_KNC ) str += "KNC "; + if (features & CPU_FEATURE_AVX512F) str += "AVX512F "; + if (features & CPU_FEATURE_AVX512DQ) str += "AVX512DQ "; + if (features & CPU_FEATURE_AVX512PF) str += "AVX512PF "; + if (features & CPU_FEATURE_AVX512ER) str += "AVX512ER "; + if (features & CPU_FEATURE_AVX512CD) str += "AVX512CD "; + if (features & CPU_FEATURE_AVX512BW) str += "AVX512BW "; + if (features & CPU_FEATURE_AVX512VL) str += "AVX512VL "; + if (features & CPU_FEATURE_AVX512IFMA) str += "AVX512IFMA "; + if (features & CPU_FEATURE_AVX512VBMI) str += "AVX512VBMI "; + return str; + } + + std::string stringOfISA (int isa) + { + if (isa == SSE) return "SSE"; + if (isa == SSE2) return "SSE2"; + if (isa == SSE3) return "SSE3"; + if (isa == SSSE3) return "SSSE3"; + if (isa == SSE41) return "SSE4_1"; + if (isa == SSE42) return "SSE4_2"; + if (isa == AVX) return "AVX"; + if (isa == AVXI) return "AVXI"; + if (isa == AVX2) return "AVX2"; + if (isa == KNC) return "KNC"; + if (isa == AVX512KNL) return "AVX512KNL"; + return "UNKNOWN"; + } +} + +//////////////////////////////////////////////////////////////////////////////// +/// Windows Platform +//////////////////////////////////////////////////////////////////////////////// + +#ifdef _WIN32 + +#define WIN32_LEAN_AND_MEAN +#include + +namespace ospcommon +{ + std::string getExecutableFileName() { + char filename[1024]; + if (!GetModuleFileName(nullptr, filename, sizeof(filename))) return std::string(); + return std::string(filename); + } + + size_t getNumberOfLogicalThreads() + { + static int nThreads = -1; + if (nThreads != -1) return nThreads; + + OSVERSIONINFO osvi; + ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&osvi); + + typedef WORD (WINAPI *GetActiveProcessorGroupCountFunc)(); + typedef DWORD (WINAPI *GetActiveProcessorCountFunc)(WORD); + HMODULE hlib = LoadLibrary("Kernel32"); + GetActiveProcessorGroupCountFunc pGetActiveProcessorGroupCount = (GetActiveProcessorGroupCountFunc)GetProcAddress(hlib, "GetActiveProcessorGroupCount"); + GetActiveProcessorCountFunc pGetActiveProcessorCount = (GetActiveProcessorCountFunc) GetProcAddress(hlib, "GetActiveProcessorCount"); + + if (pGetActiveProcessorGroupCount && pGetActiveProcessorCount && + ((osvi.dwMajorVersion > 6) || ((osvi.dwMajorVersion == 6) && (osvi.dwMinorVersion >= 1)))) + { + int groups = pGetActiveProcessorGroupCount(); + int totalProcessors = 0; + for (int i = 0; i < groups; i++) + totalProcessors += pGetActiveProcessorCount(i); + nThreads = totalProcessors; + } + else + { + SYSTEM_INFO sysinfo; + GetSystemInfo(&sysinfo); + nThreads = sysinfo.dwNumberOfProcessors; + } + return nThreads; + } + + int getTerminalWidth() + { + HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); + if (handle == INVALID_HANDLE_VALUE) return 80; + CONSOLE_SCREEN_BUFFER_INFO info = { { 0 } }; + GetConsoleScreenBufferInfo(handle, &info); + return info.dwSize.X; + } + + double getSeconds() { + LARGE_INTEGER freq, val; + QueryPerformanceFrequency(&freq); + QueryPerformanceCounter(&val); + return (double)val.QuadPart / (double)freq.QuadPart; + } +} +#endif + +//////////////////////////////////////////////////////////////////////////////// +/// Linux Platform +//////////////////////////////////////////////////////////////////////////////// + +#ifdef __LINUX__ + +#include +#include + +namespace ospcommon +{ + std::string getExecutableFileName() + { + char pid[32]; sprintf(pid, "/proc/%d/exe", getpid()); + char buf[1024]; + int bytes = readlink(pid, buf, sizeof(buf)-1); + if (bytes != -1) buf[bytes] = '\0'; + return std::string(buf); + } +} + +#endif + +//////////////////////////////////////////////////////////////////////////////// +/// Mac OS X Platform +//////////////////////////////////////////////////////////////////////////////// + +#ifdef __MACOSX__ + +#include + +namespace ospcommon +{ + std::string getExecutableFileName() + { + char buf[1024]; + uint32_t size = sizeof(buf); + if (_NSGetExecutablePath(buf, &size) != 0) return std::string(); + return std::string(buf); + } +} + +#endif + +//////////////////////////////////////////////////////////////////////////////// +/// Unix Platform +//////////////////////////////////////////////////////////////////////////////// + +#if defined(__UNIX__) + +#include +#include +#include + +namespace ospcommon +{ + size_t getNumberOfLogicalThreads() { + static int nThreads = -1; + if (nThreads == -1) nThreads = sysconf(_SC_NPROCESSORS_CONF); + return nThreads; + } + + int getTerminalWidth() + { + struct winsize info; + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &info) < 0) return 80; + return info.ws_col; + } + +#if defined(__MIC__) + + static double getFrequencyInMHz() + { + struct timeval tvstart, tvstop; + unsigned long long int cycles[2]; + + gettimeofday(&tvstart, nullptr); + cycles[0] = rdtsc(); + gettimeofday(&tvstart, nullptr); + usleep(250000); + gettimeofday(&tvstop, nullptr); + cycles[1] = rdtsc(); + gettimeofday(&tvstop, nullptr); + + const unsigned long microseconds = ((tvstop.tv_sec-tvstart.tv_sec)*1000000) + (tvstop.tv_usec-tvstart.tv_usec); + unsigned long mhz = (unsigned long) (cycles[1]-cycles[0]) / microseconds; + + //std::cout << "MIC frequency is " << mhz << " MHz" << std::endl; + return (double)mhz; + } + + static double micFrequency = getFrequencyInMHz(); + +#endif + + double getSeconds() { +#if !defined(__MIC__) + struct timeval tp; gettimeofday(&tp,NULL); + return double(tp.tv_sec) + double(tp.tv_usec)/1E6; +#else + return double(rdtsc()) / double(micFrequency*1E6); +#endif + } +} +#endif + diff --git a/common/sysinfo.h b/common/sysinfo.h new file mode 100644 index 0000000000..81c685fae4 --- /dev/null +++ b/common/sysinfo.h @@ -0,0 +1,178 @@ +// ======================================================================== // +// 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 + +#define CACHELINE_SIZE 64 + +#if !defined(PAGE_SIZE) + #define PAGE_SIZE 4096 +#endif + +#define MAX_THREADS 512 +#define MAX_MIC_CORES (MAX_THREADS/4) + +#include "common.h" + +/* define isa namespace and ISA bitvector */ +#if defined(__MIC__) +# define isa knc +# define ISA KNC +# define ISA_STR "KNC" +#elif defined (__AVX512F__) +# define isa avx512 +# define ISA AVX512KNL +# define ISA_STR "AVX512KNL" +#elif defined (__AVX2__) +# define isa avx2 +# define ISA AVX2 +# define ISA_STR "AVX2" +#elif defined(__AVXI__) +# define isa avxi +# define ISA AVXI +# define ISA_STR "AVXI" +#elif defined(__AVX__) +# define isa avx +# define ISA AVX +# define ISA_STR "AVX" +#elif defined (__SSE4_2__) +# define isa sse42 +# define ISA SSE42 +# define ISA_STR "SSE4.2" +#elif defined (__SSE4_1__) +# define isa sse41 +# define ISA SSE41 +# define ISA_STR "SSE4.1" +#elif defined(__SSSE3__) +# define isa ssse3 +# define ISA SSSE3 +# define ISA_STR "SSSE3" +#elif defined(__SSE3__) +# define isa sse3 +# define ISA SSE3 +# define ISA_STR "SSE3" +#elif defined(__SSE2__) +# define isa sse2 +# define ISA SSE2 +# define ISA_STR "SSE2" +#elif defined(__SSE__) +# define isa sse +# define ISA SSE +# define ISA_STR "SSE" +#else +#error Unknown ISA +#endif + +#if defined (__MACOSX__) +#if defined (__INTEL_COMPILER) +#define DEFAULT_ISA SSSE3 +#else +#define DEFAULT_ISA SSE3 +#endif +#else +#define DEFAULT_ISA SSE2 +#endif + +namespace ospcommon +{ + enum CPUModel { + CPU_UNKNOWN, + CPU_CORE1, + CPU_CORE2, + CPU_CORE_NEHALEM, + CPU_CORE_SANDYBRIDGE, + CPU_HASWELL, + CPU_KNC, + CPU_KNL + }; + + /*! get the full path to the running executable */ + OSPCOMMON_INTERFACE std::string getExecutableFileName(); + + /*! return platform name */ + OSPCOMMON_INTERFACE std::string getPlatformName(); + + /*! get the full name of the compiler */ + OSPCOMMON_INTERFACE std::string getCompilerName(); + + /*! return the name of the CPU */ + OSPCOMMON_INTERFACE std::string getCPUVendor(); + + /*! get microprocessor model */ + OSPCOMMON_INTERFACE CPUModel getCPUModel(); + + /*! converts CPU model into string */ + OSPCOMMON_INTERFACE std::string stringOfCPUModel(CPUModel model); + + /*! CPU features */ + static const int CPU_FEATURE_SSE = 1 << 0; + static const int CPU_FEATURE_SSE2 = 1 << 1; + static const int CPU_FEATURE_SSE3 = 1 << 2; + static const int CPU_FEATURE_SSSE3 = 1 << 3; + static const int CPU_FEATURE_SSE41 = 1 << 4; + static const int CPU_FEATURE_SSE42 = 1 << 5; + static const int CPU_FEATURE_POPCNT = 1 << 6; + static const int CPU_FEATURE_AVX = 1 << 7; + static const int CPU_FEATURE_F16C = 1 << 8; + static const int CPU_FEATURE_RDRAND = 1 << 9; + static const int CPU_FEATURE_AVX2 = 1 << 10; + static const int CPU_FEATURE_FMA3 = 1 << 11; + static const int CPU_FEATURE_LZCNT = 1 << 12; + static const int CPU_FEATURE_BMI1 = 1 << 13; + static const int CPU_FEATURE_BMI2 = 1 << 14; + static const int CPU_FEATURE_KNC = 1 << 15; + static const int CPU_FEATURE_AVX512F = 1 << 16; + static const int CPU_FEATURE_AVX512DQ = 1 << 17; + static const int CPU_FEATURE_AVX512PF = 1 << 18; + static const int CPU_FEATURE_AVX512ER = 1 << 19; + static const int CPU_FEATURE_AVX512CD = 1 << 20; + static const int CPU_FEATURE_AVX512BW = 1 << 21; + static const int CPU_FEATURE_AVX512VL = 1 << 22; + static const int CPU_FEATURE_AVX512IFMA = 1 << 23; + static const int CPU_FEATURE_AVX512VBMI = 1 << 24; + + /*! get CPU features */ + OSPCOMMON_INTERFACE int getCPUFeatures(); + + /*! convert CPU features into a string */ + OSPCOMMON_INTERFACE std::string stringOfCPUFeatures(int features); + + /*! ISAs */ + static const int SSE = CPU_FEATURE_SSE; + static const int SSE2 = SSE | CPU_FEATURE_SSE2; + static const int SSE3 = SSE2 | CPU_FEATURE_SSE3; + static const int SSSE3 = SSE3 | CPU_FEATURE_SSSE3; + static const int SSE41 = SSSE3 | CPU_FEATURE_SSE41; + static const int SSE42 = SSE41 | CPU_FEATURE_SSE42 | CPU_FEATURE_POPCNT; + static const int AVX = SSE42 | CPU_FEATURE_AVX; + static const int AVXI = AVX | CPU_FEATURE_F16C | CPU_FEATURE_RDRAND; + static const int AVX2 = AVXI | CPU_FEATURE_AVX2 | CPU_FEATURE_FMA3 | CPU_FEATURE_BMI1 | CPU_FEATURE_BMI2 | CPU_FEATURE_LZCNT; + static const int KNC = CPU_FEATURE_KNC; + static const int AVX512F = AVX2 | CPU_FEATURE_AVX512F; // FIXME: shouldn't we also test for the CPU_FEATURE_AVX512VL flag? + static const int AVX512KNL = AVX512F | CPU_FEATURE_AVX512PF | CPU_FEATURE_AVX512ER | CPU_FEATURE_AVX512CD; + + /*! converts ISA bitvector into a string */ + OSPCOMMON_INTERFACE std::string stringOfISA(int features); + + /*! return the number of logical threads of the system */ + OSPCOMMON_INTERFACE size_t getNumberOfLogicalThreads(); + + /*! returns the size of the terminal window in characters */ + OSPCOMMON_INTERFACE int getTerminalWidth(); + + /*! returns performance counter in seconds */ + OSPCOMMON_INTERFACE double getSeconds(); +} diff --git a/common/thread.cpp b/common/thread.cpp new file mode 100644 index 0000000000..13a57a4bb8 --- /dev/null +++ b/common/thread.cpp @@ -0,0 +1,336 @@ +// ======================================================================== // +// 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. // +// ======================================================================== // + +#include "thread.h" +#include "sysinfo.h" + +#include +#include + +#if defined(PTHREADS_WIN32) +#pragma comment (lib, "pthreadVC.lib") +#endif + +//////////////////////////////////////////////////////////////////////////////// +/// Windows Platform +//////////////////////////////////////////////////////////////////////////////// + +#ifdef _WIN32 + +#define WIN32_LEAN_AND_MEAN +#include + +namespace ospcommon +{ + /*! set the affinity of a given thread */ + void setAffinity(HANDLE thread, ssize_t affinity) + { + OSVERSIONINFO osvi; + ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&osvi); + typedef WORD (WINAPI *GetActiveProcessorGroupCountFunc)(); + typedef DWORD (WINAPI *GetActiveProcessorCountFunc)(WORD); + typedef BOOL (WINAPI *SetThreadGroupAffinityFunc)(HANDLE, const GROUP_AFFINITY *, PGROUP_AFFINITY); + typedef BOOL (WINAPI *SetThreadIdealProcessorExFunc)(HANDLE, PPROCESSOR_NUMBER, PPROCESSOR_NUMBER); + HMODULE hlib = LoadLibrary("Kernel32"); + GetActiveProcessorGroupCountFunc pGetActiveProcessorGroupCount = (GetActiveProcessorGroupCountFunc)GetProcAddress(hlib, "GetActiveProcessorGroupCount"); + GetActiveProcessorCountFunc pGetActiveProcessorCount = (GetActiveProcessorCountFunc)GetProcAddress(hlib, "GetActiveProcessorCount"); + SetThreadGroupAffinityFunc pSetThreadGroupAffinity = (SetThreadGroupAffinityFunc)GetProcAddress(hlib, "SetThreadGroupAffinity"); + SetThreadIdealProcessorExFunc pSetThreadIdealProcessorEx = (SetThreadIdealProcessorExFunc)GetProcAddress(hlib, "SetThreadIdealProcessorEx"); + if (pGetActiveProcessorGroupCount && pGetActiveProcessorCount && pSetThreadGroupAffinity && pSetThreadIdealProcessorEx && + ((osvi.dwMajorVersion > 6) || ((osvi.dwMajorVersion == 6) && (osvi.dwMinorVersion >= 1)))) + { + int groups = pGetActiveProcessorGroupCount(); + int totalProcessors = 0, group = 0, number = 0; + for (int i = 0; i affinity) { + group = i; + number = (int)affinity - totalProcessors; + break; + } + totalProcessors += processors; + } + + GROUP_AFFINITY groupAffinity; + groupAffinity.Group = (WORD)group; + groupAffinity.Mask = (KAFFINITY)(uint64_t(1) << number); + groupAffinity.Reserved[0] = 0; + groupAffinity.Reserved[1] = 0; + groupAffinity.Reserved[2] = 0; + if (!pSetThreadGroupAffinity(thread, &groupAffinity, NULL)) + WARNING("SetThreadGroupAffinity failed"); // on purpose only a warning + + PROCESSOR_NUMBER processorNumber; + processorNumber.Group = group; + processorNumber.Number = number; + processorNumber.Reserved = 0; + if (!pSetThreadIdealProcessorEx(thread, &processorNumber, NULL)) + WARNING("SetThreadIdealProcessorEx failed"); // on purpose only a warning + } + else + { + if (!SetThreadAffinityMask(thread, DWORD_PTR(uint64_t(1) << affinity))) + WARNING("SetThreadAffinityMask failed"); // on purpose only a warning + if (SetThreadIdealProcessor(thread, (DWORD)affinity) == (DWORD)-1) + WARNING("SetThreadIdealProcessor failed"); // on purpose only a warning + } + } + + /*! set affinity of the calling thread */ + void setAffinity(ssize_t affinity) { + setAffinity(GetCurrentThread(), affinity); + } + + struct ThreadStartupData + { + public: + ThreadStartupData (thread_func f, void* arg) + : f(f), arg(arg) {} + public: + thread_func f; + void* arg; + }; + + static void* threadStartup(ThreadStartupData* parg) + { + _mm_setcsr(_mm_getcsr() | /*FTZ:*/ (1<<15) | /*DAZ:*/ (1<<6)); + parg->f(parg->arg); + delete parg; + return NULL; + } + +#if !defined(PTHREADS_WIN32) + + /*! creates a hardware thread running on specific core */ + thread_t createThread(thread_func f, void* arg, size_t stack_size, ssize_t threadID) + { + HANDLE thread = CreateThread(NULL, stack_size, (LPTHREAD_START_ROUTINE)threadStartup, new ThreadStartupData(f,arg), 0, NULL); + if (thread == NULL) throw std::runtime_error("ospcommon::CreateThread failed"); + if (threadID >= 0) setAffinity(thread, threadID); + return thread_t(thread); + } + + /*! the thread calling this function gets yielded */ + void yield() { + SwitchToThread(); + } + + /*! waits until the given thread has terminated */ + void join(thread_t tid) { + WaitForSingleObject(HANDLE(tid), INFINITE); + CloseHandle(HANDLE(tid)); + } + + /*! destroy a hardware thread by its handle */ + void destroyThread(thread_t tid) { + TerminateThread(HANDLE(tid),0); + CloseHandle(HANDLE(tid)); + } + + // /*! creates thread local storage */ + // tls_t createTls() { + // return tls_t(size_t(TlsAlloc())); + // } + + // /*! set the thread local storage pointer */ + // void setTls(tls_t tls, void* const ptr) { + // TlsSetValue(DWORD(size_t(tls)), ptr); + // } + + // /*! return the thread local storage pointer */ + // void* getTls(tls_t tls) { + // return TlsGetValue(DWORD(size_t(tls))); + // } + + // /*! destroys thread local storage identifier */ + // void destroyTls(tls_t tls) { + // TlsFree(DWORD(size_t(tls))); + // } +#endif +} + +#endif + +//////////////////////////////////////////////////////////////////////////////// +/// Linux Platform +//////////////////////////////////////////////////////////////////////////////// + +#if defined(__LINUX__) +namespace ospcommon +{ + /*! set affinity of the calling thread */ + void setAffinity(ssize_t affinity) + { + cpu_set_t cset; + CPU_ZERO(&cset); + CPU_SET(affinity, &cset); + + if (pthread_setaffinity_np(pthread_self(), sizeof(cset), &cset) != 0) + WARNING("pthread_setaffinity_np failed"); // on purpose only a warning + } +} +#endif + +//////////////////////////////////////////////////////////////////////////////// +/// MacOSX Platform +//////////////////////////////////////////////////////////////////////////////// + +#if defined(__MACOSX__) + +#include +#include +#include + +namespace ospcommon +{ + /*! set affinity of the calling thread */ + void setAffinity(ssize_t affinity) + { + thread_affinity_policy ap; + ap.affinity_tag = affinity; + if (thread_policy_set(mach_thread_self(),THREAD_AFFINITY_POLICY,(thread_policy_t)&ap,THREAD_AFFINITY_POLICY_COUNT) != KERN_SUCCESS) + WARNING("setting thread affinity failed"); // on purpose only a warning + } +} +#endif + +//////////////////////////////////////////////////////////////////////////////// +/// Unix Platform +//////////////////////////////////////////////////////////////////////////////// + +#if defined(__UNIX__) || defined(PTHREADS_WIN32) + +#include +#include + +#if defined(__USE_NUMA__) +#include +#endif + +namespace ospcommon +{ + struct ThreadStartupData + { + public: + ThreadStartupData (thread_func f, void* arg, int affinity) + : f(f), arg(arg), affinity(affinity) {} + public: + thread_func f; + void* arg; + ssize_t affinity; + }; + + static void* threadStartup(ThreadStartupData* parg) + { + _mm_setcsr(_mm_getcsr() | /*FTZ:*/ (1<<15) | /*DAZ:*/ (1<<6)); + +#if !defined(__LINUX__) + if (parg->affinity >= 0) + setAffinity(parg->affinity); +#endif + + parg->f(parg->arg); + delete parg; + return NULL; + } + + /*! creates a hardware thread running on specific core */ + thread_t createThread(thread_func f, void* arg, size_t stack_size, ssize_t threadID) + { +#ifdef __MIC__ + threadID++; // start counting at 1 on MIC +#endif + + /* set stack size */ + pthread_attr_t attr; + pthread_attr_init(&attr); + if (stack_size > 0) pthread_attr_setstacksize (&attr, stack_size); + + /* create thread */ + pthread_t* tid = new pthread_t; + if (pthread_create(tid,&attr,(void*(*)(void*))threadStartup,new ThreadStartupData(f,arg,threadID)) != 0) + throw std::runtime_error("ospcommon::pthread_create failed"); + + /* set affinity */ +#if defined(__LINUX__) + if (threadID >= 0) { + cpu_set_t cset; + CPU_ZERO(&cset); + CPU_SET(threadID, &cset); + if (pthread_setaffinity_np(*tid,sizeof(cpu_set_t),&cset)) + WARNING("pthread_setaffinity_np failed"); // on purpose only a warning + } +#endif + + return thread_t(tid); + } + + /*! the thread calling this function gets yielded */ + void yield() { + sched_yield(); + } + + /*! waits until the given thread has terminated */ + void join(thread_t tid) { + if (pthread_join(*(pthread_t*)tid, NULL) != 0) + throw std::runtime_error("ospcommon::pthread_join failed"); + delete (pthread_t*)tid; + } + + /*! destroy a hardware thread by its handle */ + void destroyThread(thread_t tid) { + pthread_cancel(*(pthread_t*)tid); + delete (pthread_t*)tid; + } + + // /*! creates thread local storage */ + // tls_t createTls() { + // static int cntr = 0; + // pthread_key_t* key = new pthread_key_t; + // if (pthread_key_create(key,NULL) != 0) + // FATAL("pthread_key_create failed"); + + // return tls_t(key); + // } + + // /*! return the thread local storage pointer */ + // void* getTls(tls_t tls) + // { + // assert(tls); + // return pthread_getspecific(*(pthread_key_t*)tls); + // } + + // /*! set the thread local storage pointer */ + // void setTls(tls_t tls, void* const ptr) + // { + // assert(tls); + // if (pthread_setspecific(*(pthread_key_t*)tls, ptr) != 0) + // FATAL("pthread_setspecific failed"); + // } + + // /*! destroys thread local storage identifier */ + // void destroyTls(tls_t tls) + // { + // assert(tls); + // if (pthread_key_delete(*(pthread_key_t*)tls) != 0) + // FATAL("pthread_key_delete failed"); + // delete (pthread_key_t*)tls; + // } +} + +#endif diff --git a/common/thread.h b/common/thread.h new file mode 100644 index 0000000000..2b81271118 --- /dev/null +++ b/common/thread.h @@ -0,0 +1,124 @@ +// ======================================================================== // +// 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.h" + +namespace ospcommon +{ + /*! type for thread */ + typedef struct opaque_thread_t* thread_t; + + /*! signature of thread start function */ + typedef void (*thread_func)(void*); + + /*! creates a hardware thread running on specific logical thread */ + OSPCOMMON_INTERFACE thread_t createThread(thread_func f, void* arg, size_t + stack_size = 0, ssize_t threadID = -1); + + /*! set affinity of the calling thread */ + OSPCOMMON_INTERFACE void setAffinity(ssize_t affinity); + + /*! the thread calling this function gets yielded */ + OSPCOMMON_INTERFACE void yield(); + + /*! waits until the given thread has terminated */ + OSPCOMMON_INTERFACE void join(thread_t tid); + + /*! destroy handle of a thread */ + OSPCOMMON_INTERFACE void destroyThread(thread_t tid); + + // /*! type for handle to thread local storage */ + // typedef struct opaque_tls_t* tls_t; + + // /*! creates thread local storage */ + // tls_t createTls(); + + // /*! set thea thread local storage pointer */ + // void setTls(tls_t tls, void* const ptr); + + // /*! return the thread local storage pointer */ + // void* getTls(tls_t tls); + + // /*! destroys thread local storage identifier */ + // void destroyTls(tls_t tls); + + +// /*! manages thread local variables */ +// template +// struct ThreadLocalData +// { +// public: + +// __forceinline ThreadLocalData (void* init) +// : ptr(nullptr), init(init) {} + +// __forceinline ~ThreadLocalData () { +// clear(); +// } + +// __forceinline void clear() +// { +// if (ptr) destroyTls(ptr); ptr = nullptr; +// for (size_t i=0; ireset(); +// } + +// __forceinline Type* get() const +// { +// if (ptr == nullptr) { +// Lock lock(mutex); +// if (ptr == nullptr) ptr = createTls(); +// } +// Type* lptr = (Type*) getTls(ptr); +// if (unlikely(lptr == nullptr)) { +// setTls(ptr,lptr = new Type(init)); +// Lock lock(mutex); +// threads.push_back(lptr); +// } +// return lptr; +// } + +// __forceinline const Type& operator *( void ) const { return *get(); } +// __forceinline Type& operator *( void ) { return *get(); } +// __forceinline const Type* operator ->( void ) const { return get(); } +// __forceinline Type* operator ->( void ) { return get(); } + + +// private: +// mutable tls_t ptr; +// void* init; +// mutable AtomicMutex mutex; +// public: +// mutable std::vector threads; +// }; + +// #if defined(__MIC__) +// void printThreadInfo(); +// #endif +} diff --git a/ospray/render/obj/OBJMaterial.h b/common/vec.cpp similarity index 50% rename from ospray/render/obj/OBJMaterial.h rename to common/vec.cpp index 77527c6865..f6c937a90c 100644 --- a/ospray/render/obj/OBJMaterial.h +++ b/common/vec.cpp @@ -14,31 +14,64 @@ // limitations under the License. // // ======================================================================== // -#pragma once - -#include "ospray/common/Material.h" -#include "ospray/texture/Texture2D.h" - -namespace ospray { - namespace obj { - - typedef vec3f Color; - - /*! implements the Material used by the \ref ospray_render_obj */ - struct OBJMaterial : public Material { - Texture2D *map_d; float d; /*! opacity: 0 (transparent), 1 (opaque) */ - Texture2D *map_Kd; Color Kd; /*! diffuse reflectance: 0 (none), 1 (full) */ - Texture2D *map_Ks; Color Ks; /*! specular reflectance: 0 (none), 1 (full) */ - Texture2D *map_Ns; float Ns; /*! specular exponent: 0 (diffuse), infinity (specular) */ - Texture2D *map_Bump; /*! bump map */ - - //! \brief common function to help printf-debugging - /*! Every derived class should overrride this! */ - virtual std::string toString() const { return "ospray::objrenderer::OBJMaterial"; } - - //! \brief commit the material's parameters - virtual void commit(); - }; - - } // ::ospray::obj -} // ::ospray +#include "vec.h" + +namespace ospcommon { + // ------------------------------------------------------- + // parsing from strings + // ------------------------------------------------------- + vec2f toVec2f(const char *ptr) + { + assert(ptr); + vec2f v; + int rc = sscanf(ptr,"%f %f",&v.x,&v.y); + assert(rc == 2); + return v; + } + + vec3f toVec3f(const char *ptr) + { + assert(ptr); + vec3f v; + int rc = sscanf(ptr,"%f %f %f",&v.x,&v.y,&v.z); + assert(rc == 3); + return v; + } + + vec4f toVec4f(const char *ptr) + { + assert(ptr); + vec4f v; + int rc = sscanf(ptr,"%f %f %f %f",&v.x,&v.y,&v.z,&v.w); + assert(rc == 4); + return v; + } + + vec2i toVec2i(const char *ptr) + { + assert(ptr); + vec2i v; + int rc = sscanf(ptr,"%i %i",&v.x,&v.y); + assert(rc == 2); + return v; + } + + vec3i toVec3i(const char *ptr) + { + assert(ptr); + vec3i v; + int rc = sscanf(ptr,"%i %i %i",&v.x,&v.y,&v.z); + assert(rc == 3); + return v; + } + + vec4i toVec4i(const char *ptr) + { + assert(ptr); + vec4i v; + int rc = sscanf(ptr,"%i %i %i %i",&v.x,&v.y,&v.z,&v.w); + assert(rc == 4); + return v; + } + +} // ::ospcommon diff --git a/common/vec.h b/common/vec.h new file mode 100644 index 0000000000..32748ebc26 --- /dev/null +++ b/common/vec.h @@ -0,0 +1,515 @@ +// ======================================================================== // +// 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.h" +#include "constants.h" +#include "math.h" +#include + +namespace ospcommon { + + template struct vec_t + { + typedef T scalar_t; + typedef T Scalar; + }; + + template + struct vec_t { + typedef T scalar_t; + typedef T Scalar; + + inline vec_t() {}; + inline 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) {} + + template + explicit inline vec_t(const vec_t &o) : x(o.x), y(o.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 vec_t { + typedef T scalar_t; + typedef T Scalar; + + inline vec_t() {}; + inline vec_t(scalar_t s) : x(s), y(s), z(s) {}; + inline vec_t(scalar_t x, scalar_t y, scalar_t z) : x(x), y(y), z(z) {}; + inline vec_t(const vec_t &o) : x(o.x), y(o.y), z(o.z) {} + + template + explicit inline vec_t(const vec_t &o) : x(o.x), y(o.y), z(o.z) {} + + inline const T& operator []( const size_t axis ) const { assert(axis < 3); return (&x)[axis]; } + inline T& operator []( const size_t axis ) { assert(axis < 3); return (&x)[axis]; } + + // inline vec_t(const vec_t &o) : x(o.x), y(o.y), z(o.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 vec_t { + typedef T scalar_t; + typedef T Scalar; + + inline vec_t() {}; + inline vec_t(scalar_t s) : x(s), y(s), z(s) {}; + inline vec_t(scalar_t x, scalar_t y, scalar_t z) : x(x), y(y), z(z) {}; + inline vec_t(const vec_t &o) : x(o.x), y(o.y), z(o.z) {} + inline vec_t(const vec_t &o) : x(o.x), y(o.y), z(o.z) {} + + inline const T& operator []( const size_t axis ) const { assert(axis < 3); return (&x)[axis]; } + inline T& operator []( const size_t axis ) { assert(axis < 3); return (&x)[axis]; } + + /*! 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; } + + inline operator vec_t() const { return vec_t(x,y,z); } + + T x, y, z; + union { float w; unsigned u; int a; }; + }; + + template + struct vec_t { + typedef T scalar_t; + typedef T Scalar; + + inline vec_t() {}; + inline vec_t(scalar_t s) : x(s), y(s), z(s), w(s) {}; + inline vec_t(scalar_t x, scalar_t y, scalar_t z, scalar_t w) : x(x), y(y), z(z), w(w) {}; + inline vec_t(const vec_t &o) : x(o.x), y(o.y), z(o.z), w(o.w) {} + template + explicit inline vec_t(const vec_t &o) : x(x), y(y), z(o.z), w(o.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; + }; + + // ------------------------------------------------------- + // unary operators + // ------------------------------------------------------- + template inline vec_t operator-(const vec_t &v) + { return vec_t(-v.x,-v.y); } + template inline vec_t operator-(const vec_t &v) + { return vec_t(-v.x,-v.y,-v.z); } + template inline vec_t operator-(const vec_t &v) + { return vec_t(-v.x,-v.y,-v.z); } + template inline vec_t operator-(const vec_t &v) + { return vec_t(-v.x,-v.y,-v.z,-v.w); } + + template inline vec_t operator+(const vec_t &v) + { return vec_t(+v.x,+v.y); } + template inline vec_t operator+(const vec_t &v) + { return vec_t(+v.x,+v.y,+v.z); } + template inline vec_t operator+(const vec_t &v) + { return vec_t(+v.x,+v.y,+v.z); } + template inline vec_t operator+(const vec_t &v) + { return vec_t(+v.x,+v.y,+v.z,+v.w); } + + // ------------------------------------------------------- + // unary functors + // ------------------------------------------------------- +#define unary_functor(op) \ + template inline vec_t op(const vec_t &v)\ + { return vec_t(op(v.x),op(v.y)); }\ + template inline vec_t op(const vec_t &v)\ + { return vec_t(op(v.x),op(v.y),op(v.z)); }\ + template inline vec_t op(const vec_t &v)\ + { return vec_t(op(v.x),op(v.y),op(v.z)); }\ + 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); +#undef unary_functor + + // ------------------------------------------------------- + // binary operators, same type + // ------------------------------------------------------- +#define binary_operator(name,op) \ + /* "vec op vec" */ \ + template \ + inline vec_t name(const vec_t &a, \ + const vec_t &b) \ + { return vec_t(a.x op b.x,a.y op b.y); } \ + \ + template \ + inline vec_t name(const vec_t &a, \ + const vec_t &b) \ + { return vec_t(a.x op b.x,a.y op b.y,a.z op b.z); } \ + \ + template \ + inline vec_t name(const vec_t &a, \ + const vec_t &b) \ + { return vec_t(a.x op b.x,a.y op b.y,a.z op b.z,a.w op b.w); } \ + \ + /* "vec op scalar" */ \ + template \ + inline vec_t name(const vec_t &a, \ + const T &b) \ + { return vec_t(a.x op b,a.y op b); } \ + \ + template \ + inline vec_t name(const vec_t &a, \ + const T &b) \ + { return vec_t(a.x op b,a.y op b,a.z op b); } \ + \ + template \ + inline vec_t name(const vec_t &a, \ + const T &b) \ + { return vec_t(a.x op b,a.y op b,a.z op b,a.w op b); } \ + \ + /* "scalar op vec" */ \ + template \ + inline vec_t name(const T a, \ + const vec_t &b) \ + { return vec_t(a op b.x,a op b.y); } \ + \ + template \ + inline vec_t name(const T a, \ + const vec_t &b) \ + { return vec_t(a op b.x,a op b.y,a op b.z); } \ + \ + template \ + inline vec_t name(const T a, \ + 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%,%); +#undef binary_operator + + // ------------------------------------------------------- + // binary operators, same type + // ------------------------------------------------------- +#define binary_operator(name,op) \ + /* "vec op vec" */ \ + template \ + inline vec_t &name(vec_t &a, \ + const vec_t &b) \ + { a.x op b.x; a.y op b.y; return a; } \ + \ + template \ + inline vec_t &name(vec_t &a, \ + const vec_t &b) \ + { a.x op b.x; a.y op b.y; a.z op b.z; return a; } \ + \ + template \ + inline vec_t &name(vec_t &a, \ + const vec_t &b) \ + { a.x op b.x; a.y op b.y; a.z op b.z; a.w op b.w; return a; } \ + \ + /* "vec op scalar" */ \ + template \ + inline vec_t &name(vec_t &a, \ + const T &b) \ + { a.x op b; a.y op b; return a; } \ + \ + template \ + inline vec_t &name(vec_t &a, \ + const T &b) \ + { a.x op b; a.y op b; a.z op b; return a; } \ + \ + template \ + inline vec_t &name(vec_t &a, \ + 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/=,/=); +#undef binary_operator + + // ------------------------------------------------------- + // ternary operators (just for compatibilty with old embree + // ------------------------------------------------------- + template inline + vec_t madd(const vec_t &a, const vec_t &b, const vec_t &c) + { return vec_t( madd(a.x,b.x,c.x), madd(a.y,b.y,c.y), madd(a.z,b.z,c.z)); } + + // ------------------------------------------------------- + // comparison operators + // ------------------------------------------------------- + template + inline bool operator==(const vec_t &a, const vec_t &b) + { return a.x==b.x && a.y==b.y; } + + template + inline bool operator==(const vec_t &a, const vec_t &b) + { return a.x==b.x && a.y==b.y && a.z==b.z; } + + template + inline bool operator==(const vec_t &a, const vec_t &b) + { return a.x==b.x && a.y==b.y && a.z==b.z && a.w==b.w; } + + template + inline bool operator!=(const vec_t &a, const vec_t &b) + { return !(a==b); } + + template + inline bool operator!=(const vec_t &a, const vec_t &b) + { return !(a==b); } + + template + inline bool operator!=(const vec_t &a, const vec_t &b) + { return !(a==b); } + + 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) + { return a.x + inline bool anyLessThan(const vec_t &a, const vec_t &b) + { return a.x + inline bool anyLessThan(const vec_t &a, const vec_t &b) + { return a.x inline T dot(const vec_t &a, const vec_t &b) + { return a.x*b.x+a.y*b.y; } + template inline T dot(const vec_t &a, const vec_t &b) + { return a.x*b.x+a.y*b.y+a.z*b.z; } + template inline T dot(const vec_t &a, const vec_t &b) + { return a.x*b.x+a.y*b.y+a.z*b.z; } + template inline T dot(const vec_t &a, const vec_t &b) + { return a.x*b.x+a.y*b.y+a.z*b.z; } + template inline T dot(const vec_t &a, const vec_t &b) + { return a.x*b.x+a.y*b.y+a.z*b.z; } + template inline T dot(const vec_t &a, const vec_t &b) + { return a.x*b.x+a.y*b.y+a.z*b.z+a.w*b.w; } + + // ------------------------------------------------------- + // length functions + // ------------------------------------------------------- + template + inline T length(const vec_t &v) + { return sqrt(dot(v,v)); } + + // ------------------------------------------------------- + // cross product + // ------------------------------------------------------- + template inline vec_t cross(const vec_t &a, + const vec_t &b) + { return vec_t(a.y*b.z-a.z*b.y, + a.z*b.x-a.x*b.z, + a.x*b.y-a.y*b.x); } + + // ------------------------------------------------------- + // normalize() + // ------------------------------------------------------- + template inline vec_t normalize(const vec_t &v) + { return v * rsqrt(dot(v,v)); } + + // ------------------------------------------------------- + // ostream operators + // ------------------------------------------------------- + template + inline std::ostream &operator<<(std::ostream &o, const vec_t &v) + { o << "(" << v.x << "," << v.y << ")"; return o; } + template + inline std::ostream &operator<<(std::ostream &o, const vec_t &v) + { o << "(" << v.x << "," << v.y << "," << v.z << ")"; return o; } + template + inline std::ostream &operator<<(std::ostream &o, const vec_t &v) + { o << "(" << v.x << "," << v.y << "," << v.z << "," << v.w << ")"; return o; } + + // "inherit" std::min/max/etc for basic types + using std::min; + using std::max; + + // ------------------------------------------------------- + // binary functors + // ------------------------------------------------------- +#define define_functor(f) \ + template \ + 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)); } \ + \ + template \ + 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)); } \ + \ + template \ + 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); +#undef define_functor + + // ------------------------------------------------------- + // reductions + // ------------------------------------------------------- + template + inline T reduce_add(const vec_t &v) + { return v.x+v.y; } + template + inline T reduce_add(const vec_t &v) + { return v.x+v.y+v.z; } + template + inline T reduce_add(const vec_t &v) + { return v.x+v.y+v.z+v.w; } + + template + inline T reduce_mul(const vec_t &v) + { return v.x*v.y; } + template + inline T reduce_mul(const vec_t &v) + { return v.x*v.y*v.z; } + template + inline T reduce_mul(const vec_t &v) + { return v.x*v.y*v.z*v.w; } + + template + inline T reduce_min(const vec_t &v) + { return min(v.x,v.y); } + template + inline T reduce_min(const vec_t &v) + { return min(min(v.x,v.y),v.z); } + template + inline T reduce_min(const vec_t &v) + { return min(min(v.x,v.y),min(v.z,v.w)); } + + template + inline T reduce_max(const vec_t &v) + { return max(v.x,v.y); } + template + inline T reduce_max(const vec_t &v) + { return max(max(v.x,v.y),v.z); } + template + inline T reduce_max(const vec_t &v) + { return max(max(v.x,v.y),max(v.z,v.w)); } + + // ------------------------------------------------------- + // select + // ------------------------------------------------------- + template + inline vec_t select(bool s, const vec_t &a, const vec_t &b) + { return vec_t(select(s,a.x,b.x),select(s,a.y,b.y),select(s,a.z,b.z)); } + + // ------------------------------------------------------- + // all vec2 variants + // ------------------------------------------------------- + typedef vec_t vec2uc; + typedef vec_t vec2c; + typedef vec_t vec2ui; + typedef vec_t vec2i; + typedef vec_t vec2ul; + typedef vec_t vec2l; + typedef vec_t vec2f; + typedef vec_t vec2d; + + // ------------------------------------------------------- + // all vec3 variants + // ------------------------------------------------------- + typedef vec_t vec3uc; + typedef vec_t vec3c; + typedef vec_t vec3ui; + typedef vec_t vec3i; + typedef vec_t vec3ul; + typedef vec_t vec3l; + typedef vec_t vec3f; + typedef vec_t vec3d; + + typedef vec_t vec3fa; + typedef vec_t vec3ia; + + // ------------------------------------------------------- + // all vec4 variants + // ------------------------------------------------------- + typedef vec_t vec4uc; + typedef vec_t vec4c; + typedef vec_t vec4ui; + typedef vec_t vec4i; + typedef vec_t vec4ul; + typedef vec_t vec4l; + typedef vec_t vec4f; + typedef vec_t vec4d; + + // ------------------------------------------------------- + // parsing from strings + // ------------------------------------------------------- + vec2f toVec2f(const char *ptr); + vec3f toVec3f(const char *ptr); + vec4f toVec4f(const char *ptr); + vec2i toVec2i(const char *ptr); + vec3i toVec3i(const char *ptr); + vec4i toVec4i(const char *ptr); + + +} // ::ospcommon diff --git a/doc/dox/doxyconfig.in b/doc/dox/doxyconfig.in index f00d311340..f739b0b8cc 100755 --- a/doc/dox/doxyconfig.in +++ b/doc/dox/doxyconfig.in @@ -1077,7 +1077,7 @@ FORMULA_FONTSIZE = 10 # typically be disabled. For large projects the javascript based search engine # can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. -SEARCHENGINE = NO +SEARCHENGINE = YES # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a PHP enabled web server instead of at the web client @@ -1087,7 +1087,7 @@ SEARCHENGINE = NO # full text search. The disadvantages are that it is more difficult to setup # and does not have live searching capabilities. -#SERVER_BASED_SEARCH = NO +SERVER_BASED_SEARCH = NO #--------------------------------------------------------------------------- # configuration options related to the LaTeX output diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt index 936d9a7b00..d4be3743a0 100644 --- a/modules/CMakeLists.txt +++ b/modules/CMakeLists.txt @@ -15,10 +15,10 @@ ## ======================================================================== ## IF (NOT WIN32) # not yet... -FILE(GLOB plugins RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/ *) -FOREACH(plugin ${plugins}) - IF (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${plugin}/CMakeLists.txt) - ADD_SUBDIRECTORY(${plugin}) - ENDIF (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${plugin}/CMakeLists.txt) -ENDFOREACH(plugin ${plugins}) + FILE(GLOB plugins RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/ *) + FOREACH(plugin ${plugins}) + IF (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${plugin}/CMakeLists.txt) + ADD_SUBDIRECTORY(${plugin}) + ENDIF (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${plugin}/CMakeLists.txt) + ENDFOREACH(plugin ${plugins}) ENDIF() diff --git a/modules/opengl/util.cpp b/modules/opengl/util.cpp index b9e8c92a60..00f70d921c 100644 --- a/modules/opengl/util.cpp +++ b/modules/opengl/util.cpp @@ -15,7 +15,8 @@ // ======================================================================== // #include "util.h" -#include +#include "common/vec.h" +// #include #ifdef __APPLE__ #include @@ -25,9 +26,10 @@ #include namespace ospray { - namespace opengl { + typedef ospcommon::vec2i vec2i; + typedef ospcommon::vec3f vec3f; - using embree::cross; + namespace opengl { OSPTexture2D getOSPDepthTextureFromOpenGLPerspective() { @@ -120,7 +122,8 @@ namespace ospray { } // nearest texture filtering required for depth textures -- we don't want interpolation of depth values... - OSPTexture2D depthTexture = ospNewTexture2D(glDepthBufferWidth, glDepthBufferHeight, OSP_FLOAT, ospDepth, OSP_TEXTURE_FILTER_NEAREST); + vec2i texSize(glDepthBufferWidth, glDepthBufferHeight); + OSPTexture2D depthTexture = ospNewTexture2D((osp::vec2i&)texSize, OSP_TEXTURE_R32F, ospDepth, OSP_TEXTURE_FILTER_NEAREST); delete[] ospDepth; diff --git a/modules/seismic/SeismicHorizonFile.h b/modules/seismic/SeismicHorizonFile.h index d5516d238f..1795404eb2 100644 --- a/modules/seismic/SeismicHorizonFile.h +++ b/modules/seismic/SeismicHorizonFile.h @@ -19,7 +19,7 @@ #include "ospray/common/OSPCommon.h" #include #include -#include "modules/loaders/TriangleMeshFile.h" +#include "apps/volumeViewer/loaders/TriangleMeshFile.h" //! \brief A concrete implementation of the TriangleMeshFile class //! for reading horizon data stored in seismic file formats on disk. diff --git a/modules/seismic/SeismicVolumeFile.h b/modules/seismic/SeismicVolumeFile.h index 6fef58279c..e7f8508dd5 100644 --- a/modules/seismic/SeismicVolumeFile.h +++ b/modules/seismic/SeismicVolumeFile.h @@ -19,7 +19,7 @@ #include "ospray/common/OSPCommon.h" #include #include -#include "modules/loaders/VolumeFile.h" +#include "apps/volumeViewer/loaders/VolumeFile.h" //! \brief A concrete implementation of the VolumeFile class //! for reading voxel data stored in seismic file formats on disk. diff --git a/modules/seismic/SymbolRegistry.cpp b/modules/seismic/SymbolRegistry.cpp index b53980035a..a8a7219f49 100644 --- a/modules/seismic/SymbolRegistry.cpp +++ b/modules/seismic/SymbolRegistry.cpp @@ -14,7 +14,7 @@ // limitations under the License. // // ======================================================================== // -#include "modules/loaders/OSPObjectFile.h" +#include "apps/volumeViewer/loaders/OSPObjectFile.h" #include "SeismicHorizonFile.h" #include "SeismicVolumeFile.h" diff --git a/modules/tachyon/CMakeLists.txt b/modules/tachyon/CMakeLists.txt index b20a16e606..52e0513520 100644 --- a/modules/tachyon/CMakeLists.txt +++ b/modules/tachyon/CMakeLists.txt @@ -59,9 +59,10 @@ IF (OSPRAY_MODULE_TACHYON) INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/ospray) INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/ospray/include) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/) + INCLUDE_DIRECTORIES(${EMBREE_INCLUDE_DIRS}) INCLUDE_DIRECTORIES_ISPC(${PROJECT_SOURCE_DIR}) INCLUDE_DIRECTORIES_ISPC(${PROJECT_SOURCE_DIR}/ospray) - INCLUDE_DIRECTORIES_ISPC(${EMBREE_DIR}/include) + INCLUDE_DIRECTORIES_ISPC(${EMBREE_INCLUDE_DIRS}) YACC_FILE(parser.yy) LEX_FILE(lexer.ll) @@ -71,7 +72,7 @@ IF (OSPRAY_MODULE_TACHYON) TachyonRenderer.ispc ) - OSPRAY_LIBRARY_LINK_LIBRARIES(ospray_module_tachyon ospray) + OSPRAY_LIBRARY_LINK_LIBRARIES(ospray_module_tachyon ospray ospray_common) IF (NOT THIS_IS_MIC) ADD_EXECUTABLE(ospTachyon @@ -81,6 +82,6 @@ IF (OSPRAY_MODULE_TACHYON) parser_y.cpp Loc.cpp ) - TARGET_LINK_LIBRARIES(ospTachyon ospray ospray_glut3d) + TARGET_LINK_LIBRARIES(ospTachyon ospray ospray_common ospray_glut3d) ENDIF() ENDIF() diff --git a/modules/tachyon/Model.cpp b/modules/tachyon/Model.cpp index 362545586d..69cbe1bd47 100644 --- a/modules/tachyon/Model.cpp +++ b/modules/tachyon/Model.cpp @@ -88,7 +88,7 @@ namespace ospray { } Model::Model() - : bounds(embree::empty), + : bounds(ospcommon::empty), camera(NULL), smoothTrisVA(NULL), backgroundColor(.1f), @@ -240,7 +240,7 @@ namespace ospray { tessellateSphereOctant(va,sphere,dw,dvw,duw,depth-1); tessellateSphereOctant(va,sphere,duv,dvw,duw,depth-1); } else { - vec3i base = vec3f(va->coord.size()); + vec3i base = vec3i(va->coord.size()); va->coord.push_back(sphere.center+sphere.rad*du); va->coord.push_back(sphere.center+sphere.rad*dv); va->coord.push_back(sphere.center+sphere.rad*dw); @@ -304,10 +304,10 @@ namespace ospray { void tessellateCylinder(VertexArray *va,Cylinder &cylinder) { vec3f dw = cylinder.apex - cylinder.base; - float l = embree::length(dw); + float l = length(dw); - embree::AffineSpace3f space; - space.l = embree::frame(normalize(dw)); + AffineSpace3f space; + space.l = frame(normalize(dw)); space.p = cylinder.base; vec3i base(va->coord.size()); diff --git a/modules/tachyon/Viewer.cpp b/modules/tachyon/Viewer.cpp index 400d97ac99..50ad0b3040 100644 --- a/modules/tachyon/Viewer.cpp +++ b/modules/tachyon/Viewer.cpp @@ -198,6 +198,8 @@ namespace ospray { ospCommit(camera); renderer = ospNewRenderer(renderType); + ospSet1i(renderer, "aoSamples", 1); + ospSet1i(renderer, "shadowsEnabled", 1); Assert2(renderer,"could not create renderer"); ospSetObject(renderer,"model",model); @@ -205,9 +207,9 @@ namespace ospray { ospSet1i(renderer,"do_shadows",doShadows); ospCommit(renderer); - }; + } - virtual void keypress(char key, const vec2f where) + void keypress(char key, const vec2i &where) override { switch (key) { case 'X': @@ -279,7 +281,7 @@ namespace ospray { Glut3DWidget::reshape(_newSize); if (fb) ospFreeFrameBuffer(fb); const auto &newSize = reinterpret_cast(_newSize); - fb = ospNewFrameBuffer(newSize,OSP_RGBA_I8,OSP_FB_COLOR|OSP_FB_ACCUM); + fb = ospNewFrameBuffer(newSize, OSP_FB_SRGBA, OSP_FB_COLOR|OSP_FB_ACCUM); ospSetf(camera,"aspect",viewPort.aspect); ospCommit(camera); } diff --git a/ospray/CMakeLists.txt b/ospray/CMakeLists.txt index d65b0af65a..9f4cf4c65d 100644 --- a/ospray/CMakeLists.txt +++ b/ospray/CMakeLists.txt @@ -30,54 +30,80 @@ SET(CMAKE_THREAD_PREFER_PTHREAD TRUE) FIND_PACKAGE(Threads REQUIRED) # ------------------------------------------------------- -# Setup tasking system build configuration +# Find or build Embree # ------------------------------------------------------- -SET(OSPRAY_TASKING_SYSTEM TBB CACHE STRING - "Use TBB or OpenMP as for per-node thread tasking system") -SET_PROPERTY(CACHE OSPRAY_TASKING_SYSTEM PROPERTY STRINGS TBB OpenMP) -MARK_AS_ADVANCED(OSPRAY_TASKING_SYSTEM) +SET(REQUIRED_MINIMUM_EMBREE 2.7.1) -IF(${OSPRAY_TASKING_SYSTEM} STREQUAL "TBB") - SET(USE_TBB TRUE) - SET(USE_TBB TRUE PARENT_SCOPE) +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}) + ENDIF() + ENDIF() ELSE() - SET(USE_TBB FALSE) - SET(USE_TBB FALSE PARENT_SCOPE) + # 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() -IF(USE_TBB) - FIND_PACKAGE(TBB REQUIRED) - ADD_DEFINITIONS(-DOSPRAY_USE_TBB) - INCLUDE_DIRECTORIES(${TBB_INCLUDE_DIRS}) -ELSE(USE_TBB) - UNSET(TBB_INCLUDE_DIR CACHE) - UNSET(TBB_LIBRARY CACHE) - UNSET(TBB_LIBRARY_DEBUG CACHE) - UNSET(TBB_LIBRARY_MALLOC CACHE) - UNSET(TBB_LIBRARY_MALLOC_DEBUG CACHE) - UNSET(TBB_INCLUDE_DIR_MIC CACHE) - UNSET(TBB_LIBRARY_MIC CACHE) - UNSET(TBB_LIBRARY_MALLOC_MIC CACHE) -ENDIF(USE_TBB) +INCLUDE_DIRECTORIES(${EMBREE_INCLUDE_DIRS}) +INCLUDE_DIRECTORIES_ISPC(${EMBREE_INCLUDE_DIRS}) -# ------------------------------------------------------- -# Build and configure embree -# ------------------------------------------------------- - -# NOTE(jda) - Embree assumes that USE_TBB will be defined correctly (above)... -# 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 ${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 - device/nwlayer.cpp + include/ospray/ospray.h + include/ospray/OSPDataType.h + include/ospray/OSPTexture.h math/box.ispc math/Distribution2D.ispc @@ -90,15 +116,16 @@ SET(OSPRAY_SOURCES common/ISPC_KNL_Backend.h common/Managed.cpp common/ObjectHandle.cpp - common/OSPDataType.h common/Data.cpp common/Model.ispc common/Model.cpp common/Material.cpp - common/Library.cpp common/Thread.cpp - common/Texture.h - common/parallel_for.h + + common/tasking/parallel_for.h + common/tasking/async.h + common/tasking/TaskingTypeTraits.h + common/tasking/TaskSys.cpp fb/FrameBuffer.ispc fb/FrameBuffer.cpp @@ -180,10 +207,6 @@ SET(OSPRAY_SOURCES render/simpleAO/SimpleAOMaterial.cpp render/simpleAO/SimpleAOMaterial.ih render/simpleAO/SimpleAOMaterial.ispc - render/obj/OBJRenderer.ispc - render/obj/OBJMaterial.ispc - render/obj/OBJRenderer.cpp - render/obj/OBJMaterial.cpp render/scivis/SciVisRenderer.ispc render/scivis/SciVisMaterial.ispc render/scivis/SciVisMaterial.ih @@ -229,6 +252,9 @@ IF (OSPRAY_MPI) CONFIGURE_MPI() SET(OSPRAY_SOURCES ${OSPRAY_SOURCES} + mpi/buffers.h + mpi/command.h + mpi/MPIDevice.cpp mpi/MPICommon.cpp mpi/MPILoadBalancer.cpp @@ -245,15 +271,6 @@ IF (OSPRAY_MPI) fb/DisplayWall.cpp ) - - # ============================================ - OSPRAY_ADD_EXECUTABLE(ospCreateCompositeTestCubes - mpi/testing/createCompositeTestCubes - ) - OSPRAY_EXE_LINK_LIBRARIES(ospCreateCompositeTestCubes - ospray - ) - ENDIF() # ------------------------------------------------------- @@ -282,6 +299,7 @@ IF (OSPRAY_BUILD_COI_DEVICE) MARK_AS_ADVANCED(LIBCOI_DEVICE) MARK_AS_ADVANCED(LIBCOI_HOST) SET(OSPRAY_MIC_COI ON PARENT_SCOPE) + # NOTE(jda) - hardcoded paths (!)...use a find_package() here? INCLUDE_DIRECTORIES(/opt/intel/mic/coi/include) INCLUDE_DIRECTORIES(/usr/include/intel-coi) IF (THIS_IS_MIC) @@ -304,19 +322,20 @@ ENDIF() OSPRAY_ADD_LIBRARY(ospray SHARED ${OSPRAY_SOURCES}) OSPRAY_LIBRARY_LINK_LIBRARIES(ospray + ospray_common ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS} ) IF (THIS_IS_MIC) OSPRAY_LIBRARY_LINK_LIBRARIES(ospray - embree_xeonphi - ${TBB_LIBRARIES_MIC} + ${EMBREE_LIBRARY_XEONPHI} + ${TASKING_SYSTEM_LIBS_MIC} ) ELSE() OSPRAY_LIBRARY_LINK_LIBRARIES(ospray - embree - ${TBB_LIBRARIES} + ${EMBREE_LIBRARIES} + ${TASKING_SYSTEM_LIBS} ) ENDIF() @@ -331,6 +350,15 @@ ENDIF() OSPRAY_SET_LIBRARY_VERSION(ospray) OSPRAY_INSTALL_LIBRARY(ospray) +IF(NOT THIS_IS_MIC) + # build ospTutorial, for testing + ADD_EXECUTABLE(ospTutorial ../apps/ospTutorial.cpp) + OSPRAY_EXE_LINK_LIBRARIES(ospTutorial ospray ospray_common) + # C version + ADD_EXECUTABLE(ospTutorialC ../apps/ospTutorial.c) + OSPRAY_EXE_LINK_LIBRARIES(ospTutorialC ospray ospray_common) +ENDIF() + ############################################################## # MPI DEVICE - mpi worker @@ -347,7 +375,7 @@ IF (OSPRAY_MPI) ENDIF() OSPRAY_ADD_EXECUTABLE(ospray_mpi_worker mpi/MPIWorker.cpp) - OSPRAY_EXE_LINK_LIBRARIES(ospray_mpi_worker ospray) + OSPRAY_EXE_LINK_LIBRARIES(ospray_mpi_worker ospray ospray_common) OSPRAY_INSTALL_EXE(ospray_mpi_worker) ENDIF() @@ -367,6 +395,7 @@ IF (OSPRAY_BUILD_COI_DEVICE) OSPRAY_ADD_EXECUTABLE(ospray_coi_worker api/COIDeviceWorker.cpp) OSPRAY_EXE_LINK_LIBRARIES(ospray_coi_worker ospray + ospray_common ${LIBCOI_DEVICE} ) # ------------------------------------------------------------ diff --git a/ospray/api/API.cpp b/ospray/api/API.cpp index 41a75bbfac..a78dfa5319 100644 --- a/ospray/api/API.cpp +++ b/ospray/api/API.cpp @@ -64,11 +64,11 @@ namespace ospray { } // ::ospray - std::string getPidString() { - char s[100]; - sprintf(s, "(pid %i)", getpid()); - return s; - } +std::string getPidString() { + char s[100]; + sprintf(s, "(pid %i)", getpid()); + return s; +} #define ASSERT_DEVICE() if (ospray::api::Device::current == NULL) \ throw std::runtime_error("OSPRay not yet initialized " \ @@ -76,748 +76,724 @@ namespace ospray { "call an ospray API function before " \ "first calling ospInit())"+getPidString()); - using namespace ospray; +using namespace ospray; - extern "C" void ospInit(int *_ac, const char **_av) - { - if (ospray::api::Device::current) { - throw std::runtime_error("OSPRay error: device already exists " - "(did you call ospInit twice?)"); - } +extern "C" void ospInit(int *_ac, const char **_av) +{ + if (ospray::api::Device::current) { + throw std::runtime_error("OSPRay error: device already exists " + "(did you call ospInit twice?)"); + } - auto *nThreads = getenv("OSPRAY_THREADS"); - if (nThreads) { - numThreads = atoi(nThreads); - } + auto *nThreads = getenv("OSPRAY_THREADS"); + if (nThreads) { + numThreads = atoi(nThreads); + } - /* call ospray::init to properly parse common args like - --osp:verbose, --osp:debug etc */ - ospray::init(_ac,&_av); + /* call ospray::init to properly parse common args like + --osp:verbose, --osp:debug etc */ + ospray::init(_ac,&_av); - const char *OSP_MPI_LAUNCH_FROM_ENV = getenv("OSPRAY_MPI_LAUNCH"); + const char *OSP_MPI_LAUNCH_FROM_ENV = getenv("OSPRAY_MPI_LAUNCH"); - if (OSP_MPI_LAUNCH_FROM_ENV) { + if (OSP_MPI_LAUNCH_FROM_ENV) { #ifdef OSPRAY_MPI - std::cout << "#osp: launching ospray mpi ring - make sure that mpd is running" << std::endl; - ospray::api::Device::current - = mpi::createMPI_LaunchWorkerGroup(_ac,_av,OSP_MPI_LAUNCH_FROM_ENV); + std::cout << "#osp: launching ospray mpi ring - make sure that mpd is running" << std::endl; + ospray::api::Device::current + = mpi::createMPI_LaunchWorkerGroup(_ac,_av,OSP_MPI_LAUNCH_FROM_ENV); #else - throw std::runtime_error("OSPRay MPI support not compiled in"); + throw std::runtime_error("OSPRay MPI support not compiled in"); #endif - } + } - if (_ac && _av) { - // we're only supporting local rendering for now - network device - // etc to come. - for (int i=1;i<*_ac;i++) { + if (_ac && _av) { + // we're only supporting local rendering for now - network device + // etc to come. + for (int i=1;i<*_ac;i++) { - if (std::string(_av[i]) == "--osp:mpi") { + if (std::string(_av[i]) == "--osp:mpi") { #ifdef OSPRAY_MPI - removeArgs(*_ac,(char **&)_av,i,1); - ospray::api::Device::current - = mpi::createMPI_RanksBecomeWorkers(_ac,_av); + removeArgs(*_ac,(char **&)_av,i,1); + ospray::api::Device::current + = mpi::createMPI_RanksBecomeWorkers(_ac,_av); #else - throw std::runtime_error("OSPRay MPI support not compiled in"); + throw std::runtime_error("OSPRay MPI support not compiled in"); #endif - --i; - continue; - } + --i; + continue; + } - if (std::string(_av[i]) == "--osp:coi") { + if (std::string(_av[i]) == "--osp:coi") { #ifdef __MIC__ - throw std::runtime_error("The COI device can only be created on the host"); + throw std::runtime_error("The COI device can only be created on the host"); #elif defined(OSPRAY_MIC_COI) - removeArgs(*_ac,(char **&)_av,i,1); - ospray::api::Device::current - = ospray::coi::createCoiDevice(_ac,_av); + removeArgs(*_ac,(char **&)_av,i,1); + ospray::api::Device::current + = ospray::coi::createCoiDevice(_ac,_av); #else - throw std::runtime_error("OSPRay's COI support not compiled in"); + throw std::runtime_error("OSPRay's COI support not compiled in"); #endif - --i; - continue; - } + --i; + continue; + } - if (std::string(_av[i]) == "--osp:mpi-launch") { + if (std::string(_av[i]) == "--osp:mpi-launch") { #ifdef OSPRAY_MPI - if (i+2 > *_ac) - throw std::runtime_error("--osp:mpi-launch expects an argument"); - const char *launchCommand = strdup(_av[i+1]); - removeArgs(*_ac,(char **&)_av,i,2); - ospray::api::Device::current - = mpi::createMPI_LaunchWorkerGroup(_ac,_av,launchCommand); + if (i+2 > *_ac) + throw std::runtime_error("--osp:mpi-launch expects an argument"); + const char *launchCommand = strdup(_av[i+1]); + removeArgs(*_ac,(char **&)_av,i,2); + ospray::api::Device::current + = mpi::createMPI_LaunchWorkerGroup(_ac,_av,launchCommand); #else - throw std::runtime_error("OSPRay MPI support not compiled in"); + throw std::runtime_error("OSPRay MPI support not compiled in"); #endif - --i; - continue; - } + --i; + continue; + } - const char *listenArgName = "--osp:mpi-listen"; - if (!strncmp(_av[i],listenArgName,strlen(listenArgName))) { + const char *listenArgName = "--osp:mpi-listen"; + if (!strncmp(_av[i],listenArgName,strlen(listenArgName))) { #ifdef OSPRAY_MPI - const char *fileNameToStorePortIn = NULL; - if (strlen(_av[i]) > strlen(listenArgName)) { - fileNameToStorePortIn = strdup(_av[i]+strlen(listenArgName)+1); - } - removeArgs(*_ac,(char **&)_av,i,1); - ospray::api::Device::current - = mpi::createMPI_ListenForWorkers(_ac,_av,fileNameToStorePortIn); + const char *fileNameToStorePortIn = NULL; + if (strlen(_av[i]) > strlen(listenArgName)) { + fileNameToStorePortIn = strdup(_av[i]+strlen(listenArgName)+1); + } + removeArgs(*_ac,(char **&)_av,i,1); + ospray::api::Device::current + = mpi::createMPI_ListenForWorkers(_ac,_av,fileNameToStorePortIn); #else - throw std::runtime_error("OSPRay MPI support not compiled in"); + throw std::runtime_error("OSPRay MPI support not compiled in"); #endif - --i; - continue; - } - + --i; + continue; } } - - // no device created on cmd line, yet, so default to localdevice - if (ospray::api::Device::current == NULL) { - ospray::api::Device::current = new ospray::api::LocalDevice(_ac,_av); - } - } - - - /*! destroy a given frame buffer. - - due to internal reference counting the framebuffer may or may not be deleted immediately - */ - extern "C" void ospFreeFrameBuffer(OSPFrameBuffer fb) - { - ASSERT_DEVICE(); - Assert(fb != NULL); - ospray::api::Device::current->release(fb); } - extern "C" OSPFrameBuffer ospNewFrameBuffer(const osp::vec2i &size, - const OSPFrameBufferFormat mode, - const int channels) - { - ASSERT_DEVICE(); - return ospray::api::Device::current->frameBufferCreate((const vec2i&)size,mode,channels); - } - - //! load module \ from shard lib libospray_module_\.so, or - extern "C" error_t ospLoadModule(const char *moduleName) - { - ASSERT_DEVICE(); - return ospray::api::Device::current->loadModule(moduleName); - } - - extern "C" const void *ospMapFrameBuffer(OSPFrameBuffer fb, - OSPFrameBufferChannel channel) - { - ASSERT_DEVICE(); - return ospray::api::Device::current->frameBufferMap(fb,channel); - } - - extern "C" void ospUnmapFrameBuffer(const void *mapped, - OSPFrameBuffer fb) - { - ASSERT_DEVICE(); - Assert(mapped != NULL && "invalid mapped pointer in ospUnmapFrameBuffer"); - ospray::api::Device::current->frameBufferUnmap(mapped,fb); - } - - extern "C" OSPModel ospNewModel() - { - ASSERT_DEVICE(); - return ospray::api::Device::current->newModel(); - } - - extern "C" void ospAddGeometry(OSPModel model, OSPGeometry geometry) - { - ASSERT_DEVICE(); - Assert(model != NULL && "invalid model in ospAddGeometry"); - Assert(geometry != NULL && "invalid geometry in ospAddGeometry"); - return ospray::api::Device::current->addGeometry(model,geometry); - } - - extern "C" void ospRemoveGeometry(OSPModel model, OSPGeometry geometry) - { - ASSERT_DEVICE(); - Assert(model != NULL && "invalid model in ospRemoveGeometry"); - Assert(geometry != NULL && "invalid geometry in ospRemoveGeometry"); - return ospray::api::Device::current->removeGeometry(model, geometry); - } - - extern "C" void ospAddVolume(OSPModel model, OSPVolume volume) - { - ASSERT_DEVICE(); - Assert(model != NULL && "invalid model in ospAddVolume"); - Assert(volume != NULL && "invalid volume in ospAddVolume"); - return ospray::api::Device::current->addVolume(model, volume); - } - - extern "C" void ospRemoveVolume(OSPModel model, OSPVolume volume) - { - ASSERT_DEVICE(); - Assert(model != NULL && "invalid model in ospRemoveVolume"); - Assert(volume != NULL && "invalid volume in ospRemoveVolume"); - return ospray::api::Device::current->removeVolume(model, volume); - } - - /*! create a new data buffer, with optional init data and control flags */ - extern "C" OSPData ospNewData(size_t nitems, OSPDataType format, const void *init, int flags) - { - ASSERT_DEVICE(); - return ospray::api::Device::current->newData(nitems,format,(void*)init,flags); - } - - /*! add a data array to another object */ - extern "C" void ospSetData(OSPObject object, const char *bufName, OSPData data) - { - // assert(!rendering); - ASSERT_DEVICE(); - LOG("ospSetData(...,\"" << bufName << "\",...)"); - return ospray::api::Device::current->setObject(object,bufName,(OSPObject)data); - } - - /*! add an object parameter to another object */ - extern "C" void ospSetParam(OSPObject target, const char *bufName, OSPObject value) - { - ASSERT_DEVICE(); - static bool warned = false; - if (!warned) { - std::cout << "'ospSetParam()' has been deprecated. Please use the new naming convention of 'ospSetObject()' instead" << std::endl; - warned = true; - } - LOG("ospSetParam(...,\"" << bufName << "\",...)"); - return ospray::api::Device::current->setObject(target,bufName,value); - } - - /*! set/add a pixel op to a frame buffer */ - extern "C" void ospSetPixelOp(OSPFrameBuffer fb, OSPPixelOp op) - { - ASSERT_DEVICE(); - LOG("ospSetPixelOp(...,...)"); - return ospray::api::Device::current->setPixelOp(fb,op); - } - - /*! add an object parameter to another object */ - extern "C" void ospSetObject(OSPObject target, const char *bufName, OSPObject value) - { - ASSERT_DEVICE(); - LOG("ospSetObject(...,\"" << bufName << "\",...)"); - return ospray::api::Device::current->setObject(target,bufName,value); - } - - /*! \brief create a new pixelOp of given type - - return 'NULL' if that type is not known */ - extern "C" OSPPixelOp ospNewPixelOp(const char *_type) - { - ASSERT_DEVICE(); - Assert2(_type,"invalid render type identifier in ospNewPixelOp"); - LOG("ospNewPixelOp(" << _type << ")"); - int L = strlen(_type); - char *type = (char *)alloca(L+1); - for (int i=0;i<=L;i++) { - char c = _type[i]; - if (c == '-' || c == ':') - c = '_'; - type[i] = c; - } - OSPPixelOp pixelOp = ospray::api::Device::current->newPixelOp(type); - return pixelOp; - } - - /*! \brief create a new renderer of given type - - return 'NULL' if that type is not known */ - extern "C" OSPRenderer ospNewRenderer(const char *_type) - { - ASSERT_DEVICE(); - - Assert2(_type,"invalid render type identifier in ospNewRenderer"); - LOG("ospNewRenderer(" << _type << ")"); - - std::string type(_type); - for (size_t i = 0; i < type.size(); i++) { - if (type[i] == '-' || type[i] == ':') - type[i] = '_'; - } - OSPRenderer renderer = ospray::api::Device::current->newRenderer(type.c_str()); - if ((ospray::logLevel > 0) && (renderer == NULL)) { - std::cerr << "#ospray: could not create renderer '" << type << "'" << std::endl; - } - return renderer; - } - - /*! \brief create a new geometry of given type - - return 'NULL' if that type is not known */ - extern "C" OSPGeometry ospNewGeometry(const char *type) - { - ASSERT_DEVICE(); - Assert(type != NULL && "invalid geometry type identifier in ospNewGeometry"); - LOG("ospNewGeometry(" << type << ")"); - OSPGeometry geometry = ospray::api::Device::current->newGeometry(type); - if ((ospray::logLevel > 0) && (geometry == NULL)) - std::cerr << "#ospray: could not create geometry '" << type << "'" << std::endl; - return geometry; - } - - /*! \brief create a new material of given type - - return 'NULL' if that type is not known */ - extern "C" OSPMaterial ospNewMaterial(OSPRenderer renderer, const char *type) - { - ASSERT_DEVICE(); - // Assert2(renderer != NULL, "invalid renderer handle in ospNewMaterial"); - Assert2(type != NULL, "invalid material type identifier in ospNewMaterial"); - LOG("ospNewMaterial(" << renderer << ", " << type << ")"); - OSPMaterial material = ospray::api::Device::current->newMaterial(renderer, type); - if ((ospray::logLevel > 0) && (material == NULL)) - std::cerr << "#ospray: could not create material '" << type << "'" << std::endl; - return material; - } - - extern "C" OSPLight ospNewLight(OSPRenderer renderer, const char *type) - { - ASSERT_DEVICE(); - Assert2(type != NULL, "invalid light type identifier in ospNewLight"); - LOG("ospNewLight(" << renderer << ", " << type << ")"); - OSPLight light = ospray::api::Device::current->newLight(renderer, type); - if ((ospray::logLevel > 0) && (light == NULL)) - std::cerr << "#ospray: could not create light '" << type << "'" << std::endl; - return light; - } - - /*! \brief create a new camera of given type - - return 'NULL' if that type is not known */ - extern "C" OSPCamera ospNewCamera(const char *type) - { - ASSERT_DEVICE(); - Assert(type != NULL && "invalid camera type identifier in ospNewCamera"); - LOG("ospNewCamera(" << type << ")"); - OSPCamera camera = ospray::api::Device::current->newCamera(type); - if ((ospray::logLevel > 0) && (camera == NULL)) - std::cerr << "#ospray: could not create camera '" << type << "'" << std::endl; - return camera; - } - - extern "C" OSPTexture2D ospNewTexture2D(int width, - int height, - OSPDataType type, - void *data, - int flags) - { - ASSERT_DEVICE(); - Assert2(width > 0, "Width must be greater than 0 in ospNewTexture2D"); - Assert2(height > 0, "Height must be greater than 0 in ospNewTexture2D"); - LOG("ospNewTexture2D( " << width << ", " << height << ", " << type << ", " << data << ", " << flags << ")"); - return ospray::api::Device::current->newTexture2D(width, height, type, data, flags); - } - - /*! \brief create a new volume of given type, return 'NULL' if that type is not known */ - extern "C" OSPVolume ospNewVolume(const char *type) - { - ASSERT_DEVICE(); - Assert(type != NULL && "invalid volume type identifier in ospNewVolume"); - LOG("ospNewVolume(" << type << ")"); - OSPVolume volume = ospray::api::Device::current->newVolume(type); - if (ospray::logLevel > 0) { - if (volume) - cout << "ospNewVolume: " << ((ospray::Volume*)volume)->toString() << endl; - else - std::cerr << "#ospray: could not create volume '" << type << "'" << std::endl; - } - if ((ospray::logLevel > 0) && (volume == NULL)) + // no device created on cmd line, yet, so default to localdevice + if (ospray::api::Device::current == NULL) { + ospray::api::Device::current = new ospray::api::LocalDevice(_ac,_av); + } +} + + +/*! destroy a given frame buffer. + + due to internal reference counting the framebuffer may or may not be deleted immediately +*/ +extern "C" void ospFreeFrameBuffer(OSPFrameBuffer fb) +{ + ASSERT_DEVICE(); + Assert(fb != NULL); + ospray::api::Device::current->release(fb); +} + +extern "C" OSPFrameBuffer ospNewFrameBuffer(const osp::vec2i &size, + const OSPFrameBufferFormat mode, + const uint32_t channels) +{ + ASSERT_DEVICE(); + return ospray::api::Device::current->frameBufferCreate((vec2i&)size, mode, channels); +} + +//! load module \ from shard lib libospray_module_\.so, or +extern "C" int32_t ospLoadModule(const char *moduleName) +{ + ASSERT_DEVICE(); + return ospray::api::Device::current->loadModule(moduleName); +} + +extern "C" const void *ospMapFrameBuffer(OSPFrameBuffer fb, + OSPFrameBufferChannel channel) +{ + ASSERT_DEVICE(); + return ospray::api::Device::current->frameBufferMap(fb,channel); +} + +extern "C" void ospUnmapFrameBuffer(const void *mapped, + OSPFrameBuffer fb) +{ + ASSERT_DEVICE(); + Assert(mapped != NULL && "invalid mapped pointer in ospUnmapFrameBuffer"); + ospray::api::Device::current->frameBufferUnmap(mapped,fb); +} + +extern "C" OSPModel ospNewModel() +{ + ASSERT_DEVICE(); + return ospray::api::Device::current->newModel(); +} + +extern "C" void ospAddGeometry(OSPModel model, OSPGeometry geometry) +{ + ASSERT_DEVICE(); + Assert(model != NULL && "invalid model in ospAddGeometry"); + Assert(geometry != NULL && "invalid geometry in ospAddGeometry"); + return ospray::api::Device::current->addGeometry(model,geometry); +} + +extern "C" void ospAddVolume(OSPModel model, OSPVolume volume) +{ + ASSERT_DEVICE(); + Assert(model != NULL && "invalid model in ospAddVolume"); + Assert(volume != NULL && "invalid volume in ospAddVolume"); + return ospray::api::Device::current->addVolume(model, volume); +} + +extern "C" void ospRemoveGeometry(OSPModel model, OSPGeometry geometry) +{ + ASSERT_DEVICE(); + Assert(model != NULL && "invalid model in ospRemoveGeometry"); + Assert(geometry != NULL && "invalid geometry in ospRemoveGeometry"); + return ospray::api::Device::current->removeGeometry(model, geometry); +} + +/*! create a new data buffer, with optional init data and control flags */ +extern "C" OSPData ospNewData(size_t nitems, OSPDataType format, const void *init, const uint32_t flags) +{ + ASSERT_DEVICE(); + return ospray::api::Device::current->newData(nitems,format,(void*)init,flags); +} + +/*! add a data array to another object */ +extern "C" void ospSetData(OSPObject object, const char *bufName, OSPData data) +{ + // assert(!rendering); + ASSERT_DEVICE(); + LOG("ospSetData(...,\"" << bufName << "\",...)"); + return ospray::api::Device::current->setObject(object,bufName,(OSPObject)data); +} + +/*! add an object parameter to another object */ +extern "C" void ospSetParam(OSPObject target, const char *bufName, OSPObject value) +{ + ASSERT_DEVICE(); + static bool warned = false; + if (!warned) { + std::cout << "'ospSetParam()' has been deprecated. Please use the new naming convention of 'ospSetObject()' instead" << std::endl; + warned = true; + } + LOG("ospSetParam(...,\"" << bufName << "\",...)"); + return ospray::api::Device::current->setObject(target,bufName,value); +} + +/*! set/add a pixel op to a frame buffer */ +extern "C" void ospSetPixelOp(OSPFrameBuffer fb, OSPPixelOp op) +{ + ASSERT_DEVICE(); + LOG("ospSetPixelOp(...,...)"); + return ospray::api::Device::current->setPixelOp(fb,op); +} + +/*! add an object parameter to another object */ +extern "C" void ospSetObject(OSPObject target, const char *bufName, OSPObject value) +{ + ASSERT_DEVICE(); + LOG("ospSetObject(...,\"" << bufName << "\",...)"); + return ospray::api::Device::current->setObject(target,bufName,value); +} + +/*! \brief create a new pixelOp of given type + + return 'NULL' if that type is not known */ +extern "C" OSPPixelOp ospNewPixelOp(const char *_type) +{ + ASSERT_DEVICE(); + Assert2(_type,"invalid render type identifier in ospNewPixelOp"); + LOG("ospNewPixelOp(" << _type << ")"); + int L = strlen(_type); + char *type = (char *)alloca(L+1); + for (int i=0;i<=L;i++) { + char c = _type[i]; + if (c == '-' || c == ':') + c = '_'; + type[i] = c; + } + OSPPixelOp pixelOp = ospray::api::Device::current->newPixelOp(type); + return pixelOp; +} + +/*! \brief create a new renderer of given type + + return 'NULL' if that type is not known */ +extern "C" OSPRenderer ospNewRenderer(const char *_type) +{ + ASSERT_DEVICE(); + + Assert2(_type,"invalid render type identifier in ospNewRenderer"); + LOG("ospNewRenderer(" << _type << ")"); + + std::string type(_type); + for (size_t i = 0; i < type.size(); i++) { + if (type[i] == '-' || type[i] == ':') + type[i] = '_'; + } + OSPRenderer renderer = ospray::api::Device::current->newRenderer(type.c_str()); + if ((ospray::logLevel > 0) && (renderer == NULL)) { + std::cerr << "#ospray: could not create renderer '" << type << "'" << std::endl; + } + return renderer; +} + +/*! \brief create a new geometry of given type + + return 'NULL' if that type is not known */ +extern "C" OSPGeometry ospNewGeometry(const char *type) +{ + ASSERT_DEVICE(); + Assert(type != NULL && "invalid geometry type identifier in ospNewGeometry"); + LOG("ospNewGeometry(" << type << ")"); + OSPGeometry geometry = ospray::api::Device::current->newGeometry(type); + if ((ospray::logLevel > 0) && (geometry == NULL)) + std::cerr << "#ospray: could not create geometry '" << type << "'" << std::endl; + return geometry; +} + +/*! \brief create a new material of given type + + return 'NULL' if that type is not known */ +extern "C" OSPMaterial ospNewMaterial(OSPRenderer renderer, const char *type) +{ + ASSERT_DEVICE(); + // Assert2(renderer != NULL, "invalid renderer handle in ospNewMaterial"); + Assert2(type != NULL, "invalid material type identifier in ospNewMaterial"); + LOG("ospNewMaterial(" << renderer << ", " << type << ")"); + OSPMaterial material = ospray::api::Device::current->newMaterial(renderer, type); + if ((ospray::logLevel > 0) && (material == NULL)) + std::cerr << "#ospray: could not create material '" << type << "'" << std::endl; + return material; +} + +extern "C" OSPLight ospNewLight(OSPRenderer renderer, const char *type) +{ + ASSERT_DEVICE(); + Assert2(type != NULL, "invalid light type identifier in ospNewLight"); + LOG("ospNewLight(" << renderer << ", " << type << ")"); + OSPLight light = ospray::api::Device::current->newLight(renderer, type); + if ((ospray::logLevel > 0) && (light == NULL)) + std::cerr << "#ospray: could not create light '" << type << "'" << std::endl; + return light; +} + +/*! \brief create a new camera of given type + + return 'NULL' if that type is not known */ +extern "C" OSPCamera ospNewCamera(const char *type) +{ + ASSERT_DEVICE(); + Assert(type != NULL && "invalid camera type identifier in ospNewCamera"); + LOG("ospNewCamera(" << type << ")"); + OSPCamera camera = ospray::api::Device::current->newCamera(type); + if ((ospray::logLevel > 0) && (camera == NULL)) + std::cerr << "#ospray: could not create camera '" << type << "'" << std::endl; + return camera; +} + +extern "C" OSPTexture2D ospNewTexture2D(const osp::vec2i &size, + const OSPTextureFormat type, + void *data, + const uint32_t flags) +{ + ASSERT_DEVICE(); + Assert2(size.x > 0, "Width must be greater than 0 in ospNewTexture2D"); + Assert2(size.y > 0, "Height must be greater than 0 in ospNewTexture2D"); + LOG("ospNewTexture2D( (" << size.x << ", " << size.y << "), " << type << ", " << data << ", " << flags << ")"); + return ospray::api::Device::current->newTexture2D((vec2i&)size, type, data, flags); +} + +/*! \brief create a new volume of given type, return 'NULL' if that type is not known */ +extern "C" OSPVolume ospNewVolume(const char *type) +{ + ASSERT_DEVICE(); + Assert(type != NULL && "invalid volume type identifier in ospNewVolume"); + LOG("ospNewVolume(" << type << ")"); + OSPVolume volume = ospray::api::Device::current->newVolume(type); + if (ospray::logLevel > 0) { + if (volume) + cout << "ospNewVolume: " << ((ospray::Volume*)volume)->toString() << endl; + else std::cerr << "#ospray: could not create volume '" << type << "'" << std::endl; - return volume; - } - - /*! \brief create a new transfer function of given type - return 'NULL' if that type is not known */ - extern "C" OSPTransferFunction ospNewTransferFunction(const char *type) - { - ASSERT_DEVICE(); - Assert(type != NULL && "invalid transfer function type identifier in ospNewTransferFunction"); - LOG("ospNewTransferFunction(" << type << ")"); - OSPTransferFunction transferFunction = ospray::api::Device::current->newTransferFunction(type); - if(ospray::logLevel > 0) { - if(transferFunction) - cout << "ospNewTransferFunction: " << ((ospray::TransferFunction*)transferFunction)->toString() << endl; - else - std::cerr << "#ospray: could not create transfer function '" << type << "'" << std::endl; - } - if ((ospray::logLevel > 0) && (transferFunction == NULL)) - std::cerr << "#ospray: could not create transferFunction '" << type << "'" << std::endl; - return transferFunction; } - - extern "C" void ospFrameBufferClear(OSPFrameBuffer fb, - const uint32_t fbChannelFlags) - { - ASSERT_DEVICE(); - ospray::api::Device::current->frameBufferClear(fb,fbChannelFlags); - } - - /*! \brief call a renderer to render given model into given framebuffer - - model _may_ be empty (though most framebuffers will expect one!) */ - extern "C" void ospRenderFrame(OSPFrameBuffer fb, - OSPRenderer renderer, - const uint32_t fbChannelFlags - ) - { - ASSERT_DEVICE(); + if ((ospray::logLevel > 0) && (volume == NULL)) + std::cerr << "#ospray: could not create volume '" << type << "'" << std::endl; + return volume; +} + +/*! \brief create a new transfer function of given type + return 'NULL' if that type is not known */ +extern "C" OSPTransferFunction ospNewTransferFunction(const char *type) +{ + ASSERT_DEVICE(); + Assert(type != NULL && "invalid transfer function type identifier in ospNewTransferFunction"); + LOG("ospNewTransferFunction(" << type << ")"); + OSPTransferFunction transferFunction = ospray::api::Device::current->newTransferFunction(type); + if(ospray::logLevel > 0) { + if(transferFunction) + cout << "ospNewTransferFunction: " << ((ospray::TransferFunction*)transferFunction)->toString() << endl; + else + std::cerr << "#ospray: could not create transfer function '" << type << "'" << std::endl; + } + if ((ospray::logLevel > 0) && (transferFunction == NULL)) + std::cerr << "#ospray: could not create transferFunction '" << type << "'" << std::endl; + return transferFunction; +} + +extern "C" void ospFrameBufferClear(OSPFrameBuffer fb, + const uint32_t fbChannelFlags) +{ + ASSERT_DEVICE(); + ospray::api::Device::current->frameBufferClear(fb,fbChannelFlags); +} + +/*! \brief call a renderer to render given model into given framebuffer + + model _may_ be empty (though most framebuffers will expect one!) */ +extern "C" float ospRenderFrame(OSPFrameBuffer fb, + OSPRenderer renderer, + const uint32_t fbChannelFlags + ) +{ + ASSERT_DEVICE(); #if 0 - double t0 = ospray::getSysTime(); - ospray::api::Device::current->renderFrame(fb,renderer,fbChannelFlags); - double t_frame = ospray::getSysTime() - t0; - static double nom = 0.f; - static double den = 0.f; - den = 0.95f*den + 1.f; - nom = 0.95f*nom + t_frame; - std::cout << "done rendering, time per frame = " << (t_frame*1000.f) << "ms, avg'ed fps = " << (den/nom) << std::endl; + double t0 = ospray::getSysTime(); + ospray::api::Device::current->renderFrame(fb,renderer,fbChannelFlags); + double t_frame = ospray::getSysTime() - t0; + static double nom = 0.f; + static double den = 0.f; + den = 0.95f*den + 1.f; + nom = 0.95f*nom + t_frame; + std::cout << "done rendering, time per frame = " << (t_frame*1000.f) << "ms, avg'ed fps = " << (den/nom) << std::endl; #else - // rendering = true; - ospray::api::Device::current->renderFrame(fb,renderer,fbChannelFlags); - // rendering = false; + // rendering = true; + return ospray::api::Device::current->renderFrame(fb,renderer,fbChannelFlags); + // rendering = false; #endif - } - - extern "C" void ospCommit(OSPObject object) - { - // assert(!rendering); - - ASSERT_DEVICE(); - Assert(object && "invalid object handle to commit to"); - LOG("ospCommit(...)"); - ospray::api::Device::current->commit(object); - } - - extern "C" void ospSetString(OSPObject _object, const char *id, const char *s) - { - ASSERT_DEVICE(); - ospray::api::Device::current->setString(_object,id,s); - } - - extern "C" void ospSetf(OSPObject _object, const char *id, float x) - { - ASSERT_DEVICE(); - ospray::api::Device::current->setFloat(_object,id,x); - } - - extern "C" void ospSet1f(OSPObject _object, const char *id, float x) - { - ASSERT_DEVICE(); - ospray::api::Device::current->setFloat(_object,id,x); - } - extern "C" void ospSet1i(OSPObject _object, const char *id, int32_t x) - { - ASSERT_DEVICE(); - ospray::api::Device::current->setInt(_object,id,x); - } - - extern "C" void ospSeti(OSPObject _object, const char *id, int x) - { - ASSERT_DEVICE(); - ospray::api::Device::current->setInt(_object,id,x); - } - - /*! Copy data into the given volume. */ - extern "C" int ospSetRegion(OSPVolume object, void *source, - const osp::vec3i &index, - const osp::vec3i &count) - { - ASSERT_DEVICE(); - return(ospray::api::Device::current->setRegion(object, source, (const vec3i&)index, (const vec3i&)count)); - } - - /*! add a vec2f parameter to an object */ - extern "C" void ospSetVec2f(OSPObject _object, const char *id, const osp::vec2f &v) - { - ASSERT_DEVICE(); - ospray::api::Device::current->setVec2f(_object, id, (const vec2f &)v); - } - - /*! add a vec2i parameter to an object */ - extern "C" void ospSetVec2i(OSPObject _object, const char *id, const osp::vec2i &v) - { - ASSERT_DEVICE(); - ospray::api::Device::current->setVec2i(_object, id, (const vec2i &)v); - } - - /*! add a vec3f parameter to another object */ - extern "C" void ospSetVec3f(OSPObject _object, const char *id, const osp::vec3f &v) - { - ASSERT_DEVICE(); - ospray::api::Device::current->setVec3f(_object,id,(const vec3f &)v); - } - - /*! add a vec4f parameter to another object */ - extern "C" void ospSetVec4f(OSPObject _object, const char *id, const osp::vec4f &v) - { - ASSERT_DEVICE(); - ospray::api::Device::current->setVec4f(_object,id,(const vec4f &)v); - } - - /*! add a vec3i parameter to another object */ - extern "C" void ospSetVec3i(OSPObject _object, const char *id, const osp::vec3i &v) - { - ASSERT_DEVICE(); - ospray::api::Device::current->setVec3i(_object,id,(const vec3i &)v); - } - - /*! add a vec2f parameter to another object */ - extern "C" void ospSet2f(OSPObject _object, const char *id, float x, float y) - { - ASSERT_DEVICE(); - ospray::api::Device::current->setVec2f(_object,id,ospray::vec2f(x,y)); - } - - /*! add a vec2f parameter to another object */ - extern "C" void ospSet2fv(OSPObject _object, const char *id, const float *xy) - { - ASSERT_DEVICE(); - ospray::api::Device::current->setVec2f(_object,id,vec2f(xy[0],xy[1])); - } - - /*! add a vec2i parameter to another object */ - extern "C" void ospSet2i(OSPObject _object, const char *id, int x, int y) - { - ASSERT_DEVICE(); - ospray::api::Device::current->setVec2i(_object,id,vec2i(x,y)); - } - - /*! add a vec2i parameter to another object */ - extern "C" void ospSet2iv(OSPObject _object, const char *id, const int *xy) - { - ASSERT_DEVICE(); - ospray::api::Device::current->setVec2i(_object,id,vec2i(xy[0],xy[1])); - } - - /*! add a vec3f parameter to another object */ - extern "C" void ospSet3f(OSPObject _object, const char *id, float x, float y, float z) - { - ASSERT_DEVICE(); - ospray::api::Device::current->setVec3f(_object,id,vec3f(x,y,z)); - } - - /*! add a vec3f parameter to another object */ - extern "C" void ospSet3fv(OSPObject _object, const char *id, const float *xyz) - { - ASSERT_DEVICE(); - ospray::api::Device::current->setVec3f(_object,id,vec3f(xyz[0],xyz[1],xyz[2])); - } - - /*! add a vec3i parameter to another object */ - extern "C" void ospSet3i(OSPObject _object, const char *id, int x, int y, int z) - { - ASSERT_DEVICE(); - ospray::api::Device::current->setVec3i(_object,id,vec3f(x,y,z)); - } - - /*! add a vec3i parameter to another object */ - extern "C" void ospSet3iv(OSPObject _object, const char *id, const int *xyz) - { - ASSERT_DEVICE(); - ospray::api::Device::current->setVec3i(_object,id,vec3f(xyz[0],xyz[1],xyz[2])); - } - - /*! add a vec4f parameter to another object */ - extern "C" void ospSet4f(OSPObject _object, const char *id, float x, float y, float z, float w) - { - ASSERT_DEVICE(); - ospray::api::Device::current->setVec4f(_object,id,vec4f(x,y,z,w)); - } - - /*! add a vec4f parameter to another object */ - extern "C" void ospSet4fv(OSPObject _object, const char *id, const float *xyzw) - { - ASSERT_DEVICE(); - ospray::api::Device::current->setVec4f(_object,id,vec4f(xyzw[0],xyzw[1],xyzw[2],xyzw[3])); - } - - /*! add a void pointer to another object */ - extern "C" void ospSetVoidPtr(OSPObject _object, const char *id, void *v) - { - ASSERT_DEVICE(); - ospray::api::Device::current->setVoidPtr(_object,id,v); - } - - extern "C" void ospRelease(OSPObject _object) - { - ASSERT_DEVICE(); - if (!_object) return; - ospray::api::Device::current->release(_object); - } - - //! assign given material to given geometry - extern "C" void ospSetMaterial(OSPGeometry geometry, OSPMaterial material) - { - ASSERT_DEVICE(); - Assert2(geometry,"NULL geometry passed to ospSetMaterial"); - ospray::api::Device::current->setMaterial(geometry,material); - } - - //! Get the handle of the named data array associated with an object. - extern "C" int ospGetData(OSPObject object, const char *name, OSPData *value) { - ASSERT_DEVICE(); - return(ospray::api::Device::current->getData(object, name, value)); - } - - //! Get a copy of the data in an array (the application is responsible for freeing this pointer). - extern "C" int ospGetDataValues(OSPData object, void **pointer, size_t *count, OSPDataType *type) { - ASSERT_DEVICE(); - return(ospray::api::Device::current->getDataValues(object, pointer, count, type)); - } - - //! Get the named scalar floating point value associated with an object. - extern "C" int ospGetf(OSPObject object, const char *name, float *value) - { - ASSERT_DEVICE(); - return(ospray::api::Device::current->getf(object, name, value)); - } - - //! Get the named scalar integer associated with an object. - extern "C" int ospGeti(OSPObject object, const char *name, int *value) - { - ASSERT_DEVICE(); - return(ospray::api::Device::current->geti(object, name, value)); - } - - //! Get the material associated with a geometry object. - extern "C" int ospGetMaterial(OSPGeometry geometry, OSPMaterial *value) - { - ASSERT_DEVICE(); - return(ospray::api::Device::current->getMaterial(geometry, value)); - } - - //! Get the named object associated with an object. - extern "C" int ospGetObject(OSPObject object, const char *name, OSPObject *value) - { - ASSERT_DEVICE(); - return(ospray::api::Device::current->getObject(object, name, value)); - } - - //! Retrieve a NULL-terminated list of the parameter names associated with an object. - extern "C" int ospGetParameters(OSPObject object, char ***value) { - ASSERT_DEVICE(); - return(ospray::api::Device::current->getParameters(object, value)); - } - - //! Get a pointer to a copy of the named character string associated with an object. - extern "C" int ospGetString(OSPObject object, const char *name, char **value) - { - ASSERT_DEVICE(); - return(ospray::api::Device::current->getString(object, name, value)); - } - - //! Get the type of the named parameter or the given object (if 'name' is NULL). - extern "C" int ospGetType(OSPObject object, const char *name, OSPDataType *value) - { - ASSERT_DEVICE(); - return(ospray::api::Device::current->getType(object, name, value)); - } - - //! Get the named 2-vector floating point value associated with an object. - extern "C" int ospGetVec2f(OSPObject object, const char *name, osp::vec2f *value) - { - ASSERT_DEVICE(); - return(ospray::api::Device::current->getVec2f(object, name, (vec2f *)value)); - } - - //! Get the named 3-vector floating point value associated with an object. - extern "C" int ospGetVec3f(OSPObject object, const char *name, osp::vec3f *value) - { - ASSERT_DEVICE(); - return(ospray::api::Device::current->getVec3f(object, name, (vec3f *)value)); - } - - //! Get the named 3-vector integer value associated with an object. - extern "C" int ospGetVec3i(OSPObject object, const char *name, osp::vec3i *value) - { - ASSERT_DEVICE(); - return(ospray::api::Device::current->getVec3i(object, name, (vec3i *)value)); - } - - /*! \brief create a new instance geometry that instantiates another - model. the resulting geometry still has to be added to another - model via ospAddGeometry */ - extern "C" OSPGeometry ospNewInstance(OSPModel modelToInstantiate, - const osp::affine3f &xfm) - { - ASSERT_DEVICE(); - // return ospray::api::Device::current->newInstance(modelToInstantiate,xfm); - OSPGeometry geom = ospNewGeometry("instance"); - ospSet3fv(geom,"xfm.l.vx",&xfm.l.vx.x); - ospSet3fv(geom,"xfm.l.vy",&xfm.l.vy.x); - ospSet3fv(geom,"xfm.l.vz",&xfm.l.vz.x); - ospSet3fv(geom,"xfm.p",&xfm.p.x); - ospSetObject(geom,"model",modelToInstantiate); - return geom; - } - - extern "C" void ospPick(OSPPickResult *result, OSPRenderer renderer, const osp::vec2f &screenPos) - { - ASSERT_DEVICE(); - Assert2(renderer, "NULL renderer passed to ospPick"); - if (!result) return; - *result = ospray::api::Device::current->pick(renderer, (const vec2f &)screenPos); - } - - //! \brief allows for switching the MPI scope from "per rank" to "all ranks" - extern "C" void ospdApiMode(OSPDApiMode mode) - { - ASSERT_DEVICE(); - ospray::api::Device::current->apiMode(mode); - } +} + +extern "C" void ospCommit(OSPObject object) +{ + // assert(!rendering); + + ASSERT_DEVICE(); + Assert(object && "invalid object handle to commit to"); + LOG("ospCommit(...)"); + ospray::api::Device::current->commit(object); +} + +extern "C" void ospSetString(OSPObject _object, const char *id, const char *s) +{ + ASSERT_DEVICE(); + ospray::api::Device::current->setString(_object,id,s); +} + +extern "C" void ospSetf(OSPObject _object, const char *id, float x) +{ + ASSERT_DEVICE(); + ospray::api::Device::current->setFloat(_object,id,x); +} + +extern "C" void ospSet1f(OSPObject _object, const char *id, float x) +{ + ASSERT_DEVICE(); + ospray::api::Device::current->setFloat(_object,id,x); +} +extern "C" void ospSet1i(OSPObject _object, const char *id, int32_t x) +{ + ASSERT_DEVICE(); + ospray::api::Device::current->setInt(_object,id,x); +} + +extern "C" void ospSeti(OSPObject _object, const char *id, int x) +{ + ASSERT_DEVICE(); + ospray::api::Device::current->setInt(_object,id,x); +} + +/*! Copy data into the given volume. */ +extern "C" int ospSetRegion(OSPVolume object, void *source, + const osp::vec3i &index, const osp::vec3i &count) +{ + ASSERT_DEVICE(); + return(ospray::api::Device::current->setRegion(object, source, + (vec3i&)index, + (vec3i&)count)); +} + +/*! add a vec2f parameter to an object */ +extern "C" void ospSetVec2f(OSPObject _object, const char *id, const osp::vec2f &v) +{ + ASSERT_DEVICE(); + ospray::api::Device::current->setVec2f(_object, id, (const vec2f &)v); +} + +/*! add a vec2i parameter to an object */ +extern "C" void ospSetVec2i(OSPObject _object, const char *id, const osp::vec2i &v) +{ + ASSERT_DEVICE(); + ospray::api::Device::current->setVec2i(_object, id, (const vec2i &)v); +} + +/*! add a vec3f parameter to another object */ +extern "C" void ospSetVec3f(OSPObject _object, const char *id, const osp::vec3f &v) +{ + ASSERT_DEVICE(); + ospray::api::Device::current->setVec3f(_object,id,(const vec3f &)v); +} + +/*! add a vec4f parameter to another object */ +extern "C" void ospSetVec4f(OSPObject _object, const char *id, const osp::vec4f &v) +{ + ASSERT_DEVICE(); + ospray::api::Device::current->setVec4f(_object,id,(const vec4f &)v); +} + +/*! add a vec3i parameter to another object */ +extern "C" void ospSetVec3i(OSPObject _object, const char *id, const osp::vec3i &v) +{ + ASSERT_DEVICE(); + ospray::api::Device::current->setVec3i(_object,id,(const vec3i &)v); +} + +/*! add a vec2f parameter to another object */ +extern "C" void ospSet2f(OSPObject _object, const char *id, float x, float y) +{ + ASSERT_DEVICE(); + ospray::api::Device::current->setVec2f(_object,id,ospray::vec2f(x,y)); +} + +/*! add a vec2f parameter to another object */ +extern "C" void ospSet2fv(OSPObject _object, const char *id, const float *xy) +{ + ASSERT_DEVICE(); + ospray::api::Device::current->setVec2f(_object,id,vec2f(xy[0],xy[1])); +} + +/*! add a vec2i parameter to another object */ +extern "C" void ospSet2i(OSPObject _object, const char *id, int x, int y) +{ + ASSERT_DEVICE(); + ospray::api::Device::current->setVec2i(_object,id,vec2i(x,y)); +} + +/*! add a vec2i parameter to another object */ +extern "C" void ospSet2iv(OSPObject _object, const char *id, const int *xy) +{ + ASSERT_DEVICE(); + ospray::api::Device::current->setVec2i(_object,id,vec2i(xy[0],xy[1])); +} + +/*! add a vec3f parameter to another object */ +extern "C" void ospSet3f(OSPObject _object, const char *id, float x, float y, float z) +{ + ASSERT_DEVICE(); + ospray::api::Device::current->setVec3f(_object,id,vec3f(x,y,z)); +} + +/*! add a vec3f parameter to another object */ +extern "C" void ospSet3fv(OSPObject _object, const char *id, const float *xyz) +{ + ASSERT_DEVICE(); + ospray::api::Device::current->setVec3f(_object,id,vec3f(xyz[0],xyz[1],xyz[2])); +} + +/*! add a vec3i parameter to another object */ +extern "C" void ospSet3i(OSPObject _object, const char *id, int x, int y, int z) +{ + ASSERT_DEVICE(); + ospray::api::Device::current->setVec3i(_object,id,vec3i(x,y,z)); +} + +/*! add a vec3i parameter to another object */ +extern "C" void ospSet3iv(OSPObject _object, const char *id, const int *xyz) +{ + ASSERT_DEVICE(); + ospray::api::Device::current->setVec3i(_object,id,vec3i(xyz[0],xyz[1],xyz[2])); +} + +/*! add a vec4f parameter to another object */ +extern "C" void ospSet4f(OSPObject _object, const char *id, float x, float y, float z, float w) +{ + ASSERT_DEVICE(); + ospray::api::Device::current->setVec4f(_object,id,vec4f(x,y,z,w)); +} + +/*! add a vec4f parameter to another object */ +extern "C" void ospSet4fv(OSPObject _object, const char *id, const float *xyzw) +{ + ASSERT_DEVICE(); + ospray::api::Device::current->setVec4f(_object,id,vec4f(xyzw[0],xyzw[1],xyzw[2],xyzw[3])); +} + +/*! add a void pointer to another object */ +extern "C" void ospSetVoidPtr(OSPObject _object, const char *id, void *v) +{ + ASSERT_DEVICE(); + ospray::api::Device::current->setVoidPtr(_object,id,v); +} + +extern "C" void ospRelease(OSPObject _object) +{ + ASSERT_DEVICE(); + if (!_object) return; + ospray::api::Device::current->release(_object); +} + +//! assign given material to given geometry +extern "C" void ospSetMaterial(OSPGeometry geometry, OSPMaterial material) +{ + ASSERT_DEVICE(); + Assert2(geometry,"NULL geometry passed to ospSetMaterial"); + ospray::api::Device::current->setMaterial(geometry,material); +} + +//! Get the handle of the named data array associated with an object. +extern "C" int ospGetData(OSPObject object, const char *name, OSPData *value) { + ASSERT_DEVICE(); + return(ospray::api::Device::current->getData(object, name, value)); +} + +//! Get a copy of the data in an array (the application is responsible for freeing this pointer). +extern "C" int ospGetDataValues(OSPData object, void **pointer, size_t *count, OSPDataType *type) { + ASSERT_DEVICE(); + return(ospray::api::Device::current->getDataValues(object, pointer, count, type)); +} + +//! Get the named scalar floating point value associated with an object. +extern "C" int ospGetf(OSPObject object, const char *name, float *value) +{ + ASSERT_DEVICE(); + return(ospray::api::Device::current->getf(object, name, value)); +} + +//! Get the named scalar integer associated with an object. +extern "C" int ospGeti(OSPObject object, const char *name, int *value) +{ + ASSERT_DEVICE(); + return(ospray::api::Device::current->geti(object, name, value)); +} + +//! Get the material associated with a geometry object. +extern "C" int ospGetMaterial(OSPGeometry geometry, OSPMaterial *value) +{ + ASSERT_DEVICE(); + return(ospray::api::Device::current->getMaterial(geometry, value)); +} + +//! Get the named object associated with an object. +extern "C" int ospGetObject(OSPObject object, const char *name, OSPObject *value) +{ + ASSERT_DEVICE(); + return(ospray::api::Device::current->getObject(object, name, value)); +} + +//! Retrieve a NULL-terminated list of the parameter names associated with an object. +extern "C" int ospGetParameters(OSPObject object, char ***value) { + ASSERT_DEVICE(); + return(ospray::api::Device::current->getParameters(object, value)); +} + +//! Get a pointer to a copy of the named character string associated with an object. +extern "C" int ospGetString(OSPObject object, const char *name, char **value) +{ + ASSERT_DEVICE(); + return(ospray::api::Device::current->getString(object, name, value)); +} + +//! Get the type of the named parameter or the given object (if 'name' is NULL). +extern "C" int ospGetType(OSPObject object, const char *name, OSPDataType *value) +{ + ASSERT_DEVICE(); + return(ospray::api::Device::current->getType(object, name, value)); +} + +//! Get the named 2-vector floating point value associated with an object. +extern "C" int ospGetVec2f(OSPObject object, const char *name, osp::vec2f *value) +{ + ASSERT_DEVICE(); + return(ospray::api::Device::current->getVec2f(object, name, (vec2f *)value)); +} + +//! Get the named 3-vector floating point value associated with an object. +extern "C" int ospGetVec3f(OSPObject object, const char *name, osp::vec3f *value) +{ + ASSERT_DEVICE(); + return(ospray::api::Device::current->getVec3f(object, name, (vec3f *)value)); +} + +//! Get the named 3-vector integer value associated with an object. +extern "C" int ospGetVec3i(OSPObject object, const char *name, osp::vec3i *value) +{ + ASSERT_DEVICE(); + return(ospray::api::Device::current->getVec3i(object, name, (vec3i *)value)); +} + +/*! \brief create a new instance geometry that instantiates another + model. the resulting geometry still has to be added to another + model via ospAddGeometry */ +extern "C" OSPGeometry ospNewInstance(OSPModel modelToInstantiate, + const osp::affine3f &xfm) +{ + ASSERT_DEVICE(); + // return ospray::api::Device::current->newInstance(modelToInstantiate,xfm); + OSPGeometry geom = ospNewGeometry("instance"); + ospSet3fv(geom,"xfm.l.vx",&xfm.l.vx.x); + ospSet3fv(geom,"xfm.l.vy",&xfm.l.vy.x); + ospSet3fv(geom,"xfm.l.vz",&xfm.l.vz.x); + ospSet3fv(geom,"xfm.p",&xfm.p.x); + ospSetObject(geom,"model",modelToInstantiate); + return geom; +} + +extern "C" void ospPick(OSPPickResult *result, + OSPRenderer renderer, + const osp::vec2f &screenPos) +{ + ASSERT_DEVICE(); + Assert2(renderer, "NULL renderer passed to ospPick"); + if (!result) return; + *result = ospray::api::Device::current->pick(renderer, (const vec2f&)screenPos); +} + +//! \brief allows for switching the MPI scope from "per rank" to "all ranks" +// extern "C" void ospdApiMode(OSPDApiMode mode) +// { +// ASSERT_DEVICE(); +// ospray::api::Device::current->apiMode(mode); +// } #ifdef OSPRAY_MPI - //! \brief initialize the ospray engine (for use with MPI-parallel app) - /*! \detailed Note the application must call this function "INSTEAD OF" - MPI_Init(), NOT "in addition to" */ - extern "C" void ospdMpiInit(int *ac, char ***av, OSPDRenderMode mode) - { - if (ospray::api::Device::current != NULL) - throw std::runtime_error("#osp:mpi: OSPRay already initialized!?"); - ospray::mpi::initDistributedAPI(ac,av,mode); - } - - //! the 'lid to the pot' of ospdMpiInit(). - /*! does both an osp shutdown and an mpi shutdown for the mpi group - created with ospdMpiInit */ - extern "C" void ospdMpiShutdown() - { - } +//! \brief initialize the ospray engine (for use with MPI-parallel app) +/*! \detailed Note the application must call this function "INSTEAD OF" + MPI_Init(), NOT "in addition to" */ +extern "C" void ospdMpiInit(int *ac, char ***av, OSPDRenderMode mode) +{ + if (ospray::api::Device::current != NULL) + throw std::runtime_error("#osp:mpi: OSPRay already initialized!?"); + ospray::mpi::initDistributedAPI(ac,av,mode); +} + +//! the 'lid to the pot' of ospdMpiInit(). +/*! does both an osp shutdown and an mpi shutdown for the mpi group + created with ospdMpiInit */ +extern "C" void ospdMpiShutdown() +{ +} #endif - extern "C" OSPPickData ospUnproject(OSPRenderer renderer, const osp::vec2f &screenPos) - { - static bool warned = false; - if (!warned) { - std::cout << "'ospUnproject()' has been deprecated. Please use the new function 'ospPick()' instead" << std::endl; - warned = true; - } - ASSERT_DEVICE(); - Assert2(renderer, "NULL renderer passed to ospUnproject"); - vec2f flippedScreenPos = vec2f(screenPos.x, 1.0f - screenPos.y); - OSPPickResult pick = ospray::api::Device::current->pick(renderer, flippedScreenPos); - OSPPickData res = { pick.hit, pick.position.x, pick.position.y, pick.position.z }; - return res; - } - - extern "C" void ospSampleVolume(float **results, - OSPVolume volume, - const osp::vec3f *worldCoordinates, - const size_t &count) - { - ASSERT_DEVICE(); - Assert2(volume, "NULL volume passed to ospSampleVolume"); - - if (count == 0) { - *results = NULL; - return; - } +extern "C" void ospSampleVolume(float **results, + OSPVolume volume, + const osp::vec3f &worldCoordinates, + const size_t count) +{ + ASSERT_DEVICE(); + Assert2(volume, "NULL volume passed to ospSampleVolume"); - Assert2(worldCoordinates, "NULL worldCoordinates passed to ospSampleVolume"); - - ospray::api::Device::current->sampleVolume(results, volume, (const vec3f *)worldCoordinates, count); + if (count == 0) { + *results = NULL; + return; } + ospray::api::Device::current->sampleVolume(results, volume, (vec3f*)&worldCoordinates, count); +} + diff --git a/ospray/api/COIDeviceHost.cpp b/ospray/api/COIDeviceHost.cpp index 45904c9c13..956576ac62 100644 --- a/ospray/api/COIDeviceHost.cpp +++ b/ospray/api/COIDeviceHost.cpp @@ -358,14 +358,11 @@ namespace ospray { OSPLight newLight(OSPRenderer _renderer, const char *type) override; /*! create a new Texture2D object */ - OSPTexture2D newTexture2D(int width, - int height, - OSPDataType type, - void *data, - int flags) override; + OSPTexture2D newTexture2D(const vec2i &size, const OSPTextureFormat, + void *data, const uint32 flags) override; /*! call a renderer to render a frame buffer */ - void renderFrame(OSPFrameBuffer _sc, + float renderFrame(OSPFrameBuffer _sc, OSPRenderer _renderer, const uint32 fbChannelFlags) override; @@ -743,7 +740,7 @@ namespace ospray { } /*! call a renderer to render a frame buffer */ - void COIDevice::renderFrame(OSPFrameBuffer _sc, + float COIDevice::renderFrame(OSPFrameBuffer _sc, OSPRenderer _renderer, const uint32 fbChannelFlags) { @@ -751,8 +748,10 @@ namespace ospray { args.write((ObjectHandle&)_sc); args.write((ObjectHandle&)_renderer); args.write((uint32&)fbChannelFlags); - callFunction(OSPCOI_RENDER_FRAME,args,nullptr,false); + float retValue = 1.0f; + callFunction(OSPCOI_RENDER_FRAME,args, &retValue, sizeof(retValue)); callFunction(OSPCOI_RENDER_FRAME_SYNC,args,nullptr,true); + return retValue; } @@ -886,26 +885,23 @@ namespace ospray { } /*! create a new texture2D */ - OSPTexture2D COIDevice::newTexture2D(int width, - int height, - OSPDataType type, - void *data, - int flags) + OSPTexture2D COIDevice::newTexture2D(const vec2i &sz, + const OSPTextureFormat type, void *data, const uint32 flags) { COIRESULT result; DataStream args; ObjectHandle ID = ObjectHandle::alloc(); - if (width * height == 0) { + if (sz.x * sz.y == 0) { throw std::runtime_error("cowardly refusing to create empty texture..."); } args.write(ID); - args.write((int32)width); - args.write((int32)height); + args.write((int32)sz.x); + args.write((int32)sz.y); args.write((int32)type); args.write((int32)flags); - int64 numBytes = sizeOf(type)*width*height; + int64 numBytes = sizeOf(type) * sz.x * sz.y; for (auto &engine : engines) { COIBUFFER coiBuffer; // PRINT(nitems); @@ -1025,7 +1021,7 @@ namespace ospray { args.write((uint32)mode); args.write(channels); - Assert(mode == OSP_RGBA_I8); + Assert(mode == OSP_FB_RGBA8); COIFrameBuffer *fb = new COIFrameBuffer; fbList[handle] = fb; fb->hostMem = new int32[size.x*size.y]; diff --git a/ospray/api/COIDeviceWorker.cpp b/ospray/api/COIDeviceWorker.cpp index bf7c3a77a2..2e39690753 100644 --- a/ospray/api/COIDeviceWorker.cpp +++ b/ospray/api/COIDeviceWorker.cpp @@ -520,14 +520,13 @@ namespace ospray { { DataStream args(argsPtr); ObjectHandle handle = args.get(); - int width = args.get(); - int height = args.get(); + vec2i size = args.get(); int type = args.get(); int flags = args.get(); COIBufferAddRef(bufferPtr[0]); - Texture2D *tx = Texture2D::createTexture(width, height, (OSPDataType)type, bufferPtr[0], flags); + Texture2D *tx = Texture2D::createTexture(size, (OSPTextureFormat)type, bufferPtr[0], flags); handle.assign(tx); if (ospray::debugMode) COIProcessProxyFlush(); @@ -642,7 +641,7 @@ namespace ospray { /*! remove an existing geometry from a model */ struct GeometryLocator { - bool operator()(const embree::Ref &g) const { + bool operator()(const Ref &g) const { return ptr == &*g; } Geometry *ptr; @@ -676,7 +675,7 @@ namespace ospray { /*! remove an existing volume from a model */ struct VolumeLocator { - bool operator()(const embree::Ref &g) const { + bool operator()(const Ref &g) const { return ptr == &*g; } Volume *ptr; @@ -723,7 +722,8 @@ namespace ospray { uint32 channelFlags = args.get(); FrameBuffer *fb = (FrameBuffer*)_fb.lookup(); Renderer *r = (Renderer*)renderer.lookup(); - r->renderFrame(fb,channelFlags); + float v = r->renderFrame(fb,channelFlags); + memcpy(retVal, &v, retValSize); } COINATIVELIBEXPORT diff --git a/ospray/api/Device.h b/ospray/api/Device.h index 3aea6c1654..bfcbdeae4c 100644 --- a/ospray/api/Device.h +++ b/ospray/api/Device.h @@ -43,7 +43,7 @@ namespace ospray { /*! map frame buffer */ virtual const void *frameBufferMap(OSPFrameBuffer fb, - OSPFrameBufferChannel) = 0; + const OSPFrameBufferChannel) = 0; /*! unmap previously mapped frame buffer */ virtual void frameBufferUnmap(const void *mapped, @@ -171,7 +171,8 @@ namespace ospray { virtual OSPMaterial newMaterial(OSPRenderer _renderer, const char *type) = 0; /*! create a new Texture2D object */ - virtual OSPTexture2D newTexture2D(int width, int height, OSPDataType type, void *data, int flags) = 0; + virtual OSPTexture2D newTexture2D(const vec2i &size, + const OSPTextureFormat, void *data, const uint32 flags) = 0; /*! have given renderer create a new Light */ virtual OSPLight newLight(OSPRenderer _renderer, const char *type) = 0; @@ -191,7 +192,7 @@ namespace ospray { const uint32 fbChannelFlags) = 0; /*! call a renderer to render a frame buffer */ - virtual void renderFrame(OSPFrameBuffer _sc, + virtual float renderFrame(OSPFrameBuffer _sc, OSPRenderer _renderer, const uint32 fbChannelFlags) = 0; @@ -225,7 +226,7 @@ namespace ospray { virtual OSPPickResult pick(OSPRenderer renderer, const vec2f &screenPos) { throw std::runtime_error("pick() not impelemnted for this device"); - }; + } /*! switch API mode for distriubted API extensions */ virtual void apiMode(OSPDApiMode mode) diff --git a/ospray/api/LocalDevice.cpp b/ospray/api/LocalDevice.cpp index 6b47c10b81..947caa9d85 100644 --- a/ospray/api/LocalDevice.cpp +++ b/ospray/api/LocalDevice.cpp @@ -33,6 +33,8 @@ #include namespace ospray { + extern RTCDevice g_embreeDevice; + namespace api { void embreeErrorFunc(const RTCError code, const char* str) @@ -44,12 +46,8 @@ namespace ospray { LocalDevice::LocalDevice(int *_ac, const char **_av) { char *logLevelFromEnv = getenv("OSPRAY_LOG_LEVEL"); - if (logLevelFromEnv) + if (logLevelFromEnv && logLevel == 0) logLevel = atoi(logLevelFromEnv); - else - logLevel = 0; - - ospray::init(_ac,&_av); // ------------------------------------------------------- // initialize embree. (we need to do this here rather than in @@ -61,11 +59,11 @@ namespace ospray { embreeConfig << " threads=1,verbose=2"; else if(numThreads > 0) embreeConfig << " threads=" << numThreads; - rtcInit(embreeConfig.str().c_str()); + g_embreeDevice = rtcNewDevice(embreeConfig.str().c_str()); - rtcSetErrorFunction(embreeErrorFunc); // needs to come after rtcInit + rtcDeviceSetErrorFunction(g_embreeDevice, embreeErrorFunc); - RTCError erc = rtcGetError(); + RTCError erc = rtcDeviceGetError(g_embreeDevice); if (erc != RTC_NO_ERROR) { // why did the error function not get called !? std::cerr << "#osp:init: embree internal error number " << (int)erc << std::endl; @@ -77,7 +75,7 @@ namespace ospray { LocalDevice::~LocalDevice() { - rtcExit(); + rtcDeleteDevice(g_embreeDevice); } OSPFrameBuffer @@ -88,9 +86,11 @@ namespace ospray { FrameBuffer::ColorBufferFormat colorBufferFormat = mode; //FrameBuffer::RGBA_UINT8;//FLOAT32; bool hasDepthBuffer = (channels & OSP_FB_DEPTH)!=0; bool hasAccumBuffer = (channels & OSP_FB_ACCUM)!=0; + bool hasVarianceBuffer = (channels & OSP_FB_VARIANCE)!=0; FrameBuffer *fb = new LocalFrameBuffer(size,colorBufferFormat, - hasDepthBuffer,hasAccumBuffer); + hasDepthBuffer,hasAccumBuffer, + hasVarianceBuffer); fb->refInc(); return (OSPFrameBuffer)fb; } @@ -171,7 +171,7 @@ namespace ospray { /*! remove an existing geometry from a model */ struct GeometryLocator { - bool operator()(const embree::Ref &g) const { + bool operator()(const Ref &g) const { return ptr == &*g; } Geometry *ptr; @@ -207,7 +207,7 @@ namespace ospray { /*! remove an existing volume from a model */ struct VolumeLocator { - bool operator()(const embree::Ref &g) const { + bool operator()(const Ref &g) const { return ptr == &*g; } Volume *ptr; @@ -613,10 +613,12 @@ namespace ospray { } /*! create a new Texture2D object */ - OSPTexture2D LocalDevice::newTexture2D(int width, int height, OSPDataType type, void *data, int flags) { - Assert(width > 0 && "Width must be greater than 0 in LocalDevice::newTexture2D"); - Assert(height > 0 && "Height must be greater than 0 in LocalDevice::newTexture2D"); - Texture2D *tx = Texture2D::createTexture(width, height, type, data, flags); + OSPTexture2D LocalDevice::newTexture2D(const vec2i &size, + const OSPTextureFormat type, void *data, const uint32 flags) + { + Assert(size.x > 0 && "Width must be greater than 0 in LocalDevice::newTexture2D"); + Assert(size.y > 0 && "Height must be greater than 0 in LocalDevice::newTexture2D"); + Texture2D *tx = Texture2D::createTexture(size, type, data, flags); if(tx) tx->refInc(); return (OSPTexture2D)tx; } @@ -651,11 +653,11 @@ namespace ospray { /*! call a renderer to render a frame buffer */ - void LocalDevice::renderFrame(OSPFrameBuffer _fb, + float LocalDevice::renderFrame(OSPFrameBuffer _fb, OSPRenderer _renderer, const uint32 fbChannelFlags) { - FrameBuffer *fb = (FrameBuffer *)_fb; + FrameBuffer *fb = (FrameBuffer *)_fb; // SwapChain *sc = (SwapChain *)_sc; Renderer *renderer = (Renderer *)_renderer; // Model *model = (Model *)_model; @@ -666,7 +668,7 @@ namespace ospray { // FrameBuffer *fb = sc->getBackBuffer(); try { - renderer->renderFrame(fb,fbChannelFlags); + return renderer->renderFrame(fb,fbChannelFlags); } catch (std::runtime_error e) { std::cerr << "=======================================================" << std::endl; std::cerr << "# >>> ospray fatal error <<< " << std::endl << e.what() << std::endl; diff --git a/ospray/api/LocalDevice.h b/ospray/api/LocalDevice.h index b644a3b8a4..38673bf23c 100644 --- a/ospray/api/LocalDevice.h +++ b/ospray/api/LocalDevice.h @@ -16,7 +16,11 @@ #pragma once +//ospray #include "Device.h" +//embree +#include "embree2/rtcore.h" + /*! \file localdevice.h Implements the "local" device for local rendering */ @@ -48,7 +52,7 @@ namespace ospray { /*! set a frame buffer's pixel op object */ void setPixelOp(OSPFrameBuffer _fb, OSPPixelOp _op) override; - + /*! create a new model */ OSPModel newModel() override; @@ -195,19 +199,16 @@ namespace ospray { OSPLight newLight(OSPRenderer _renderer, const char *type) override; /*! create a new Texture2D object */ - OSPTexture2D newTexture2D(int width, - int height, - OSPDataType type, - void *data, - int flags) override; + OSPTexture2D newTexture2D(const vec2i &size, const OSPTextureFormat, + void *data, const uint32 flags) override; /*! clear the specified channel(s) of the frame buffer specified in 'whichChannels' - + if whichChannel&OSP_FB_COLOR!=0, clear the color buffer to - '0,0,0,0'. + '0,0,0,0'. if whichChannel&OSP_FB_DEPTH!=0, clear the depth buffer to - +inf. + +inf. if whichChannel&OSP_FB_ACCUM!=0, clear the accum buffer to 0,0,0,0, and reset accumID. @@ -216,8 +217,8 @@ namespace ospray { const uint32 fbChannelFlags) override; /*! call a renderer to render a frame buffer */ - void renderFrame(OSPFrameBuffer _sc, - OSPRenderer _renderer, + float renderFrame(OSPFrameBuffer _sc, + OSPRenderer _renderer, const uint32 fbChannelFlags) override; //! release (i.e., reduce refcount of) given object @@ -241,7 +242,6 @@ namespace ospray { OSPVolume volume, const vec3f *worldCoordinates, const size_t &count) override; - }; } // ::ospray::api diff --git a/ospray/common/Data.cpp b/ospray/common/Data.cpp index fdfda67d76..a8862a56f9 100644 --- a/ospray/common/Data.cpp +++ b/ospray/common/Data.cpp @@ -19,9 +19,6 @@ // stl #include -using embree::alignedFree; -using embree::alignedMalloc; - namespace ospray { Data::Data(size_t numItems, OSPDataType type, void *init, int flags) : diff --git a/ospray/common/Library.cpp b/ospray/common/Library.cpp deleted file mode 100644 index 42d2cbee11..0000000000 --- a/ospray/common/Library.cpp +++ /dev/null @@ -1,74 +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. // -// ======================================================================== // - -// ospray -#include "Library.h" -// std - -#ifdef _WIN32 -# define WIN32_LEAN_AND_MEAN -# include -#else -# include -#endif - -namespace ospray { - - std::vector loadedLibs; - - void loadLibrary(const std::string &_name) - { -#ifdef OSPRAY_TARGET_MIC - std::string name = _name+"_mic"; -#else - std::string name = _name; -#endif - - for (int i=0;iname == name) - // lib already loaded. - return; - - Library *lib = new Library; - lib->name = name; - lib->lib = embree::openLibrary(name); - if (lib->lib == NULL) - throw std::runtime_error("could not open module lib "+name); - - loadedLibs.push_back(lib); - } - void *getSymbol(const std::string &name) - { - for (int i=0;ilib, name); - if (sym) return sym; - } - - // if none found in the loaded libs, try the default lib ... -#ifdef _WIN32 - void *sym = GetProcAddress(GetModuleHandle(0), name.c_str()); // look in exe (i.e. when linked statically) - if (!sym) { - MEMORY_BASIC_INFORMATION mbi; - VirtualQuery(getSymbol, &mbi, sizeof(mbi)); // get handle to current dll via a known function - sym = GetProcAddress((HINSTANCE)(mbi.AllocationBase), name.c_str()); // look in ospray.dll (i.e. when linked dynamically) - } -#else - void *sym = dlsym(RTLD_DEFAULT,name.c_str()); -#endif - return sym; - } - -} // ::ospray diff --git a/ospray/common/Library.h b/ospray/common/Library.h index 6971942e24..4a383ce790 100644 --- a/ospray/common/Library.h +++ b/ospray/common/Library.h @@ -16,19 +16,9 @@ #pragma once -//ospray stuff -#include "Managed.h" - -//embree stuff -#include "common/sys/library.h" +#include "common/library.h" namespace ospray { - struct Library - { - std::string name; - embree::lib_t lib; - }; - - void loadLibrary(const std::string &name); - void *getSymbol(const std::string &name); + using ospcommon::getSymbol; + using ospcommon::loadLibrary; } diff --git a/ospray/common/Managed.cpp b/ospray/common/Managed.cpp index 97b42f13fc..577a5758de 100644 --- a/ospray/common/Managed.cpp +++ b/ospray/common/Managed.cpp @@ -70,6 +70,7 @@ namespace ospray { ptr = object; type = OSP_OBJECT; } + void ManagedObject::Param::set(const char *str) { Assert2(this,"trying to set null parameter"); @@ -77,6 +78,7 @@ namespace ospray { this->s = strdup(str); type = OSP_STRING; } + void ManagedObject::Param::set(void *ptr) { Assert2(this,"trying to set null parameter"); @@ -84,6 +86,7 @@ namespace ospray { (void*&)this->ptr = ptr; type = OSP_VOID_PTR; } + void ManagedObject::Param::clear() { Assert2(this,"trying to clear null parameter"); @@ -94,6 +97,7 @@ namespace ospray { type = OSP_OBJECT; ptr = NULL; } + ManagedObject::Param::Param(const char *name) : name(NULL), type(OSP_FLOAT), ptr(NULL) { @@ -160,4 +164,30 @@ namespace ospray { } } + void ManagedObject::emitMessage(const std::string &kind, + const std::string &message) const + { + std::cerr << " " + toString() + << " " + kind + ": " + message + "." << std::endl; + } + + void ManagedObject::exitOnCondition(bool condition, + const std::string &message) const + { + if (!condition) + return; + emitMessage("ERROR", message); + exit(1); + } + + void ManagedObject::warnOnCondition(bool condition, + const std::string &message) const + { + if (!condition) + return; + + emitMessage("WARNING", message); + } + + } // ::ospray diff --git a/ospray/common/Managed.h b/ospray/common/Managed.h index fe1a269a18..e6664e8f91 100644 --- a/ospray/common/Managed.h +++ b/ospray/common/Managed.h @@ -103,7 +103,7 @@ namespace ospray { */ - struct ManagedObject : public embree::RefCount + struct ManagedObject : public RefCount { /*! \brief constructor */ ManagedObject(); @@ -248,6 +248,17 @@ namespace ospray { /*! \detailed this object will no longer get update notifications from us */ void unregisterListener(ManagedObject *noLongerListening); + + //! Print an error message. + void emitMessage(const std::string &kind, const std::string &message) const; + + //! Error checking. + void exitOnCondition(bool condition, const std::string &message) const; + + //! Warning condition. + void warnOnCondition(bool condition, const std::string &message) const; + + // ------------------------------------------------------- // member variables // ------------------------------------------------------- diff --git a/ospray/common/Model.cpp b/ospray/common/Model.cpp index 90bc095a8b..7255131409 100644 --- a/ospray/common/Model.cpp +++ b/ospray/common/Model.cpp @@ -30,6 +30,8 @@ namespace ospray { using std::cout; using std::endl; + extern RTCDevice g_embreeDevice; + Model::Model() { managedObjectType = OSP_MODEL; @@ -44,10 +46,10 @@ namespace ospray { << geometry.size() << " geometries and " << volume.size() << " volumes" << std::endl << std::flush; } - ispc::Model_init(getIE(), geometry.size(), volume.size()); + ispc::Model_init(getIE(), g_embreeDevice, geometry.size(), volume.size()); embreeSceneHandle = (RTCScene)ispc::Model_getEmbreeSceneHandle(getIE()); - bounds = embree::empty; + bounds = empty; // for now, only implement triangular geometry... for (size_t i=0; i < geometry.size(); i++) { diff --git a/ospray/common/Model.ih b/ospray/common/Model.ih index 0b28a2fc1b..fdd02d1586 100644 --- a/ospray/common/Model.ih +++ b/ospray/common/Model.ih @@ -22,6 +22,7 @@ #include "ospray/volume/Volume.ih" // embree stuff +#include "embree2/rtcore.isph" #include "embree2/rtcore_scene.isph" struct Model { diff --git a/ospray/common/Model.ispc b/ospray/common/Model.ispc index 13d5cc75ce..97a8065f0f 100644 --- a/ospray/common/Model.ispc +++ b/ospray/common/Model.ispc @@ -31,18 +31,22 @@ export void *uniform Model_create(void *uniform cppE) return (void *uniform)model; } -export void Model_init(void *uniform _model, uniform int32 numGeometries, uniform int32 numVolumes) +export void Model_init(void *uniform _model, + void *uniform embreeDevice, + uniform int32 numGeometries, + uniform int32 numVolumes) { uniform Model *uniform model = (uniform Model *uniform)_model; if (model->embreeSceneHandle) rtcDeleteScene(model->embreeSceneHandle); - model->embreeSceneHandle = rtcNewScene(//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); - + 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); + 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 b9cd166552..19e1481f38 100644 --- a/ospray/common/OSPCommon.cpp +++ b/ospray/common/OSPCommon.cpp @@ -15,40 +15,37 @@ // ======================================================================== // #include "OSPCommon.h" +#ifdef OSPRAY_USE_INTERNAL_TASKING +# include "ospray/common/tasking/TaskSys.h" +#endif +#include "ospray/common/tasking/async.h" // embree #include "embree2/rtcore.h" -#include "common/sys/sysinfo.h" -// std -#include -#ifdef _WIN32 -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# endif -# include // for GetSystemTime -#else -#include -#include -#endif +#include "common/sysinfo.h" +//stl +#include namespace ospray { + RTCDevice g_embreeDevice = NULL; + /*! 64-bit malloc. allows for alloc'ing memory larger than 64 bits */ extern "C" void *malloc64(size_t size) { - return embree::alignedMalloc(size); + return ospcommon::alignedMalloc(size); } /*! 64-bit malloc. allows for alloc'ing memory larger than 64 bits */ extern "C" void free64(void *ptr) { - return embree::alignedFree(ptr); + return ospcommon::alignedFree(ptr); } /*! logging level - '0' means 'no logging at all', increasing numbers mean increasing verbosity of log messages */ - uint32 logLevel = 0; + uint32_t logLevel = 0; bool debugMode = false; - int32 numThreads = -1; //!< for default (==maximum) number of OSPRay/Embree threads + int32_t numThreads = -1; //!< for default (==maximum) number of OSPRay/Embree threads WarnOnce::WarnOnce(const std::string &s) : s(s) @@ -87,55 +84,56 @@ namespace ospray { abort(); } - double getSysTime() { -#ifdef _WIN32 - SYSTEMTIME tp; GetSystemTime(&tp); - return double(tp.wSecond) + double(tp.wMilliseconds) / 1E3; -#else - struct timeval tp; gettimeofday(&tp,NULL); - return double(tp.tv_sec) + double(tp.tv_usec)/1E6; -#endif + void removeArgs(int &ac, char **&av, int where, int howMany) + { + for (int i=where+howMany;i); - case OSP_UCHAR3: return sizeof(embree::Vec3); - case OSP_UCHAR4: return sizeof(uint32); + case OSP_UCHAR2: return sizeof(vec2uc); + case OSP_UCHAR3: return sizeof(vec3uc); + case OSP_UCHAR4: return sizeof(vec4uc); + case OSP_USHORT: return sizeof(uint16); case OSP_INT: return sizeof(int32); - case OSP_INT2: return sizeof(embree::Vec2); - case OSP_INT3: return sizeof(embree::Vec3); - case OSP_INT4: return sizeof(embree::Vec4); + case OSP_INT2: return sizeof(vec2i); + case OSP_INT3: return sizeof(vec3i); + case OSP_INT4: return sizeof(vec4i); case OSP_UINT: return sizeof(uint32); - case OSP_UINT2: return sizeof(embree::Vec2); - case OSP_UINT3: return sizeof(embree::Vec3); - case OSP_UINT4: return sizeof(embree::Vec4); + case OSP_UINT2: return sizeof(vec2ui); + case OSP_UINT3: return sizeof(vec3ui); + case OSP_UINT4: return sizeof(vec4ui); case OSP_LONG: return sizeof(int64); - case OSP_LONG2: return sizeof(embree::Vec2); - case OSP_LONG3: return sizeof(embree::Vec3); - case OSP_LONG4: return sizeof(embree::Vec4); + case OSP_LONG2: return sizeof(vec2l); + case OSP_LONG3: return sizeof(vec3l); + case OSP_LONG4: return sizeof(vec4l); case OSP_ULONG: return sizeof(uint64); - case OSP_ULONG2: return sizeof(embree::Vec2); - case OSP_ULONG3: return sizeof(embree::Vec3); - case OSP_ULONG4: return sizeof(embree::Vec4); + case OSP_ULONG2: return sizeof(vec2ul); + case OSP_ULONG3: return sizeof(vec3ul); + case OSP_ULONG4: return sizeof(vec4ul); case OSP_FLOAT: return sizeof(float); - case OSP_FLOAT2: return sizeof(embree::Vec2); - case OSP_FLOAT3: return sizeof(embree::Vec3); - case OSP_FLOAT4: return sizeof(embree::Vec4); - case OSP_FLOAT3A: return sizeof(embree::Vec3fa); + case OSP_FLOAT2: return sizeof(vec2f); + case OSP_FLOAT3: return sizeof(vec3f); + case OSP_FLOAT4: return sizeof(vec4f); + case OSP_FLOAT3A: return sizeof(vec3fa); case OSP_DOUBLE: return sizeof(double); default: break; }; @@ -196,11 +194,9 @@ namespace ospray { std::stringstream error; error << __FILE__ << ":" << __LINE__ << ": unknown OSPDataType " << (int)type; throw std::runtime_error(error.str()); - } OSPDataType typeForString(const char *string) { - if (string == NULL) return(OSP_UNKNOWN); if (strcmp(string, "char" ) == 0) return(OSP_CHAR); if (strcmp(string, "double") == 0) return(OSP_DOUBLE); @@ -216,12 +212,29 @@ namespace ospray { if (strcmp(string, "uchar2") == 0) return(OSP_UCHAR2); if (strcmp(string, "uchar3") == 0) return(OSP_UCHAR3); if (strcmp(string, "uchar4") == 0) return(OSP_UCHAR4); + if (strcmp(string, "ushort") == 0) return(OSP_USHORT); if (strcmp(string, "uint" ) == 0) return(OSP_UINT); if (strcmp(string, "uint2" ) == 0) return(OSP_UINT2); if (strcmp(string, "uint3" ) == 0) return(OSP_UINT3); if (strcmp(string, "uint4" ) == 0) return(OSP_UINT4); return(OSP_UNKNOWN); + } + + size_t sizeOf(const OSPTextureFormat type) { + switch (type) { + case OSP_TEXTURE_RGBA8: + case OSP_TEXTURE_SRGBA: return sizeof(uint32); + case OSP_TEXTURE_RGBA32F: return sizeof(vec4f); + case OSP_TEXTURE_RGB8: + case OSP_TEXTURE_SRGB: return sizeof(vec3uc); + case OSP_TEXTURE_RGB32F: return sizeof(vec3f); + case OSP_TEXTURE_R8: return sizeof(uint8); + case OSP_TEXTURE_R32F: return sizeof(float); + } + std::stringstream error; + error << __FILE__ << ":" << __LINE__ << ": unknown OSPTextureFormat " << (int)type; + throw std::runtime_error(error.str()); } } // ::ospray diff --git a/ospray/common/OSPCommon.h b/ospray/common/OSPCommon.h index d60837d313..c2757f0aed 100644 --- a/ospray/common/OSPCommon.h +++ b/ospray/common/OSPCommon.h @@ -23,12 +23,11 @@ #include "OSPConfig.h" #ifdef _WIN32 - typedef unsigned long long id_t; -#endif - -#if defined(__WIN32__) || defined(_WIN32) // ----------- windows only ----------- -# define _USE_MATH_DEFINES 1 +typedef unsigned long long id_t; +# ifndef _USE_MATH_DEFINES +# define _USE_MATH_DEFINES +# endif # include # include # ifdef _M_X64 @@ -41,6 +40,12 @@ typedef int ssize_t; # include "unistd.h" #endif +#if 1 +#include "../../common/AffineSpace.h" +#include "../../common/intrinsics.h" +#include "../../common/RefCount.h" +#include "../../common/malloc.h" +#else // embree #include "common/math/vec2.h" #include "common/math/vec3.h" @@ -49,6 +54,7 @@ typedef int ssize_t; #include "common/math/affinespace.h" // includes "common/math/linearspace[23].h" #include "common/sys/ref.h" #include "common/sys/alloc.h" +#endif // C++11 #include @@ -65,6 +71,7 @@ namespace ospray { typedef std::lock_guard LockGuard; typedef std::condition_variable Condition; + using namespace ospcommon; } #define SCOPED_LOCK(x) \ @@ -73,7 +80,8 @@ namespace ospray { #endif // ospray -#include "ospray/common/OSPDataType.h" +#include "ospray/OSPDataType.h" +#include "ospray/OSPTexture.h" // std #include // for int64_t etc @@ -97,27 +105,9 @@ namespace ospray { #pragma warning(disable:177 ) // variable declared but was never referenced #endif -#if 0//NOTE: this causes crashes in standard library containers on MIC... -//#ifdef OSPRAY_TARGET_MIC -inline void* operator new(size_t size) throw(std::bad_alloc) { return embree::alignedMalloc(size); } -inline void operator delete(void* ptr) throw() { embree::alignedFree(ptr); } -inline void* operator new[](size_t size) throw(std::bad_alloc) { return embree::alignedMalloc(size); } -inline void operator delete[](void* ptr) throw() { embree::alignedFree(ptr); } -#endif - //! main namespace for all things ospray (for internal code) namespace ospray { - using embree::one; - using embree::empty; - using embree::zero; - using embree::inf; - using embree::deg2rad; - using embree::rad2deg; - using embree::sign; - using embree::clamp; - using embree::frac; - /*! basic types */ typedef ::int64_t int64; typedef ::uint64_t uint64; @@ -133,74 +123,13 @@ namespace ospray { typedef ::int64_t index_t; - /*! OSPRay's two-int vector class */ - typedef embree::Vec2i vec2i; - /*! OSPRay's three-unsigned char vector class */ - typedef embree::Vec3 vec3uc; - /*! OSPRay's 4x unsigned char vector class */ - typedef embree::Vec4 vec4uc; - /*! OSPRay's 2x uint32 vector class */ - typedef embree::Vec2 vec2ui; - /*! OSPRay's 3x uint32 vector class */ - typedef embree::Vec3 vec3ui; - /*! OSPRay's 4x uint32 vector class */ - typedef embree::Vec4 vec4ui; - /*! OSPRay's 3x int32 vector class */ - typedef embree::Vec3 vec3i; - /*! OSPRay's four-int vector class */ - typedef embree::Vec4i vec4i; - /*! OSPRay's two-float vector class */ - typedef embree::Vec2f vec2f; - /*! OSPRay's three-float vector class */ - typedef embree::Vec3f vec3f; - /*! OSPRay's three-float vector class (aligned to 16b-boundaries) */ - typedef embree::Vec3fa vec3fa; - /*! OSPRay's four-float vector class */ - typedef embree::Vec4f vec4f; - - typedef embree::BBox box2ui; - typedef embree::BBox region2i; - typedef embree::BBox region2ui; - - typedef embree::BBox box3i; - typedef embree::BBox box3ui; - - typedef embree::BBox3f box3f; - typedef embree::BBox3fa box3fa; - typedef embree::BBox box3uc; - typedef embree::BBox box4f; - typedef embree::BBox3fa box3fa; - - /*! affice space transformation */ - typedef embree::AffineSpace2f affine2f; - typedef embree::AffineSpace3f affine3f; - typedef embree::AffineSpace3fa affine3fa; - typedef embree::AffineSpace3f AffineSpace3f; - typedef embree::AffineSpace3fa AffineSpace3fa; - - typedef embree::LinearSpace2f linear2f; - typedef embree::LinearSpace3f linear3f; - typedef embree::LinearSpace3fa linear3fa; - typedef embree::LinearSpace3f LinearSpace3f; - typedef embree::LinearSpace3fa LinearSpace3fa; - - using embree::Ref; - using embree::RefCount; - - using embree::cross; - using embree::volume; - - /*! return system time in seconds */ - OSPRAY_INTERFACE double getSysTime(); - void init(int *ac, const char ***av); - /*! remove specified num arguments from an ac/av arglist */ - OSPRAY_INTERFACE void removeArgs(int &ac, char **&av, int where, int howMany); /*! for debugging. compute a checksum for given area range... */ OSPRAY_INTERFACE void *computeCheckSum(const void *ptr, size_t numBytes); OSPRAY_INTERFACE void doAssertion(const char *file, int line, const char *expr, const char *expl); +#ifndef Assert #ifdef NDEBUG # define Assert(expr) /* nothing */ # define Assert2(expr,expl) /* nothing */ @@ -212,9 +141,10 @@ namespace ospray { ((void)((expr) ? 0 : ((void)ospray::doAssertion(__FILE__, __LINE__, #expr, expl), 0))) # define AssertError(errMsg) \ doAssertion(__FILE__,__LINE__, (errMsg), NULL) +#endif #endif - inline size_t rdtsc() { return embree::rdtsc(); } + inline size_t rdtsc() { return ospcommon::rdtsc(); } /*! logging level (cmdline: --osp:loglevel \) */ extern uint32 logLevel; @@ -225,11 +155,14 @@ namespace ospray { extern int32 numThreads; /*! size of OSPDataType */ - OSPRAY_INTERFACE size_t sizeOf(OSPDataType type); + OSPRAY_INTERFACE size_t sizeOf(const OSPDataType); /*! Convert a type string to an OSPDataType. */ OSPRAY_INTERFACE OSPDataType typeForString(const char *string); + /*! size of OSPTextureFormat */ + OSPRAY_INTERFACE size_t sizeOf(const OSPTextureFormat); + struct WarnOnce { WarnOnce(const std::string &s); private: @@ -253,7 +186,6 @@ namespace ospray { } return result; } - } // ::ospray #ifdef _WIN32 @@ -261,8 +193,3 @@ namespace ospray { #endif #define NOTIMPLEMENTED throw std::runtime_error(std::string(__PRETTY_FUNCTION__)+": not implemented..."); -template -inline T divRoundUp(const T&a, const T&b) { return (a+(b-T(1)))/b; } - - - diff --git a/ospray/common/OSPCommon.ih b/ospray/common/OSPCommon.ih index 6af070af8e..7cb0b38491 100644 --- a/ospray/common/OSPCommon.ih +++ b/ospray/common/OSPCommon.ih @@ -42,6 +42,8 @@ inline void* uniform align_ptr(void* uniform ptr) { #endif #define PRINT(x) print(#x" = %\n", x) +// prints first unmasked element +#define PRINT0(x) print(#x"[%] = %\n", count_trailing_zeros(lanemask()), extract(x, count_trailing_zeros(lanemask()))) /*! ispc copy of embree error handling callback */ void error_handler(const RTCError code, const int8* str); diff --git a/ospray/common/OSPConfig.h.in b/ospray/common/OSPConfig.h.in index 01f6a4ee15..f6b4a8c556 100644 --- a/ospray/common/OSPConfig.h.in +++ b/ospray/common/OSPConfig.h.in @@ -36,7 +36,6 @@ #cmakedefine OSPRAY_EXP_IMAGE_COMPOSITING #cmakedefine OSPRAY_EXP_DISTRIBUTED_VOLUME #cmakedefine OSPRAY_EXP_ALPHA_BLENDING -#cmakedefine OSPRAY_MPI_DISTRIBUTED #endif #cmakedefine OSPRAY_VOLUME_VOXELRANGE_IN_APP #cmakedefine OSPRAY_PIN_ASYNC diff --git a/ospray/common/Ray.ih b/ospray/common/Ray.ih index 58e6dee134..74fd2511b7 100644 --- a/ospray/common/Ray.ih +++ b/ospray/common/Ray.ih @@ -20,14 +20,6 @@ #include "ospray/math/vec.ih" #include "ospray/math/box.ih" -#ifdef OSPRAY_INTERSECTION_FILTER -struct Geometry; -struct Ray; - -typedef void (*IntersectionFilterFunc)(uniform Geometry *uniform THIS, - varying Ray &ray); -#endif - /*! \brief ospray ray class This impelment the base ospray ray class; it is 'derived' @@ -75,10 +67,6 @@ struct Ray { int primID_hi64; void *uniform userData; -#ifdef OSPRAY_INTERSECTION_FILTER - uniform IntersectionFilterFunc intersectionFilter; -#endif - }; #define infinity (1e20f) @@ -106,9 +94,6 @@ inline void setRay(Ray &ray, const vec3f &ray_org, const vec3f &ray_dir) ray.geomID = -1; ray.primID = -1; ray.instID = -1; -#ifdef OSPRAY_INTERSECTION_FILTER - ray.intersectionFilter = NULL; -#endif } /*! initialize a new ray with given parameters */ @@ -127,9 +112,6 @@ inline void setRay(Ray &ray, const vec3f &ray_org, const vec3f &ray_dir, ray.geomID = -1; ray.primID = -1; ray.instID = -1; -#ifdef OSPRAY_INTERSECTION_FILTER - ray.intersectionFilter = NULL; -#endif } /*! helper function that performs a ray-box test */ diff --git a/ospray/common/Thread.cpp b/ospray/common/Thread.cpp index e700d1dc63..f5440693ee 100644 --- a/ospray/common/Thread.cpp +++ b/ospray/common/Thread.cpp @@ -18,7 +18,7 @@ #include "Thread.h" // embree -# include "common/sys/thread.h" +# include "common/thread.h" namespace ospray { @@ -27,22 +27,25 @@ namespace ospray { Thread *t = (Thread *)arg; if (t->desiredThreadID >= 0) { printf("pinning to thread %i\n",t->desiredThreadID); - embree::setAffinity(t->desiredThreadID); + ospcommon::setAffinity(t->desiredThreadID); } + _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); + _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); + t->run(); } void Thread::join() { - embree::join(tid); + ospcommon::join(tid); } /*! start thread execution */ void Thread::start(int threadID) { desiredThreadID = threadID; - this->tid = embree::createThread(&ospray_Thread_runThread,this); + this->tid = ospcommon::createThread(&ospray_Thread_runThread,this); } } diff --git a/ospray/common/Thread.h b/ospray/common/Thread.h index a74de9cd0c..8c23707251 100644 --- a/ospray/common/Thread.h +++ b/ospray/common/Thread.h @@ -20,8 +20,8 @@ // ospray #include "OSPCommon.h" -// embree -#include "common/sys/thread.h" +// ospcommon +#include "common/thread.h" namespace ospray { @@ -43,7 +43,7 @@ namespace ospray { thread got started will not have any effect */ int desiredThreadID; //! the thread ID reported by embree's createThread - embree::thread_t tid; + ospcommon::thread_t tid; }; } diff --git a/ospray/common/default.ih b/ospray/common/default.ih deleted file mode 100644 index ac760e11ac..0000000000 --- a/ospray/common/default.ih +++ /dev/null @@ -1,18 +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 - diff --git a/ospray/common/ospray.rc b/ospray/common/ospray.rc index 8354fcb5aa..a764e0531f 100644 --- a/ospray/common/ospray.rc +++ b/ospray/common/ospray.rc @@ -1,10 +1,5 @@ #include "ospray/version.h" -#define OSPRAY_VERSION_MAJOR 0 -#define OSPRAY_VERSION_MINOR 9 -#define OSPRAY_VERSION_PATCH 1 -#define OSPRAY_VERSION "0.9.1" - 1 VERSIONINFO FILEVERSION OSPRAY_VERSION_MAJOR,OSPRAY_VERSION_MINOR,0 PRODUCTVERSION OSPRAY_VERSION_MAJOR,OSPRAY_VERSION_MINOR,0 diff --git a/ospray/common/tasking/TaskSys.cpp b/ospray/common/tasking/TaskSys.cpp new file mode 100644 index 0000000000..ba71864d81 --- /dev/null +++ b/ospray/common/tasking/TaskSys.cpp @@ -0,0 +1,216 @@ +// ======================================================================== // +// 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. // +// ======================================================================== // + +#include "TaskSys.h" +//ospray +#include "common/sysinfo.h" +#include "common/thread.h" +//stl +#include +#include + +namespace ospray { + struct TaskSys { + bool initialized; + bool running; + + void init(size_t maxNumRenderTasks); + static TaskSys global; + static void *threadStub(void *); + inline Ref getNextActiveTask(); + + //! Queue of tasks that have ALREADY been acitvated, and that are ready + //! to run + __aligned(64) Task *volatile activeListFirst; + __aligned(64) Task *volatile activeListLast; + + Mutex __aligned(64) mutex; + Condition __aligned(64) tasksAvailable; + + void threadFunction(); + + std::vector threads; + + TaskSys() + : activeListFirst(nullptr), activeListLast(nullptr), + initialized(false), running(false) + {} + + ~TaskSys(); + }; + + TaskSys __aligned(64) TaskSys::global; + + inline void Task::workOnIt() + { + size_t myCompleted = 0; + while (1) { + const size_t thisJobID = numJobsStarted++; + if (thisJobID >= numJobsInTask) + break; + + run(thisJobID); + ++myCompleted; + } + + if (myCompleted != 0) { + const size_t nowCompleted = (numJobsCompleted += myCompleted); + if (nowCompleted == numJobsInTask) { + SCOPED_LOCK(mutex); + status = Task::COMPLETED; + allJobsCompletedCond.notify_all(); + } + } + } + + void Task::wait(bool workOnIt) + { + if (status == Task::COMPLETED) { + return; + } + + if (workOnIt) { + this->workOnIt(); + } + + std::unique_lock lock(mutex); + allJobsCompletedCond.wait(lock, [&](){return status == Task::COMPLETED;}); + } + + void Task::scheduleAndWait(size_t numJobs, ScheduleOrder order) + { + schedule(numJobs,order); + wait(); + } + + inline Ref TaskSys::getNextActiveTask() + { + while (1) { + std::unique_lock lock(mutex); + tasksAvailable.wait(lock, [&](){ + return !(activeListFirst == nullptr && running); + }); + + if (!running) { + return nullptr; + } + + Ref front = activeListFirst; + if (front->numJobsStarted >= front->numJobsInTask) { + if (activeListFirst == activeListLast) { + activeListFirst = activeListLast = nullptr; + } else { + activeListFirst = activeListFirst->next; + } + continue; + } + assert(front.ptr); + return front; + } + } + + void Task::initTaskSystem(const size_t maxNumRenderTasks) + { + TaskSys::global.init(maxNumRenderTasks); + } + + void Task::schedule(size_t numJobs, ScheduleOrder order) + { + refInc(); + this->order = order; + numJobsInTask = numJobs; + status = Task::SCHEDULED; + if (numMissingDependencies == 0) + activate(); + } + + inline void Task::activate() + { + if (!TaskSys::global.initialized) + throw std::runtime_error("TASK SYSTEM NOT YET INITIALIZED"); + { + SCOPED_LOCK(TaskSys::global.mutex); + bool wasEmpty = TaskSys::global.activeListFirst == nullptr; + if (wasEmpty) { + TaskSys::global.activeListFirst = TaskSys::global.activeListLast = this; + this->next = nullptr; + TaskSys::global.tasksAvailable.notify_all(); + } else { + if (order == Task::BACK_OF_QUEUE) { + this->next = nullptr; + TaskSys::global.activeListLast->next = this; + TaskSys::global.activeListLast = this; + } else { + this->next = TaskSys::global.activeListFirst; + TaskSys::global.activeListFirst = this; + } + } + status = Task::ACTIVE; + } + } + + void TaskSys::threadFunction() + { + while (1) { + Ref task = getNextActiveTask(); + if (!running) { + return; + } + assert(task); + task->workOnIt(); + } + } + + TaskSys::~TaskSys() + { + running = false; + tasksAvailable.notify_all(); + for (int i = 0; i < threads.size(); ++i) { + join(threads[i]); + } + } + + void *TaskSys::threadStub(void *) + { + TaskSys::global.threadFunction(); + return nullptr; + } + + void TaskSys::init(size_t numThreads) + { + if (initialized) + throw std::runtime_error("#osp: task system initialized twice!"); + + initialized = true; + running = true; + + if (numThreads != 0) { +#if defined(__MIC__) + numThreads = std::min(numThreads, + (size_t)std::thread::hardware_concurrency()-4); +#else + numThreads = std::min(numThreads, + (size_t)std::thread::hardware_concurrency()); +#endif + } + + /* generate all threads */ + for (size_t t=1; t +#include + +namespace ospray { + +//NOTE(jda) - This checks at compile time if T implements the method +// 'void T::operator()'. +template +struct has_operator_method +{ + template class checker; + + template + static std::true_type test(checker *); + + template + static std::false_type test(...); + + using type = decltype(test(nullptr)); + static const bool value = std::is_same::value; +}; + +//NOTE(jda) - This checks at compile time if T implements the method +// 'void T::operator(P taskIndex)', where P is an integral type +// (must be short, int, uint, or size_t) at compile-time. To be used +// inside a static_assert(). +template +struct has_operator_method_with_integral_param +{ + using T_SHORT_PARAM = void(T::*)(short) const; + using T_INT_PARAM = void(T::*)(int) const; + using T_UNSIGNED_PARAM = void(T::*)(unsigned int) const; + using T_SIZET_PARAM = void(T::*)(size_t) const; + + using PARAM_IS_SHORT = std::is_same; + using PARAM_IS_INT = std::is_same; + using PARAM_IS_UNSIGNED = std::is_same; + using PARAM_IS_SIZET = std::is_same; + + static const bool value = has_operator_method::value && + (PARAM_IS_SHORT::value + || PARAM_IS_INT::value + || PARAM_IS_UNSIGNED::value + || PARAM_IS_SIZET::value); +}; + +}//namespace ospray diff --git a/ospray/common/tasking/async.h b/ospray/common/tasking/async.h new file mode 100644 index 0000000000..b208602dc2 --- /dev/null +++ b/ospray/common/tasking/async.h @@ -0,0 +1,70 @@ +// ======================================================================== // +// 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 + +#ifdef OSPRAY_TASKING_TBB +# include +#elif defined(OSPRAY_TASKING_CILK) +# include +#elif defined(OSPRAY_TASKING_INTERNAL) +# include "ospray/common/tasking/TaskSys.h" +#endif + +namespace ospray { + +// NOTE(jda) - This abstraction takes a lambda which should take captured +// variables by *value* to ensure no captured references race +// with the task itself. + +// NOTE(jda) - No priority is associated with this call, but could be added +// later with a hint enum, using a default value for the priority +// to not require specifying it. +template +inline void async(const TASK_T& fcn) +{ + static_assert(has_operator_method::value, + "ospray::async() requires the implementation of method " + "'void TASK_T::operator()'."); + +#ifdef OSPRAY_TASKING_TBB + struct LocalTBBTask : public tbb::task + { + TASK_T func; + tbb::task* execute() override { func(); return nullptr; } + LocalTBBTask( const TASK_T& f ) : func(f) {} + }; + + tbb::task::enqueue(*new(tbb::task::allocate_root())LocalTBBTask(fcn)); +#elif defined(OSPRAY_TASKING_CILK) + cilk_spawn fcn(); +#elif defined(OSPRAY_TASKING_INTERNAL) + struct LocalTask : public Task { + TASK_T t; + LocalTask(const TASK_T& fcn) : Task("LocalTask"), t(std::move(fcn)) {} + void run(size_t) override { t(); } + }; + + Ref task = new LocalTask(fcn); + task->schedule(1, Task::FRONT_OF_QUEUE); +#else// OpenMP or Debug --> synchronous! + fcn(); +#endif +} + +}//namespace ospray diff --git a/ospray/common/parallel_for.h b/ospray/common/tasking/parallel_for.h similarity index 51% rename from ospray/common/parallel_for.h rename to ospray/common/tasking/parallel_for.h index 68375d9471..41e5caf8fb 100644 --- a/ospray/common/parallel_for.h +++ b/ospray/common/tasking/parallel_for.h @@ -16,22 +16,52 @@ #pragma once -#ifdef OSPRAY_USE_TBB -# include +#include + +#ifdef OSPRAY_TASKING_TBB +# include +#elif defined(OSPRAY_TASKING_CILK) +# include +#elif defined(OSPRAY_TASKING_INTERNAL) +# include "ospray/common/tasking/TaskSys.h" #endif namespace ospray { -template -inline void parallel_for(int nTasks, const T& fcn) +// NOTE(jda) - This abstraction wraps "fork-join" parallelism, with an implied +// synchronizsation after all of the tasks have run. +template +inline void parallel_for(int nTasks, const TASK_T& fcn) { -#ifdef OSPRAY_USE_TBB + static_assert(has_operator_method_with_integral_param::value, + "ospray::parallel_for() requires the implementation of method " + "'void TASK_T::operator(P taskIndex), where P is of type " + "short, int, uint, or size_t."); + +#ifdef OSPRAY_TASKING_TBB tbb::parallel_for(0, nTasks, 1, fcn); -#else +#elif defined(OSPRAY_TASKING_CILK) + cilk_for (int taskIndex = 0; taskIndex < nTasks; ++taskIndex) { + fcn(taskIndex); + } +#elif defined(OSPRAY_TASKING_OMP) # pragma omp parallel for schedule(dynamic) for (int taskIndex = 0; taskIndex < nTasks; ++taskIndex) { fcn(taskIndex); } +#elif defined(OSPRAY_TASKING_INTERNAL) + struct LocalTask : public Task { + const TASK_T &t; + LocalTask(const TASK_T& fcn) : Task("LocalTask"), t(fcn) {} + void run(size_t taskIndex) override { t(taskIndex); } + }; + + Ref task = new LocalTask(fcn); + task->scheduleAndWait(nTasks); +#else // Debug (no tasking system) + for (int taskIndex = 0; taskIndex < nTasks; ++taskIndex) { + fcn(taskIndex); + } #endif } diff --git a/ospray/device/buffers.cpp b/ospray/device/buffers.cpp deleted file mode 100644 index 35a669bc58..0000000000 --- a/ospray/device/buffers.cpp +++ /dev/null @@ -1,22 +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. // -// ======================================================================== // - -#include "buffers.h" - -namespace ospray { - namespace nwlayer { - } -} diff --git a/ospray/device/nwlayer.cpp b/ospray/device/nwlayer.cpp deleted file mode 100644 index 24ecffd3f2..0000000000 --- a/ospray/device/nwlayer.cpp +++ /dev/null @@ -1,45 +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. // -// ======================================================================== // - -#include "nwlayer.h" - -namespace ospray { - namespace nwlayer { - - inline std::string toString(long l) - { std::stringstream ss; ss << l; return ss.str(); } - - void RemoteWorker::handleCommand(const CommandTag cmd, ReadBuffer &args) - { - throw std::runtime_error("unknown command "+toString(cmd)); - } - - void RemoteWorker::executeCommands() - { - assert(comm); - assert(device); - CommandTag cmd; - ReadBuffer args; - while (1) { - PING; - comm->recv(cmd,args); - PRINT(cmd); - handleCommand(cmd,args); - } - } - - } // ::ospray::nwlayer -} // ::ospray diff --git a/ospray/device/nwlayer.h b/ospray/device/nwlayer.h deleted file mode 100644 index 23fab27379..0000000000 --- a/ospray/device/nwlayer.h +++ /dev/null @@ -1,101 +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 - -/*! \file ospray/device/nwlayer.h \brief Defines the basic network layer abstraction */ - -// ospray -#include "ospray/device/buffers.h" -#include "ospray/device/command.h" -#include "ospray/api/Device.h" -// embree -#include "common/sys/network.h" - -namespace ospray { - namespace nwlayer { - - /*! a "communicator" is the abstraction for the class that can - send messages/commands to remote clients */ - struct Communicator { - /* receive from *master* to *all* clients */ - virtual void bcast(const WriteBuffer &args) = 0; - virtual void sendTo(const uint32 clientID, - const WriteBuffer &args) = 0; - /*! flush the send queue, making sure that the last command was - properly executed. this may introduce (quite) some delay, so - be wary of this call */ - virtual void flushSendQueue() = 0; - /* receive from *master* */ - virtual void recv(CommandTag &cmd, ReadBuffer &args) = 0; - }; - - struct MPICommunicator : public Communicator { - }; - struct TCPCommunicator : public Communicator { - std::vector remote; - }; - - - /*! a network "worker" is the instance that handles a device's API - calls on a remote node */ - struct RemoteWorker { - /*! communicator through which we receive commands */ - Communicator *comm; - /*! device which we use by default to execute the commands we received */ - ospray::api::Device *device; - virtual void handleCommand(const CommandTag cmd, ReadBuffer &args) = 0; - virtual void executeCommands(); - }; - - /*! base class for all kinds of devices in which API calls get - packed up as command streams that then get sent (or broadcast) - to different workers */ - struct RemoteDevice : public ospray::api::Device { - }; - - /*! the remote rendering device simply forwards all calls to the - remote worker (which may use a device of its choice to compute - the pixels), and returns a (possibly compressed) image back */ - struct RemoteRenderingDevice : public RemoteDevice { - }; - - /*! the MPI *group* device has a set of N nodes that are all in - the same MPI group and communiate with each other through a - common intracommunicator. Rank 0 acts as a master and does the - control/load balancing of the other ranks, but by itself - doesn't do anything else (if the same node is to also render - pixels it should simply be added twice; once as rank0, and - once as rank1. */ - struct MPIGroupDevice { - struct DeviceInterface : public RemoteDevice - { - }; - struct Worker : public RemoteWorker - { - }; - }; - - /*! the MPI *cluster* device has a dedicated master node for - control and load balancing, has all workers running in a - different MPI group, and has master and workers communicate - through a MPI-*inter*-communicator (the workers also have a - intracommunicator among themselves */ - struct MPIClusterDevice { - }; - - } // ::ospray::nwlayer -} // ::ospray diff --git a/ospray/embree-v2.7.1/common/lexers/CMakeLists.txt b/ospray/embree-v2.7.1/common/lexers/CMakeLists.txt index 7f47e0c83c..a8abe07940 100644 --- a/ospray/embree-v2.7.1/common/lexers/CMakeLists.txt +++ b/ospray/embree-v2.7.1/common/lexers/CMakeLists.txt @@ -29,3 +29,4 @@ ADD_LIBRARY(lexers${EXT} STATIC TARGET_LINK_LIBRARIES(lexers${EXT} sys${EXT}) SET_PROPERTY(TARGET lexers${EXT} PROPERTY FOLDER common) +SET_TARGET_PROPERTIES(lexers${EXT} PROPERTIES COMPILE_FLAGS "-DDONT_WARN_INCLUDE_EMBREE_INTERNALS=1") diff --git a/ospray/embree-v2.7.1/common/simd/CMakeLists.txt b/ospray/embree-v2.7.1/common/simd/CMakeLists.txt index 6c1488fb00..3ff2217c24 100644 --- a/ospray/embree-v2.7.1/common/simd/CMakeLists.txt +++ b/ospray/embree-v2.7.1/common/simd/CMakeLists.txt @@ -17,8 +17,10 @@ IF (__XEON__) ADD_LIBRARY(simd STATIC sse.cpp) SET_PROPERTY(TARGET simd PROPERTY FOLDER common) + SET_TARGET_PROPERTIES(simd PROPERTIES COMPILE_FLAGS "-DDONT_WARN_INCLUDE_EMBREE_INTERNALS=1") ELSE () INCLUDE(icc_xeonphi) ADD_LIBRARY(simd_xeonphi STATIC vboolf16_avx512.cpp) + SET_TARGET_PROPERTIES(simd_xeonphi PROPERTIES COMPILE_FLAGS "-DDONT_WARN_INCLUDE_EMBREE_INTERNALS=1") ENDIF () diff --git a/ospray/embree-v2.7.1/common/sys/CMakeLists.txt b/ospray/embree-v2.7.1/common/sys/CMakeLists.txt index 8c3f1968bd..89df96237a 100644 --- a/ospray/embree-v2.7.1/common/sys/CMakeLists.txt +++ b/ospray/embree-v2.7.1/common/sys/CMakeLists.txt @@ -52,6 +52,7 @@ ADD_LIBRARY(sys STATIC TARGET_LINK_LIBRARIES(sys ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS} ${ADDITIONAL_LIBRARIES}) SET_PROPERTY(TARGET sys PROPERTY FOLDER common) +SET_TARGET_PROPERTIES(sys PROPERTIES COMPILE_FLAGS "-DDONT_WARN_INCLUDE_EMBREE_INTERNALS=1") ELSE () @@ -72,5 +73,6 @@ ADD_LIBRARY(sys_xeonphi STATIC ) TARGET_LINK_LIBRARIES(sys_xeonphi ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS}) +SET_TARGET_PROPERTIES(sys_xeonphi PROPERTIES COMPILE_FLAGS "-DDONT_WARN_INCLUDE_EMBREE_INTERNALS=1") ENDIF () diff --git a/ospray/embree-v2.7.1/common/sys/filename.h b/ospray/embree-v2.7.1/common/sys/filename.h index 39bfa5ad07..84b5be9164 100644 --- a/ospray/embree-v2.7.1/common/sys/filename.h +++ b/ospray/embree-v2.7.1/common/sys/filename.h @@ -18,6 +18,10 @@ #include "platform.h" +#if WARN_INCLUDE_EMBREE_FILENAME +# error "warning: includign embree/filename" +#endif + namespace embree { /*! Convenience class for handling file names and paths. */ diff --git a/ospray/embree-v2.7.1/common/sys/platform.h b/ospray/embree-v2.7.1/common/sys/platform.h index 7f986f472e..c30c7b3b11 100644 --- a/ospray/embree-v2.7.1/common/sys/platform.h +++ b/ospray/embree-v2.7.1/common/sys/platform.h @@ -16,6 +16,10 @@ #pragma once +#ifndef DONT_WARN_INCLUDE_EMBREE_INTERNALS +# error "warning: including embree internals (common/sys/platform.h) from outside of embree/ directory!" +#endif + #define _CRT_SECURE_NO_WARNINGS #include diff --git a/ospray/embree-v2.7.1/common/tasking/taskscheduler_tbb.h b/ospray/embree-v2.7.1/common/tasking/taskscheduler_tbb.h index 12e972fb42..475a64a49f 100644 --- a/ospray/embree-v2.7.1/common/tasking/taskscheduler_tbb.h +++ b/ospray/embree-v2.7.1/common/tasking/taskscheduler_tbb.h @@ -314,7 +314,7 @@ namespace embree /* remember exception to throw */ std::exception_ptr except = nullptr; - if (cancellingException) except = cancellingException; + if (cancellingException != nullptr) except = cancellingException; /* wait for all threads to terminate */ atomic_add(&threadCounter,-1); @@ -322,7 +322,7 @@ namespace embree cancellingException = nullptr; /* re-throw proper exception */ - if (except) + if (except != nullptr) std::rethrow_exception(except); } diff --git a/ospray/embree-v2.7.1/include/embree2/rtcore_scene.h b/ospray/embree-v2.7.1/include/embree2/rtcore_scene.h index 1e0e703d74..8ace537f5a 100644 --- a/ospray/embree-v2.7.1/include/embree2/rtcore_scene.h +++ b/ospray/embree-v2.7.1/include/embree2/rtcore_scene.h @@ -59,7 +59,7 @@ typedef struct __RTCScene {}* RTCScene; /*! Creates a new scene. WARNING: This function is deprecated, use rtcDeviceNewScene instead. */ -RTCORE_API RTCORE_DEPRECATED RTCScene rtcNewScene (RTCSceneFlags flags, RTCAlgorithmFlags aflags); +// RTCORE_API RTCORE_DEPRECATED RTCScene rtcNewScene (RTCSceneFlags flags, RTCAlgorithmFlags aflags); /*! Creates a new scene. */ RTCORE_API RTCScene rtcDeviceNewScene (RTCDevice device, RTCSceneFlags flags, RTCAlgorithmFlags aflags); diff --git a/ospray/embree-v2.7.1/include/embree2/rtcore_scene.isph b/ospray/embree-v2.7.1/include/embree2/rtcore_scene.isph index bd9b7711b2..ae879177a1 100644 --- a/ospray/embree-v2.7.1/include/embree2/rtcore_scene.isph +++ b/ospray/embree-v2.7.1/include/embree2/rtcore_scene.isph @@ -53,9 +53,9 @@ enum RTCAlgorithmFlags typedef uniform struct __RTCScene {}* uniform RTCScene; /*! Creates a new scene. - WARNING: This function is deprecated, use rtcDeviceNewScene instead. -*/ -RTCORE_DEPRECATED RTCScene rtcNewScene (uniform RTCSceneFlags flags, uniform RTCAlgorithmFlags aflags); +// WARNING: This function is deprecated, use rtcDeviceNewScene instead. +// */ +// RTCORE_DEPRECATED RTCScene rtcNewScene (uniform RTCSceneFlags flags, uniform RTCAlgorithmFlags aflags); /*! Creates a new scene. */ RTCScene rtcDeviceNewScene (RTCDevice device, uniform RTCSceneFlags flags, uniform RTCAlgorithmFlags aflags); diff --git a/ospray/embree-v2.7.1/kernels/common/rtcore.cpp b/ospray/embree-v2.7.1/kernels/common/rtcore.cpp index 183c763f5f..836b2389d9 100644 --- a/ospray/embree-v2.7.1/kernels/common/rtcore.cpp +++ b/ospray/embree-v2.7.1/kernels/common/rtcore.cpp @@ -59,6 +59,7 @@ namespace embree Lock lock(g_mutex); if (g_device) throw_RTCError(RTC_INVALID_OPERATION,"already initialized"); g_device = new Device(cfg,true); + PING; PRINT(g_device); RTCORE_CATCH_END(g_device); } diff --git a/ospray/embree-v2.7.1/kernels/common/rtcore_ispc.cpp b/ospray/embree-v2.7.1/kernels/common/rtcore_ispc.cpp index 5c41bc7c32..dc7095cf20 100644 --- a/ospray/embree-v2.7.1/kernels/common/rtcore_ispc.cpp +++ b/ospray/embree-v2.7.1/kernels/common/rtcore_ispc.cpp @@ -90,7 +90,8 @@ namespace embree extern "C" RTCScene ispcNewScene (RTCSceneFlags flags, RTCAlgorithmFlags aflags) { if (!isCoherent(flags) && !isIncoherent(flags)) flags = RTCSceneFlags(flags | RTC_SCENE_COHERENT); - return rtcNewScene(flags,aflags); + throw std::runtime_error("ispcNewScene is no longer working in ospray - do not use any more"); + // return rtcNewScene(flags,aflags); } extern "C" RTCScene ispcNewScene2 (RTCDevice device, RTCSceneFlags flags, RTCAlgorithmFlags aflags) diff --git a/ospray/embree-v2.7.1/kernels/xeon/CMakeLists.txt b/ospray/embree-v2.7.1/kernels/xeon/CMakeLists.txt index 11220dbb7d..3e052abb49 100644 --- a/ospray/embree-v2.7.1/kernels/xeon/CMakeLists.txt +++ b/ospray/embree-v2.7.1/kernels/xeon/CMakeLists.txt @@ -207,31 +207,32 @@ ENDIF() ADD_ISPC_LIBRARY(embree ${EMBREE_LIB_TYPE} ${EMBREE_LIBRARY_FILES}) SET_PROPERTY(TARGET embree PROPERTY FOLDER kernels) +SET_TARGET_PROPERTIES(embree PROPERTIES COMPILE_FLAGS "-DDONT_WARN_INCLUDE_EMBREE_INTERNALS=1") IF (TARGET_SSE42 AND EMBREE_LIBRARY_FILES_SSE42) ADD_LIBRARY(embree_sse42 STATIC ${EMBREE_LIBRARY_FILES_SSE42}) - SET_TARGET_PROPERTIES(embree_sse42 PROPERTIES COMPILE_FLAGS "${FLAGS_SSE42}") + SET_TARGET_PROPERTIES(embree_sse42 PROPERTIES COMPILE_FLAGS "${FLAGS_SSE42} -DDONT_WARN_INCLUDE_EMBREE_INTERNALS=1") SET_PROPERTY(TARGET embree_sse42 PROPERTY FOLDER kernels) SET(EMBREE_LIBRARIES ${EMBREE_LIBRARIES} embree_sse42) ENDIF () IF (TARGET_AVX AND EMBREE_LIBRARY_FILES_AVX) ADD_LIBRARY(embree_avx STATIC ${EMBREE_LIBRARY_FILES_AVX}) - SET_TARGET_PROPERTIES(embree_avx PROPERTIES COMPILE_FLAGS "${FLAGS_AVX}") + SET_TARGET_PROPERTIES(embree_avx PROPERTIES COMPILE_FLAGS "${FLAGS_AVX} -DDONT_WARN_INCLUDE_EMBREE_INTERNALS=1") SET_PROPERTY(TARGET embree_avx PROPERTY FOLDER kernels) SET(EMBREE_LIBRARIES ${EMBREE_LIBRARIES} embree_avx) - ENDIF() +ENDIF() IF (TARGET_AVX2 AND EMBREE_LIBRARY_FILES_AVX2) ADD_LIBRARY(embree_avx2 STATIC ${EMBREE_LIBRARY_FILES_AVX2}) - SET_TARGET_PROPERTIES(embree_avx2 PROPERTIES COMPILE_FLAGS "${FLAGS_AVX2}") + SET_TARGET_PROPERTIES(embree_avx2 PROPERTIES COMPILE_FLAGS "${FLAGS_AVX2} -DDONT_WARN_INCLUDE_EMBREE_INTERNALS=1") SET_PROPERTY(TARGET embree_avx2 PROPERTY FOLDER kernels) SET(EMBREE_LIBRARIES ${EMBREE_LIBRARIES} embree_avx2) ENDIF() IF (TARGET_AVX512 AND EMBREE_LIBRARY_FILES_AVX512) ADD_LIBRARY(embree_avx512 STATIC ${EMBREE_LIBRARY_FILES_AVX512}) - SET_TARGET_PROPERTIES(embree_avx512 PROPERTIES COMPILE_FLAGS "${FLAGS_AVX512}") + SET_TARGET_PROPERTIES(embree_avx512 PROPERTIES COMPILE_FLAGS "${FLAGS_AVX512} -DDONT_WARN_INCLUDE_EMBREE_INTERNALS=1") SET_PROPERTY(TARGET embree_avx512 PROPERTY FOLDER kernels) SET(EMBREE_LIBRARIES ${EMBREE_LIBRARIES} embree_avx512) ENDIF() @@ -252,3 +253,6 @@ IF (WIN32) ELSE() INSTALL(TARGETS embree LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT lib NAMELINK_SKIP) ENDIF() + + +#SET_TARGET_PROPERTIES(embree PROPERTIES COMPILE_FLAGS " -DDONT_WARN_INCLUDE_EMBREE_INTERNALS=1") diff --git a/ospray/embree-v2.7.1/kernels/xeon/builders/heuristic_binning.h b/ospray/embree-v2.7.1/kernels/xeon/builders/heuristic_binning.h index 42c6838623..f4e4fa41ce 100644 --- a/ospray/embree-v2.7.1/kernels/xeon/builders/heuristic_binning.h +++ b/ospray/embree-v2.7.1/kernels/xeon/builders/heuristic_binning.h @@ -43,7 +43,7 @@ namespace embree num = min(BINS,size_t(4.0f + 0.05f*pinfo.size())); #endif const vfloat4 diag = (vfloat4) pinfo.centBounds.size(); - scale = select(diag > vfloat4(1E-34f),vfloat4(0.99f*num)/diag,vfloat4(0.0f)); + scale = select(diag > vfloat4(1E-13f),vfloat4(0.99f*num)/diag,vfloat4(0.0f)); ofs = (vfloat4) pinfo.centBounds.lower; } @@ -156,7 +156,7 @@ namespace embree } /*! bins an array of primitives */ - __forceinline void bin (const PrimRef* prims, size_t N, const BinMapping& mapping) + __forceinline void bin(const PrimRef* prims, size_t N, const BinMapping& mapping) { if (N == 0) return; @@ -425,7 +425,7 @@ namespace embree } /*! bins an array of primitives */ - __forceinline void bin (const PrimRef* prims, size_t N, const BinMapping<16>& mapping) + __forceinline void bin(const PrimRef* prims, size_t N, const BinMapping<16>& mapping) { const vfloat16 init_min(pos_inf); diff --git a/ospray/embree-v2.7.1/kernels/xeonphi/CMakeLists.txt b/ospray/embree-v2.7.1/kernels/xeonphi/CMakeLists.txt index 8c20e00d5e..8ba9dd65ae 100644 --- a/ospray/embree-v2.7.1/kernels/xeonphi/CMakeLists.txt +++ b/ospray/embree-v2.7.1/kernels/xeonphi/CMakeLists.txt @@ -24,7 +24,7 @@ INCLUDE(icc_xeonphi) -ADD_DEFINITIONS(-D__TARGET_XEON_PHI__) +ADD_DEFINITIONS(-D__TARGET_XEON_PHI__ -DDONT_WARN_INCLUDE_EMBREE_INTERNALS=1) ADD_ISPC_LIBRARY(embree_xeonphi ${EMBREE_LIB_TYPE} diff --git a/ospray/fb/FrameBuffer.cpp b/ospray/fb/FrameBuffer.cpp index 0af655a9d6..a563111c06 100644 --- a/ospray/fb/FrameBuffer.cpp +++ b/ospray/fb/FrameBuffer.cpp @@ -23,25 +23,22 @@ namespace ospray { FrameBuffer::FrameBuffer(const vec2i &size, ColorBufferFormat colorBufferFormat, bool hasDepthBuffer, - bool hasAccumBuffer) + bool hasAccumBuffer, + bool hasVarianceBuffer) : size(size), colorBufferFormat(colorBufferFormat), hasDepthBuffer(hasDepthBuffer), hasAccumBuffer(hasAccumBuffer), - accumID(-1) + hasVarianceBuffer(hasVarianceBuffer) { managedObjectType = OSP_FRAMEBUFFER; Assert(size.x > 0 && size.y > 0); } - void FrameBuffer::commit() - { - const float gamma = getParam1f("gamma", 1.0f); - ispc::FrameBuffer_set_gamma(ispcEquivalent, gamma); - } - /*! helper function for debugging. write out given pixels in PPM format */ - void writePPM(const std::string &fileName, const vec2i &size, const uint32 *pixels) + void writePPM(const std::string &fileName, + const vec2i &size, + const uint32 *pixels) { FILE *file = fopen(fileName.c_str(),"w"); if (!file) { @@ -57,7 +54,10 @@ namespace ospray { } // helper function to write a (float) image as (flipped) PFM file - void writePFM(const std::string &fileName, const vec2i &size, const int channel, const float *pixel) + void writePFM(const std::string &fileName, + const vec2i &size, + const int channel, + const float *pixel) { FILE *file = fopen(fileName.c_str(),"w"); if (!file) { diff --git a/ospray/fb/FrameBuffer.h b/ospray/fb/FrameBuffer.h index b554dfc0fe..d5b9a5706b 100644 --- a/ospray/fb/FrameBuffer.h +++ b/ospray/fb/FrameBuffer.h @@ -24,33 +24,6 @@ namespace ospray { - /*! helper function to convert float-color into rgba-uint format */ - inline uint32 cvt_uint32(const float f) - { - return (int32)(255.9f * std::max(std::min(f,1.f),0.f)); - } - - /*! helper function to convert float-color into rgba-uint format */ - inline uint32 cvt_uint32(const vec4f &v) - { - return - (cvt_uint32(v.x) << 0) | - (cvt_uint32(v.y) << 8) | - (cvt_uint32(v.z) << 16) | - (cvt_uint32(v.w) << 24); - } - - /*! helper function to convert float-color into rgba-uint format */ - inline uint32 cvt_uint32(const vec3f &v) - { - return - (cvt_uint32(v.x) << 0) | - (cvt_uint32(v.y) << 8) | - (cvt_uint32(v.z) << 16); - } - - - /*! abstract frame buffer class */ struct FrameBuffer : public ManagedObject { /*! app-mappable format of the color buffer. make sure that this @@ -61,9 +34,8 @@ namespace ospray { FrameBuffer(const vec2i &size, ColorBufferFormat colorBufferFormat, bool hasDepthBuffer, - bool hasAccumBuffer); - - virtual void commit(); + bool hasAccumBuffer, + bool hasVarianceBuffer = false); virtual const void *mapDepthBuffer() = 0; virtual const void *mapColorBuffer() = 0; @@ -79,25 +51,26 @@ namespace ospray { virtual std::string toString() const { return "ospray::FrameBuffer"; } - /*! indicates whether the app requested this frame buffer to have - an accumulation buffer */ - bool hasAccumBuffer; /*! indicates whether the app requested this frame buffer to have an (application-mappable) depth buffer */ bool hasDepthBuffer; + /*! indicates whether the app requested this frame buffer to have + an accumulation buffer */ + bool hasAccumBuffer; + bool hasVarianceBuffer; /*! buffer format of the color buffer */ ColorBufferFormat colorBufferFormat; - /*! tracks how many times we have already accumulated into this - frame buffer. A value of '<0' means that accumulation is - disabled (in which case the renderer may not access the - accumulation buffer); in all other cases this value indicates - how many frames have already been accumulated in this frame - buffer. Note that it is up to the application to properly - reset the accumulationID (using ospClearAccum(fb)) if anything + /*! 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 changes that requires clearing the accumulation buffer. */ - int32 accumID; + virtual int32 accumID(const vec2i &tile) = 0; + virtual float tileError(const vec2i &tile) = 0; + + //! returns error of frame + virtual float endFrame(const float errorThreshold) = 0; Ref pixelOp; }; @@ -107,6 +80,7 @@ namespace ospray { void writePPM(const std::string &fileName, const vec2i &size, uint32 *pixels); //! helper function to write a (float) image as (flipped) PFM file - void writePFM(const std::string &fileName, const vec2i &size, const int channel, const float *pixels); + void writePFM(const std::string &fileName, const vec2i &size, + const int channel, const float *pixels); } // ::ospray diff --git a/ospray/fb/FrameBuffer.ih b/ospray/fb/FrameBuffer.ih index 89c68bc05b..5c75910a2b 100644 --- a/ospray/fb/FrameBuffer.ih +++ b/ospray/fb/FrameBuffer.ih @@ -37,8 +37,6 @@ struct FrameBuffer { vec2i size; /*!< size (width x height) of frame buffer, in pixels */ vec2f rcpSize; /*! one over size (precomputed) */ - uniform float gamma; /*! gamma correction */ - int32 accumID; FrameBuffer_ColorBufferFormat colorBufferFormat; @@ -50,7 +48,7 @@ struct FrameBuffer /*! helper function to convert float-color into rgba-uint format */ inline uint32 cvt_uint32(const float f) { - return (int32)(255.9f * max(min(f,1.f),0.f)); + return (int32)(255.f * clamp(f, 0.f, 1.f)); } /*! helper function to convert float-color into rgba-uint format */ diff --git a/ospray/fb/FrameBuffer.ispc b/ospray/fb/FrameBuffer.ispc index 3040efa41a..761e979562 100644 --- a/ospray/fb/FrameBuffer.ispc +++ b/ospray/fb/FrameBuffer.ispc @@ -20,7 +20,6 @@ void FrameBuffer_Constructor(FrameBuffer *uniform self, void *uniform cClassPtr) { self->cClassPtr = cClassPtr; - self->accumID = -1; self->size.x = 0; self->size.y = 0; self->rcpSize.x = 0.f; @@ -33,17 +32,9 @@ void FrameBuffer_set(FrameBuffer *uniform self, const uniform uint32 size_y, uniform int32 colorBufferFormat) { - self->accumID = -1; self->size.x = size_x; self->size.y = size_y; self->rcpSize.x = 1.f/size_x; self->rcpSize.y = 1.f/size_y; self->colorBufferFormat = (uniform FrameBuffer_ColorBufferFormat)colorBufferFormat; } - -export void FrameBuffer_set_gamma(void *uniform _self, - const uniform float gamma) -{ - uniform FrameBuffer *uniform self = (uniform FrameBuffer *uniform)_self; - self->gamma = gamma; -} diff --git a/ospray/fb/LocalFB.cpp b/ospray/fb/LocalFB.cpp index 329d666fc0..0342019f25 100644 --- a/ospray/fb/LocalFB.cpp +++ b/ospray/fb/LocalFB.cpp @@ -14,34 +14,34 @@ // limitations under the License. // // ======================================================================== // +//ospray #include "LocalFB.h" #include "LocalFB_ispc.h" -using embree::alignedFree; -using embree::alignedMalloc; - namespace ospray { LocalFrameBuffer::LocalFrameBuffer(const vec2i &size, ColorBufferFormat colorBufferFormat, bool hasDepthBuffer, - bool hasAccumBuffer, + bool hasAccumBuffer, + bool hasVarianceBuffer, void *colorBufferToUse) - : FrameBuffer(size, colorBufferFormat, hasDepthBuffer, hasAccumBuffer) - { + : FrameBuffer(size, colorBufferFormat, hasDepthBuffer, hasAccumBuffer, hasVarianceBuffer) + { Assert(size.x > 0); Assert(size.y > 0); if (colorBufferToUse) colorBuffer = colorBufferToUse; else { - switch(colorBufferFormat) { - case OSP_RGBA_NONE: + switch (colorBufferFormat) { + case OSP_FB_NONE: colorBuffer = NULL; break; - case OSP_RGBA_F32: + case OSP_FB_RGBA8: + case OSP_FB_SRGBA: colorBuffer = (vec4f*)alignedMalloc(sizeof(vec4f)*size.x*size.y); break; - case OSP_RGBA_I8: + case OSP_FB_RGBA32F: colorBuffer = (uint32*)alignedMalloc(sizeof(uint32)*size.x*size.y); break; default: @@ -53,47 +53,74 @@ namespace ospray { depthBuffer = (float*)alignedMalloc(sizeof(float)*size.x*size.y); else depthBuffer = NULL; - + if (hasAccumBuffer) accumBuffer = (vec4f*)alignedMalloc(sizeof(vec4f)*size.x*size.y); else accumBuffer = NULL; + + tilesx = divRoundUp(size.x, TILE_SIZE); + tiles = tilesx * divRoundUp(size.y, TILE_SIZE); + tileAccumID = new int32[tiles]; + memset(tileAccumID, 0, tiles*sizeof(int32)); + + if (hasVarianceBuffer) { + varianceBuffer = (vec4f*)alignedMalloc(sizeof(vec4f)*size.x*size.y); + tileErrorBuffer = new float[tiles]; + // maximum number of regions: all regions are of size 3 are split in half + errorRegion.reserve(divRoundUp(tiles*2, 3)); + } else { + varianceBuffer = NULL; + tileErrorBuffer = NULL; + } + ispcEquivalent = ispc::LocalFrameBuffer_create(this,size.x,size.y, colorBufferFormat, colorBuffer, depthBuffer, - accumBuffer); + accumBuffer, + varianceBuffer, + tileAccumID, + tileErrorBuffer); } - - LocalFrameBuffer::~LocalFrameBuffer() + + LocalFrameBuffer::~LocalFrameBuffer() { - if (depthBuffer) alignedFree(depthBuffer); + alignedFree(depthBuffer); + alignedFree(colorBuffer); + alignedFree(accumBuffer); + alignedFree(varianceBuffer); + delete[] tileAccumID; + delete[] tileErrorBuffer; + } - if (colorBuffer) - switch(colorBufferFormat) { - case OSP_RGBA_F32: - alignedFree(colorBuffer); - break; - case OSP_RGBA_I8: - alignedFree(colorBuffer); - break; - default: - throw std::runtime_error("color buffer format not supported"); - } - if (accumBuffer) alignedFree(accumBuffer); + std::string LocalFrameBuffer::toString() const + { + return "ospray::LocalFrameBuffer"; } void LocalFrameBuffer::clear(const uint32 fbChannelFlags) { if (fbChannelFlags & OSP_FB_ACCUM) { - ispc::LocalFrameBuffer_clearAccum(getIE()); - accumID = 0; + // it is only necessary to reset the accumID, + // LocalFrameBuffer_accumulateTile takes care of clearing the + // accumulation buffers + memset(tileAccumID, 0, tiles*sizeof(int32)); + + // always also clear error buffer (if present) + if (hasVarianceBuffer) { + 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), vec2i(tilesx, divRoundUp(size.y, TILE_SIZE)))); + } } } void LocalFrameBuffer::setTile(Tile &tile) { -#if 1 if (pixelOp) pixelOp->preAccum(tile); if (accumBuffer) @@ -101,36 +128,99 @@ namespace ospray { if (pixelOp) pixelOp->postAccum(tile); if (colorBuffer) { - switch(colorBufferFormat) { - case OSP_RGBA_I8: - ispc::LocalFrameBuffer_writeTile_RGBA_I8(getIE(),(ispc::Tile&)tile); + switch (colorBufferFormat) { + case OSP_FB_RGBA8: + ispc::LocalFrameBuffer_writeTile_RGBA8(getIE(),(ispc::Tile&)tile); + break; + case OSP_FB_SRGBA: + ispc::LocalFrameBuffer_writeTile_SRGBA(getIE(),(ispc::Tile&)tile); break; - case OSP_RGBA_F32: - ispc::LocalFrameBuffer_writeTile_RGBA_F32(getIE(),(ispc::Tile&)tile); + case OSP_FB_RGBA32F: + ispc::LocalFrameBuffer_writeTile_RGBA32F(getIE(),(ispc::Tile&)tile); break; default: NOTIMPLEMENTED; } } -#else - ispc::LocalFrameBuffer_setTile(getIE(),(ispc::Tile&)tile); -#endif + } + + int32 LocalFrameBuffer::accumID(const vec2i &tile) + { + return tileAccumID[tile.y * tilesx + tile.x]; + } + + float LocalFrameBuffer::tileError(const vec2i &tile) + { + const int idx = tile.y * tilesx + tile.x; + return hasVarianceBuffer ? tileErrorBuffer[idx] : inf; + } + + 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 * tilesx + 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 * tilesx + 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 reference 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; + } else + return inf; } const void *LocalFrameBuffer::mapDepthBuffer() { - // waitForRenderTaskToBeReady(); this->refInc(); return (const void *)depthBuffer; } - + const void *LocalFrameBuffer::mapColorBuffer() { - // waitForRenderTaskToBeReady(); this->refInc(); return (const void *)colorBuffer; } - + void LocalFrameBuffer::unmap(const void *mappedMem) { Assert(mappedMem == colorBuffer || mappedMem == depthBuffer ); diff --git a/ospray/fb/LocalFB.h b/ospray/fb/LocalFB.h index d60f48a60a..238fdd96ee 100644 --- a/ospray/fb/LocalFB.h +++ b/ospray/fb/LocalFB.h @@ -28,25 +28,34 @@ namespace ospray { NULL */ float *depthBuffer; /*!< one float per pixel, may be NULL */ 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 + int32 tilesx; + int32 tiles; LocalFrameBuffer(const vec2i &size, ColorBufferFormat colorBufferFormat, bool hasDepthBuffer, - bool hasAccumBuffer, + bool hasAccumBuffer, + bool hasVarianceBuffer, void *colorBufferToUse=NULL); virtual ~LocalFrameBuffer(); - - //! \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 - { return "ospray::LocalFrameBuffer"; } + std::string toString() const override; - virtual void setTile(Tile &tile); + void setTile(Tile &tile) override; + int32 accumID(const vec2i &tile) override; + float tileError(const vec2i &tile) override; + float endFrame(const float errorThreshold) override; - virtual const void *mapColorBuffer(); - virtual const void *mapDepthBuffer(); - virtual void unmap(const void *mappedMem); - virtual void clear(const uint32 fbChannelFlags); + const void *mapColorBuffer() override; + const void *mapDepthBuffer() override; + void unmap(const void *mappedMem) override; + void clear(const uint32 fbChannelFlags) override; }; } // ::ospray diff --git a/ospray/fb/LocalFB.ih b/ospray/fb/LocalFB.ih index 41de71e671..a03fe5bc87 100644 --- a/ospray/fb/LocalFB.ih +++ b/ospray/fb/LocalFB.ih @@ -22,11 +22,14 @@ /*! a Local FrameBuffer that stores all pixel values (color, depth, accum) in a plain 2D array of pixels (one array per component) */ -struct LocalFB +struct LocalFB { FrameBuffer super; /*!< superclass that we inherit from */ void *colorBuffer; uniform float *depthBuffer; 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; }; - diff --git a/ospray/fb/LocalFB.ispc b/ospray/fb/LocalFB.ispc index dcc5459195..49308da2b5 100644 --- a/ospray/fb/LocalFB.ispc +++ b/ospray/fb/LocalFB.ispc @@ -16,187 +16,51 @@ #include "LocalFB.ih" -// number of floats each task is clearing; must be a a mulitple of 16 -#define CLEAR_BLOCK_SIZE (32 * 1024) - -export void LocalFrameBuffer_clearAccum(void *uniform _fb) -{ - uniform LocalFB *uniform fb = (uniform LocalFB *uniform)_fb; - fb->super.accumID = 0; - - if (fb->accumBuffer) { - uniform size_t num_floats = 4*fb->super.size.x*fb->super.size.y; - uniform size_t num_blocks = (num_floats + CLEAR_BLOCK_SIZE - 1) / CLEAR_BLOCK_SIZE; - - //NOTE(jda) - this needs to be threaded? seems to perform ok as-is... - for(uniform int taskIndex = 0; taskIndex < num_blocks; ++taskIndex) { - uniform float *uniform fbPointer - = (uniform float *uniform)&fb->accumBuffer[0].x; - uniform float *uniform block = fbPointer + taskIndex * CLEAR_BLOCK_SIZE; - uniform size_t num_floats = 4*fb->super.size.x*fb->super.size.y; - - uniform int end = min(CLEAR_BLOCK_SIZE, - num_floats - taskIndex * CLEAR_BLOCK_SIZE); - foreach (x=0 ... end) - block[x] = 0.f; - } - } -} - //! \brief write tile into the given frame buffer's color buffer /*! \detailed this buffer _must_ exist when this fct is called, and it - _must_ have RGBA_I8 format */ -export void LocalFrameBuffer_writeTile_RGBA_I8(void *uniform _fb, - uniform Tile &tile) -{ - uniform LocalFB *uniform fb = (uniform LocalFB *uniform)_fb; - uniform uint32 *uniform color = (uniform uint32 *uniform)fb->colorBuffer; - uniform float *uniform depth = (uniform float *uniform)fb->depthBuffer; - if (!color) - // actually, this should never happen ... - return; - - VaryingTile *uniform varyTile = (VaryingTile *uniform)&tile; - for (uniform uint32 iy=0;iy= tile.region.upper.y) continue; - - uniform uint32 chunkID = iy*(TILE_SIZE/programCount); - - for (uint32 iix = tile.region.lower.x+programIndex; - iixsuper.size.x+iix; - unmasked { - varying vec4f col = make_vec4f(varyTile->r[chunkID], - varyTile->g[chunkID], - varyTile->b[chunkID], - varyTile->a[chunkID]); - - // XXX hardcoded gamma, should use pixelops! - col = max(col,make_vec4f(0.f)); - // alpha is never gamma-corrected - col = make_vec4f(pow(make_vec3f(col), 1.f/2.2f), col.w); - - const uint32 asRGBA = cvt_uint32(col); - - // uniform bool hasDepth = (fb->depthBuffer != NULL); - // const uniform float accScale = 1.f/(fb->inherited.accumID+1); - // if (fb->inherited.colorBufferFormat == ColorBufferFormat_RGBA_FLOAT32) { - // uniform vec4f *uniform color - // = fb->colorBuffer - // ? (uniform vec4f *uniform)fb->colorBuffer - // : NULL; - // uniform vec4f *uniform accum - // = fb->accumBuffer - // ? (uniform vec4f *uniform)fb->accumBuffer - // : NULL; - // uniform float *uniform depth - // = fb->depthBuffer - // ? (uniform float *uniform)fb->depthBuffer - // : NULL; - // for (uniform int i=0;iinherited.size.x+x; - // const vec4f value = getRGBA(tile,pixID); - // if (x < fb->inherited.size.x & y < fb->inherited.size.y) { - // if (accum) { - // vec4f acc = accum[ofs]+value; - // accum[ofs] = acc; - // if (color) { - // color[ofs] = pow(max(acc * accScale,make_vec4f(0.f)), rcpf(fb->inherited.gamma)); - // } - // } else - // if (color) - // color[ofs] = pow(max(value,make_vec4f(0.f)), rcpf(fb->inherited.gamma)); - // if (depth) - // fb->depthBuffer[ofs] = tile.z[pixID]; - // } - // } - // } else if (fb->super.colorBufferFormat == ColorBufferFormat_RGBA_UINT8) { - // uniform uint32 *uniform color - // = fb->colorBuffer - // ? (uniform uint32 *uniform)fb->colorBuffer - // : NULL; - // uniform vec4f *uniform accum - // = fb->accumBuffer - // ? (uniform vec4f *uniform)fb->accumBuffer - // : NULL; - // uniform float *uniform depth - // = fb->depthBuffer - // ? (uniform float *uniform)fb->depthBuffer - // : NULL; - - - // for (uniform int i=0;isuper.size.x+x; - // const vec4f value = getRGBA(tile,pixID); - // if (x < fb->super.size.x & y < fb->super.size.y) { - // if (accum) { - // vec4f acc = accum[ofs]+value; - // accum[ofs] = acc; - // if (color) { - // color[ofs] = cvt_uint32(pow(max(acc * accScale,make_vec4f(0.f)), rcpf(fb->super.gamma))); - // } - // } else - // if (color) - // color[ofs] = cvt_uint32(pow(max(value,make_vec4f(0.f)), rcpf(fb->super.gamma))); - // if (depth) - // fb->depthBuffer[ofs] = tile.z[pixID]; - // } - } - color[pixelID] = asRGBA; - if (depth) - fb->depthBuffer[pixelID] = varyTile->z[chunkID]; - } - } + _must_ have format 'name' */ +#define template_writeTile(name, type, cvt) \ +export void LocalFrameBuffer_writeTile_##name(void *uniform _fb, \ + uniform Tile &tile) \ +{ \ + uniform LocalFB *uniform fb = (uniform LocalFB *uniform)_fb; \ + uniform type *uniform color = (uniform type *uniform)fb->colorBuffer; \ + uniform float *uniform depth = (uniform float *uniform)fb->depthBuffer; \ + if (!color) \ + /* actually, this should never happen ... */ \ + return; \ + \ + VaryingTile *uniform varyTile = (VaryingTile *uniform)&tile; \ + for (uniform uint32 iy=0;iy= tile.region.upper.y) continue; \ + \ + uniform uint32 chunkID = iy*(TILE_SIZE/programCount); \ + \ + for (uint32 iix = tile.region.lower.x+programIndex; \ + iixsuper.size.x+iix; \ + unmasked { \ + varying vec4f col = make_vec4f(varyTile->r[chunkID], \ + varyTile->g[chunkID], \ + varyTile->b[chunkID], \ + varyTile->a[chunkID]); \ + \ + const type cvtCol = cvt(col); \ + } \ + color[pixelID] = cvtCol; \ + if (depth) fb->depthBuffer[pixelID] = varyTile->z[chunkID]; \ + } \ + } \ } -//! \brief write tile into the given frame buffer's color buffer -/*! \detailed this buffer _must_ exist when this fct is called, and it - _must_ have RGBA_F32 format */ -export void LocalFrameBuffer_writeTile_RGBA_F32(void *uniform _fb, - uniform Tile &tile) -{ - uniform LocalFB *uniform fb = (uniform LocalFB *uniform)_fb; - uniform vec4f *uniform color = (uniform vec4f *uniform)fb->colorBuffer; - uniform float *uniform depth = (uniform float *uniform)fb->depthBuffer; - if (!color) - // actually, this should never happen ... - return; - - VaryingTile *uniform varyTile = (VaryingTile *uniform)&tile; - for (uniform uint32 iy=0;iy= tile.region.upper.y) continue; - - uniform uint32 chunkID = iy*(TILE_SIZE/programCount); - - for (uint32 iix = tile.region.lower.x+programIndex; - iixsuper.size.x+iix; - unmasked { - varying vec4f col = make_vec4f(varyTile->r[chunkID], - varyTile->g[chunkID], - varyTile->b[chunkID], - varyTile->a[chunkID]); - - // XXX not even hardcoded gamma for float buffer, should use pixelops anyway - col = max(col, make_vec4f(0.f)); - } - color[pixelID] = col; - if (depth) - fb->depthBuffer[pixelID] = varyTile->z[chunkID]; - } - } -} +template_writeTile(RGBA8, uint32, cvt_uint32); +template_writeTile(SRGBA, uint32, linear_to_srgba8); +inline vec4f cvt_nop(const vec4f &v) { return v; }; +template_writeTile(RGBA32F, vec4f, cvt_nop); +#undef template_writeTile //! \brief accumulate tile into BOTH accum buffer AND tile. @@ -207,12 +71,16 @@ export void LocalFrameBuffer_accumulateTile(void *uniform _fb, uniform Tile &tile) { uniform LocalFB *uniform fb = (uniform LocalFB *uniform)_fb; - uniform vec4f *uniform accum = (uniform vec4f *uniform)fb->accumBuffer; + uniform vec4f *uniform accum = fb->accumBuffer; if (!accum) return; - const float accScale = rcpf(fb->super.accumID+1); - VaryingTile *uniform varyTile = (VaryingTile *uniform)&tile; + + uniform vec4f *uniform variance = fb->varianceBuffer; + const uniform float accScale = rcpf(tile.accumID+1); + const uniform float accHalfScale = rcpf(tile.accumID/2+1); + float err = 0.f; + for (uniform uint32 iy=0;iy= tile.region.upper.y) continue; @@ -227,7 +95,7 @@ export void LocalFrameBuffer_accumulateTile(void *uniform _fb, /*! todo: rather than gathering, replace this code with 'load4f's and swizzles */ varying vec4f acc = make_vec4f(0.f); - if (fb->super.accumID > 0) + if (tile.accumID > 0) acc = accum[pixelID]; unmasked { acc.x += varyTile->r[chunkID]; @@ -235,17 +103,51 @@ export void LocalFrameBuffer_accumulateTile(void *uniform _fb, acc.z += varyTile->b[chunkID]; acc.w += varyTile->a[chunkID]; } - accum[pixelID] = acc; + acc = acc * accScale; + + // variance buffer accumulates every other frame + if (variance && (tile.accumID & 1) == 1) { + varying vec3f vari = make_vec3f(0.f); + if (tile.accumID > 1) + vari = make_vec3f(variance[pixelID]); + unmasked { + vari.x += varyTile->r[chunkID]; + vari.y += varyTile->g[chunkID]; + vari.z += varyTile->b[chunkID]; + } + variance[pixelID] = make_vec4f(vari); + + const vec3f acc3 = make_vec3f(acc); + const float den2 = reduce_add(acc3); + if (den2 > 0.0f) { + const vec3f diff = absf(acc3 - accHalfScale * vari); + err += reduce_add(diff) * rsqrtf(den2); + } + } unmasked { - varyTile->r[chunkID] = accScale * acc.x; - varyTile->g[chunkID] = accScale * acc.y; - varyTile->b[chunkID] = accScale * acc.z; - varyTile->a[chunkID] = accScale * acc.w; + varyTile->r[chunkID] = acc.x; + varyTile->g[chunkID] = acc.y; + varyTile->b[chunkID] = acc.z; + varyTile->a[chunkID] = acc.w; } } } + + const uniform vec2i tileIdx = tile.region.lower/TILE_SIZE; + const uniform int32 tileId = tileIdx.y*fb->numTiles.x + tileIdx.x; + fb->tileAccumID[tileId]++; + + // error is also only updated every other frame to avoid alternating error + // (get a monotone sequence) + 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); + // print("[%, %]: \t%\t%\n", tileIdx.x, tileIdx.y, errf); + fb->tileErrorBuffer[tileId] = errf; + } } @@ -255,7 +157,10 @@ export void *uniform LocalFrameBuffer_create(void *uniform cClassPtr, uniform int32 colorBufferFormat, void *uniform colorBuffer, void *uniform depthBuffer, - void *uniform accumBuffer) + void *uniform accumBuffer, + void *uniform varianceBuffer, + void *uniform tileAccumID, + void *uniform tileErrorBuffer) { uniform LocalFB *uniform self = uniform new uniform LocalFB; FrameBuffer_Constructor(&self->super,cClassPtr); @@ -264,5 +169,9 @@ export void *uniform LocalFrameBuffer_create(void *uniform cClassPtr, self->colorBuffer = colorBuffer; self->depthBuffer = (uniform float *uniform)depthBuffer; self->accumBuffer = (uniform vec4f *uniform)accumBuffer; + 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; return self; } diff --git a/ospray/fb/PixelOp.h b/ospray/fb/PixelOp.h index 98276187e1..0f77e71576 100644 --- a/ospray/fb/PixelOp.h +++ b/ospray/fb/PixelOp.h @@ -41,7 +41,7 @@ namespace ospray { */ struct PixelOp : public ManagedObject { - struct Instance : public embree::RefCount + struct Instance : public RefCount { FrameBuffer *fb; /*! gets called every time the frame buffer got 'commit'ted */ diff --git a/ospray/fb/Tile.h b/ospray/fb/Tile.h index bcd1c08090..a6d1d0a5ca 100644 --- a/ospray/fb/Tile.h +++ b/ospray/fb/Tile.h @@ -50,6 +50,19 @@ namespace ospray { vec2f rcp_fbSize; int32 generation; int32 children; + int32 accumID; //!< how often has been accumulated into this tile + + Tile() {} + Tile(const vec2i &tile, const vec2i &fbsize, const int32 accumId) + : fbSize(fbsize), + rcp_fbSize(rcp(vec2f(fbsize))), + generation(0), + children(0), + accumID(accumId) + { + region.lower = tile * TILE_SIZE; + region.upper = min(region.lower + TILE_SIZE, fbsize); + } }; } // ::ospray diff --git a/ospray/fb/Tile.ih b/ospray/fb/Tile.ih index 3475975f6d..6b70ef10ea 100644 --- a/ospray/fb/Tile.ih +++ b/ospray/fb/Tile.ih @@ -32,6 +32,7 @@ struct Tile { uniform vec2f rcp_fbSize; uniform int32 generation; uniform int32 children; + uniform int32 accumID; }; struct VaryingTile { @@ -45,6 +46,7 @@ struct VaryingTile { uniform vec2f rcp_fbSize; uniform int32 generation; uniform int32 children; + uniform int32 accumID; }; inline vec4f setRGBA(uniform Tile &tile, varying uint32 i, const varying vec4f rgba) diff --git a/ospray/geometry/Cylinders.ispc b/ospray/geometry/Cylinders.ispc index 1536cb9778..c431216f76 100644 --- a/ospray/geometry/Cylinders.ispc +++ b/ospray/geometry/Cylinders.ispc @@ -45,15 +45,13 @@ struct Cylinders { typedef uniform float uniform_float; -void Cylinders_bounds(uniform Cylinders *uniform geometry, - uniform size_t primID, - uniform box3fa &bbox) +unmasked void Cylinders_bounds(uniform Cylinders *uniform geometry, + uniform size_t primID, + uniform box3fa &bbox) { uniform uint8 *uniform cylinderPtr = geometry->data + geometry->bytesPerCylinder*primID; - uniform float radius = geometry->radius; - if (geometry->offset_radius >= 0) { - radius = *((uniform float *)(cylinderPtr+geometry->offset_radius)); - } + uniform bool offr = geometry->offset_radius >= 0; + uniform float radius = offr ? *((uniform float *)(cylinderPtr+geometry->offset_radius)) : geometry->radius; uniform vec3f v0 = *((uniform vec3f*)(cylinderPtr+geometry->offset_v0)); uniform vec3f v1 = *((uniform vec3f*)(cylinderPtr+geometry->offset_v1)); bbox = make_box3fa(min(v0,v1)-make_vec3f(radius), @@ -122,7 +120,7 @@ void Cylinders_intersect(uniform Cylinders *uniform geometry, // we need hit in object space, in postIntersect it is in world-space const vec3f P = ray.t*ray.dir - A; const vec3f V = cross(P,AB); - ray.Ng = normalize(cross(AB,V)); + ray.Ng = cross(AB,V); } } @@ -155,7 +153,7 @@ static void Cylinders_postIntersect(uniform Geometry *uniform geometry, } } -export void *uniform Cylinders_create(void *uniform cppEquivalent) +export void *uniform Cylinders_create(void *uniform cppEquivalent) { uniform Cylinders *uniform geom = uniform new uniform Cylinders; Geometry_Constructor(&geom->geometry,cppEquivalent, diff --git a/ospray/geometry/Geometry.h b/ospray/geometry/Geometry.h index bb5b6b817a..79578244a8 100644 --- a/ospray/geometry/Geometry.h +++ b/ospray/geometry/Geometry.h @@ -37,7 +37,7 @@ namespace ospray { struct Geometry : public ManagedObject { //! constructor - Geometry() : bounds(embree::empty) { managedObjectType = OSP_GEOMETRY; } + Geometry() : bounds(empty) { managedObjectType = OSP_GEOMETRY; } //! set given geometry's material. /*! all material assignations should go through this function; the diff --git a/ospray/geometry/Instance.cpp b/ospray/geometry/Instance.cpp index 4b07ce95d0..10db1408de 100644 --- a/ospray/geometry/Instance.cpp +++ b/ospray/geometry/Instance.cpp @@ -69,7 +69,7 @@ namespace ospray { const vec3f v110(b.lower.x,b.upper.y,b.upper.z); const vec3f v111(b.upper.x,b.upper.y,b.upper.z); - bounds = embree::empty; + bounds = empty; bounds.extend(xfmPoint(xfm,v000)); bounds.extend(xfmPoint(xfm,v001)); bounds.extend(xfmPoint(xfm,v010)); diff --git a/ospray/geometry/Isosurfaces.h b/ospray/geometry/Isosurfaces.h index 1bce521a50..7c7fe5a42f 100644 --- a/ospray/geometry/Isosurfaces.h +++ b/ospray/geometry/Isosurfaces.h @@ -47,7 +47,11 @@ namespace ospray { Implements the \ref geometry_isosurfaces geometry */ - struct Isosurfaces : public Geometry { + struct Isosurfaces : public Geometry + { + //! constructor + Isosurfaces(); + //! \brief common function to help printf-debugging virtual std::string toString() const { return "ospray::Isosurfaces"; } @@ -60,8 +64,6 @@ namespace ospray { size_t numIsovalues; float *isovalues; - - Isosurfaces(); }; /*! @} */ diff --git a/ospray/geometry/Spheres.cpp b/ospray/geometry/Spheres.cpp index f8ed7b2b16..25642bbd6e 100644 --- a/ospray/geometry/Spheres.cpp +++ b/ospray/geometry/Spheres.cpp @@ -51,7 +51,9 @@ namespace ospray { sphereData = getParamData("spheres"); materialList = getParamData("materialList"); colorData = getParamData("color"); - + colorOffset = getParam1i("color_offset",0); + colorStride = getParam1i("color_stride",4*sizeof(float)); + if (sphereData.ptr == NULL) { throw std::runtime_error("#ospray:geometry/spheres: no 'spheres' data " "specified"); @@ -88,7 +90,8 @@ namespace ospray { ispc::SpheresGeometry_set(getIE(),model->getIE(), sphereData->data,_materialList, - colorData?(ispc::vec4f*)colorData->data:NULL, + colorData?(unsigned char*)colorData->data:NULL, + colorOffset, colorStride, numSpheres,bytesPerSphere, radius,materialID, offset_center,offset_radius, diff --git a/ospray/geometry/Spheres.h b/ospray/geometry/Spheres.h index e8ba9be5d8..876b99ba86 100644 --- a/ospray/geometry/Spheres.h +++ b/ospray/geometry/Spheres.h @@ -74,7 +74,17 @@ namespace ospray { Ref sphereData; Ref materialList; void *_materialList; - Ref colorData; /*!< sphere color array (vec3fa) */ + /*! data array from which we read the per-sphere color data; if + NULL we do not have per-sphere data */ + 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 */ + size_t colorStride; + /*! offset in colorData array for accessing i'th sphere's + color. color of sphere i will be read as 3 floats from + 'colorOffset+i*colorStride */ + size_t colorOffset; Spheres(); ~Spheres(); diff --git a/ospray/geometry/Spheres.ispc b/ospray/geometry/Spheres.ispc index 67e52f1079..a38d3eaef6 100644 --- a/ospray/geometry/Spheres.ispc +++ b/ospray/geometry/Spheres.ispc @@ -26,11 +26,10 @@ #include "embree2/rtcore_geometry_user.isph" struct Spheres { - uniform Geometry geometry; //!< inherited geometry fields + uniform Geometry super; //!< inherited geometry fields uniform uint8 *uniform data; uniform Material *uniform *materialList; - uniform vec4f *uniform color; float radius; int materialID; @@ -38,6 +37,11 @@ struct Spheres { int offset_radius; int offset_materialID; int offset_colorID; + + uint8 *color_data; + int color_stride; + int color_offset; + int32 numSpheres; int32 bytesPerSphere; }; @@ -54,32 +58,42 @@ static void Spheres_postIntersect(uniform Geometry *uniform geometry, dg.Ng = dg.Ns = ray.Ng; - if ((flags & DG_COLOR) && self->color) { + if ((flags & DG_COLOR) && self->color_data) { + uint32 colorID = 0; if (self->offset_colorID >= 0) { - uniform uint8 *varying spherePtr = self->data + self->bytesPerSphere*ray.primID; - uint32 colorID = *((uniform uint32 *varying)(spherePtr+self->offset_colorID)); - dg.color = self->color[colorID]; + uniform uint8 *varying spherePtr = + self->data + self->bytesPerSphere*ray.primID; + colorID = *((uniform uint32 *varying)(spherePtr+self->offset_colorID)); } else { - dg.color = self->color[ray.primID]; + colorID = ray.primID; } + uint32 colorAddr = self->color_offset+colorID*self->color_stride; + 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; - dg.materialID = *((uniform uint32 *varying)(spherePtr+self->offset_materialID)); + 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)); + uniform uint8 *varying spherePtr = self->data + + self->bytesPerSphere*ray.primID; + dg.materialID = + *((uniform uint32 *varying)(spherePtr+self->offset_materialID)); if (self->materialList) { dg.material = self->materialList[dg.materialID]; } @@ -87,30 +101,33 @@ static void Spheres_postIntersect(uniform Geometry *uniform geometry, } } -void Spheres_bounds(uniform Spheres *uniform geometry, - uniform size_t primID, - uniform box3fa &bbox) +unmasked void Spheres_bounds(uniform Spheres *uniform self, + uniform size_t primID, + uniform box3fa &bbox) { - uniform uint8 *uniform spherePtr = geometry->data + geometry->bytesPerSphere*((uniform int64)primID); - uniform float radius = geometry->radius; - - if (geometry->offset_radius >= 0) { - radius = *((uniform float *uniform)(spherePtr+geometry->offset_radius)); - } - uniform vec3f center = *((uniform vec3f*uniform)(spherePtr+geometry->offset_center)); + uniform uint8 *uniform spherePtr = self->data + + self->bytesPerSphere*((uniform int64)primID); + uniform bool offr = self->offset_radius >= 0; + uniform float radius = + offr ? *((uniform float *uniform)(spherePtr+self->offset_radius)) : + self->radius; + uniform vec3f center = + *((uniform vec3f*uniform)(spherePtr+self->offset_center)); bbox = make_box3fa(center-make_vec3f(radius),center+make_vec3f(radius)); } -void Spheres_intersect(uniform Spheres *uniform geometry, +void Spheres_intersect(uniform Spheres *uniform self, varying Ray &ray, uniform size_t primID) { - uniform uint8 *uniform spherePtr = geometry->data + geometry->bytesPerSphere*((uniform int64)primID); - uniform float radius = geometry->radius; - if (geometry->offset_radius >= 0) { - radius = *((uniform float *uniform)(spherePtr+geometry->offset_radius)); + uniform uint8 *uniform spherePtr = + self->data + self->bytesPerSphere*((uniform int64)primID); + uniform float radius = self->radius; + if (self->offset_radius >= 0) { + radius = *((uniform float *uniform)(spherePtr+self->offset_radius)); } - uniform vec3f center = *((uniform vec3f*uniform)(spherePtr+geometry->offset_center)); + uniform vec3f center = + *((uniform vec3f*uniform)(spherePtr+self->offset_center)); const vec3f A = center - ray.org; const float a = dot(ray.dir,ray.dir); @@ -135,59 +152,63 @@ void Spheres_intersect(uniform Spheres *uniform geometry, } if (hit) { ray.primID = primID; - ray.geomID = geometry->geometry.geomID; + ray.geomID = self->super.geomID; ray.instID = -1; // cannot easily be moved to postIntersect // we need hit in object space, in postIntersect it is in world-space - ray.Ng = normalize(ray.org + ray.t*ray.dir - center); + ray.Ng = ray.org + ray.t*ray.dir - center; } } -export void *uniform Spheres_create(void *uniform cppEquivalent) +export void *uniform Spheres_create(void *uniform cppEquivalent) { - uniform Spheres *uniform geom = uniform new uniform Spheres; - Geometry_Constructor(&geom->geometry,cppEquivalent, + uniform Spheres *uniform self = uniform new uniform Spheres; + Geometry_Constructor(&self->super,cppEquivalent, Spheres_postIntersect, NULL,0,NULL); - return geom; + return self; } -export void SpheresGeometry_set(void *uniform _geom, - void *uniform _model, - void *uniform data, - void *uniform materialList, - uniform vec4f *uniform color, - int uniform numSpheres, - int uniform bytesPerSphere, - float uniform radius, - int uniform materialID, - int uniform offset_center, - int uniform offset_radius, - int uniform offset_materialID, - int uniform offset_colorID) +export void SpheresGeometry_set(void *uniform _self, + void *uniform _model, + void *uniform data, + void *uniform materialList, + uint8 *uniform color_data, + int uniform color_offset, + int uniform color_stride, + int uniform numSpheres, + int uniform bytesPerSphere, + float uniform radius, + int uniform materialID, + int uniform offset_center, + int uniform offset_radius, + int uniform offset_materialID, + int uniform offset_colorID) { - uniform Spheres *uniform geom = (uniform Spheres *uniform)_geom; + uniform Spheres *uniform self = (uniform Spheres *uniform)_self; uniform Model *uniform model = (uniform Model *uniform)_model; uniform uint32 geomID = rtcNewUserGeometry(model->embreeSceneHandle,numSpheres); - geom->geometry.model = model; - geom->geometry.geomID = geomID; - geom->materialList = (Material **)materialList; - geom->color = color; - geom->numSpheres = numSpheres; - geom->radius = radius; - geom->data = (uniform uint8 *uniform)data; - geom->materialID = materialID; - geom->bytesPerSphere = bytesPerSphere; - - geom->offset_center = offset_center; - geom->offset_radius = offset_radius; - geom->offset_materialID = offset_materialID; - geom->offset_colorID = offset_colorID; - - rtcSetUserData(model->embreeSceneHandle,geomID,geom); + self->super.model = model; + self->super.geomID = geomID; + self->materialList = (Material **)materialList; + self->color_data = color_data; + self->color_stride = color_stride; + self->color_offset = color_offset; + self->numSpheres = numSpheres; + self->radius = radius; + self->data = (uniform uint8 *uniform)data; + self->materialID = materialID; + self->bytesPerSphere = bytesPerSphere; + + self->offset_center = offset_center; + self->offset_radius = offset_radius; + self->offset_materialID = offset_materialID; + self->offset_colorID = offset_colorID; + + rtcSetUserData(model->embreeSceneHandle,geomID,self); rtcSetBoundsFunction(model->embreeSceneHandle,geomID, (uniform RTCBoundsFunc)&Spheres_bounds); rtcSetIntersectFunction(model->embreeSceneHandle,geomID, diff --git a/ospray/geometry/TriangleMesh.cpp b/ospray/geometry/TriangleMesh.cpp index e6be0b77d8..e6931af209 100644 --- a/ospray/geometry/TriangleMesh.cpp +++ b/ospray/geometry/TriangleMesh.cpp @@ -22,7 +22,6 @@ # include "ospray/mpi/MPICommon.h" #endif - // ospray #include "TriangleMesh.h" #include "ospray/common/Model.h" @@ -186,7 +185,7 @@ namespace ospray { (void*)this->index,0, sizeOf(indexData->type)); - bounds = embree::empty; + bounds = empty; for (int i=0;i #include -#include "ospray/common/OSPDataType.h" +#include "ospray/OSPDataType.h" +#include "ospray/OSPTexture.h" #ifdef _WIN32 # ifdef ospray_EXPORTS @@ -54,67 +55,38 @@ #endif #ifdef __GNUC__ - #define OSP_DEPRECATED __attribute__((deprecated)) +#define OSP_DEPRECATED __attribute__((deprecated)) #elif defined(_MSC_VER) - #define OSP_DEPRECATED __declspec(deprecated) +#define OSP_DEPRECATED __declspec(deprecated) #else - #define OSP_DEPRECATED +#define OSP_DEPRECATED #endif -/*! namespace for classes in the public core API */ -namespace osp { - - struct vec2f { float x, y; }; - struct vec2i { int x, y; }; - struct vec3f { float x, y, z; }; - struct vec3fa { float x, y, z; union { int a; unsigned u; float w; }; }; - struct vec3i { int x, y, z; }; - struct vec4f { float x, y, z, w; }; - struct box2i { vec2i lower, upper; }; - struct box3f { vec3f lower, upper; }; - struct linear3f { vec3f vx, vy, vz; }; - struct affine3f { linear3f l; vec3f p; }; - - typedef uint64_t uint64; - - struct ManagedObject { uint64 ID; virtual ~ManagedObject() {} }; - struct FrameBuffer : public ManagedObject {}; - struct Renderer : public ManagedObject {}; - struct Camera : public ManagedObject {}; - struct Model : public ManagedObject {}; - struct Data : public ManagedObject {}; - struct Geometry : public ManagedObject {}; - struct Material : public ManagedObject {}; - struct Volume : public ManagedObject {}; - struct TransferFunction : public ManagedObject {}; - struct Texture2D : public ManagedObject {}; - struct Light : public ManagedObject {}; - struct PixelOp : public ManagedObject {}; - -} // ::osp +/*! OSPRay format constants for Frame Buffer creation */ +typedef enum { + OSP_FB_NONE, //!< framebuffer will not be mapped by application + OSP_FB_RGBA8, //!< one dword per pixel: rgb+alpha, each one byte + OSP_FB_SRGBA, //!< one dword per pixel: rgb (in sRGB space) + alpha, each one byte + OSP_FB_RGBA32F, //!< one float4 per pixel: rgb+alpha, each one float +/* TODO + OSP_FB_RGB8, //!< three 8-bit unsigned chars per pixel + OSP_FB_RGB32F, ? + OSP_FB_SRGB, //!< three 8-bit unsigned chars (in sRGB space) per pixel +*/ +} OSPFrameBufferFormat; +/*! OSPRay channel constants for Frame Buffer (can be OR'ed together) */ typedef enum { OSP_FB_COLOR=(1<<0), OSP_FB_DEPTH=(1<<1), OSP_FB_ACCUM=(1<<2), -// OSP_FB_ALPHA=(1<<3) // not used anywhere; use OSP_FB_COLOR with a frame buffer format containing alpha in 4th channel + OSP_FB_VARIANCE=(1<<3) } OSPFrameBufferChannel; -/*! OSPRay constants for Frame Buffer creation ('and' ed together) */ -typedef enum { - OSP_RGBA_NONE, - OSP_RGBA_I8, /*!< one dword per pixel: rgb+alpha, each one byte */ - OSP_RGB_I8, /*!< three 8-bit unsigned chars per pixel XXX unsupported! */ - OSP_RGBA_F32, /*!< one float4 per pixel: rgb+alpha, each one float */ -// OSP_SRGBA_I8, /*!< one dword per pixel: rgb (in sRGB space) + alpha, each one byte */ -// OSP_SRGB_I8, /*!< three 8-bit unsigned chars (in sRGB space) per pixel */ -} OSPFrameBufferFormat; - //! constants for switching the OSPRay MPI Scope between 'per rank' and 'all ranks' /*! \see ospdApiMode */ typedef enum { - - //! \brief all ospNew(), ospSet(), etc calls affect only the current rank + //! \brief all ospNew(), ospSet(), etc calls affect only the current rank /*! \detailed in this mode, all ospXyz() calls made on a given rank will ONLY affect state ont hat rank. This allows for configuring a (globally known) object differnetly on each different rank (also @@ -122,7 +94,7 @@ typedef enum { OSPD_MODE_INDEPENDENT, OSPD_RANK=OSPD_MODE_INDEPENDENT /*!< alias for OSP_MODE_INDEPENDENT, reads better in code */, - //! \brief all ospNew(), ospSet() calls affect all ranks + //! \brief all ospNew(), ospSet() calls affect all ranks /*! \detailed In this mode, ONLY rank 0 should call ospXyz() functions, but all objects defined through those functions---and all parameters set through those---will apply equally to all @@ -136,7 +108,7 @@ typedef enum { OSPD_MODE_MASTERED, OSPD_MASTER=OSPD_MODE_MASTERED /*!< alias for OSP_MODE_MASTERED, reads better in code */, - //! \brief all ospNew(), ospSet() are called collaboratively by all ranks + //! \brief all ospNew(), ospSet() are called collaboratively by all ranks /*! \detailed In this mode, ALL ranks must call (the same!) api function, the result is collaborative across all nodes in the sense that any object being created gets created across all @@ -145,29 +117,76 @@ typedef enum { OSPD_ALL=OSPD_MODE_COLLABORATIVE /*!< alias for OSP_MODE_COLLABORATIVE, reads better in code */ } OSPDApiMode; -// /*! flags that can be passed to OSPNewGeometry; can be OR'ed together */ -// typedef enum { -// /*! experimental: currently used to specify that the app ranks - -// together - hold a logical piece of geometry, with the back-end -// ospray workers then fetching that on demand..... */ -// OSP_DISTRIBUTED_GEOMETRY = (1<<0), -// } OSPGeometryCreationFlags; +/*! flags that can be passed to OSPNewGeometry; can be OR'ed together */ +typedef enum { + /*! experimental: currently used to specify that the app ranks - + together - hold a logical piece of geometry, with the back-end + ospray workers then fetching that on demand..... */ + OSP_DISTRIBUTED_GEOMETRY = (1<<0), +} OSPGeometryCreationFlags; /*! flags that can be passed to OSPNewData; can be OR'ed together */ typedef enum { OSP_DATA_SHARED_BUFFER = (1<<0), } OSPDataCreationFlags; -/*! flags that can be passed to ospNewTexture2D(); can be OR'ed together */ typedef enum { - OSP_TEXTURE_SHARED_BUFFER = (1<<0), - OSP_TEXTURE_FILTER_NEAREST = (1<<1) /*!< use nearest-neighbor interpolation rather than the default bilinear interpolation */ -} OSPTextureCreationFlags; + OSPD_Z_COMPOSITE +} OSPDRenderMode; -typedef enum { - OSP_OK=0, /*! no error; any value other than zero means 'some kind of error' */ - OSP_GENERAL_ERROR /*! unspecified error */ -} OSPResult; + +#ifdef __cplusplus +namespace osp { + /*! namespace for classes in the public core API */ + +#ifdef OSPRAY_EXTERNAL_VECTOR_TYPES + /*! we assume the app already defines osp::vec types. Note those + HAVE to be compatible with the data layouts used below. + + Note: this feature allows the application to use its own vector + type library in the following way + + a) include your own vector library (say, ospcommon::vec3f etc, + when using the ospcommon library) + + b) make sure the proper vec3f etc are defined in a osp:: namespace, e.g., using + namespace osp { + typedef ospcommon::vec3f vec3f; + } + + c) defines OSPRAY_EXTERNAL_VECTOR_TYPES + + d) include ospray.h + ! */ +#else + struct vec2f { float x, y; }; + struct vec2i { int x, y; }; + struct vec3f { float x, y, z; }; + struct vec3fa { float x, y, z; union { int a; unsigned u; float w; }; }; + struct vec3i { int x, y, z; }; + struct vec4f { float x, y, z, w; }; + struct box2i { vec2i lower, upper; }; + struct box3f { vec3f lower, upper; }; + struct linear3f { vec3f vx, vy, vz; }; + struct affine3f { linear3f l; vec3f p; }; +#endif + + typedef uint64_t uint64; + + struct ManagedObject { uint64 ID; virtual ~ManagedObject() {} }; + struct FrameBuffer : public ManagedObject {}; + struct Renderer : public ManagedObject {}; + struct Camera : public ManagedObject {}; + struct Model : public ManagedObject {}; + struct Data : public ManagedObject {}; + struct Geometry : public ManagedObject {}; + struct Material : public ManagedObject {}; + struct Volume : public ManagedObject {}; + struct TransferFunction : public ManagedObject {}; + struct Texture2D : public ManagedObject {}; + struct Light : public ManagedObject {}; + struct PixelOp : public ManagedObject {}; +} // ::osp typedef osp::FrameBuffer *OSPFrameBuffer; typedef osp::Renderer *OSPRenderer; @@ -183,92 +202,127 @@ typedef osp::Texture2D *OSPTexture2D; typedef osp::ManagedObject *OSPObject; typedef osp::PixelOp *OSPPixelOp; -/*! an error type. '0' means 'no error' */ -typedef int32_t error_t; +/* C++ DOES support default initializers */ +#define OSP_DEFAULT_VAL(a) a + +#else + +typedef struct { float x, y; } osp_vec2f; +typedef struct { int x, y; } osp_vec2i; +typedef struct { float x, y, z; } osp_vec3f; +typedef struct { float x, y, z; + union { int a; unsigned u; float w; }; } osp_vec3fa; +typedef struct { int x, y, z; } osp_vec3i; +typedef struct { float x, y, z, w; } osp_vec4f; +typedef struct { osp_vec2i lower, upper; } osp_box2i; +typedef struct { osp_vec3f lower, upper; } osp_box3f; +typedef struct { osp_vec3f vx, vy, vz; } osp_linear3f; +typedef struct { osp_linear3f l; osp_vec3f p; } osp_affine3f; + +/*! abstract object types. in C99, those are all the same because C99 + doesn't know inheritance, and we want to make sure that a + OSPGeometry can still be passed to a function that expects a + OSPObject, etc */ +typedef struct _OSPManagedObject *OSPManagedObject, + *OSPRenderer, + *OSPCamera, + *OSPFrameBuffer, + *OSPModel, + *OSPData, + *OSPGeometry, + *OSPMaterial, + *OSPLight, + *OSPVolume, + *OSPTransferFunction, + *OSPTexture2D, + *OSPObject, + *OSPPixelOp; + +/* C99 does NOT support default initializers, so we use this macro + to define them away */ +#define OSP_DEFAULT_VAL(a) /* no default arguments on C99 */ + +#endif +#ifdef __cplusplus extern "C" { - //! initialize the ospray engine (for single-node user application) - OSPRAY_INTERFACE void ospInit(int *ac, const char **av); +#endif - typedef enum { - OSPD_Z_COMPOSITE - } OSPDRenderMode; + //! initialize the ospray engine (for single-node user application) + OSPRAY_INTERFACE void ospInit(int *ac, const char **av); -#ifdef OSPRAY_MPI_DISTRIBUTED //! \brief allows for switching the MPI mode btween collaborative, mastered, and independent - OSPRAY_INTERFACE - void ospdApiMode(OSPDApiMode mode); + OSPRAY_INTERFACE void ospdApiMode(OSPDApiMode); - //! the 'lid to the pot' of ospdMpiInit(). + //! the 'lid to the pot' of ospdMpiInit(). /*! does both an osp shutdown and an mpi shutdown for the mpi group created with ospdMpiInit */ - OSPRAY_INTERFACE - void ospdMpiInit(int *ac, char ***av, OSPDRenderMode renderMode=OSPD_Z_COMPOSITE); + OSPRAY_INTERFACE + void ospdMpiInit(int *ac, char ***av, OSPDRenderMode mode OSP_DEFAULT_VAL(=OSPD_Z_COMPOSITE)); /*! the 'lid to the pot' of ospdMpiInit(). shuts down both ospray *and* the MPI layer created with ospdMpiInit */ - OSPRAY_INTERFACE - void ospdMpiShutdown(); -#endif + OSPRAY_INTERFACE void ospdMpiShutdown(); //! load plugin 'name' from shard lib libospray_module_.so /*! returns 0 if the module could be loaded, else it returns an error code > 0 */ - OSPRAY_INTERFACE error_t ospLoadModule(const char *pluginName); + OSPRAY_INTERFACE int32_t ospLoadModule(const char *pluginName); - //! use renderer to render a frame. - /*! What input to tuse for rendering the frame is encoded in the - renderer's parameters, typically in "world". */ - OSPRAY_INTERFACE void ospRenderFrame(OSPFrameBuffer fb, - OSPRenderer renderer, - const uint32_t fbChannelFlags=OSP_FB_COLOR); + //! use renderer to render a frame. + /*! What input to use for rendering the frame is encoded in the + renderer's parameters, typically in "world". + return estimate of variance if framebuffer has VARIANCE buffer */ + OSPRAY_INTERFACE float ospRenderFrame(OSPFrameBuffer, + OSPRenderer, + const uint32_t frameBufferChannels OSP_DEFAULT_VAL(=OSP_FB_COLOR)); - //! create a new renderer of given type + //! create a new renderer of given type /*! return 'NULL' if that type is not known */ OSPRAY_INTERFACE OSPRenderer ospNewRenderer(const char *type); - - //! create a new pixel op of given type + + //! create a new pixel op of given type /*! return 'NULL' if that type is not known */ OSPRAY_INTERFACE OSPPixelOp ospNewPixelOp(const char *type); - + //! set a frame buffer's pixel op */ - OSPRAY_INTERFACE void ospSetPixelOp(OSPFrameBuffer fb, OSPPixelOp op); + OSPRAY_INTERFACE void ospSetPixelOp(OSPFrameBuffer, OSPPixelOp); - //! create a new geometry of given type + //! create a new geometry of given type /*! return 'NULL' if that type is not known */ OSPRAY_INTERFACE OSPGeometry ospNewGeometry(const char *type); //! let given renderer create a new material of given type - OSPRAY_INTERFACE OSPMaterial ospNewMaterial(OSPRenderer renderer, const char *type); + OSPRAY_INTERFACE OSPMaterial ospNewMaterial(OSPRenderer, const char *type); //! let given renderer create a new light of given type - OSPRAY_INTERFACE OSPLight ospNewLight(OSPRenderer renderer, const char *type); - + OSPRAY_INTERFACE OSPLight ospNewLight(OSPRenderer, const char *type); + //! release (i.e., reduce refcount of) given object /*! note that all objects in ospray are refcounted, so one cannot - explicitly "delete" any object. instead, each object is created - with a refcount of 1, and this refcount will be - increased/decreased every time another object refers to this - object resp releases its hold on it; if the refcount is 0 the - object will automatically get deleted. For example, you can - create a new material, assign it to a geometry, and immediately - after this assignation release its refcount; the material will - stay 'alive' as long as the given geometry requires it. */ - OSPRAY_INTERFACE void ospRelease(OSPObject obj); - + explicitly "delete" any object. instead, each object is created + with a refcount of 1, and this refcount will be + increased/decreased every time another object refers to this + object resp releases its hold on it; if the refcount is 0 the + object will automatically get deleted. For example, you can + create a new material, assign it to a geometry, and immediately + after this assignation release its refcount; the material will + stay 'alive' as long as the given geometry requires it. */ + OSPRAY_INTERFACE void ospRelease(OSPObject); + //! assign given material to given geometry - OSPRAY_INTERFACE void ospSetMaterial(OSPGeometry geometry, OSPMaterial material); + OSPRAY_INTERFACE void ospSetMaterial(OSPGeometry, OSPMaterial); - //! \brief create a new camera of given type + //! \brief create a new camera of given type /*! \detailed The default camera type supported in all ospray versions is "perspective" (\ref perspective_camera). For a list of supported camera type in this version of ospray, see \ref ospray_supported_cameras - + \returns 'NULL' if that type is not known, else a handle to the created camera */ OSPRAY_INTERFACE OSPCamera ospNewCamera(const char *type); - //! \brief create a new volume of given type + //! \brief create a new volume of given type /*! \detailed return 'NULL' if that type is not known */ OSPRAY_INTERFACE OSPVolume ospNewVolume(const char *type); @@ -281,66 +335,78 @@ extern "C" { //! \brief create a new transfer function of given type /*! \detailed return 'NULL' if that type is not known */ OSPRAY_INTERFACE OSPTransferFunction ospNewTransferFunction(const char * type); - + //! \brief create a new Texture2D with the given parameters /*! \detailed return 'NULL' if the texture could not be created with the given parameters */ - OSPRAY_INTERFACE OSPTexture2D ospNewTexture2D(int width, int height, OSPDataType type, void *data = NULL, int flags = 0); - +#ifdef __cplusplus + OSPRAY_INTERFACE OSPTexture2D ospNewTexture2D(const osp::vec2i &size, + const OSPTextureFormat, + void *source = NULL, + const uint32_t textureCreationFlags = 0); +#else + OSPRAY_INTERFACE OSPTexture2D ospNewTexture2D(const osp_vec2i *size, + const OSPTextureFormat, + void *source, + const uint32_t textureCreationFlags); +#endif //! \brief clears the specified channel(s) of the frame buffer /*! \detailed clear the specified channel(s) of the frame buffer specified in 'whichChannels' - if whichChannel&OSP_FB_COLOR!=0, clear the color buffer to '0,0,0,0' - if whichChannel&OSP_FB_DEPTH!=0, clear the depth buffer to +inf - if whichChannel&OSP_FB_ACCUM!=0, clear the accum buffer to 0,0,0,0, and reset accumID + if whichChannels & OSP_FB_COLOR != 0, clear the color buffer to '0,0,0,0' + if whichChannels & OSP_FB_DEPTH != 0, clear the depth buffer to +inf + if whichChannels & OSP_FB_ACCUM != 0, clear the accum buffer to 0,0,0,0, and reset accumID */ - OSPRAY_INTERFACE void ospFrameBufferClear(OSPFrameBuffer fb, const uint32_t whichChannel); + OSPRAY_INTERFACE void ospFrameBufferClear(OSPFrameBuffer, const uint32_t frameBufferChannels); // ------------------------------------------------------- - /*! \defgroup ospray_data Data Buffer Handling + /*! \defgroup ospray_data Data Buffer Handling \ingroup ospray_api - \{ + \{ */ - /*! create a new data buffer, with optional init data and control flags + /*! create a new data buffer, with optional init data and control flags - Valid flags that can be or'ed together into the flags value: + 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 - valid for the duration that this data array is being used. - */ - OSPRAY_INTERFACE OSPData ospNewData(size_t numItems, OSPDataType format, const void *init=NULL, int flags=0); + In this case the calling program guarantees that the 'init' pointer will remain + valid for the duration that this data array is being used. + */ + OSPRAY_INTERFACE OSPData ospNewData(size_t numItems, + OSPDataType, + const void *source OSP_DEFAULT_VAL(=NULL), + const uint32_t dataCreationFlags OSP_DEFAULT_VAL(=0)); /*! \} */ // ------------------------------------------------------- - /*! \defgroup ospray_framebuffer Frame Buffer Manipulation + /*! \defgroup ospray_framebuffer Frame Buffer Manipulation + + \ingroup ospray_api - \ingroup ospray_api - - \{ + \{ */ - /*! \brief create a new framebuffer (actual format is internal to ospray) + /*! \brief create a new framebuffer (actual format is internal to ospray) Creates a new frame buffer of given size, externalFormat, and channel type(s). \param externalFormat describes the format the color buffer has *on the host*, and the format that 'ospMapFrameBuffer' will - eventually return. Valid values are OSP_FB_RBGA_FLOAT, - OSP_FB_RBGA_I8, OSP_FB_RGB_I8, and OSP_FB_NONE (note that + eventually return. Valid values are OSP_FB_SRGBA, OSP_FB_RGBA8, + OSP_FB_RGBA32F, and OSP_FB_NONE (note that OSP_FB_NONE is a perfectly reasonably choice for a framebuffer that will be used only internally, see notes below). The origin of the screen coordinate system is the lower left corner (as in OpenGL). \param channelFlags specifies which channels the frame buffer has, - and is or'ed together from the values OSP_FB_COLOR, + and is OR'ed together from the values OSP_FB_COLOR, OSP_FB_DEPTH, and/or OSP_FB_ACCUM. If a certain buffer value is _not_ specified, the given buffer will not be present (see notes below). - + \param size size (in pixels) of frame buffer. Note that ospray makes a very clear distinction between the @@ -362,23 +428,58 @@ extern "C" { the output of the tone mapper. In this case, when using a pixel format of OSP_FB_NONE the pixels from the path tracing stage will never ever be transferred to the application. - */ - OSPRAY_INTERFACE OSPFrameBuffer ospNewFrameBuffer(const osp::vec2i &size, - const OSPFrameBufferFormat externalFormat=OSP_RGBA_I8, - const int channelFlags=OSP_FB_COLOR); + */ +#ifdef __cplusplus + OSPRAY_INTERFACE OSPFrameBuffer ospNewFrameBuffer(const osp::vec2i &size, + const OSPFrameBufferFormat format = OSP_FB_SRGBA, + const uint32_t frameBufferChannels = OSP_FB_COLOR); +#else + OSPRAY_INTERFACE OSPFrameBuffer ospNewFrameBuffer(const osp_vec2i *size, + const OSPFrameBufferFormat, + const uint32_t frameBufferChannels); +#endif + + // \brief Set a given region of the volume to a given set of voxels + /*! \detailed Given a block of voxels (of dimensions 'blockDim', + located at the memory region pointed to by 'source', copy the + given voxels into volume, at the region of addresses + [regionCoords...regionCoord+regionSize]. + */ +#ifdef __cplusplus + OSPRAY_INTERFACE int ospSetRegion(/*! the object we're writing this block of pixels into */ + OSPVolume, + /* points to the first voxel to be copies. The + voxels at 'source' MUST have dimensions + 'regionSize', must be organized in 3D-array + order, and must have the same voxel type as the + volume.*/ + void *source, + /*! coordinates of the lower, left, front corner of + the target region.*/ + const osp::vec3i ®ionCoords, + /*! size of the region that we're writing to; MUST + be the same as the dimensions of source[][][] */ + const osp::vec3i ®ionSize); +#else + OSPRAY_INTERFACE int ospSetRegion(OSPVolume, + void *source, + const osp_vec3i *regionCoords, + const osp_vec3i *regionSize); +#endif + - /*! \brief free a framebuffer + /*! \brief free a framebuffer - due to refcounting the frame buffer may not immeidately be deleted + due to refcounting the frame buffer may not immediately be deleted at this time */ - OSPRAY_INTERFACE void ospFreeFrameBuffer(OSPFrameBuffer fb); + OSPRAY_INTERFACE void ospFreeFrameBuffer(OSPFrameBuffer); /*! \brief map app-side content of a framebuffer (see \ref frame_buffer_handling) */ - OSPRAY_INTERFACE const void *ospMapFrameBuffer(OSPFrameBuffer fb, - OSPFrameBufferChannel=OSP_FB_COLOR); + OSPRAY_INTERFACE const void *ospMapFrameBuffer(OSPFrameBuffer, + const OSPFrameBufferChannel OSP_DEFAULT_VAL(=OSP_FB_COLOR)); /*! \brief unmap a previously mapped frame buffer (see \ref frame_buffer_handling) */ - OSPRAY_INTERFACE void ospUnmapFrameBuffer(const void *mapped, OSPFrameBuffer fb); + OSPRAY_INTERFACE void ospUnmapFrameBuffer(const void *mapped, OSPFrameBuffer); /*! \} */ @@ -388,102 +489,66 @@ extern "C" { \ingroup ospray_api - @{ + @{ */ /*! add a c-string (zero-terminated char *) parameter to another object */ - OSPRAY_INTERFACE void ospSetString(OSPObject _object, const char *id, const char *s); + OSPRAY_INTERFACE void ospSetString(OSPObject, const char *id, const char *s); - /*! add a object-typed parameter to another object - - \warning this call has been superseded by ospSetObject, and will eventually get removed */ - OSP_DEPRECATED OSPRAY_INTERFACE void ospSetParam(OSPObject _object, const char *id, OSPObject object); + /*! add a object-typed parameter to another object + + \warning this call has been superseded by ospSetObject, and will eventually get removed */ + OSP_DEPRECATED OSPRAY_INTERFACE void ospSetParam(OSPObject, const char *id, OSPObject other); /*! add a object-typed parameter to another object */ - OSPRAY_INTERFACE void ospSetObject(OSPObject _object, const char *id, OSPObject object); + OSPRAY_INTERFACE void ospSetObject(OSPObject, const char *id, OSPObject other); /*! add a data array to another object */ - OSPRAY_INTERFACE void ospSetData(OSPObject _object, const char *id, OSPData data); + OSPRAY_INTERFACE void ospSetData(OSPObject, const char *id, OSPData); /*! add 1-float parameter to given object */ - OSPRAY_INTERFACE void ospSetf(OSPObject _object, const char *id, float x); + OSPRAY_INTERFACE void ospSetf(OSPObject, const char *id, float x); /*! add 1-float parameter to given object */ - OSPRAY_INTERFACE void ospSet1f(OSPObject _object, const char *id, float x); + OSPRAY_INTERFACE void ospSet1f(OSPObject, const char *id, float x); /*! add 1-int parameter to given object */ - OSPRAY_INTERFACE void ospSet1i(OSPObject _object, const char *id, int32_t x); + OSPRAY_INTERFACE void ospSet1i(OSPObject, const char *id, int32_t x); /*! add a 2-float parameter to a given object */ - OSPRAY_INTERFACE void ospSet2f(OSPObject _object, const char *id, float x, float y); + OSPRAY_INTERFACE void ospSet2f(OSPObject, const char *id, float x, float y); /*! add 2-float parameter to given object */ - OSPRAY_INTERFACE void ospSet2fv(OSPObject _object, const char *id, const float *xy); + OSPRAY_INTERFACE void ospSet2fv(OSPObject, const char *id, const float *xy); /*! add a 2-int parameter to a given object */ - OSPRAY_INTERFACE void ospSet2i(OSPObject _object, const char *id, int x, int y); + OSPRAY_INTERFACE void ospSet2i(OSPObject, const char *id, int x, int y); /*! add 2-int parameter to given object */ - OSPRAY_INTERFACE void ospSet2iv(OSPObject _object, const char *id, const int *xy); + OSPRAY_INTERFACE void ospSet2iv(OSPObject, const char *id, const int *xy); /*! add 3-float parameter to given object */ - OSPRAY_INTERFACE void ospSet3f(OSPObject _object, const char *id, float x, float y, float z); + OSPRAY_INTERFACE void ospSet3f(OSPObject, const char *id, float x, float y, float z); /*! add 3-float parameter to given object */ - OSPRAY_INTERFACE void ospSet3fv(OSPObject _object, const char *id, const float *xyz); - - /*! add 4-float parameter to given object */ - OSPRAY_INTERFACE void ospSet4f(OSPObject _object, const char *id, float x, float y, float z, float w); - - /*! add 4-float parameter to given object */ - OSPRAY_INTERFACE void ospSet4fv(OSPObject _object, const char *id, const float *xyzw); + OSPRAY_INTERFACE void ospSet3fv(OSPObject, const char *id, const float *xyz); /*! add 3-int parameter to given object */ - OSPRAY_INTERFACE void ospSet3i(OSPObject _object, const char *id, int x, int y, int z); + OSPRAY_INTERFACE void ospSet3i(OSPObject, const char *id, int x, int y, int z); /*! add 3-int parameter to given object */ - void ospSet3iv(OSPObject _object, const char *id, const int *xyz); - - - // \brief Set a given region of the volume to a given set of voxels - /*! \detailed Given a block of voxels (of dimensions 'blockDim', - located at the memory region pointed to by 'source', copy the - given voxels into volume, at the region of addresses - [regionCoords...regionCoord+regionSize]. - */ - OSPRAY_INTERFACE int ospSetRegion(/*! the object we're writing this block of pixels into */ - OSPVolume object, - /* points to the first voxel to be copies. The - voxels at 'soruce' MUST have dimensions - 'regionSize', must be organized in 3D-array - order, and must have the same voxel type as the - volume.*/ - void *source, - /*! coordinates of the lower, left, front corner of - the target region.*/ - const osp::vec3i ®ionCoords, - /*! size of the region that we're writing to; MUST - be the same as the dimensions of source[][][] */ - const osp::vec3i ®ionSize); - - /*! add 2-float parameter to given object */ - OSPRAY_INTERFACE void ospSetVec2f(OSPObject _object, const char *id, const osp::vec2f &v); - - /*! add 2-int parameter to given object */ - OSPRAY_INTERFACE void ospSetVec2i(OSPObject _object, const char *id, const osp::vec2i &v); - - /*! add 3-float parameter to given object */ - OSPRAY_INTERFACE void ospSetVec3f(OSPObject _object, const char *id, const osp::vec3f &v); + OSPRAY_INTERFACE void ospSet3iv(OSPObject, const char *id, const int *xyz); /*! add 4-float parameter to given object */ - OSPRAY_INTERFACE void ospSetVec4f(OSPObject _object, const char *id, const osp::vec4f &v); + OSPRAY_INTERFACE void ospSet4f(OSPObject, const char *id, float x, float y, float z, float w); - /*! add 3-int parameter to given object */ - OSPRAY_INTERFACE void ospSetVec3i(OSPObject _object, const char *id, const osp::vec3i &v); + /*! add 4-float parameter to given object */ + OSPRAY_INTERFACE void ospSet4fv(OSPObject, const char *id, const float *xyzw); /*! add untyped void pointer to object - this will *ONLY* work in local rendering! */ - OSPRAY_INTERFACE void ospSetVoidPtr(OSPObject _object, const char *id, void *v); + OSPRAY_INTERFACE void ospSetVoidPtr(OSPObject, const char *id, void *v); - /*! \brief Object and parameter introspection. */ +#ifdef __cplusplus + /*! \brief Object and parameter introspection. These are all DEPRECATED. */ /*! */ /*! These functions are used to retrieve the type or handle of an object, */ /*! or the name, type, or value of a parameter associated with an object. */ @@ -500,7 +565,10 @@ extern "C" { /*! \brief Get a copy of the data in an array (the application is responsible for freeing this pointer). */ /*! \warning this call has been deprecated and will eventually be removed */ - OSP_DEPRECATED OSPRAY_INTERFACE int ospGetDataValues(OSPData object, void **pointer, size_t *count, OSPDataType *type); + OSP_DEPRECATED OSPRAY_INTERFACE int ospGetDataValues(OSPData object, + void **pointer, + size_t *count, + OSPDataType *type); /*! \brief Get the named scalar floating point value associated with an object. */ /*! \warning this call has been deprecated and will eventually be removed */ @@ -542,31 +610,53 @@ extern "C" { /*! \warning this call has been deprecated and will eventually be removed */ OSP_DEPRECATED OSPRAY_INTERFACE int ospGetVec3i(OSPObject object, const char *name, osp::vec3i *value); + // probably want to deprecate those as well: + + /*! add 2-float parameter to given object */ + OSPRAY_INTERFACE void ospSetVec2f(OSPObject, const char *id, const osp::vec2f &v); + + /*! add 2-int parameter to given object */ + OSPRAY_INTERFACE void ospSetVec2i(OSPObject, const char *id, const osp::vec2i &v); + + /*! add 3-float parameter to given object */ + OSPRAY_INTERFACE void ospSetVec3f(OSPObject, const char *id, const osp::vec3f &v); + + /*! add 3-int parameter to given object */ + OSPRAY_INTERFACE void ospSetVec3i(OSPObject, const char *id, const osp::vec3i &v); + + /*! add 4-float parameter to given object */ + OSPRAY_INTERFACE void ospSetVec4f(OSPObject, const char *id, const osp::vec4f &v); +#endif /*! @} end of ospray_params */ // ------------------------------------------------------- - /*! \defgroup ospray_geometry Geometry Handling + /*! \defgroup ospray_geometry Geometry Handling \ingroup ospray_api - - \{ + + \{ */ /*! add an already created geometry to a model */ - OSPRAY_INTERFACE void ospAddGeometry(OSPModel model, OSPGeometry mesh); + OSPRAY_INTERFACE void ospAddGeometry(OSPModel, OSPGeometry); /*! \} end of ospray_trianglemesh */ /*! \brief remove an existing geometry from a model */ - OSPRAY_INTERFACE void ospRemoveGeometry(OSPModel model, OSPGeometry mesh); + OSPRAY_INTERFACE void ospRemoveGeometry(OSPModel, OSPGeometry); /*! \brief create a new instance geometry that instantiates another model. the resulting geometry still has to be added to another model via ospAddGeometry */ +#ifdef __cplusplus OSPRAY_INTERFACE OSPGeometry ospNewInstance(OSPModel modelToInstantiate, - const osp::affine3f &xfm); + const osp::affine3f &transform); +#else + OSPRAY_INTERFACE OSPGeometry ospNewInstance(OSPModel modelToInstantiate, + const osp_affine3f *transform); +#endif // ------------------------------------------------------- - /*! \defgroup ospray_model OSPRay Model Handling + /*! \defgroup ospray_model OSPRay Model Handling \ingroup ospray_api models are the equivalent of 'scenes' in embree (ie, @@ -575,34 +665,37 @@ extern "C" { contain more than just embree triangle meshes - they can also contain cameras, materials, volume data, etc, as well as references to (and instances of) other models. - - \{ + + \{ */ /*! \brief create a new ospray model. */ OSPRAY_INTERFACE OSPModel ospNewModel(); /*! \} */ - + /*! \brief commit changes to an object */ - OSPRAY_INTERFACE void ospCommit(OSPObject object); + OSPRAY_INTERFACE void ospCommit(OSPObject); + +#ifdef __cplusplus /*! \brief represents the result returned by an ospPick operation */ - extern "C" typedef struct { + typedef struct { osp::vec3f position; //< the position of the hit point (in world-space) bool hit; //< whether or not a hit actually occured } OSPPickResult; /*! \brief returns the world-space position of the geometry seen at [0-1] normalized screen-space pixel coordinates (if any) */ - OSPRAY_INTERFACE void ospPick(OSPPickResult *result, OSPRenderer renderer, const osp::vec2f &screenPos); + OSPRAY_INTERFACE void ospPick(OSPPickResult*, OSPRenderer, const osp::vec2f &screenPos); +#else + typedef struct { + osp_vec3f position; //< the position of the hit point (in world-space) + int hit; //< whether or not a hit actually occured + } OSPPickResult; - extern "C" /*OSP_DEPRECATED*/ typedef struct { - bool hit; - float world_x, world_y, world_z; - } OSPPickData; + OSPRAY_INTERFACE void ospPick(OSPPickResult*, OSPRenderer, const osp_vec2f *screenPos); +#endif - /*! \warning this call has been superseded by ospPick, and will eventually get removed */ - OSP_DEPRECATED OSPRAY_INTERFACE OSPPickData ospUnproject(OSPRenderer renderer, const osp::vec2f &screenPos); /*! \brief Samples the given volume at the provided world-space coordinates. @@ -615,8 +708,20 @@ extern "C" { as needed for data probes, etc. in applications. It is not intended for large-scale sampling of volumes. */ - OSPRAY_INTERFACE void ospSampleVolume(float **results, OSPVolume volume, const osp::vec3f *worldCoordinates, const size_t &count); +#ifdef __cplusplus + OSPRAY_INTERFACE void ospSampleVolume(float **results, + OSPVolume, + const osp::vec3f &worldCoordinates, + const size_t count); +#else + OSPRAY_INTERFACE void ospSampleVolume(float **results, + OSPVolume, + const osp_vec3f *worldCoordinates, + const size_t count); +#endif +#ifdef __cplusplus } // extern "C" +#endif /*! \} */ diff --git a/ospray/lights/AmbientLight.cpp b/ospray/lights/AmbientLight.cpp index 88ba440930..e308d9d31e 100644 --- a/ospray/lights/AmbientLight.cpp +++ b/ospray/lights/AmbientLight.cpp @@ -22,7 +22,7 @@ namespace ospray { : color(1.f) , intensity(1.f) { - ispcEquivalent = ispc::AmbientLight_create(this); + ispcEquivalent = ispc::AmbientLight_create(); } //! Commit parameters understood by the AmbientLight diff --git a/ospray/lights/AmbientLight.ispc b/ospray/lights/AmbientLight.ispc index 933e58717f..379acb4be9 100644 --- a/ospray/lights/AmbientLight.ispc +++ b/ospray/lights/AmbientLight.ispc @@ -18,7 +18,8 @@ #include "ospray/math/sampling.ih" #include "ospray/math/LinearSpace.ih" -struct AmbientLight { +struct AmbientLight +{ Light super; //!< inherited light fields vec3f radiance; //!< RGB color and intensity of light @@ -28,38 +29,46 @@ struct AmbientLight { // Implementation ////////////////////////////////////////////////////////////////////////////// -varying LightSample AmbientLight_sample(const uniform Light *uniform _self, - const varying DifferentialGeometry &dg, - const varying vec2f &s) +// XXX importance sampling is only done into the positive hemisphere +// ==> poor support for translucent materials +Light_SampleRes AmbientLight_sample(const uniform Light* uniform super, + const DifferentialGeometry& dg, + const vec2f& s) { - uniform AmbientLight *uniform self = (uniform AmbientLight *uniform)_self; - LightSample sample; + uniform AmbientLight* uniform self = (uniform AmbientLight* uniform)super; + Light_SampleRes res; const vec3f localDir = cosineSampleHemisphere(s); - sample.direction = frame(dg.Ns) * localDir; - sample.pdf = cosineSampleHemispherePDF(localDir); - sample.distance = inf; - sample.radiance = self->radiance * rcp(sample.pdf); + res.dir = frame(dg.Ns) * localDir; + res.pdf = cosineSampleHemispherePDF(localDir); + res.dist = inf; + res.weight = self->radiance * rcp(res.pdf); - return sample; + return res; } -varying vec3f AmbientLight_evalEnv(const uniform Light *uniform _self, - const varying vec3f &) +Light_EvalRes AmbientLight_eval(const uniform Light* uniform super, + const DifferentialGeometry& dg, + const vec3f& dir) { - uniform AmbientLight *uniform self = (uniform AmbientLight *uniform)_self; - return self->radiance; + uniform AmbientLight* uniform self = (uniform AmbientLight* uniform)super; + Light_EvalRes res; + + res.value = self->radiance; + res.dist = inf; + res.pdf = cosineSampleHemispherePDF(max(dot(dg.Ns, dir), 0.f)); + + return res; } -void AmbientLight_Constructor(uniform AmbientLight *uniform self, - void *uniform cppEquivalent, - const uniform vec3f &radiance) +void AmbientLight_Constructor(uniform AmbientLight* uniform self, + const uniform vec3f& radiance) { - Light_Constructor(&self->super, cppEquivalent); + Light_Constructor(&self->super); self->radiance = radiance; self->super.sample = AmbientLight_sample; - self->super.evalEnv = AmbientLight_evalEnv; + self->super.eval = AmbientLight_eval; } @@ -67,17 +76,17 @@ void AmbientLight_Constructor(uniform AmbientLight *uniform self, ////////////////////////////////////////////////////////////////////////////// //! Create an ispc-side AmbientLight object -export void *uniform AmbientLight_create(void *uniform cppEquivalent) +export void *uniform AmbientLight_create() { - uniform AmbientLight *uniform self = uniform new uniform AmbientLight; - AmbientLight_Constructor(self, cppEquivalent, make_vec3f(1.f)); + uniform AmbientLight* uniform self = uniform new uniform AmbientLight; + AmbientLight_Constructor(self, make_vec3f(1.f)); return self; } //! Set the parameters of an ispc-side AmbientLight object -export void AmbientLight_set(void *uniform _self, - const uniform vec3f &radiance) +export void AmbientLight_set(void* uniform super, + const uniform vec3f& radiance) { - uniform AmbientLight *uniform self = (uniform AmbientLight *uniform)_self; + uniform AmbientLight* uniform self = (uniform AmbientLight* uniform)super; self->radiance = radiance; } diff --git a/ospray/lights/DirectionalLight.cpp b/ospray/lights/DirectionalLight.cpp index da23d0b2b0..d5566c14c8 100644 --- a/ospray/lights/DirectionalLight.cpp +++ b/ospray/lights/DirectionalLight.cpp @@ -24,7 +24,7 @@ namespace ospray { , intensity(1.f) , angularDiameter(0.f) { - ispcEquivalent = ispc::DirectionalLight_create(this); + ispcEquivalent = ispc::DirectionalLight_create(); } //! Commit parameters understood by the DirectionalLight diff --git a/ospray/lights/DirectionalLight.ispc b/ospray/lights/DirectionalLight.ispc index 9f6f476e3f..2c516312d7 100644 --- a/ospray/lights/DirectionalLight.ispc +++ b/ospray/lights/DirectionalLight.ispc @@ -18,49 +18,59 @@ #include "ospray/math/sampling.ih" #include "ospray/math/LinearSpace.ih" -struct DirectionalLight { +struct DirectionalLight +{ Light super; //!< inherited light fields - vec3f direction; //!< direction *towards* the light source + linear3f frame; //!< coordinate frame, with vz == direction *towards* the light source vec3f radiance; //!< RGB color and intensity of light float cosAngle; //!< Angular limit of the cone light in an easier to use form: cosine of the half angle in radians float pdf; //!< Probability to sample a direction to the light }; -// for very small cones treat as singular light, because float precision is not good enough +// for very small cones treat as singular light, because float precision is not good enough #define COS_ANGLE_MAX 0.99999988f // Implementation ////////////////////////////////////////////////////////////////////////////// -varying LightSample DirectionalLight_sample(const uniform Light *uniform _self, - const varying DifferentialGeometry &dg, - const varying vec2f &s) +Light_SampleRes DirectionalLight_sample(const uniform Light* uniform super, + const DifferentialGeometry& dg, + const vec2f& s) { - const DirectionalLight *uniform self = (DirectionalLight *uniform)_self; - LightSample sample; + const DirectionalLight* uniform self = (DirectionalLight* uniform)super; + Light_SampleRes res; - sample.direction = self->direction; - sample.distance = inf; - sample.pdf = self->pdf; + res.dir = self->frame.vz; + res.dist = inf; + res.pdf = self->pdf; if (self->cosAngle < COS_ANGLE_MAX) - sample.direction = frame(sample.direction) * uniformSampleCone(self->cosAngle, s); + res.dir = self->frame * uniformSampleCone(self->cosAngle, s); - sample.radiance = self->radiance; + res.weight = self->radiance; // *pdf/pdf cancel - return sample; + return res; } -varying vec3f DirectionalLight_evalEnv(const uniform Light *uniform _self, - const varying vec3f &dir) +Light_EvalRes DirectionalLight_eval(const uniform Light* uniform super, + const DifferentialGeometry&, + const vec3f& dir) { - uniform DirectionalLight *uniform self = (uniform DirectionalLight *uniform)_self; - if (self->cosAngle < COS_ANGLE_MAX && dot(self->direction, dir) > self->cosAngle) - return self->radiance * self->pdf; - else - return make_vec3f(0.f); + uniform DirectionalLight* uniform self = (uniform DirectionalLight* uniform)super; + Light_EvalRes res; + res.dist = inf; + + if (self->cosAngle < COS_ANGLE_MAX && dot(self->frame.vz, dir) > self->cosAngle) { + res.value = self->radiance * self->pdf; + res.pdf = self->pdf; + } else { + res.value = make_vec3f(0.f); + res.pdf = 0.f; + } + + return res; } @@ -68,26 +78,25 @@ varying vec3f DirectionalLight_evalEnv(const uniform Light *uniform _self, ////////////////////////////////////////////////////////////////////////////// //! Set the parameters of an ispc-side DirectionalLight object -export void DirectionalLight_set(void *uniform _self, - const uniform vec3f &direction, - const uniform vec3f &radiance, - const uniform float cosAngle) +export void DirectionalLight_set(void* uniform super, + const uniform vec3f& direction, + const uniform vec3f& radiance, + uniform float cosAngle) { - uniform DirectionalLight *uniform self = (uniform DirectionalLight *uniform)_self; - self->direction = direction; + uniform DirectionalLight* uniform self = (uniform DirectionalLight* uniform)super; + self->frame = frame(direction); self->radiance = radiance; self->cosAngle = cosAngle; - self->pdf = cosAngle < COS_ANGLE_MAX ? uniformSampleConePDF(cosAngle) : 1.f; + self->pdf = cosAngle < COS_ANGLE_MAX ? uniformSampleConePDF(cosAngle) : inf; } //! Create an ispc-side DirectionalLight object -export void *uniform DirectionalLight_create(void *uniform cppEquivalent) +export void* uniform DirectionalLight_create() { - uniform DirectionalLight *uniform self = uniform new uniform DirectionalLight; - Light_Constructor(&self->super, cppEquivalent); + uniform DirectionalLight* uniform self = uniform new uniform DirectionalLight; + Light_Constructor(&self->super); self->super.sample = DirectionalLight_sample; - // TODO: an (indirectly) visible sun disc causes too high variance, needs to be fixed with MIS - // self->super.evalEnv = DirectionalLight_evalEnv; + self->super.eval = DirectionalLight_eval; DirectionalLight_set(self, make_vec3f(0.f, 0.f, 1.f), make_vec3f(1.f), 1.f); return self; diff --git a/ospray/lights/HDRILight.cpp b/ospray/lights/HDRILight.cpp index 9247760cac..416e96cbb4 100644 --- a/ospray/lights/HDRILight.cpp +++ b/ospray/lights/HDRILight.cpp @@ -25,7 +25,7 @@ namespace ospray { , map(NULL) , intensity(1.f) { - ispcEquivalent = ispc::HDRILight_create(this); + ispcEquivalent = ispc::HDRILight_create(); } HDRILight::~HDRILight() diff --git a/ospray/lights/HDRILight.ispc b/ospray/lights/HDRILight.ispc index 12e236e22d..e15d43621a 100644 --- a/ospray/lights/HDRILight.ispc +++ b/ospray/lights/HDRILight.ispc @@ -36,24 +36,25 @@ struct HDRILight // Implementation ////////////////////////////////////////////////////////////////////////////// -varying LightSample HDRILight_sample_dummy(const uniform Light *uniform, - const varying DifferentialGeometry &, - const varying vec2f &) +// sample function used when no environment map is given: black +Light_SampleRes HDRILight_sample_dummy(const uniform Light* uniform, + const DifferentialGeometry&, + const vec2f&) { - LightSample sample; - memset(&sample, 0, sizeof(LightSample)); - return sample; + Light_SampleRes res; + memset(&res, 0, sizeof(Light_SampleRes)); + return res; } -varying LightSample HDRILight_sample(const uniform Light *uniform _self, - const varying DifferentialGeometry &dg, - const varying vec2f &s) +Light_SampleRes HDRILight_sample(const uniform Light* uniform super, + const DifferentialGeometry&, + const vec2f& s) { - uniform HDRILight *uniform self = (uniform HDRILight *uniform)_self; - LightSample sample; + uniform HDRILight* uniform self = (uniform HDRILight* uniform)super; + Light_SampleRes res; Sample2D sample2d = Distribution2D_sample(self->distribution, s); - // Distribution2D samples wihtin bin i as (i, i+1), whereas we provided + // Distribution2D samples within bin i as (i, i+1), whereas we provided // average importance for (i-0.5, i+0.5), thus shift by 0.5 sample2d.uv = sample2d.uv - self->map->halfTexel; @@ -64,27 +65,39 @@ varying LightSample HDRILight_sample(const uniform Light *uniform _self, sincos(theta, &sinTheta, &cosTheta); const vec3f localDir = cartesian(phi, sinTheta, cosTheta); - sample.direction = self->light2world * localDir; + res.dir = self->light2world * localDir; - sample.pdf = sample2d.pdf * rcp(two_pi * M_PI * sinTheta); + res.pdf = sample2d.pdf * one_over_two_pi_sqr * rcp(sinTheta); - sample.distance = inf; - sample.radiance = get3f(self->map, sample2d.uv) * self->intensity / sample.pdf; + res.dist = inf; + res.weight = get3f(self->map, sample2d.uv) * self->intensity / res.pdf; - return sample; + return res; } -varying vec3f HDRILight_evalEnv(const uniform Light *uniform _self, - const varying vec3f &dir) +Light_EvalRes HDRILight_eval(const uniform Light* uniform super, + const DifferentialGeometry&, + const vec3f& dir) { - uniform HDRILight *uniform self = (uniform HDRILight *uniform)_self; + uniform HDRILight* uniform self = (uniform HDRILight* uniform)super; + Light_EvalRes res; const vec3f localDir = self->world2light * dir; const float u = atan2(localDir.y, localDir.x) * one_over_two_pi; const float v = acos(localDir.z) * one_over_pi; + const vec2f uv = make_vec2f(u, v); - return get3f(self->map, make_vec2f(u, v)) * self->intensity; + res.value = 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) + const vec2f uvd = frac(uv + self->map->halfTexel); + res.pdf = Distribution2D_pdf(self->distribution, uvd); + res.pdf *= one_over_two_pi_sqr * rsqrt(1.f - sqr(localDir.z)); + + return res; } @@ -92,12 +105,12 @@ varying vec3f HDRILight_evalEnv(const uniform Light *uniform _self, ////////////////////////////////////////////////////////////////////////////// //! Set the parameters of an ispc-side HDRILight object -export void HDRILight_set(void *uniform _self, - const uniform linear3f &light2world, - void *uniform map, - const uniform float intensity) +export void HDRILight_set(void* uniform super, + const uniform linear3f& light2world, + void* uniform map, + uniform float intensity) { - uniform HDRILight *uniform self = (uniform HDRILight *uniform)_self; + uniform HDRILight* uniform self = (uniform HDRILight* uniform)super; if (self->distribution != NULL) { Distribution2D_destroy(self->distribution); @@ -106,9 +119,9 @@ export void HDRILight_set(void *uniform _self, if (map) { self->light2world = light2world; - self->world2light = rcp(light2world); + self->world2light = rcp(light2world); - self->map = (uniform Texture2D *uniform)map; + self->map = (uniform Texture2D* uniform)map; self->intensity = intensity; self->rcpSize = 1.f/self->map->sizef; @@ -120,7 +133,7 @@ export void HDRILight_set(void *uniform _self, // for i==0 we have a wrap-around, which is wanted for x (phi), but actually not for y (theta), // because then light (importance) from the south-pole is leaking to the north-pole // however, sin(theta) is zero then, thus we will never sample there - uniform float* uniform importance = uniform new uniform float[width*height]; + uniform float* uniform importance = uniform new uniform float[width*height]; for (uniform int y = 0; y < height; y++) { uniform float fy = y*self->rcpSize.y; uniform float sinTheta = sin(fy * M_PI); @@ -138,19 +151,19 @@ export void HDRILight_set(void *uniform _self, // no delete[] importance: ownership was transferred to Distribution2D self->super.sample = HDRILight_sample; - self->super.evalEnv = HDRILight_evalEnv; + self->super.eval = HDRILight_eval; } else { self->super.sample = HDRILight_sample_dummy; - self->super.evalEnv = defaultEvalEnv; + self->super.eval = Light_eval; } } //! Create an ispc-side HDRILight object -export void *uniform HDRILight_create(void *uniform cppEquivalent) +export void *uniform HDRILight_create() { - uniform HDRILight *uniform self = uniform new uniform HDRILight; + uniform HDRILight* uniform self = uniform new uniform HDRILight; - Light_Constructor(&self->super, cppEquivalent); + Light_Constructor(&self->super); self->super.sample = HDRILight_sample_dummy; self->distribution = NULL; @@ -160,10 +173,9 @@ export void *uniform HDRILight_create(void *uniform cppEquivalent) } //! Destroy an ispc-side HDRILight object -export void HDRILight_destroy(void *uniform _self) -{ - uniform HDRILight *uniform self = (uniform HDRILight *uniform)_self; +export void HDRILight_destroy(void* uniform super) +{ + uniform HDRILight* uniform self = (uniform HDRILight* uniform)super; Distribution2D_destroy(self->distribution); delete self; } - diff --git a/ospray/lights/Light.ih b/ospray/lights/Light.ih index 2367cb6706..d4ed16926d 100644 --- a/ospray/lights/Light.ih +++ b/ospray/lights/Light.ih @@ -20,41 +20,44 @@ struct Light; -struct LightSample +struct Light_SampleRes { - vec3f radiance; //!< radiance for this sample that arrives at the given point, already weighted by pdf - vec3f direction; //!< direction towards the light source - float distance; //!< largest valid parameter value for a shadow ray - float pdf; //!< probability that this sample was taken + vec3f weight; //!< radiance that arrives at the given point divided by pdf + vec3f dir; //!< direction towards the light source + float dist; //!< largest valid t_far value for a shadow ray + float pdf; //!< probability density that this sample was taken }; //! compute the weighted radiance at a point caused by a sample on the light source // by convention, giving (0, 0) as "random" numbers should sample the "center" // of the light source (used by the raytracing renderers such as the OBJ renderer) -typedef varying LightSample (*Light_SampleFct)(const uniform Light *uniform _self, - /*! point to generate the sample for >*/ const varying DifferentialGeometry &dg, - /*! random numbers to generate the sample >*/ const varying vec2f &s); +typedef Light_SampleRes (*Light_SampleFunc)(const uniform Light* uniform self, + const DifferentialGeometry& dg, /*! point to generate the sample for >*/ + const vec2f& s); /*! random numbers to generate the sample >*/ -//! compute the radiance caused by the light source (pointed to by the given direction) from inf -typedef varying vec3f (*Light_EvalEnvFct)(const uniform Light *uniform _self, -/*! direction towards the light source >*/const varying vec3f &dir); +struct Light_EvalRes +{ + vec3f value; //!< radiance that arrives at the given point (not weighted by pdf) + float dist; + float pdf; //!< probability density that the direction would have been sampled +}; -struct Light { - Light_SampleFct sample; - Light_EvalEnvFct evalEnv; +//! compute the radiance, distance and pdf caused by the light source (pointed to by the given direction) +typedef Light_EvalRes (*Light_EvalFunc)(const uniform Light* uniform self, + const DifferentialGeometry& dg, /*! point to evaluate illumination for >*/ + const vec3f& dir); /*! direction towards the light source >*/ - //! Pointer back to the C++ equivalent of this class. - void *uniform cppEquivalent; -}; +struct Light +{ + Light_SampleFunc sample; + Light_EvalFunc eval; +}; -varying vec3f defaultEvalEnv(const uniform Light *uniform, const varying vec3f &); +Light_EvalRes Light_eval(const uniform Light* uniform self, const DifferentialGeometry& dg, const vec3f& dir); -//! constructor for ispc-side light object -inline void Light_Constructor(uniform Light *uniform self, - void *uniform cppEquivalent) +inline void Light_Constructor(uniform Light* uniform self) { - self->cppEquivalent = cppEquivalent; - self->evalEnv = defaultEvalEnv; + self->eval = Light_eval; } diff --git a/ospray/lights/Light.ispc b/ospray/lights/Light.ispc index 7fe95752fe..24c8051bee 100644 --- a/ospray/lights/Light.ispc +++ b/ospray/lights/Light.ispc @@ -16,8 +16,13 @@ #include "Light.ih" -varying vec3f defaultEvalEnv(const uniform Light *uniform, - const varying vec3f &) +Light_EvalRes Light_eval(const uniform Light* uniform, + const DifferentialGeometry&, + const vec3f&) { - return make_vec3f(0.f); + Light_EvalRes res; + res.value = make_vec3f(0.f); + res.dist = inf; + res.pdf = 0.f; + return res; } diff --git a/ospray/lights/PointLight.cpp b/ospray/lights/PointLight.cpp index d317cf8ccc..c5b4390a73 100644 --- a/ospray/lights/PointLight.cpp +++ b/ospray/lights/PointLight.cpp @@ -24,7 +24,7 @@ namespace ospray { , intensity(1.f) , radius(0.f) { - ispcEquivalent = ispc::PointLight_create(this); + ispcEquivalent = ispc::PointLight_create(); } //! Commit parameters understood by the PointLight @@ -40,6 +40,7 @@ namespace ospray { } OSP_REGISTER_LIGHT(PointLight, PointLight); + OSP_REGISTER_LIGHT(PointLight, point); OSP_REGISTER_LIGHT(PointLight, SphereLight); OSP_REGISTER_LIGHT(PointLight, sphere); } diff --git a/ospray/lights/PointLight.ispc b/ospray/lights/PointLight.ispc index 39c6727bde..152e644b8f 100644 --- a/ospray/lights/PointLight.ispc +++ b/ospray/lights/PointLight.ispc @@ -18,7 +18,8 @@ #include "ospray/math/sampling.ih" #include "ospray/math/LinearSpace.ih" -struct PointLight { +struct PointLight +{ Light super; //!< inherited light fields vec3f position; //!< light position @@ -30,12 +31,12 @@ struct PointLight { // Implementation ////////////////////////////////////////////////////////////////////////////// -varying LightSample PointLight_sample(const uniform Light *uniform _self, - const varying DifferentialGeometry &dg, - const varying vec2f &s) +Light_SampleRes PointLight_sample(const uniform Light* uniform super, + const DifferentialGeometry& dg, + const vec2f& s) { - const PointLight *uniform self = (PointLight *uniform)_self; - LightSample sample; + const PointLight* uniform self = (PointLight* uniform)super; + Light_SampleRes res; // extant light vector from the hit point const vec3f dir = self->position - dg.P; @@ -43,60 +44,98 @@ varying LightSample PointLight_sample(const uniform Light *uniform _self, const float invdist = rsqrt(dist2); // normalized light vector - sample.direction = dir * invdist; - sample.distance = dist2 * invdist; + res.dir = dir * invdist; + res.dist = dist2 * invdist; - sample.pdf = 1.f; // per default we always take this sample + res.pdf = inf; // per default we always take this res // convert from power to radiance by attenuating by distance^2 - sample.radiance = self->power * (invdist * invdist); + res.weight = self->power * sqr(invdist); const float sinTheta = self->radius * invdist; - if (self->radius > 0. & sinTheta > 0.005f) { - // sample surface of sphere as seen by hit point -> cone of directions - // for very small cones treat as point light, because float precision is not good enough + if ((self->radius > 0.f) & (sinTheta > 0.005f)) { + // res surface of sphere as seen by hit point -> cone of directions + // for very small cones treat as point light, because float precision is not good enough if (sinTheta < 1.f) { const float cosTheta = sqrt(1.f - sinTheta * sinTheta); const vec3f localDir = uniformSampleCone(cosTheta, s); - sample.direction = frame(sample.direction) * localDir; - sample.pdf = uniformSampleConePDF(cosTheta); + res.dir = frame(res.dir) * localDir; + res.pdf = uniformSampleConePDF(cosTheta); const float c = localDir.z; - sample.distance = c*sample.distance - sqrt(self->radius*self->radius - (1.f - c*c) * dist2); + res.dist = c*res.dist - sqrt(sqr(self->radius) - (1.f - c*c) * dist2); + // TODO scale radiance by actual distance } else { // inside sphere const vec3f localDir = cosineSampleHemisphere(s); - sample.direction = frame(dg.Ns) * localDir; - sample.pdf = cosineSampleHemispherePDF(localDir); + res.dir = frame(dg.Ns) * localDir; + res.pdf = cosineSampleHemispherePDF(localDir); // TODO: - sample.radiance = self->power * rcp(self->radius*self->radius); - sample.distance = self->radius; + res.weight = self->power * rcp(sqr(self->radius)); + res.dist = self->radius; } } - return sample; + return res; } +Light_EvalRes PointLight_eval(const uniform Light* uniform super, + const DifferentialGeometry& dg, + const vec3f& dir) +{ + const PointLight* uniform self = (PointLight* uniform)super; + Light_EvalRes res; + res.value = make_vec3f(0.f); + res.dist = inf; + res.pdf = 0.f; + + if (self->radius > 0.f) { + const vec3f A = self->position - dg.P; + const float a = dot(dir, dir); + const float b = 2.f * dot(dir, A); + const float centerDist2 = dot(A, A); + const float c = centerDist2 - sqr(self->radius); + const float radical = sqr(b) - 4.f*a*c; + + if (radical > 0.f) { + 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) { + // 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); + const float invdist = rcp(t_near); + res.value = self->power * res.pdf * sqr(invdist); + } + } + } + + return res; +} // Exports (called from C++) ////////////////////////////////////////////////////////////////////////////// //! Set the parameters of an ispc-side PointLight object -export void PointLight_set(void *uniform _self, - const uniform vec3f &position, - const uniform vec3f &power, - const uniform float radius) +export void PointLight_set(void* uniform super, + const uniform vec3f& position, + const uniform vec3f& power, + uniform float radius) { - uniform PointLight *uniform self = (uniform PointLight *uniform)_self; + uniform PointLight* uniform self = (uniform PointLight* uniform)super; self->position = position; self->power = power; self->radius = radius; } //! Create an ispc-side PointLight object -export void *uniform PointLight_create(void *uniform cppEquivalent) +export void* uniform PointLight_create() { - uniform PointLight *uniform self = uniform new uniform PointLight; - Light_Constructor(&self->super, cppEquivalent); + uniform PointLight* uniform self = uniform new uniform PointLight; + Light_Constructor(&self->super); self->super.sample = PointLight_sample; + self->super.eval = PointLight_eval; PointLight_set(self, make_vec3f(0.f), make_vec3f(1.f), 0.f); return self; diff --git a/ospray/lights/QuadLight.cpp b/ospray/lights/QuadLight.cpp index 310d1020d7..996a934a42 100644 --- a/ospray/lights/QuadLight.cpp +++ b/ospray/lights/QuadLight.cpp @@ -32,7 +32,7 @@ namespace ospray { , color(1.f) , intensity(1.f) { - ispcEquivalent = ispc::QuadLight_create(this); + ispcEquivalent = ispc::QuadLight_create(); } //!< Copy understood parameters into class members diff --git a/ospray/lights/QuadLight.ispc b/ospray/lights/QuadLight.ispc index 7cb8f9c089..20b9b8f06c 100644 --- a/ospray/lights/QuadLight.ispc +++ b/ospray/lights/QuadLight.ispc @@ -16,7 +16,8 @@ #include "Light.ih" -struct QuadLight { +struct QuadLight +{ Light super; //!< inherited light fields vec3f position; //!< world-space corner position of the light @@ -32,14 +33,14 @@ struct QuadLight { // Implementation ////////////////////////////////////////////////////////////////////////////// -varying LightSample QuadLight_sample(const uniform Light *uniform _self, - const varying DifferentialGeometry &dg, - const varying vec2f &s) +Light_SampleRes QuadLight_sample(const uniform Light* uniform super, + const DifferentialGeometry& dg, + const vec2f& s) { - const QuadLight *uniform self = (QuadLight *uniform)_self; - LightSample sample; + const QuadLight* uniform self = (QuadLight* uniform)super; + Light_SampleRes res; - // sample position on light with density ppdf = 1/area + // res position on light with density ppdf = 1/area // TODO: use solid angle sampling const vec3f pos = self->position + self->edge1 * s.x + self->edge2 * s.y; @@ -48,17 +49,17 @@ varying LightSample QuadLight_sample(const uniform Light *uniform _self, const float dist = length(dir); // normalized light vector - sample.direction = dir / dist; - sample.distance = dist; + res.dir = dir / dist; + res.dist = dist; // convert to pdf wrt. solid angle - const float cosd = dot(self->nnormal, sample.direction); - sample.pdf = self->ppdf * (dist * dist) / abs(cosd); + const float cosd = dot(self->nnormal, res.dir); + res.pdf = self->ppdf * (dist * dist) / abs(cosd); // emit only to one side - sample.radiance = cosd > 0.f ? self->radiance * rcp(sample.pdf) : make_vec3f(0.f); + res.weight = cosd > 0.f ? self->radiance * rcp(res.pdf) : make_vec3f(0.f); - return sample; + return res; } @@ -66,17 +67,17 @@ varying LightSample QuadLight_sample(const uniform Light *uniform _self, ////////////////////////////////////////////////////////////////////////////// //! Set the parameters of an ispc-side QuadLight object -export void QuadLight_set(void *uniform _self, - const uniform vec3f &position, - const uniform vec3f &edge2, - const uniform vec3f &edge1, - const uniform vec3f &radiance) +export void QuadLight_set(void* uniform super, + const uniform vec3f& position, + const uniform vec3f& edge2, + const uniform vec3f& edge1, + const uniform vec3f& radiance) { - uniform QuadLight *uniform self = (uniform QuadLight *uniform)_self; - self->position = position; - self->edge1 = edge1; - self->edge2 = edge2; - self->radiance = radiance; + uniform QuadLight* uniform self = (uniform QuadLight* uniform)super; + self->position = position; + self->edge1 = edge1; + self->edge2 = edge2; + self->radiance = radiance; const uniform vec3f ndirection = cross(edge2, edge1); self->ppdf = rcp(length(ndirection)); @@ -84,11 +85,11 @@ export void QuadLight_set(void *uniform _self, } //! Create an ispc-side QuadLight object -export void *uniform QuadLight_create(void *uniform cppEquivalent) +export void* uniform QuadLight_create() { - uniform QuadLight *uniform self = uniform new uniform QuadLight; + uniform QuadLight* uniform self = uniform new uniform QuadLight; - Light_Constructor(&self->super, cppEquivalent); + Light_Constructor(&self->super); self->super.sample = QuadLight_sample; QuadLight_set(self, diff --git a/ospray/lights/SpotLight.cpp b/ospray/lights/SpotLight.cpp index 599c217196..04525966c2 100644 --- a/ospray/lights/SpotLight.cpp +++ b/ospray/lights/SpotLight.cpp @@ -34,7 +34,7 @@ namespace ospray { , penumbraAngle(5.f) , radius(0.f) { - ispcEquivalent = ispc::SpotLight_create(this); + ispcEquivalent = ispc::SpotLight_create(); } //!< Copy understood parameters into class members @@ -51,16 +51,17 @@ namespace ospray { const vec3f power = color * intensity; direction = normalize(direction); openingAngle = clamp(openingAngle, 0.f, 180.f); - penumbraAngle = clamp(penumbraAngle, 0.001f, 0.5f*openingAngle); + 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 cosAngleScale = 1.0f/(cosAngleMin - cosAngleMax); ispc::SpotLight_set(getIE(), (ispc::vec3f&)position, (ispc::vec3f&)direction, (ispc::vec3f&)power, cosAngleMax, - cosAngleMin, + cosAngleScale, radius); } diff --git a/ospray/lights/SpotLight.ispc b/ospray/lights/SpotLight.ispc index d9e7c445d2..10a249930a 100644 --- a/ospray/lights/SpotLight.ispc +++ b/ospray/lights/SpotLight.ispc @@ -18,54 +18,89 @@ #include "ospray/math/sampling.ih" #include "ospray/math/LinearSpace.ih" -struct SpotLight { +struct SpotLight +{ Light super; //!< inherited light fields vec3f position; //!< Position of the SpotLight - vec3f direction; //!< Direction that the SpotLight is emitting; normalized + linear3f frame; //!< coordinate frame, with vz == direction that the SpotLight is emitting vec3f power; //!< RGB color and intensity of the SpotLight float cosAngleMax; //!< Angular limit of the spot in an easier to use form: cosine of the half angle in radians - float cosAngleMin; //!< Border of the penumbra area of the spot in an easier to use form; larger than cosAngleMax + float cosAngleScale; //!< 1/(cos(border of the penumbra area) - cosAngleMax); positive float radius; //!< defines the size of the (extended) SpotLight + float diskPdf; //!< pdf of disk with radius }; // Implementation ////////////////////////////////////////////////////////////////////////////// -varying LightSample SpotLight_sample(const uniform Light *uniform _self, - const varying DifferentialGeometry &dg, - const varying vec2f &s) +Light_SampleRes SpotLight_sample(const uniform Light* uniform super, + const DifferentialGeometry& dg, + const vec2f& s) { - const SpotLight *uniform self = (SpotLight *uniform)_self; - LightSample sample; + const SpotLight* uniform self = (SpotLight* uniform)super; + Light_SampleRes res; // extant light vector from the hit point - sample.direction = self->position - dg.P; + res.dir = self->position - dg.P; if (self->radius > 0.) - sample.direction = frame(self->direction) * uniformSampleDisk(self->radius, s) + sample.direction; + res.dir = self->frame * uniformSampleDisk(self->radius, s) + res.dir; - const float dist2 = dot(sample.direction, sample.direction); + const float dist2 = dot(res.dir, res.dir); const float invdist = rsqrt(dist2); // normalized light vector - sample.direction = sample.direction * invdist; - sample.distance = dist2 * invdist; + res.dir = res.dir * invdist; + res.dist = dist2 * invdist; // cosine of the negated light direction and light vector. - const float cosAngle = -dot(self->direction, sample.direction); - const float angularAttenuation = clamp((cosAngle - self->cosAngleMax) * rcp(self->cosAngleMin - self->cosAngleMax)); + const float cosAngle = -dot(self->frame.vz, res.dir); + const float angularAttenuation = clamp((cosAngle - self->cosAngleMax) * self->cosAngleScale); if (self->radius > 0.) - sample.pdf = uniformSampleDiskPDF(self->radius) * dist2 * abs(cosAngle); + res.pdf = self->diskPdf * dist2 * abs(cosAngle); else - sample.pdf = 1.f; // we always take this sample + res.pdf = inf; // we always take this res // convert from power to radiance by attenuating by distance^2; attenuate by angle - sample.radiance = self->power * (invdist * invdist * angularAttenuation); + res.weight = self->power * (sqr(invdist) * angularAttenuation); + + return res; +} - return sample; +Light_EvalRes SpotLight_eval(const uniform Light* uniform super, + const DifferentialGeometry& dg, + const vec3f& dir) +{ + const SpotLight* uniform self = (SpotLight* uniform)super; + Light_EvalRes res; + res.value = make_vec3f(0.f); + res.dist = inf; + res.pdf = 0.f; + + if (self->radius > 0.f) { + // intersect disk + const float cosAngle = -dot(dir, self->frame.vz); + if (cosAngle > self->cosAngleMax) { // inside illuminated cone? + const vec3f vp = dg.P - self->position; + 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.value = self->power * (angularAttenuation * pdf); // *sqr(t)/sqr(t) cancels + res.dist = t; + res.pdf = pdf * sqr(t); + } + } + } + } + + return res; } @@ -73,37 +108,39 @@ varying LightSample SpotLight_sample(const uniform Light *uniform _self, ////////////////////////////////////////////////////////////////////////////// //! Set the parameters of an ispc-side SpotLight object -export void SpotLight_set(void *uniform _self, - const uniform vec3f &position, - const uniform vec3f &direction, - const uniform vec3f &power, - const uniform float cosAngleMax, - const uniform float cosAngleMin, - const uniform float radius) +export void SpotLight_set(void* uniform super, + const uniform vec3f& position, + const uniform vec3f& direction, + const uniform vec3f& power, + uniform float cosAngleMax, + uniform float cosAngleScale, + uniform float radius) { - uniform SpotLight *uniform self = (uniform SpotLight *uniform)_self; - self->position = position; - self->direction = direction; - self->power = power; - self->cosAngleMax = cosAngleMax; - self->cosAngleMin = cosAngleMin; - self->radius = radius; + uniform SpotLight* uniform self = (uniform SpotLight* uniform)super; + self->position = position; + self->frame = frame(direction); + self->power = power; + self->cosAngleMax = cosAngleMax; + self->cosAngleScale = cosAngleScale; + self->radius = radius; + self->diskPdf = uniformSampleDiskPDF(radius); } //! Create an ispc-side SpotLight object -export void *uniform SpotLight_create(void *uniform cppEquivalent) +export void* uniform SpotLight_create() { - uniform SpotLight *uniform self = uniform new uniform SpotLight; + uniform SpotLight* uniform self = uniform new uniform SpotLight; - Light_Constructor(&self->super, cppEquivalent); + Light_Constructor(&self->super); self->super.sample = SpotLight_sample; + self->super.eval = SpotLight_eval; SpotLight_set(self, make_vec3f(0.f), make_vec3f(0.f, 0.f, 1.f), make_vec3f(1.f), 0.f, - 0.01f, + 100.f, 0.f); return self; diff --git a/ospray/math/AffineSpace.ih b/ospray/math/AffineSpace.ih index 0c45ec16eb..7694377e68 100644 --- a/ospray/math/AffineSpace.ih +++ b/ospray/math/AffineSpace.ih @@ -114,3 +114,13 @@ inline varying vec2f operator*(const varying AffineSpace2f a, const varying vec2 /*! short-hand name for AffineSpace3f */ typedef AffineSpace2f affine2f; +inline void out(uniform affine3f a) +{ + print("Affine3f("); + out(a.l.vx); + out(a.l.vy); + out(a.l.vz); + out(a.p); + print(")"); +} + diff --git a/ospray/math/Distribution2D.ispc b/ospray/math/Distribution2D.ispc index 8afb72a729..cbeb3645fd 100644 --- a/ospray/math/Distribution2D.ispc +++ b/ospray/math/Distribution2D.ispc @@ -29,7 +29,7 @@ uniform float Distribution1D_create(const uniform int size, uniform float* unifo // compute reciprocal sum const uniform float rcpSum = 1.0f/sum; - // next representatble number in float greater than 1.0f + // next representable number in float greater than 1.0f const uniform float nextAfter1 = 0x1.000002p+0f; // normalize diff --git a/ospray/math/box.ih b/ospray/math/box.ih index 51b5f83757..d641b3eeee 100644 --- a/ospray/math/box.ih +++ b/ospray/math/box.ih @@ -18,6 +18,12 @@ #include "vec.ih" +//! a 1-d float bounding box (ie, a range +struct box1f { + float lower; + float upper; +}; + //! a 2-d float bounding box struct box2f { vec2f lower; @@ -57,6 +63,21 @@ struct box4f { }; +// ------------------------------------------------------- +// all box1f operations +// ------------------------------------------------------- + +/*! construct 1f range from a single float */ +inline uniform box1f make_box1f(const uniform float f) +{ uniform box1f bb; bb.lower = bb.upper = f; return bb; } + +/*! 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 uniform box1f box_union(const uniform box1f &a, const uniform box1f &b) +{ return make_box1f(min(a.lower,b.lower),max(a.upper,b.upper)); } + // ------------------------------------------------------- // box3f 'constructors' // ------------------------------------------------------- diff --git a/ospray/math/math.ih b/ospray/math/math.ih index 49b1e42572..52565fcf95 100644 --- a/ospray/math/math.ih +++ b/ospray/math/math.ih @@ -18,9 +18,9 @@ #include "ospray/common/OSPCommon.ih" -//////////////////////////////////////////////////////////////////////////////// -/// Constants -//////////////////////////////////////////////////////////////////////////////// +// ------------------------------------------------------------------ +// Constants +// ------------------------------------------------------------------ #define inf floatbits(0x7F800000) #define pos_inf floatbits(0x7F800000) @@ -34,6 +34,7 @@ #define one_over_pi 0.31830988618379069122f #define one_over_two_pi 0.15915494309189534561f #define one_over_four_pi 0.079577471545947672804f +#define one_over_two_pi_sqr 0.050660591821168885722f /*! c-style reciprocal. required since ispc 1.7 due to type changes in this version */ inline float rcpf(const float f) { return rcp(f); } @@ -46,9 +47,9 @@ inline float sqrtf(const float f) { return sqrt(f); } inline uniform float sqrtf(const uniform float f) { return sqrt(f); } /*! c-style reciprocal square root. */ -inline float rsqrtf(const float f) { return rcpf(sqrtf(f)); } +inline float rsqrtf(const float f) { return rsqrt(f); } /*! c-style reciprocal square root */ -inline uniform float rsqrtf(const uniform float f) { return rcpf(sqrtf(f)); } +inline uniform float rsqrtf(const uniform float f) { return rsqrt(f); } /*! square. */ inline float sqr(const float f) { return f*f; } @@ -117,6 +118,9 @@ inline varying float deg2rad (const varying float x) { return x * 1.74532925199 inline uniform float rad2deg (const uniform float x) { return x * 5.72957795130823208768e1f; } inline varying float rad2deg (const varying float x) { return x * 5.72957795130823208768e1f; } +inline float cos2sin(const float f) { return sqrt(max(0.f, 1.f - sqr(f))); } +inline float sin2cos(const float f) { return cos2sin(f); } + inline uniform float nextafter(const uniform float a, const uniform float b) { //! Match the behavior of the C99 math.h function. diff --git a/ospray/math/sampling.ih b/ospray/math/sampling.ih index 579684390d..45f6f257e9 100644 --- a/ospray/math/sampling.ih +++ b/ospray/math/sampling.ih @@ -25,9 +25,6 @@ #include "ospray/math/vec.ih" -inline float cos2sin(const float f) { return sqrt(max(0.f, 1.f - f * f)); } -inline float sin2cos(const float f) { return cos2sin(f); } - inline vec3f cartesian(const float phi, const float sinTheta, const float cosTheta) { float sinPhi, cosPhi; @@ -80,7 +77,7 @@ inline float powerCosineSampleHemispherePDF(const float cosTheta, const float n) return (n + 1.0f) * (0.5f / M_PI) * pow(cosTheta, n); } -inline float powerCosineSampleHemispherePDF(const vec3f dir, const float n) // TODO: order of arguments +inline float powerCosineSampleHemispherePDF(const vec3f& dir, const float n) // TODO: order of arguments { return (n + 1.0f) * (0.5f / M_PI) * pow(dir.z, n); } @@ -120,7 +117,12 @@ inline vec3f uniformSampleDisk(const float radius, const vec2f &s) inline float uniformSampleDiskPDF(const float radius) { - return rcp(M_PI * radius * radius); + return rcp(M_PI * sqr(radius)); +} + +inline uniform float uniformSampleDiskPDF(const uniform float radius) +{ + return rcp(M_PI * sqr(radius)); } diff --git a/ospray/math/vec.ih b/ospray/math/vec.ih index 7d06850ca6..5d124f489e 100644 --- a/ospray/math/vec.ih +++ b/ospray/math/vec.ih @@ -103,14 +103,25 @@ __define_ispc_vector4(float,f); ret.z = v.z; \ return ret; \ } \ - inline UV vec3##ABB##a make_vec3##ABB##a(const UV vec3##IABB##a v) \ + inline UV vec3##ABB make_vec3##ABB(const UV ITYPE x, \ + const UV ITYPE y, \ + const UV ITYPE z) \ { \ - UV vec3##ABB##a ret; \ + UV vec3##ABB ret; \ + ret.x = x; \ + ret.y = y; \ + ret.z = z; \ + return ret; \ + } \ + inline UV vec3##ABB make_vec3##ABB(const UV vec4##IABB v) \ + { \ + UV vec3##ABB ret; \ ret.x = v.x; \ ret.y = v.y; \ ret.z = v.z; \ return ret; \ } \ + /* the '3a' variants */ \ inline UV vec3##ABB##a make_vec3##ABB##a(const UV ITYPE x) \ { \ UV vec3##ABB##a ret; \ @@ -119,14 +130,20 @@ __define_ispc_vector4(float,f); ret.z = x; \ return ret; \ } \ - inline UV vec3##ABB make_vec3##ABB(const UV ITYPE x, \ - const UV ITYPE y, \ - const UV ITYPE z) \ + inline UV vec3##ABB##a make_vec3##ABB##a(const UV vec3##IABB &v) \ { \ - UV vec3##ABB ret; \ - ret.x = x; \ - ret.y = y; \ - ret.z = z; \ + UV vec3##ABB##a ret; \ + ret.x = v.x; \ + ret.y = v.y; \ + ret.z = v.z; \ + return ret; \ + } \ + inline UV vec3##ABB##a make_vec3##ABB##a(const UV vec3##IABB##a v) \ + { \ + UV vec3##ABB##a ret; \ + ret.x = v.x; \ + ret.y = v.y; \ + ret.z = v.z; \ return ret; \ } \ inline UV vec3##ABB##a make_vec3##ABB##a(const UV ITYPE x, \ @@ -139,14 +156,6 @@ __define_ispc_vector4(float,f); ret.z = z; \ return ret; \ } \ - inline UV vec3##ABB make_vec3##ABB(const UV vec4##IABB v) \ - { \ - UV vec3##ABB ret; \ - ret.x = v.x; \ - ret.y = v.y; \ - ret.z = v.z; \ - return ret; \ - } \ inline UV vec3##ABB##a make_vec3##ABB##a(const UV vec4##IABB v) \ { \ UV vec3##ABB##a ret; \ @@ -156,6 +165,10 @@ __define_ispc_vector4(float,f); return ret; \ } \ + + + + /*! defines all constructors "make_vec4[T]" for 4-vector type */ #define __define_ispc_constructors4(UV,TYPE,ABB,ITYPE,IABB) \ /*! construct vec4 from a single scalar */ \ @@ -418,11 +431,11 @@ inline varying vec3f negate(const varying vec3f &a) } \ inline vec4##abb opname (const type a, const vec4##abb b) { \ return make_vec4##abb(a op b.x, a op b.y, a op b.z, a op b.w); \ - } \ + } -#define __define_binary_operator(opname,op) \ - __define_binary_operator_typed(opname,op,f,float) \ - __define_binary_operator_typed(opname,op,i,int32) \ +#define __define_binary_operator(opname,op) \ + __define_binary_operator_typed(opname,op,f,float) \ + __define_binary_operator_typed(opname,op,i,int32) \ __define_binary_operator_typed(opname,op,ui,uint32) @@ -439,12 +452,20 @@ __define_binary_operator( mul, * ); #undef __define_binary_operator +inline float reduce_mul(const vec3f v) +{ return v.x * v.y * v.z; } +inline uniform float reduce_mul(const uniform vec3f v) +{ return v.x * v.y * v.z; } + inline float reduce_max(const vec3f v) { return max(max(v.x,v.y),v.z); } inline float reduce_add(const vec3f v) { return v.x+v.y+v.z; } +inline uniform float reduce_add(const uniform vec3f v) +{ return v.x+v.y+v.z; } + inline float reduce_avg(const vec3f v) { return (v.x+v.y+v.z)*(1.0f/3.0f); } @@ -519,22 +540,22 @@ inline vec3f safe_normalize(const vec3f v) { return v * (1.f/sqrt(max(1e-6f,dot(v,v)))); } -#define __lift_unary_fct(F) \ - inline uniform vec2f F(const uniform vec2f v) \ - { return make_vec2f(F(v.x),F(v.y)); } \ - inline vec2f F(const vec2f v) \ - { return make_vec2f(F(v.x),F(v.y)); } \ - inline uniform vec3f F(const uniform vec3f v) \ - { return make_vec3f(F(v.x),F(v.y),F(v.z)); } \ - inline vec3f F(const vec3f v) \ - { return make_vec3f(F(v.x),F(v.y),F(v.z)); } \ - inline uniform vec3fa F(const uniform vec3fa v) \ - { return make_vec3fa(F(v.x),F(v.y),F(v.z)); } \ - inline vec3fa F(const vec3fa v) \ - { return make_vec3fa(F(v.x),F(v.y),F(v.z)); } \ - inline uniform vec4f F(const uniform vec4f v) \ - { return make_vec4f(F(v.x),F(v.y),F(v.z),F(v.w)); } \ - inline vec4f F(const vec4f v) \ +#define __lift_unary_fct(F) \ + inline uniform vec2f F(const uniform vec2f v) \ + { return make_vec2f(F(v.x),F(v.y)); } \ + inline vec2f F(const vec2f v) \ + { return make_vec2f(F(v.x),F(v.y)); } \ + inline uniform vec3f F(const uniform vec3f v) \ + { return make_vec3f(F(v.x),F(v.y),F(v.z)); } \ + inline vec3f F(const vec3f v) \ + { return make_vec3f(F(v.x),F(v.y),F(v.z)); } \ + inline uniform vec3fa F(const uniform vec3fa v) \ + { return make_vec3fa(F(v.x),F(v.y),F(v.z)); } \ + inline vec3fa F(const vec3fa v) \ + { return make_vec3fa(F(v.x),F(v.y),F(v.z)); } \ + inline uniform vec4f F(const uniform vec4f v) \ + { return make_vec4f(F(v.x),F(v.y),F(v.z),F(v.w)); } \ + inline vec4f F(const vec4f v) \ { return make_vec4f(F(v.x),F(v.y),F(v.z),F(v.w)); } __lift_unary_fct(absf) @@ -542,9 +563,12 @@ __lift_unary_fct(rcpf) __lift_unary_fct(expf) __lift_unary_fct(logf) +__lift_unary_fct(floor) +__lift_unary_fct(abs) __lift_unary_fct(rcp) __lift_unary_fct(exp) __lift_unary_fct(frac) +__lift_unary_fct(sqr) #undef __lift_unary_fct @@ -676,21 +700,9 @@ inline vec3i operator-(const varying vec3i &a, const varying int32 b) inline uniform vec3i operator/(const uniform vec3i &a, const uniform int b) { return(make_vec3i(a.x / b, a.y / b, a.z / b)); } -inline vec3i max(const varying vec3i &a, const varying int32 b) -{ return(make_vec3i(max(a.x, b), max(a.y, b), max(a.z, b))); } - -// inline vec3i min(const uniform vec3i &a, const varying vec3i &b) -// { return(make_vec3i(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z))); } - -inline vec3f make_vec3f(const vec3i &a) -{ return make_vec3f(a.x, a.y, a.z); } - inline vec3f float_cast(const vec3i &a) { return make_vec3f(a); } -inline vec3i make_vec3i(const vec3f &a) -{ return make_vec3i((int)a.x, (int)a.y, (int)a.z); } - inline vec3i integer_cast(const vec3f &a) { return make_vec3i(a); } @@ -709,15 +721,15 @@ inline vec3f powf(const vec3f v, const float f) inline uniform vec3f powf(const uniform vec3f v, const uniform float f) { return make_vec3f(powf(v.x,f),powf(v.y,f),powf(v.z,f)); } -inline uniform vec3fa make_vec3fa(const uniform vec3f v) -{ return make_vec3fa(v.x,v.y,v.z); } - -inline vec3fa make_vec3fa(const vec3f v) -{ return make_vec3fa(v.x,v.y,v.z); } - inline vec3f clamp(const vec3f &a, const uniform vec3f &b, const uniform vec3f &c) { return(make_vec3f(clamp(a.x, b.x, c.x), clamp(a.y, b.y, c.y), clamp(a.z, b.z, c.z))); } +inline vec3f clamp(const vec3f &a, const vec3f &b, const vec3f &c) +{ return(make_vec3f(clamp(a.x, b.x, c.x), clamp(a.y, b.y, c.y), clamp(a.z, b.z, c.z))); } + +inline vec3i clamp(const vec3i &a, const uniform vec3i &b, const uniform vec3i &c) +{ return(make_vec3i(clamp(a.x, b.x, c.x), clamp(a.y, b.y, c.y), clamp(a.z, b.z, c.z))); } + //! The next machine representable number from 'a' in the direction of 'b'. inline uniform vec3f nextafter(const uniform vec3i &a, const uniform vec3i &b) { return(make_vec3f(nextafter(a.x, b.x), nextafter(a.y, b.y), nextafter(a.z, b.z))); } @@ -757,3 +769,93 @@ inline uniform bool isnan(uniform vec3f v) inline bool isnan(vec3f v) { return isnan(v.x+v.y+v.z); } + +inline uniform bool isnan(uniform vec3fa v) +{ return isnan(v.x+v.y+v.z); } + +inline bool isnan(vec3fa v) +{ return isnan(v.x+v.y+v.z); } + +inline void out(uniform vec3f v) { print("(%,%,%)",v.x,v.y,v.z); } +inline void out(vec3f v) { print("\n(%\n %\n %)",v.x,v.y,v.z); } +inline void out(uniform vec3i v) { print("(%,%,%)",v.x,v.y,v.z); } +inline void out(vec3i v) { print("\n(%\n %\n %)",v.x,v.y,v.z); } + + +// ------------------------------------------------------- +// set/get functions for vectors +// should eventually get moved to macros so they work for all types +// ------------------------------------------------------- + +/*! set vector 'v's value in dimension 'd' to 'f' */ +inline void set(uniform vec3f &v, const uniform uint32 dim, const uniform float f) +{ (&v.x)[dim] = f; } + +/*! get vector 'v's value in dimension 'd' */ +inline float get(const uniform vec3f &v, const uniform uint32 dim) +{ return (&v.x)[dim]; } + + +// ------------------------------------------------------- +// sRGB conversion functions +// ------------------------------------------------------- +#define APPROXIMATE_SRGB + +inline float linear_to_srgb(const float f) +{ + const float c = max(f, 0.f); +#ifdef APPROXIMATE_SRGB + return pow(c, 1.f/2.2f); +#else + return c <= 0.0031308f ? 12.92f*c : pow(c, 1.f/2.4f)*1.055f - 0.055f; +#endif +} + +inline vec4f linear_to_srgba(const vec4f c) +{ + return make_vec4f(linear_to_srgb(c.x), + linear_to_srgb(c.y), + linear_to_srgb(c.z), + max(c.w, 0f)); // alpha is never gamma-corrected +} + +inline uint32 linear_to_srgba8(const vec4f c) +{ +#if 1 + vec4f l = 255.f * min(linear_to_srgba(c), make_vec4f(1.f)); + return + ((uint32)l.x << 0) | + ((uint32)l.y << 8) | + ((uint32)l.z << 16) | + ((uint32)l.w << 24); +#else +// TODO use ISPC's float_to_srgb8 once it is fixed (issue #1198) + return + (float_to_srgb8(c.x) << 0) | + (float_to_srgb8(c.y) << 8) | + (float_to_srgb8(c.z) << 16) | + ((uint32)clamp(c.w, 0.f, 1.f) << 24); // alpha is never gamma-corrected +#endif +} + +inline float srgb_to_linear(const float f) +{ + const float c = max(f, 0.f); +#ifdef APPROXIMATE_SRGB + return pow(c, 2.2f); +#else + return c <= 0.04045f ? c/12.92f : pow((c + 0.055f)/1.055f, 2.4f); +#endif +} + +inline vec4f srgba_to_linear(const vec4f c) +{ + return make_vec4f(srgb_to_linear(c.x), + srgb_to_linear(c.y), + srgb_to_linear(c.z), + max(c.w, 0.f)); // alpha is never gamma-corrected +} + +// TODO implement srgba8_to_linear with a 256 entry LUT + +#undef APPROXIMATE_SRGB diff --git a/ospray/mpi/DistributedFrameBuffer.cpp b/ospray/mpi/DistributedFrameBuffer.cpp index dbece32b22..b7449631cc 100644 --- a/ospray/mpi/DistributedFrameBuffer.cpp +++ b/ospray/mpi/DistributedFrameBuffer.cpp @@ -17,23 +17,14 @@ #include "DistributedFrameBuffer.h" #include "DistributedFrameBuffer_ispc.h" -// embree -#include "common/sys/thread.h" - -#include "ospray/common/parallel_for.h" - -#include -//#include //NOTE(jda) - set note about std::async below... +#include "ospray/common/tasking/async.h" +#include "ospray/common/tasking/parallel_for.h" #ifdef _WIN32 # define NOMINMAX # include // for Sleep #endif -#ifdef OSPRAY_USE_TBB -# include -#endif - #define DBG(a) /* ignore */ namespace ospray { @@ -91,6 +82,28 @@ namespace ospray { Mutex gMutex; + void DFB::TileData::accumulate(const ospray::Tile &tile) + { + switch(dfb->colorBufferFormat) { + case OSP_FB_RGBA8: + ispc::DFB_accumulate_RGBA8(dfb->ispcEquivalent, + (ispc::VaryingTile *)&tile, + (ispc::VaryingTile*)&this->final, + (ispc::VaryingTile*)&this->accum, + (ispc::VaryingRGBA_I8*)&this->color, + dfb->accumId, + dfb->hasAccumBuffer); + case OSP_FB_SRGBA: + ispc::DFB_accumulate_SRGBA(dfb->ispcEquivalent, + (ispc::VaryingTile *)&tile, + (ispc::VaryingTile*)&this->final, + (ispc::VaryingTile*)&this->accum, + (ispc::VaryingRGBA_I8*)&this->color, + dfb->accumId, + dfb->hasAccumBuffer); + } + } + /*! called exactly once for each ospray::Tile that needs to get written into / composited into this dfb tile */ void DFB::AlphaBlendTile_simple::process(const ospray::Tile &tile) @@ -124,7 +137,6 @@ namespace ospray { } } } - int size = bufferedTile.size(); if (missingInCurrentGeneration == 0) { Tile **tileArray = (Tile**)alloca(sizeof(Tile*)*bufferedTile.size()); @@ -138,12 +150,7 @@ namespace ospray { this->final.region = tile.region; this->final.fbSize = tile.fbSize; this->final.rcp_fbSize = tile.rcp_fbSize; - ispc::DFB_accumulate((ispc::VaryingTile *)&bufferedTile[0]->tile, - (ispc::VaryingTile *)&this->final, - (ispc::VaryingTile *)&this->accum, - (ispc::VaryingRGBA_I8 *)&this->color, - dfb->hasAccumBuffer,dfb->accumID); - + accumulate(bufferedTile[0]->tile); dfb->tileIsCompleted(this); for (int i=0;ifinal.region = tile.region; this->final.fbSize = tile.fbSize; this->final.rcp_fbSize = tile.rcp_fbSize; - ispc::DFB_accumulate((ispc::VaryingTile *)&tile, - (ispc::VaryingTile*)&this->final, - (ispc::VaryingTile*)&this->accum, - (ispc::VaryingRGBA_I8*)&this->color, - dfb->hasAccumBuffer,dfb->accumID); + accumulate(tile); dfb->tileIsCompleted(this); } - void DFB::ZCompositeTile::newFrame() { numPartsComposited = 0; @@ -202,17 +204,11 @@ namespace ospray { } if (done) { - ispc::DFB_accumulate((ispc::VaryingTile*)&this->compositedTileData, - (ispc::VaryingTile*)&this->final, - (ispc::VaryingTile*)&this->accum, - (ispc::VaryingRGBA_I8*)&this->color, - dfb->hasAccumBuffer,dfb->accumID); + accumulate(this->compositedTileData); dfb->tileIsCompleted(this); } } - - void DFB::startNewFrame() { std::vector delayedMessage; @@ -223,6 +219,9 @@ namespace ospray { DBG(printf("rank %i starting new frame\n",mpi::world.rank)); assert(!frameIsActive); + if (hasAccumBuffer) + accumId++; + if (pixelOp) pixelOp->beginFrame(); @@ -293,24 +292,6 @@ namespace ospray { } } -#if QUEUE_PROCESSING_JOBS - void DistributedFrameBuffer::ProcThread::run() - { - embree::setAffinity(53); - return; - while (1) { - while (dfb->msgTaskQueue.queue.empty()) -#ifdef _WIN32 - Sleep(1); // 10x longer... -#else - usleep(100); -#endif - dfb->msgTaskQueue.waitAll(); - } - } -#endif - - DFB::DistributedFrameBuffer(mpi::async::CommLayer *comm, const vec2i &numPixels, size_t myID, @@ -324,21 +305,18 @@ namespace ospray { numTiles((numPixels.x+TILE_SIZE-1)/TILE_SIZE, (numPixels.y+TILE_SIZE-1)/TILE_SIZE), frameIsActive(false), frameIsDone(false), localFBonMaster(NULL), -#if QUEUE_PROCESSING_JOBS - procThread(this), -#endif + accumId(0), frameMode(WRITE_ONCE) { assert(comm); this->ispcEquivalent = ispc::DFB_create(this); - ispc::DFB_set(getIE(),numPixels.x,numPixels.y, - colorBufferFormat); + ispc::DFB_set(getIE(),numPixels.x,numPixels.y, colorBufferFormat); comm->registerObject(this,myID); createTiles(); if (comm->group->rank == 0) { - if (colorBufferFormat == OSP_RGBA_NONE) { + if (colorBufferFormat == OSP_FB_NONE) { cout << "#osp:mpi:dfb: we're the master, but framebuffer has 'NONE' " << "format; creating distriubted frame buffer WITHOUT having a " << "mappable copy on the master" << endl; @@ -346,24 +324,23 @@ namespace ospray { localFBonMaster = new LocalFrameBuffer(numPixels, colorBufferFormat, hasDepthBuffer, + false, false); } } + ispc::DFB_set(getIE(),numPixels.x,numPixels.y, colorBufferFormat); - -#if QUEUE_PROCESSING_JOBS - // procThread.run(); -#endif } void DFB::setFrameMode(FrameMode newFrameMode) { if (frameMode == newFrameMode) return; + freeTiles(); this->frameMode = newFrameMode; createTiles(); - } + } const void *DFB::mapDepthBuffer() { @@ -445,60 +422,21 @@ namespace ospray { this->tileIsCompleted(td); } - - struct DFBProcessMessageTask -#ifdef OSPRAY_USE_TBB - : public tbb::task -#endif - { - DFB *dfb; - mpi::async::CommLayer::Message *_msg; - - DFBProcessMessageTask(DFB *dfb, - mpi::async::CommLayer::Message *_msg) - : dfb(dfb), _msg(_msg) - {} - -#ifdef OSPRAY_USE_TBB - tbb::task* execute() override -#else - void execute() -#endif - { - switch (_msg->command) { - case DFB::MASTER_WRITE_TILE_NONE: - dfb->processMessage((DFB::MasterTileMessage_NONE*)_msg); - break; - case DFB::MASTER_WRITE_TILE_I8: - dfb->processMessage((DFB::MasterTileMessage_RGBA_I8*)_msg); - break; - case DFB::WORKER_WRITE_TILE: - dfb->processMessage((DFB::WriteTileMessage*)_msg); - break; - default: - assert(0); - }; - delete _msg; -#ifdef OSPRAY_USE_TBB - return nullptr; -#endif - } - }; - void DFB::tileIsCompleted(TileData *tile) { DBG(printf("rank %i: tilecompleted %i,%i\n",mpi::world.rank, tile->begin.x,tile->begin.y)); if (IamTheMaster()) { + size_t numTilesCompletedByMyTile = 0; /*! we will not do anything with the tile other than mark it's done */ { SCOPED_LOCK(mutex); - numTilesCompletedThisFrame++; + numTilesCompletedByMyTile = ++numTilesCompletedThisFrame; DBG(printf("MASTER: MARKING AS COMPLETED %i,%i -> %li %i\n", tile->begin.x,tile->begin.y,numTilesCompletedThisFrame, numTiles.x*numTiles.y)); } - if (numTilesCompletedThisFrame == numTiles.x*numTiles.y) + if (numTilesCompletedByMyTile == numTiles.x*numTiles.y) closeCurrentFrame(); } else { if (pixelOp) { @@ -506,7 +444,7 @@ namespace ospray { } switch(colorBufferFormat) { - case OSP_RGBA_NONE: { + case OSP_FB_NONE: { /* if the master doesn't have a framebufer (i.e., format 'none'), we're only telling it that we're done, but are not sending any pixels */ @@ -515,8 +453,9 @@ namespace ospray { mtm->coords = tile->begin; comm->sendTo(this->master,mtm,sizeof(*mtm)); } break; - case OSP_RGBA_I8: { - /*! if the master has rgba_i8 format, we're sending him a tile + case OSP_FB_RGBA8: + case OSP_FB_SRGBA: { + /*! if the master has RGBA8 or SRGBA format, we're sending him a tile of the proper data */ MasterTileMessage_RGBA_I8 *mtm = new MasterTileMessage_RGBA_I8; mtm->command = MASTER_WRITE_TILE_I8; @@ -529,16 +468,17 @@ namespace ospray { "implemented for distributed frame buffer"); }; + size_t numTilesCompletedByMe = 0; { SCOPED_LOCK(mutex); - numTilesCompletedThisFrame++; + numTilesCompletedByMe = ++numTilesCompletedThisFrame; DBG(printf("rank %i: MARKING AS COMPLETED %i,%i -> %i %i\n", mpi::world.rank, tile->begin.x,tile->begin.y,numTilesCompletedThisFrame, numTiles.x*numTiles.y)); } - if (numTilesCompletedThisFrame == myTiles.size()) + if (numTilesCompletedByMe == myTiles.size()) closeCurrentFrame(); } } @@ -558,13 +498,22 @@ namespace ospray { DBG(PING); -#ifdef OSPRAY_USE_TBB - auto &t = *new(tbb::task::allocate_root())DFBProcessMessageTask(this, _msg); - tbb::task::enqueue(t); -#else - DFBProcessMessageTask t(this, _msg); - t.execute(); -#endif + async([=]() { + switch (_msg->command) { + case DFB::MASTER_WRITE_TILE_NONE: + this->processMessage((DFB::MasterTileMessage_NONE*)_msg); + break; + case DFB::MASTER_WRITE_TILE_I8: + this->processMessage((DFB::MasterTileMessage_RGBA_I8*)_msg); + break; + case DFB::WORKER_WRITE_TILE: + this->processMessage((DFB::WriteTileMessage*)_msg); + break; + default: + assert(0); + }; + delete _msg; + }); DBG(PING); } @@ -572,21 +521,15 @@ namespace ospray { void DFB::closeCurrentFrame() { DBG(printf("rank %i CLOSES frame\n",mpi::world.rank)); - - //NOTE (jda) - Confused here, why lock if ok not to??? - //if (!locked) mutex.lock(); frameIsActive = false; frameIsDone = true; doneCond.notify_all(); - - //if (!locked) mutex.unlock(); } //! write given tile data into the frame buffer, sending to remove owner if //! required void DFB::setTile(ospray::Tile &tile) { - const size_t numPixels = TILE_SIZE*TILE_SIZE; DFB::TileDesc *tileDesc = this->getTileDescFor(tile.region.lower); if (!tileDesc->mine()) { @@ -595,7 +538,7 @@ namespace ospray { msg->coords = tile.region.lower; // TODO: compress pixels before sending ... memcpy(&msg->tile,&tile,sizeof(ospray::Tile)); - msg->command = WORKER_WRITE_TILE; + msg->command = WORKER_WRITE_TILE; comm->sendTo(this->worker[tileDesc->ownerID], msg,sizeof(*msg)); @@ -609,36 +552,6 @@ namespace ospray { } } - struct DFBClearTask - { - DFB *dfb; - DFBClearTask(DFB *dfb, const uint32 fbChannelFlags) - : dfb(dfb), fbChannelFlags(fbChannelFlags) - {}; - void run(size_t jobID) - { - size_t tileID = jobID; - DFB::TileData *td = dfb->myTiles[tileID]; - assert(td); - if (fbChannelFlags & OSP_FB_ACCUM) { - for (int i=0;iaccum.r[i] = 0.f; - for (int i=0;iaccum.g[i] = 0.f; - for (int i=0;iaccum.b[i] = 0.f; - for (int i=0;iaccum.a[i] = 0.f; - for (int i=0;iaccum.z[i] = inf; - } - if (fbChannelFlags & OSP_FB_DEPTH) - for (int i=0;ifinal.z[i] = inf; - if (fbChannelFlags & OSP_FB_COLOR) { - for (int i=0;ifinal.r[i] = 0.f; - for (int i=0;ifinal.g[i] = 0.f; - for (int i=0;ifinal.b[i] = 0.f; - for (int i=0;ifinal.a[i] = 0.f; - } - } - const uint32 fbChannelFlags; - }; - /*! \brief clear (the specified channels of) this frame buffer \details for the *distributed* frame buffer, we assume that @@ -649,12 +562,28 @@ namespace ospray { void DFB::clear(const uint32 fbChannelFlags) { if (!myTiles.empty()) { - DFBClearTask clearTask(this, fbChannelFlags); parallel_for(myTiles.size(), [&](int taskIndex){ - clearTask.run(taskIndex); + DFB::TileData *td = this->myTiles[taskIndex]; + assert(td); + if (fbChannelFlags & OSP_FB_ACCUM) { + for (int i=0;iaccum.r[i] = 0.f; + for (int i=0;iaccum.g[i] = 0.f; + for (int i=0;iaccum.b[i] = 0.f; + for (int i=0;iaccum.a[i] = 0.f; + for (int i=0;iaccum.z[i] = inf; + } + if (fbChannelFlags & OSP_FB_DEPTH) + for (int i=0;ifinal.z[i] = inf; + if (fbChannelFlags & OSP_FB_COLOR) { + for (int i=0;ifinal.r[i] = 0.f; + for (int i=0;ifinal.g[i] = 0.f; + for (int i=0;ifinal.b[i] = 0.f; + for (int i=0;ifinal.a[i] = 0.f; + } }); - if (fbChannelFlags & OSP_FB_ACCUM) - accumID = 0; + + if (hasAccumBuffer && (fbChannelFlags & OSP_FB_ACCUM)) + accumId = -1; // we increment at the start of the frame } } diff --git a/ospray/mpi/DistributedFrameBuffer.h b/ospray/mpi/DistributedFrameBuffer.h index c7d04d8efb..5163fc0558 100644 --- a/ospray/mpi/DistributedFrameBuffer.h +++ b/ospray/mpi/DistributedFrameBuffer.h @@ -26,32 +26,26 @@ namespace ospray { using std::cout; using std::endl; -#define QUEUE_PROCESSING_JOBS 0 - struct DistributedFrameBuffer : public mpi::async::CommLayer::Object, public virtual FrameBuffer { -#if QUEUE_PROCESSING_JOBS - struct ProcThread : public ospray::Thread { - DistributedFrameBuffer *dfb; - ProcThread(DistributedFrameBuffer *dfb) : dfb(dfb) {}; - virtual void run(); - }; - ProcThread procThread; -#endif - //! get number of pixels per tile, in x and y direction - vec2i getTileSize() const { return vec2i(TILE_SIZE); }; + vec2i getTileSize() const { return vec2i(TILE_SIZE); } //! return number of tiles in x and y direction - vec2i getNumTiles() const { return numTiles; }; + vec2i getNumTiles() const { return numTiles; } //! get number of pixels in x and y diretion vec2i getNumPixels() const { return size; } //! number of tiles that "I" own - size_t numMyTiles() const { return myTiles.size(); }; + size_t numMyTiles() const { return myTiles.size(); } + + int accumId; + int32 accumID(const vec2i &) override { return accumId; } + float tileError(const vec2i &) override { return inf; } + float endFrame(const float) override { return inf; } /*! color buffer and depth buffer on master */ @@ -105,9 +99,9 @@ namespace ospray { the DFB tile itself */ struct TileData : public TileDesc { TileData(DistributedFrameBuffer *dfb, - const vec2i &begin, - size_t tileID, - size_t ownerID); + const vec2i &begin, + size_t tileID, + size_t ownerID); /*! called exactly once at the beginning of each frame */ virtual void newFrame() = 0; @@ -120,6 +114,8 @@ namespace ospray { written into / composited into this dfb tile */ virtual void process(const ospray::Tile &tile) = 0; + void accumulate(const ospray::Tile &tile); + ospray::Tile __aligned(64) accum; /* iw: TODO - have to change this. right now, to be able to give the 'postaccum' pixel op a readily normalized tile we have to @@ -263,32 +259,6 @@ namespace ospray { tiles. will be null on all workers, and _may_ be null on the master if the master does not have a color buffer */ Ref localFBonMaster; -#if QUEUE_PROCESSING_JOBS - struct MsgTaskQueue { - std::queue > queue; - Mutex mutex; - - void addJob(Task *task) { - mutex.lock(); - queue.push(task); - mutex.unlock(); - } - - void waitAll() { - mutex.lock(); - while (!queue.empty()) { - Ref task = queue.front(); - queue.pop(); - mutex.unlock(); - task->wait(); - mutex.lock(); - } - mutex.unlock(); - } - }; - MsgTaskQueue msgTaskQueue; -#endif - inline bool IamTheMaster() const { return comm->IamTheMaster(); } //! constructor @@ -305,9 +275,9 @@ namespace ospray { // ================================================================== // framebuffer / device interface // ================================================================== - const void *mapDepthBuffer(); - const void *mapColorBuffer(); - void unmap(const void *mappedMem); + const void *mapDepthBuffer() override; + const void *mapColorBuffer() override; + void unmap(const void *mappedMem) override; /*! \brief clear (the specified channels of) this frame buffer @@ -367,7 +337,7 @@ namespace ospray { //! \brief common function to help printf-debugging /*! \detailed Every derived class should overrride this! */ - virtual std::string toString() const + std::string toString() const override { return "ospray::DistributedFrameBuffer"; } @@ -432,5 +402,3 @@ namespace ospray { }; } // ::ospray - - diff --git a/ospray/mpi/DistributedFrameBuffer.ispc b/ospray/mpi/DistributedFrameBuffer.ispc index b2cde53003..6a3ed10ca9 100644 --- a/ospray/mpi/DistributedFrameBuffer.ispc +++ b/ospray/mpi/DistributedFrameBuffer.ispc @@ -24,17 +24,6 @@ struct DistributedFrameBuffer { struct VaryingRGBA_I8 { varying uint32 color[TILE_SIZE*TILE_SIZE/programCount]; }; -// /*! the ispc equivalent of the c-side -// DistributedFrameBuffer::DFBTileData as it is sent over the -// network */ -// struct DFBTileData { -// VaryingTile accum; -// // varying float accum_r[TILE_SIZE*TILE_SIZE/programCount]; -// // varying float accum_g[TILE_SIZE*TILE_SIZE/programCount]; -// // varying float accum_b[TILE_SIZE*TILE_SIZE/programCount]; -// // varying float accum_a[TILE_SIZE*TILE_SIZE/programCount]; -// varying uint32 color[TILE_SIZE*TILE_SIZE/programCount]; -// }; export void DFB_alphaBlendBackground(VaryingTile *uniform firstTile, const uniform vec4f &bgColor) @@ -56,16 +45,9 @@ export void DFB_alphaBlendBackground(VaryingTile *uniform firstTile, export void DFB_alphaBlendTiles(VaryingTile *uniform prev, VaryingTile *uniform over) { - // print("alpha0 prev % over %\n",prev->a[0],over->a[0]); for (uniform int i=0;ir[i], - prev->g[i], - prev->b[i], - prev->a[i]); - vec4f col_over = make_vec4f(over->r[i], - over->g[i], - over->b[i], - over->a[i]); + vec4f col_prev = make_vec4f(prev->r[i], prev->g[i], prev->b[i], prev->a[i]); + vec4f col_over = make_vec4f(over->r[i], over->g[i], over->b[i], over->a[i]); vec4f col_new = col_over + col_prev * (1.f-col_over.w); prev->r[i] = col_new.x; prev->g[i] = col_new.y; @@ -74,58 +56,57 @@ export void DFB_alphaBlendTiles(VaryingTile *uniform prev, } } -export void DFB_accumulate(VaryingTile *uniform tile, - VaryingTile *uniform final, - VaryingTile *uniform accum, - VaryingRGBA_I8 *uniform color, - uniform bool hasAccumBuffer, - uniform int32 accumID) -{ - 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; - accum->b[i] = col.z; - accum->a[i] = col.w; - final->r[i] = col.x; - final->g[i] = col.y; - final->b[i] = col.z; - final->a[i] = col.w; - color->color[i] = cvt_uint32(col); - } - } else { - const float rcpAccumID = 1.f/(accumID+1); - for (uniform int i=0;ir[i], - tile->g[i], - tile->b[i], - tile->a[i]) - + make_vec4f(accum->r[i], - accum->g[i], - accum->b[i], - accum->a[i]); - - accum->r[i] = col.x; - accum->g[i] = col.y; - accum->b[i] = col.z; - accum->a[i] = col.w; - - col = col * rcpAccumID; - - final->r[i] = col.x; - final->g[i] = col.y; - final->b[i] = col.z; - final->a[i] = col.w; - color->color[i] = cvt_uint32(col); - } - } +#define template_accumulate(name, cvt) \ +export void DFB_accumulate_##name(void *uniform _self, \ + VaryingTile *uniform tile, \ + VaryingTile *uniform final, \ + VaryingTile *uniform accum, \ + VaryingRGBA_I8 *uniform color, \ + uniform int accumID, \ + uniform bool hasAccumBuffer) \ +{ \ + DistributedFrameBuffer *uniform self = (DistributedFrameBuffer*)_self; \ + 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; \ + accum->b[i] = col.z; \ + accum->a[i] = col.w; \ + final->r[i] = col.x; \ + final->g[i] = col.y; \ + final->b[i] = col.z; \ + final->a[i] = col.w; \ + \ + color->color[i] = cvt(col); \ + } \ + } else { \ + const uniform float rcpAccumID = 1.f/(accumID+1); \ + for (uniform int i=0;ir[i], tile->g[i], tile->b[i], tile->a[i]) \ + + make_vec4f(accum->r[i], accum->g[i], accum->b[i], accum->a[i]); \ + \ + accum->r[i] = col.x; \ + accum->g[i] = col.y; \ + accum->b[i] = col.z; \ + accum->a[i] = col.w; \ + \ + col = col * rcpAccumID; \ + \ + final->r[i] = col.x; \ + final->g[i] = col.y; \ + final->b[i] = col.z; \ + final->a[i] = col.w; \ + \ + color->color[i] = cvt(col); \ + } \ + } \ } +template_accumulate(RGBA8, cvt_uint32); +template_accumulate(SRGBA, linear_to_srgba8); +#undef template_accumulate + export void DFB_zComposite(VaryingTile *uniform delta, VaryingTile *uniform current) @@ -143,7 +124,8 @@ export void DFB_zComposite(VaryingTile *uniform delta, export void *uniform DFB_create(void *uniform cClassPtr) { - DistributedFrameBuffer *uniform self = uniform new uniform DistributedFrameBuffer; + DistributedFrameBuffer *uniform self = + uniform new uniform DistributedFrameBuffer; FrameBuffer_Constructor(&self->super,cClassPtr); return self; @@ -158,7 +140,9 @@ export void DFB_set(void *uniform _self, FrameBuffer_set(&self->super,size_x,size_y,colorBufferFormat); } -inline void swapFragments(VaryingTile *uniform t0, VaryingTile *uniform t1, uniform int fragID) +inline void swapFragments(VaryingTile *uniform t0, + VaryingTile *uniform t1, + uniform int fragID) { float r = t0->r[fragID]; t0->r[fragID] = t1->r[fragID]; t1->r[fragID] = r; float g = t0->g[fragID]; t0->g[fragID] = t1->g[fragID]; t1->g[fragID] = g; @@ -207,6 +191,7 @@ inline void sortAndBlendFragments(VaryingTile *uniform *uniform tileArray, } } +#if 0 task void DFB_sortAndBlendFragments_job(VaryingTile *uniform *uniform tileArray, uniform int32 numTiles) { @@ -214,10 +199,12 @@ task void DFB_sortAndBlendFragments_job(VaryingTile *uniform *uniform tileArray, uniform int end = begin + (PIXELS_PER_BLEND_JOB/programCount); sortAndBlendFragments(tileArray,numTiles,begin,end); } +#endif export void DFB_sortAndBlendFragments(VaryingTile *uniform *uniform tileArray, uniform int32 numTiles) { +// NOTE(jda) - I do not know if this should be removed...? #if 1 sortAndBlendFragments(tileArray,numTiles,0,TILE_SIZE*TILE_SIZE/programCount); #else diff --git a/ospray/mpi/MPICommon.h b/ospray/mpi/MPICommon.h index 840e55edcb..0c58c1624c 100644 --- a/ospray/mpi/MPICommon.h +++ b/ospray/mpi/MPICommon.h @@ -19,6 +19,10 @@ #include #include "ospray/common/OSPCommon.h" +// IMPI on Windows defines MPI_CALL already, erroneously +#ifdef MPI_CALL +# undef MPI_CALL +#endif /*! helper macro that checks the return value of all MPI_xxx(...) calls via MPI_CALL(xxx(...)). */ #define MPI_CALL(a) { int rc = MPI_##a; if (rc != MPI_SUCCESS) throw std::runtime_error("MPI call returned error"); } @@ -79,6 +83,6 @@ namespace ospray { group */ void init(int *ac, const char **av); - }; + } } // ::ospray diff --git a/ospray/mpi/MPIDevice.cpp b/ospray/mpi/MPIDevice.cpp index 95a900fa09..0b0df119c7 100644 --- a/ospray/mpi/MPIDevice.cpp +++ b/ospray/mpi/MPIDevice.cpp @@ -185,7 +185,6 @@ namespace ospray { cout << "=======================================================" << endl; } int rc; - MPI_Status status; app.comm = world.comm; app.makeIntraComm(); @@ -250,7 +249,6 @@ namespace ospray { const char *launchCommand) { int rc; - MPI_Status status; ospray::init(ac,&av); mpi::init(ac,av); @@ -332,10 +330,8 @@ namespace ospray { : currentApiMode(OSPD_MODE_MASTERED) { char *logLevelFromEnv = getenv("OSPRAY_LOG_LEVEL"); - if (logLevelFromEnv) + if (logLevelFromEnv && logLevel == 0) logLevel = atoi(logLevelFromEnv); - else - logLevel = 0; ospray::init(_ac,&_av); @@ -384,7 +380,6 @@ namespace ospray { OSPFrameBufferChannel channel) { int rc; - MPI_Status status; ObjectHandle handle = (const ObjectHandle &)_fb; FrameBuffer *fb = (FrameBuffer *)handle.lookup(); @@ -423,7 +418,7 @@ namespace ospray { Assert(_object); cmd.newCommand(CMD_COMMIT); const ObjectHandle handle = (const ObjectHandle&)_object; - cmd.send((const ObjectHandle&)_object); + cmd.send(handle); cmd.flush(); MPI_Barrier(MPI_COMM_WORLD); @@ -500,7 +495,6 @@ namespace ospray { size_t size = typeSize * size_t(count.x) * size_t(count.y) * size_t(count.z); if (size > 1000000000LL) throw std::runtime_error("setregion does not currently work for region sizes >= 2GB"); - // OSPData data = newData(size, type, (void *)source, OSP_DATA_SHARED_BUFFER); cmd.newCommand(CMD_SET_REGION); cmd.send((const ObjectHandle &)_volume); @@ -512,7 +506,10 @@ namespace ospray { int numFails = 0; MPI_Status status; - int rc = MPI_Recv(&numFails,1,MPI_INT,0,MPI_ANY_TAG,mpi::worker.comm,&status); + int rc = MPI_Recv(&numFails,1,MPI_INT, + 0,MPI_ANY_TAG,mpi::worker.comm,&status); + + Assert(rc == MPI_SUCCESS); return (numFails == 0); } @@ -942,7 +939,8 @@ namespace ospray { int numFails = 0; MPI_Status status; - int rc = MPI_Recv(&numFails,1,MPI_INT,0,MPI_ANY_TAG,mpi::worker.comm,&status); + int rc = MPI_Recv(&numFails,1,MPI_INT, + 0,MPI_ANY_TAG,mpi::worker.comm,&status); if (numFails == 0) return (OSPMaterial)(int64)handle; else { @@ -985,7 +983,8 @@ namespace ospray { // int MPI_Allreduce(void* , void*, int, MPI_Datatype, MPI_Op, MPI_Comm); int numFails = 0; MPI_Status status; - int rc = MPI_Recv(&numFails,1,MPI_INT,0,MPI_ANY_TAG,mpi::worker.comm,&status); + int rc = MPI_Recv(&numFails,1,MPI_INT, + 0,MPI_ANY_TAG,mpi::worker.comm,&status); if (numFails==0) return (OSPLight)(int64)handle; else { @@ -1035,7 +1034,7 @@ namespace ospray { /*! call a renderer to render a frame buffer */ - void MPIDevice::renderFrame(OSPFrameBuffer _fb, + float MPIDevice::renderFrame(OSPFrameBuffer _fb, OSPRenderer _renderer, const uint32 fbChannelFlags) { @@ -1054,7 +1053,7 @@ namespace ospray { cmd.send((int32)fbChannelFlags); cmd.flush(); - TiledLoadBalancer::instance->renderFrame(NULL,fb,fbChannelFlags); + return TiledLoadBalancer::instance->renderFrame(NULL,fb,fbChannelFlags); } //! release (i.e., reduce refcount of) given object @@ -1085,18 +1084,17 @@ namespace ospray { } /*! create a new Texture2D object */ - OSPTexture2D MPIDevice::newTexture2D(int width, int height, - OSPDataType type, void *data, int flags) + OSPTexture2D MPIDevice::newTexture2D(const vec2i &sz, + const OSPTextureFormat type, void *data, const uint32 flags) { ObjectHandle handle = ObjectHandle::alloc(); cmd.newCommand(CMD_NEW_TEXTURE2D); cmd.send(handle); - cmd.send((int32)width); - cmd.send((int32)height); + cmd.send(sz); cmd.send((int32)type); cmd.send((int32)flags); assert(data); - size_t size = ospray::sizeOf(type)*width*height; + size_t size = ospray::sizeOf(type) * sz.x * sz.y; cmd.send(size); cmd.send(data,size); @@ -1105,7 +1103,7 @@ namespace ospray { } /*! return a string represenging the given API Mode */ - const char *apiModeName(OSPDApiMode mode) + const char *apiModeName(int mode) { switch (mode) { case OSPD_MODE_INDEPENDENT: @@ -1118,7 +1116,6 @@ namespace ospray { PRINT(mode); NOTIMPLEMENTED; }; - } /*! switch API mode for distriubted API extensions */ diff --git a/ospray/mpi/MPIDevice.h b/ospray/mpi/MPIDevice.h index 1991b2f3e3..38dd596172 100644 --- a/ospray/mpi/MPIDevice.h +++ b/ospray/mpi/MPIDevice.h @@ -18,7 +18,7 @@ #include "MPICommon.h" #include "ospray/api/Device.h" -#include "ospray/device/command.h" +#include "ospray/mpi/command.h" #include "CommandStream.h" #include "ospray/common/Managed.h" @@ -219,7 +219,7 @@ namespace ospray { OSPVolume newVolume(const char *type) override; /*! call a renderer to render a frame buffer */ - void renderFrame(OSPFrameBuffer _sc, + float renderFrame(OSPFrameBuffer _sc, OSPRenderer _renderer, const uint32 fbChannelFlags) override; @@ -242,8 +242,8 @@ namespace ospray { void setMaterial(OSPGeometry _geom, OSPMaterial _mat) override; /*! create a new Texture2D object */ - OSPTexture2D newTexture2D(int width, int height, OSPDataType type, - void *data, int flags) override; + OSPTexture2D newTexture2D(const vec2i &size, const OSPTextureFormat, + void *data, const uint32 flags) override; /*! switch API mode for distriubted API extensions */ void apiMode(OSPDApiMode mode) override; @@ -263,7 +263,7 @@ namespace ospray { // ================================================================== /*! return a string represenging the given API Mode */ - const char *apiModeName(OSPDApiMode mode); + const char *apiModeName(int mode); } // ::ospray::mpi } // ::ospray diff --git a/ospray/mpi/MPILoadBalancer.cpp b/ospray/mpi/MPILoadBalancer.cpp index 9ce2dce602..b869e2f0e0 100644 --- a/ospray/mpi/MPILoadBalancer.cpp +++ b/ospray/mpi/MPILoadBalancer.cpp @@ -19,7 +19,7 @@ #include "ospray/render/Renderer.h" #include "ospray/fb/LocalFB.h" #include "ospray/mpi/DistributedFrameBuffer.h" -#include "ospray/common/parallel_for.h" +#include "ospray/common/tasking/parallel_for.h" #include @@ -35,12 +35,13 @@ namespace ospray { namespace staticLoadBalancer { - void Master::renderFrame(Renderer *tiledRenderer, - FrameBuffer *fb, - const uint32 channelFlags) + float Master::renderFrame(Renderer *tiledRenderer, + FrameBuffer *fb, + const uint32 channelFlags) { async_beginFrame(); DistributedFrameBuffer *dfb = dynamic_cast(fb); + assert(dfb); dfb->startNewFrame(); /* the client will do its magic here, and the distributed @@ -49,6 +50,8 @@ namespace ospray { dfb->waitUntilFinished(); async_endFrame(); + + return dfb->endFrame(0.f); } std::string Master::toString() const @@ -56,9 +59,9 @@ namespace ospray { return "ospray::mpi::staticLoadBalancer::Master"; } - void Slave::renderFrame(Renderer *tiledRenderer, - FrameBuffer *fb, - const uint32 channelFlags) + float Slave::renderFrame(Renderer *tiledRenderer, + FrameBuffer *fb, + const uint32 channelFlags) { async_beginFrame(); @@ -75,32 +78,19 @@ namespace ospray { const size_t tileID = taskIndex; if ((tileID % worker.size) != worker.rank) return; + 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); + #if TILE_SIZE>128 - Tile *tilePtr = new Tile; + Tile *tilePtr = new Tile(tileId, fb->size, accumID); Tile &tile = *tilePtr; #else - Tile __aligned(64) tile; + Tile __aligned(64) tile(tileId, fb->size, accumID); #endif - const size_t tile_y = tileID / numTiles_x; - const size_t tile_x = tileID - tile_y*numTiles_x; - tile.region.lower.x = tile_x * TILE_SIZE; - tile.region.lower.y = tile_y * TILE_SIZE; - tile.region.upper.x = std::min(tile.region.lower.x + TILE_SIZE, - fb->size.x); - tile.region.upper.y = std::min(tile.region.lower.y + TILE_SIZE, - fb->size.y); - tile.fbSize = fb->size; - tile.rcp_fbSize = rcp(vec2f(fb->size)); - tile.generation = 0; - tile.children = 0; - - const int spp = tiledRenderer->spp; - const int blocks = (fb->accumID > 0 || spp > 0) ? 1 : - std::min(1 << -2 * spp, TILE_SIZE*TILE_SIZE); - const size_t numJobs = ((TILE_SIZE*TILE_SIZE)/ - RENDERTILE_PIXELS_PER_JOB + blocks-1)/blocks; - - parallel_for(numJobs, [&](int taskIndex){ + + parallel_for(numJobs(tiledRenderer->spp, accumID), [&](int taskIndex){ tiledRenderer->renderTile(perFrameData, tile, taskIndex); }); @@ -114,6 +104,8 @@ namespace ospray { tiledRenderer->endFrame(perFrameData,channelFlags); async_endFrame(); + + return dfb->endFrame(0.f); } std::string Slave::toString() const diff --git a/ospray/mpi/MPILoadBalancer.h b/ospray/mpi/MPILoadBalancer.h index d351b14c0e..b87b87b015 100644 --- a/ospray/mpi/MPILoadBalancer.h +++ b/ospray/mpi/MPILoadBalancer.h @@ -35,10 +35,10 @@ namespace ospray { */ struct Master : public TiledLoadBalancer { - void renderFrame(Renderer *tiledRenderer, + float renderFrame(Renderer *tiledRenderer, FrameBuffer *fb, - const uint32 channelFlags); - std::string toString() const; + const uint32 channelFlags) override; + std::string toString() const override; }; /*! \brief the 'slave' in a tile-based master-slave *static* @@ -56,10 +56,10 @@ namespace ospray { /*! total number of worker threads across all(!) slaves */ int32 numTotalThreads; - void renderFrame(Renderer *tiledRenderer, + float renderFrame(Renderer *tiledRenderer, FrameBuffer *fb, - const uint32 channelFlags); - std::string toString() const; + const uint32 channelFlags) override; + std::string toString() const override; }; }// ::ospray::mpi::staticLoadBalancer } // ::ospray::mpi diff --git a/ospray/mpi/async/BatchedIsendIrecvMessaging.cpp b/ospray/mpi/async/BatchedIsendIrecvMessaging.cpp index dc2e42bc05..17059b62d9 100644 --- a/ospray/mpi/async/BatchedIsendIrecvMessaging.cpp +++ b/ospray/mpi/async/BatchedIsendIrecvMessaging.cpp @@ -38,10 +38,10 @@ namespace ospray { { Group *g = this->group; Action *actions[SEND_WINDOW_SIZE]; + MPI_Request request[SEND_WINDOW_SIZE]; while (1) { // usleep(80); size_t numActions = g->sendQueue.getSome(actions,SEND_WINDOW_SIZE); - auto *request = (MPI_Request*)alloca(numActions*sizeof(MPI_Request)); for (int i=0;idata,action->size,MPI_BYTE, diff --git a/ospray/mpi/async/Messaging.h b/ospray/mpi/async/Messaging.h index 798c52b9f4..54be512893 100644 --- a/ospray/mpi/async/Messaging.h +++ b/ospray/mpi/async/Messaging.h @@ -20,8 +20,6 @@ #include "ospray/common/Thread.h" namespace ospray { - using embree::thread_t; - namespace mpi { //! abstraction for any other peer node that we might want to communicate with diff --git a/ospray/device/buffers.h b/ospray/mpi/buffers.h similarity index 100% rename from ospray/device/buffers.h rename to ospray/mpi/buffers.h diff --git a/ospray/device/command.h b/ospray/mpi/command.h similarity index 98% rename from ospray/device/command.h rename to ospray/mpi/command.h index cc5524ed2e..d3c4df8a06 100644 --- a/ospray/device/command.h +++ b/ospray/mpi/command.h @@ -19,7 +19,7 @@ /*! \file ospray/device/nwlayer.h \brief Defines the basic network layer abstraction */ #include "ospray/include/ospray/ospray.h" -#include "ospray/device/buffers.h" +#include "ospray/mpi/buffers.h" namespace ospray { // namespace nwlayer { diff --git a/ospray/mpi/testing/TestDistributedApp.cpp b/ospray/mpi/testing/TestDistributedApp.cpp index 934001ceb4..6655dbaf9d 100644 --- a/ospray/mpi/testing/TestDistributedApp.cpp +++ b/ospray/mpi/testing/TestDistributedApp.cpp @@ -16,11 +16,6 @@ // ======================================================================== // -// enable the "mpi distributed" part of the ospray api -#ifndef OSPRAY_MPI_DISTRIBUTED -# define OSPRAY_MPI_DISTRIBUTED -#endif - #include #include diff --git a/ospray/mpi/worker.cpp b/ospray/mpi/worker.cpp index 8839fbe1bc..5e0053d809 100644 --- a/ospray/mpi/worker.cpp +++ b/ospray/mpi/worker.cpp @@ -56,19 +56,22 @@ void sleep(unsigned int seconds) #endif namespace ospray { + + extern RTCDevice g_embreeDevice; + namespace mpi { using std::cout; using std::endl; struct GeometryLocator { - bool operator()(const embree::Ref &g) const { + bool operator()(const Ref &g) const { return ptr == &*g; } Geometry *ptr; }; struct VolumeLocator { - bool operator()(const embree::Ref &g) const { + bool operator()(const Ref &g) const { return ptr == &*g; } Volume *ptr; @@ -100,14 +103,25 @@ namespace ospray { embreeConfig << " threads=1,verbose=2"; else if(numThreads > 0) embreeConfig << " threads=" << numThreads; - rtcInit(embreeConfig.str().c_str()); - rtcSetErrorFunction(embreeErrorFunc); // needs to come after rtcInit + // NOTE(jda) - This guard guarentees that the embree device gets cleaned + // up no matter how the scope of runWorker() is left + struct EmbreeDeviceScopeGuard { + RTCDevice embreeDevice; + ~EmbreeDeviceScopeGuard() { rtcDeleteDevice(embreeDevice); } + }; + + RTCDevice embreeDevice = rtcNewDevice(embreeConfig.str().c_str()); + g_embreeDevice = embreeDevice; + EmbreeDeviceScopeGuard guard; + guard.embreeDevice = embreeDevice; + + rtcDeviceSetErrorFunction(embreeDevice, embreeErrorFunc); - if (rtcGetError() != RTC_NO_ERROR) { + if (rtcDeviceGetError(embreeDevice) != RTC_NO_ERROR) { // why did the error function not get called !? - std::cerr << "#osp:init: embree internal error number " << (int)rtcGetError() << std::endl; - assert(rtcGetError() == RTC_NO_ERROR); + std::cerr << "#osp:init: embree internal error number " + << (int)rtcDeviceGetError(embreeDevice) << std::endl; } // ------------------------------------------------------- @@ -313,11 +327,11 @@ namespace ospray { case ospray::CMD_FRAMEBUFFER_CREATE: { const ObjectHandle handle = cmd.get_handle(); - const vec2i size = cmd.get_vec2i(); + const vec2i size = cmd.get_vec2i(); const OSPFrameBufferFormat mode = (OSPFrameBufferFormat)cmd.get_int32(); const uint32 channelFlags = cmd.get_int32(); - bool hasDepthBuffer = (channelFlags & OSP_FB_DEPTH); - bool hasAccumBuffer = (channelFlags & OSP_FB_ACCUM); + const bool hasDepthBuffer = (channelFlags & OSP_FB_DEPTH); + const bool hasAccumBuffer = (channelFlags & OSP_FB_ACCUM); // #if USE_DFB FrameBuffer *fb = new DistributedFrameBuffer(ospray::mpi::async::CommLayer::WORLD, size,handle,mode, @@ -418,15 +432,14 @@ namespace ospray { const ObjectHandle handle = cmd.get_handle(); Texture2D *texture2D = NULL; - int32 width = cmd.get_int32(); - int32 height = cmd.get_int32(); - int32 type = cmd.get_int32(); - int32 flags = cmd.get_int32(); - size_t size = cmd.get_size_t(); + const vec2i sz = cmd.get_vec2i(); + const int32 type = cmd.get_int32(); + const int32 flags = cmd.get_int32(); + const size_t size = cmd.get_size_t(); void *data = malloc(size); cmd.get_data(size,data); - texture2D = Texture2D::createTexture(width,height,(OSPDataType)type,data, + texture2D = Texture2D::createTexture(sz, (OSPTextureFormat)type, data, flags | OSP_DATA_SHARED_BUFFER); assert(texture2D); diff --git a/ospray/render/LoadBalancer.cpp b/ospray/render/LoadBalancer.cpp index a4f1110abe..30642c92c9 100644 --- a/ospray/render/LoadBalancer.cpp +++ b/ospray/render/LoadBalancer.cpp @@ -14,15 +14,15 @@ // limitations under the License. // // ======================================================================== // +// own #include "LoadBalancer.h" #include "Renderer.h" -#include - +#include "ospray/common/tasking/parallel_for.h" +// ospc +#include "common/sysinfo.h" // stl #include -#include "ospray/common/parallel_for.h" - namespace ospray { using std::cout; @@ -31,16 +31,16 @@ namespace ospray { TiledLoadBalancer *TiledLoadBalancer::instance = NULL; LocalTiledLoadBalancer::LocalTiledLoadBalancer() -#ifdef OSPRAY_USE_TBB +#ifdef OSPRAY_TASKING_TBB : tbb_init(numThreads) #endif { } /*! render a frame via the tiled load balancer */ - void LocalTiledLoadBalancer::renderFrame(Renderer *renderer, - FrameBuffer *fb, - const uint32 channelFlags) + float LocalTiledLoadBalancer::renderFrame(Renderer *renderer, + FrameBuffer *fb, + const uint32 channelFlags) { Assert(renderer); Assert(fb); @@ -52,26 +52,18 @@ namespace ospray { const int NTASKS = numTiles_x * numTiles_y; - parallel_for(NTASKS, [&](int taskIndex){ - Tile tile; + parallel_for(NTASKS, [&](int taskIndex) { const size_t tile_y = taskIndex / numTiles_x; const size_t tile_x = taskIndex - tile_y*numTiles_x; - tile.region.lower.x = tile_x * TILE_SIZE; - tile.region.lower.y = tile_y * TILE_SIZE; - tile.region.upper.x = std::min(tile.region.lower.x+TILE_SIZE,fb->size.x); - tile.region.upper.y = std::min(tile.region.lower.y+TILE_SIZE,fb->size.y); - tile.fbSize = fb->size; - tile.rcp_fbSize = rcp(vec2f(tile.fbSize)); - tile.generation = 0; - tile.children = 0; - - const int spp = renderer->spp; - const int blocks = (fb->accumID > 0 || spp > 0) ? 1 : - std::min(1 << -2 * spp, TILE_SIZE*TILE_SIZE); - const size_t numJobs = ((TILE_SIZE*TILE_SIZE)/ - RENDERTILE_PIXELS_PER_JOB + blocks-1)/blocks; - - parallel_for(numJobs, [&](int taskIndex){ + const vec2i tileID(tile_x, tile_y); + const int32 accumID = fb->accumID(tileID); + + if (fb->tileError(tileID) <= renderer->errorThreshold) + return; + + Tile tile(tileID, fb->size, accumID); + + parallel_for(numJobs(renderer->spp, accumID), [&](int taskIndex) { renderer->renderTile(perFrameData, tile, taskIndex); }); @@ -79,6 +71,8 @@ namespace ospray { }); renderer->endFrame(perFrameData,channelFlags); + + return fb->endFrame(renderer->errorThreshold); } std::string LocalTiledLoadBalancer::toString() const @@ -92,9 +86,9 @@ namespace ospray { return "ospray::InterleavedTiledLoadBalancer"; } - void InterleavedTiledLoadBalancer::renderFrame(Renderer *renderer, - FrameBuffer *fb, - const uint32 channelFlags) + float InterleavedTiledLoadBalancer::renderFrame(Renderer *renderer, + FrameBuffer *fb, + const uint32 channelFlags) { Assert(renderer); Assert(fb); @@ -108,28 +102,19 @@ namespace ospray { const int NTASKS = (numTiles_total / numDevices) + (numTiles_total % numDevices > deviceID); - parallel_for(NTASKS, [&](int taskIndex){ + parallel_for(NTASKS, [&](int taskIndex) { int tileIndex = deviceID + numDevices * taskIndex; - - Tile tile; const size_t tile_y = tileIndex / numTiles_x; const size_t tile_x = tileIndex - tile_y*numTiles_x; - tile.region.lower.x = tile_x * TILE_SIZE; - tile.region.lower.y = tile_y * TILE_SIZE; - tile.region.upper.x = std::min(tile.region.lower.x+TILE_SIZE,fb->size.x); - tile.region.upper.y = std::min(tile.region.lower.y+TILE_SIZE,fb->size.y); - tile.fbSize = fb->size; - tile.rcp_fbSize = rcp(vec2f(tile.fbSize)); - tile.generation = 0; - tile.children = 0; - - const int spp = renderer->spp; - const int blocks = (fb->accumID > 0 || spp > 0) ? 1 : - std::min(1 << -2 * spp, TILE_SIZE*TILE_SIZE); - const size_t numJobs = ((TILE_SIZE*TILE_SIZE)/ - RENDERTILE_PIXELS_PER_JOB + blocks-1)/blocks; - - parallel_for(numJobs, [&](int taskIndex){ + const vec2i tileID(tile_x, tile_y); + const int32 accumID = fb->accumID(tileID); + + if (fb->tileError(tileID) <= renderer->errorThreshold) + return; + + Tile tile(tileID, fb->size, accumID); + + parallel_for(numJobs(renderer->spp, accumID), [&](int taskIndex) { renderer->renderTile(perFrameData, tile, taskIndex); }); @@ -137,6 +122,8 @@ namespace ospray { }); renderer->endFrame(perFrameData,channelFlags); + + return fb->endFrame(renderer->errorThreshold); } } // ::ospray diff --git a/ospray/render/LoadBalancer.h b/ospray/render/LoadBalancer.h index 88091ec1f9..a314bd1dfe 100644 --- a/ospray/render/LoadBalancer.h +++ b/ospray/render/LoadBalancer.h @@ -24,7 +24,7 @@ #include "ospray/render/Renderer.h" // tbb -#ifdef OSPRAY_USE_TBB +#ifdef OSPRAY_TASKING_TBB # include #endif @@ -36,9 +36,16 @@ namespace ospray { { static TiledLoadBalancer *instance; virtual std::string toString() const = 0; - virtual void renderFrame(Renderer *tiledRenderer, + virtual float renderFrame(Renderer *tiledRenderer, FrameBuffer *fb, const uint32 channelFlags) = 0; + + static size_t numJobs(const int spp, int accumID) + { + const int blocks = (accumID > 0 || spp > 0) ? 1 : + std::min(1 << -2 * spp, TILE_SIZE*TILE_SIZE); + return divRoundUp((TILE_SIZE*TILE_SIZE)/RENDERTILE_PIXELS_PER_JOB, blocks); + } }; //! tiled load balancer for local rendering on the given machine @@ -50,13 +57,13 @@ namespace ospray { { LocalTiledLoadBalancer(); - void renderFrame(Renderer *renderer, + float renderFrame(Renderer *renderer, FrameBuffer *fb, const uint32 channelFlags) override; std::string toString() const override; -#ifdef OSPRAY_USE_TBB +#ifdef OSPRAY_TASKING_TBB tbb::task_scheduler_init tbb_init; #endif }; @@ -83,7 +90,7 @@ namespace ospray { std::string toString() const override; - void renderFrame(Renderer *tiledRenderer, + float renderFrame(Renderer *tiledRenderer, FrameBuffer *fb, const uint32 channelFlags) override; }; diff --git a/ospray/render/Renderer.cpp b/ospray/render/Renderer.cpp index 53567fe4fa..e80cddafff 100644 --- a/ospray/render/Renderer.cpp +++ b/ospray/render/Renderer.cpp @@ -36,12 +36,19 @@ namespace ospray { { epsilon = getParam1f("epsilon", 1e-6f); spp = getParam1i("spp", 1); + errorThreshold = getParam1f("varianceThreshold", 0.f); backgroundEnabled = getParam1i("backgroundEnabled", 1); maxDepthTexture = (Texture2D*)getParamObject("maxDepthTexture", NULL); model = (Model*)getParamObject("model", getParamObject("world")); - if (maxDepthTexture && (maxDepthTexture->type != OSP_FLOAT || !(maxDepthTexture->flags & OSP_TEXTURE_FILTER_NEAREST))) - static WarnOnce warning("expected maxDepthTexture provided to the renderer to be type OSP_FLOAT and have the OSP_TEXTURE_FILTER_NEAREST flag"); + if (maxDepthTexture) { + if (maxDepthTexture->type != OSP_TEXTURE_R32F + || !(maxDepthTexture->flags & OSP_TEXTURE_FILTER_NEAREST)) { + static WarnOnce warning("expected maxDepthTexture provided to the " + "renderer to be type OSP_FLOAT and have the " + "OSP_TEXTURE_FILTER_NEAREST flag"); + } + } vec3f bgColor; bgColor = getParam3f("bgColor", vec3f(1.f)); @@ -49,7 +56,8 @@ namespace ospray { if (getIE()) { ManagedObject* camera = getParamObject("camera"); if (model) { - const float diameter = model->bounds.empty() ? 1.0f : length(model->bounds.size()); + const float diameter = model->bounds.empty() ? + 1.0f : length(model->bounds.size()); epsilon *= diameter; } @@ -74,7 +82,8 @@ namespace ospray { loadLibrary("ospray_module_" + libName); } - std::map::iterator it = rendererRegistry.find(type); + std::map::iterator it + = rendererRegistry.find(type); if (it != rendererRegistry.end()) { return it->second ? (it->second)() : NULL; } @@ -85,11 +94,12 @@ namespace ospray { } std::string creatorName = "ospray_create_renderer__" + type; - creatorFct creator = (creatorFct)getSymbol(creatorName); //dlsym(RTLD_DEFAULT,creatorName.c_str()); + creatorFct creator = (creatorFct)getSymbol(creatorName); rendererRegistry[type] = creator; if (creator == NULL) { if (ospray::logLevel >= 1) { - std::cout << "#ospray: could not find renderer type '" << type << "'" << std::endl; + std::cout << "#ospray: could not find renderer type '" << type << "'" + << std::endl; } return NULL; } @@ -97,8 +107,12 @@ namespace ospray { Renderer *renderer = (*creator)(); renderer->managedObjectType = OSP_RENDERER; if (renderer == NULL && ospray::logLevel >= 1) { - std::cout << "#osp:warning[ospNewRenderer(...)]: could not create renderer of that type." << endl; - std::cout << "#osp:warning[ospNewRenderer(...)]: Note: Requested renderer type was '" << type << "'" << endl; + std::cout << "#osp:warning[ospNewRenderer(...)]:" + << " could not create renderer of that type." + << endl; + std::cout << "#osp:warning[ospNewRenderer(...)]:" + << " Note: Requested renderer type was '" << type << "'" + << endl; } return renderer; @@ -115,18 +129,15 @@ namespace ospray { return ispc::Renderer_beginFrame(getIE(),fb->getIE()); } - void Renderer::endFrame(void *perFrameData, const int32 fbChannelFlags) + void Renderer::endFrame(void *perFrameData, const int32 /*fbChannelFlags*/) { - FrameBuffer *fb = this->currentFB; - if ((fbChannelFlags & OSP_FB_ACCUM)) - fb->accumID++; - ispc::Renderer_endFrame(getIE(),perFrameData,fb->accumID); + ispc::Renderer_endFrame(getIE(),perFrameData); } - void Renderer::renderFrame(FrameBuffer *fb, const uint32 channelFlags) + float Renderer::renderFrame(FrameBuffer *fb, const uint32 channelFlags) { // double T0 = getSysTime(); - TiledLoadBalancer::instance->renderFrame(this,fb,channelFlags); + return TiledLoadBalancer::instance->renderFrame(this,fb,channelFlags); // double T1 = getSysTime(); // printf("time per frame %lf ms\n",(T1-T0)*1e3f); } @@ -136,7 +147,10 @@ namespace ospray { assert(getIE()); OSPPickResult res; - ispc::Renderer_pick(getIE(), (const ispc::vec2f&)screenPos, (ispc::vec3f&)res.position, res.hit); + ispc::Renderer_pick(getIE(), + (const ispc::vec2f&)screenPos, + (ispc::vec3f&)res.position, + res.hit); return res; } diff --git a/ospray/render/Renderer.h b/ospray/render/Renderer.h index df761cf416..6b4fd8edc0 100644 --- a/ospray/render/Renderer.h +++ b/ospray/render/Renderer.h @@ -35,7 +35,7 @@ namespace ospray { compositing or even projection/splatting based approaches */ struct Renderer : public ManagedObject { - Renderer() : spp(1) {} + Renderer() : spp(1), errorThreshold(0.0f) {} /*! \brief creates an abstract renderer class of given type @@ -51,7 +51,7 @@ namespace ospray { virtual std::string toString() const { return "ospray::Renderer"; } /*! \brief render one frame, and put it into given frame buffer */ - virtual void renderFrame(FrameBuffer *fb, + virtual float renderFrame(FrameBuffer *fb, const uint32 fbChannelFlags); //! \brief called to initialize a new frame @@ -87,7 +87,10 @@ namespace ospray { float epsilon; /*! \brief number of samples to be used per pixel in a tile */ - int32 spp; + int32 spp; + + /*! adaptive accumulation: variance-based error to reach */ + float errorThreshold; /*! \brief whether the background should be rendered (e.g. for compositing the background may be disabled) */ bool backgroundEnabled; diff --git a/ospray/render/Renderer.ih b/ospray/render/Renderer.ih index 18a3adf3a7..d3283cf4ab 100644 --- a/ospray/render/Renderer.ih +++ b/ospray/render/Renderer.ih @@ -56,15 +56,14 @@ typedef void (*Renderer_RenderSampleFct)(uniform Renderer *uniform self, typedef void (*Renderer_ToneMapFct)(uniform Renderer *uniform self, varying vec3f &color, const varying vec2i &pixelID); -typedef void (*Renderer_RenderTileFct)(uniform Renderer *uniform self, +typedef unmasked void (*Renderer_RenderTileFct)(uniform Renderer *uniform self, void *uniform perFrameData, uniform Tile &tile, uniform int taskIndex); -typedef void *uniform (*Renderer_BeginFrameFct)(uniform Renderer *uniform self, +typedef unmasked void *uniform (*Renderer_BeginFrameFct)(uniform Renderer *uniform self, uniform FrameBuffer *uniform fb); -typedef void (*Renderer_EndFrameFct)(uniform Renderer *uniform self, - void *uniform perFrameData, - const uniform int32 newAccumID); +typedef unmasked void (*Renderer_EndFrameFct)(uniform Renderer *uniform self, + void *uniform perFrameData); struct Renderer { Renderer_RenderSampleFct renderSample; diff --git a/ospray/render/Renderer.ispc b/ospray/render/Renderer.ispc index 1c535d2a5b..6e16e50253 100644 --- a/ospray/render/Renderer.ispc +++ b/ospray/render/Renderer.ispc @@ -26,14 +26,14 @@ void Renderer_default_renderSample(uniform Renderer *uniform self, { sample.z = inf; sample.alpha = 1.f; - sample.rgb = make_random_color((sample.sampleID.x<<0)+ + sample.rgb = make_random_color((sample.sampleID.x<<0 )+ (sample.sampleID.y<<14)+ - (sample.sampleID.z<<28) - ); + (sample.sampleID.z<<28)); } -static void *uniform Renderer_default_beginFrame(uniform Renderer *uniform self, - uniform FrameBuffer *uniform fb) +static unmasked void *uniform +Renderer_default_beginFrame(uniform Renderer *uniform self, + uniform FrameBuffer *uniform fb) { self->fb = fb; if (self->camera == NULL) @@ -43,20 +43,16 @@ static void *uniform Renderer_default_beginFrame(uniform Renderer *uniform self, return NULL; } -static void Renderer_default_endFrame(uniform Renderer *uniform self, - void *uniform perFrameData, - const uniform int32 accumID) +static unmasked void Renderer_default_endFrame(uniform Renderer *uniform self, + void *uniform perFrameData) { - if (self->fb) { - self->fb->accumID = accumID; - self->fb = NULL; - } + if (self->fb) self->fb = NULL; } -void Renderer_default_renderTileJob(uniform Renderer *uniform self, - void *uniform perFrameData, - uniform Tile &tile, - uniform int taskIndex) +unmasked void Renderer_default_renderTile(uniform Renderer *uniform self, + void *uniform perFrameData, + uniform Tile &tile, + uniform int taskIndex) { uniform FrameBuffer *uniform fb = self->fb; uniform Camera *uniform camera = self->camera; @@ -76,9 +72,9 @@ void Renderer_default_renderTileJob(uniform Renderer *uniform self, const uniform int begin = taskIndex * RENDERTILE_PIXELS_PER_JOB; const uniform int end = begin + RENDERTILE_PIXELS_PER_JOB; - const uniform int startSampleID = max(fb->accumID,0)*spp; + const uniform int startSampleID = max(tile.accumID, 0)*spp; - for (uniform uint32 i=begin;imaxDepthTexture) { // always sample center of pixel vec2f depthTexCoord; @@ -99,13 +96,15 @@ void Renderer_default_renderTileJob(uniform Renderer *uniform self, } vec3f col = make_vec3f(0.f); const uint32 pixel = z_order.xs[index] + (z_order.ys[index] * TILE_SIZE); - for (uniform uint32 s = 0; srcpSize.x; - cameraSample.screen.y = (screenSample.sampleID.y + pixel_dv) * fb->rcpSize.y; + cameraSample.screen.x = (screenSample.sampleID.x + pixel_du) + * fb->rcpSize.x; + cameraSample.screen.y = (screenSample.sampleID.y + pixel_dv) + * fb->rcpSize.y; // TODO: fix correlations / better RNG cameraSample.lens.x = precomputedHalton3(startSampleID+s); @@ -121,37 +120,43 @@ void Renderer_default_renderTileJob(uniform Renderer *uniform self, setRGBAZ(tile,pixel,col,screenSample.alpha,screenSample.z); } } else { - if (fb->accumID >= 0) { - pixel_du = precomputedHalton2(fb->accumID); - pixel_dv = precomputedHalton3(fb->accumID); + if (tile.accumID >= 0) { + pixel_du = precomputedHalton2(tile.accumID); + pixel_dv = precomputedHalton3(tile.accumID); } ScreenSample screenSample; - screenSample.sampleID.z = fb->accumID; + screenSample.sampleID.z = tile.accumID; screenSample.z = inf; screenSample.alpha = 0.f; CameraSample cameraSample; - const uniform int blocks = fb->accumID > 0 || spp > 0 ? 1 : min(1 << -2 * spp, TILE_SIZE*TILE_SIZE); + const uniform int blocks = tile.accumID > 0 + || spp > 0 ? 1 : min(1 << -2 * spp, + TILE_SIZE*TILE_SIZE); const uniform int begin = taskIndex * RENDERTILE_PIXELS_PER_JOB; - const uniform int end = min(begin + RENDERTILE_PIXELS_PER_JOB, TILE_SIZE*TILE_SIZE/blocks); + const uniform int end = min(begin + RENDERTILE_PIXELS_PER_JOB, + TILE_SIZE*TILE_SIZE/blocks); - for (uint32 i=begin+programIndex;i= fb->size.x) | (screenSample.sampleID.y >= fb->size.y)) { continue; } - cameraSample.screen.x = (screenSample.sampleID.x + pixel_du) * fb->rcpSize.x; - cameraSample.screen.y = (screenSample.sampleID.y + pixel_dv) * fb->rcpSize.y; + cameraSample.screen.x = (screenSample.sampleID.x + pixel_du) + * fb->rcpSize.x; + cameraSample.screen.y = (screenSample.sampleID.y + pixel_dv) + * fb->rcpSize.y; camera->initRay(camera,screenSample.ray,cameraSample); - // set ray t value for early ray termination if we have a maximum depth texture + // set ray t value for early ray termination if we have a maximum depth + // texture if (self->maxDepthTexture) { // always sample center of pixel vec2f depthTexCoord; @@ -164,7 +169,8 @@ void Renderer_default_renderTileJob(uniform Renderer *uniform self, self->renderSample(self,perFrameData,screenSample); for (uniform int p = 0; p < blocks; p++) { - const uint32 pixel = z_order.xs[i*blocks+p] + (z_order.ys[i*blocks+p] * TILE_SIZE); + const uint32 pixel = z_order.xs[i*blocks+p] + + (z_order.ys[i*blocks+p] * TILE_SIZE); assert(pixel < TILE_SIZE*TILE_SIZE); setRGBAZ(tile,pixel,screenSample.rgb,screenSample.alpha,screenSample.z); } @@ -183,7 +189,7 @@ void Renderer_Constructor(uniform Renderer *uniform self, self->backgroundEnabled = true; self->maxDepthTexture = NULL; self->renderSample = Renderer_default_renderSample; - self->renderTile = Renderer_default_renderTileJob; + self->renderTile = Renderer_default_renderTile; self->beginFrame = Renderer_default_beginFrame; self->endFrame = Renderer_default_endFrame; self->toneMap = NULL; @@ -220,11 +226,10 @@ export void *uniform Renderer_beginFrame(void *uniform _self, export void Renderer_endFrame(void *uniform _self, - void *uniform perFrameData, - const uniform int32 newAccumID) + void *uniform perFrameData) { uniform Renderer *uniform self = (uniform Renderer *uniform)_self; - self->endFrame(self,perFrameData,newAccumID); + self->endFrame(self, perFrameData); } export void Renderer_set(void *uniform _self, diff --git a/ospray/render/obj/OBJMaterial.cpp b/ospray/render/obj/OBJMaterial.cpp deleted file mode 100644 index 2f2b4ce8cc..0000000000 --- a/ospray/render/obj/OBJMaterial.cpp +++ /dev/null @@ -1,56 +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. // -// ======================================================================== // - -#include "OBJMaterial.h" -#include "OBJMaterial_ispc.h" -#include "ospray/common/Data.h" - -namespace ospray { - namespace obj { - - //! \brief commit the material's parameters - void OBJMaterial::commit() - { - if (ispcEquivalent == NULL) - ispcEquivalent = ispc::OBJMaterial_create(this); - - map_d = (Texture2D*)getParamObject("map_d", NULL); - map_Kd = (Texture2D*)getParamObject("map_Kd", getParamObject("map_kd", NULL)); - map_Ks = (Texture2D*)getParamObject("map_Ks", getParamObject("map_ks", NULL)); - map_Ns = (Texture2D*)getParamObject("map_Ns", getParamObject("map_ns", NULL)); - map_Bump = (Texture2D*)getParamObject("map_Bump", getParamObject("map_bump", NULL)); - - d = getParam1f("d", 1.f); - Kd = getParam3f("kd", getParam3f("Kd", vec3f(.8f))); - Ks = getParam3f("ks", getParam3f("Ks", vec3f(0.f))); - Ns = getParam1f("ns", getParam1f("Ns", 10.f)); - - ispc::OBJMaterial_set(getIE(), - map_d ? map_d->getIE() : NULL, - d, - map_Kd ? map_Kd->getIE() : NULL, - (ispc::vec3f&)Kd, - map_Ks ? map_Ks->getIE() : NULL, - (ispc::vec3f&)Ks, - map_Ns ? map_Ns->getIE() : NULL, - Ns, - map_Bump != NULL ? map_Bump->getIE() : NULL ); - } - - OSP_REGISTER_MATERIAL(OBJMaterial,OBJMaterial); - - } // ::ospray::obj -} // ::ospray diff --git a/ospray/render/obj/OBJMaterial.ispc b/ospray/render/obj/OBJMaterial.ispc deleted file mode 100644 index 6583367b31..0000000000 --- a/ospray/render/obj/OBJMaterial.ispc +++ /dev/null @@ -1,47 +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. // -// ======================================================================== // - -#include "OBJMaterial.ih" - -export void *uniform OBJMaterial_create(void *uniform cppE) -{ - uniform OBJMaterial *uniform mat = uniform new uniform OBJMaterial; - mat->super.cppEquivalent = cppE; - return mat; -} - -export void OBJMaterial_set(void *uniform _mat, - const void *uniform map_d, - const uniform float &d, - const void *uniform map_Kd, - const uniform vec3f &Kd, - const void *uniform map_Ks, - const uniform vec3f &Ks, - const void *uniform map_Ns, - const uniform float &Ns, - const void *uniform map_Bump) -{ - uniform OBJMaterial *uniform self = (uniform OBJMaterial *uniform)_mat; - self->map_d = (uniform Texture2D *uniform)map_d; - self->d = d; - self->map_Kd = (uniform Texture2D *uniform)map_Kd; - self->Kd = Kd; - self->map_Ks = (uniform Texture2D *uniform)map_Ks; - self->Ks = Ks; - self->map_Ns = (uniform Texture2D *uniform)map_Ns; - self->Ns = Ns; - self->map_Bump = (uniform Texture2D *uniform)map_Bump; -} diff --git a/ospray/render/obj/OBJRenderer.cpp b/ospray/render/obj/OBJRenderer.cpp deleted file mode 100644 index edad8307b7..0000000000 --- a/ospray/render/obj/OBJRenderer.cpp +++ /dev/null @@ -1,71 +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. // -// ======================================================================== // - -// obj -#include "OBJRenderer.h" -#include "OBJMaterial.h" -// ospray -#include "ospray/common/Data.h" -#include "ospray/lights/Light.h" -//sys -#include -// ispc exports -#include "OBJRenderer_ispc.h" - -namespace ospray { - namespace obj { - - void OBJRenderer::commit() - { - Renderer::commit(); - - lightData = (Data*)getParamData("lights"); - - lightArray.clear(); - - if (lightData) - for (int i = 0; i < lightData->size(); i++) - lightArray.push_back(((Light**)lightData->data)[i]->getIE()); - - void **lightPtr = lightArray.empty() ? NULL : &lightArray[0]; - - vec3f bgColor; - bgColor = getParam3f("bgColor", vec3f(1.f)); - - const bool shadowsEnabled = bool(getParam1i("shadowsEnabled", 1)); - - ispc::OBJRenderer_set(getIE(), - (ispc::vec3f&)bgColor, - shadowsEnabled, - lightPtr, lightArray.size()); - } - - OBJRenderer::OBJRenderer() - { - ispcEquivalent = ispc::OBJRenderer_create(this); - } - - /*! \brief create a material of given type */ - Material *OBJRenderer::createMaterial(const char *type) - { - Material *mat = new OBJMaterial; - return mat; - } - - OSP_REGISTER_RENDERER(OBJRenderer,OBJ); - OSP_REGISTER_RENDERER(OBJRenderer,obj); - } // ::ospray::obj -} // ::ospray diff --git a/ospray/render/obj/OBJRenderer.h b/ospray/render/obj/OBJRenderer.h deleted file mode 100644 index 71e6ba9fd4..0000000000 --- a/ospray/render/obj/OBJRenderer.h +++ /dev/null @@ -1,65 +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 - -/*! \defgroup ospray_render_obj "Wavefront OBJ" Material-based Renderer - - \brief Implements the Wavefront OBJ Material Model - - \ingroup ospray_supported_renderers - - This renderer implementes a shading model roughly based on the - Wavefront OBJ material format. In particular, this renderer - implements the Material model as implemented in \ref - ospray::OBJMaterial, and implements a recursive ray tracer on top of - this mateiral model. - - Note that this renderer is NOT fully compatible with the Wavefront - OBJ specifications - in particular, we do not support the different - illumination models as specified in the 'illum' field, and always - perform full ray tracing with the given material parameters. - -*/ - -// ospray -#include "ospray/render/Renderer.h" -#include "ospray/common/Material.h" - -// system -#include - -namespace ospray { - - namespace obj { - - /*! \brief Renderer for the OBJ Wavefront Material/Lighting format - - See \ref ospray_render_obj - */ - struct OBJRenderer : public Renderer { - OBJRenderer(); - virtual std::string toString() const { return "ospray::OBJRenderer"; } - virtual void commit(); - virtual Material *createMaterial(const char *type); - - std::vector lightArray; // the 'IE's of the XXXLights - Data *lightData; - }; - - } // ::ospray::api -} // ::ospray - diff --git a/ospray/render/obj/OBJRenderer.ispc b/ospray/render/obj/OBJRenderer.ispc deleted file mode 100644 index 774832e2ff..0000000000 --- a/ospray/render/obj/OBJRenderer.ispc +++ /dev/null @@ -1,246 +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. // -// ======================================================================== // - -// ospray -#include "ospray/fb/FrameBuffer.ih" -#include "ospray/render/util.ih" -#include "ospray/common/Model.ih" -#include "ospray/texture/Texture2D.ih" -#include "ospray/lights/Light.ih" -#include "ospray/render/Renderer.ih" -// obj renderer -#include "OBJMaterial.ih" - -#define ALPHA_THRESHOLD (.05f) - -struct OBJRenderer { - Renderer super; - - const uniform Light *uniform *uniform lights; - uint32 numLights; - - vec3f bgColor; - bool shadowsEnabled; -}; - -inline float lightAlpha(Ray &ray, uniform Model *uniform model, const float weight, const uniform float epsilon) -{ - float alpha = 1.f; - int max_depth = 8; - 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 OBJMaterial *objMaterial = (uniform OBJMaterial *)dg.material; - - float material_opacity = 1.f; - - if(objMaterial == NULL) { - material_opacity = dg.color.w; - } else { - foreach_unique( mat in objMaterial ) { - 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 (--max_depth <= 0) - return 0.f; - - ray.t0 = ray.t + epsilon; - ray.t = org_t_max; - ray.primID = -1; - ray.geomID = -1; - ray.instID = -1; - } -} - -inline void OBJRenderer_shadeRay(const uniform OBJRenderer *uniform self, varying ScreenSample &sample) -{ - Ray &ray = sample.ray; - // ISPC issue #703. Switch to 'nice' code once ISPC #703 is fixed. - // print("ray.dir % % %\n",ray.dir.x,ray.dir.y,ray.dir.z); - vec3f color = make_vec3f(0.f); - float path_opacity = 1.f; - int max_depth = 10; - uniform int depth = 0; - bool depthGotSet = 0; - - sample.z = infinity; - while (1) { - traceRay(self->super.model,ray); - - if (ray.geomID < 0) { - sample.rgb = self->super.backgroundEnabled ? color + path_opacity * self->bgColor : color; - sample.alpha = self->super.backgroundEnabled ? 1.f : 1.f - path_opacity; - sample.z = 1; - return; - } - - vec3f local_shade_color = make_vec3f(0.f); - - DifferentialGeometry dg; - postIntersect(self->super.model, - dg, - ray, - DG_NG|DG_NS|DG_NORMALIZE|DG_FACEFORWARD|DG_MATERIALID|DG_COLOR|DG_TEXCOORD); - - uniform Material *material = dg.material; - uniform OBJMaterial *objMaterial = (uniform OBJMaterial *)material; - - float d = 1.f; - float Ns = 0.f; - vec3f Kd = make_vec3f(0.f,1.f,0.f); - vec3f Ks = make_vec3f(0.f); -// vec3f bump = make_vec3f(0.f); // not yet supported - - if (!objMaterial) { - //color = color + path_opacity * make_vec3f(dg.color); - //return color; - d = dg.color.w; - Kd = make_vec3f(dg.color); - } else { - foreach_unique (mat in objMaterial) { - // textures modify (mul) values, see http://paulbourke.net/dataformats/mtl/ - d = mat->d * get1f(mat->map_d, dg.st, 1.f); - Kd = mat->Kd * make_vec3f(dg.color); - if (mat->map_Kd) { - vec4f Kd_from_map = get4f(mat->map_Kd,dg.st); - Kd = Kd * make_vec3f(Kd_from_map); - d *= Kd_from_map.w; - } - Ks = mat->Ks * get3f(mat->map_Ks, dg.st, make_vec3f(1.f)); - Ns = mat->Ns * get1f(mat->map_Ns, dg.st, 1.f); -// bump = get3f(mat->map_Bump, dg.st, make_vec3f(0.f)); - } - } - - if (d >= .5 && !depthGotSet) { - sample.z = ray.t; - depthGotSet = true; - } - - const float local_opacity = path_opacity * d; - - max_depth -= 1; - if (max_depth <= 0) { - sample.rgb = color; - sample.alpha = 1.f - path_opacity; - return; - } - - if (local_opacity > 0.01f) { // worth shading? - const vec3f R = ray.dir - (2.f * dot(ray.dir, dg.Ns))*dg.Ns; - const vec3f P = dg.P + self->super.epsilon * dg.Ng; - - //Some fake hard coded ambient light - color = color + local_opacity * Kd * .05; - - //calculate shading for all lights - for (uniform int i = 0; self->lights && i < self->numLights; i++) { - const uniform Light *uniform l = self->lights[i]; - const vec2f s = make_vec2f(0.f); - const LightSample light = l->sample(l, dg, s); - - if (reduce_max(light.radiance) > 0.f) { // any potential contribution? - const float cosNL = abs(dot(light.direction, dg.Ns)); - const float cosLR = max(0.f, dot(light.direction, R)); - const vec3f unshaded_light_contrib = local_opacity * (Kd * cosNL + Ks * powf(cosLR, Ns)) * light.radiance; - - if (self->shadowsEnabled) { - const float max_contrib = reduce_max(unshaded_light_contrib); - if (max_contrib > .01f) { - Ray shadowRay; - setRay(shadowRay, P, light.direction); - const float light_alpha = lightAlpha(shadowRay, self->super.model, max_contrib, self->super.epsilon); - local_shade_color = local_shade_color + light_alpha * unshaded_light_contrib; - } - } else - local_shade_color = local_shade_color + unshaded_light_contrib; - } - } - - color = color + local_shade_color; - } - - path_opacity = path_opacity * (1.f - d); - if (path_opacity < 0.01f) { - //remaining contribution too low kill path - sample.rgb = color; - sample.alpha = 1.f - path_opacity; - return; - } - - ray.t0 = ray.t + self->super.epsilon; - ray.t = infinity; - ray.primID = -1; - ray.geomID = -1; - ray.instID = -1; - } - - sample.rgb = color; - sample.alpha = 1.f - path_opacity; - return; -} - -void OBJRenderer_renderSample(uniform Renderer *uniform _self, - void *uniform perFrameData, - varying ScreenSample &sample) -{ - uniform OBJRenderer *uniform self = (uniform OBJRenderer *uniform)_self; - OBJRenderer_shadeRay(self, sample); -} - - -// Exports (called from C++) -////////////////////////////////////////////////////////////////////////////// - -export void OBJRenderer_set(void *uniform _self, - const uniform vec3f &bgColor, - const uniform bool shadowsEnabled, - void **uniform lights, - const uniform uint32 numLights) -{ - uniform OBJRenderer *uniform self = (uniform OBJRenderer *uniform)_self; - - self->bgColor = bgColor; - self->shadowsEnabled = shadowsEnabled; - self->lights = (const uniform Light *uniform *uniform)lights; - self->numLights = numLights; -} - -export void *uniform OBJRenderer_create(void *uniform cppE) -{ - uniform OBJRenderer *uniform self = uniform new uniform OBJRenderer; - Renderer_Constructor(&self->super,cppE); - self->super.renderSample = OBJRenderer_renderSample; - OBJRenderer_set(self, make_vec3f(1.f), true, NULL, 0); - - return self; -} diff --git a/ospray/render/pathtracer/PathTracer.cpp b/ospray/render/pathtracer/PathTracer.cpp index a13a30c9ab..2af527299c 100644 --- a/ospray/render/pathtracer/PathTracer.cpp +++ b/ospray/render/pathtracer/PathTracer.cpp @@ -66,9 +66,10 @@ namespace ospray { const int32 maxDepth = getParam1i("maxDepth", 20); const float minContribution = getParam1f("minContribution", 0.01f); + const float maxRadiance = getParam1f("maxContribution", getParam1f("maxRadiance", inf)); Texture2D *backplate = (Texture2D*)getParamObject("backplate", NULL); - ispc::PathTracer_set(getIE(), maxDepth, minContribution, + ispc::PathTracer_set(getIE(), maxDepth, minContribution, maxRadiance, backplate ? backplate->getIE() : NULL, lightPtr, lightArray.size()); } diff --git a/ospray/render/pathtracer/PathTracer.ih b/ospray/render/pathtracer/PathTracer.ih index 6da3584a22..61ebcf7e44 100644 --- a/ospray/render/pathtracer/PathTracer.ih +++ b/ospray/render/pathtracer/PathTracer.ih @@ -30,6 +30,7 @@ struct PathTracer { int32 maxDepth; float minContribution; + float maxRadiance; Texture2D* uniform backplate; const uniform Light *uniform *uniform lights; diff --git a/ospray/render/pathtracer/PathTracer.ispc b/ospray/render/pathtracer/PathTracer.ispc index 14242abc72..7ae21ce5c9 100644 --- a/ospray/render/pathtracer/PathTracer.ispc +++ b/ospray/render/pathtracer/PathTracer.ispc @@ -20,61 +20,27 @@ #include "materials/Medium.ih" #include "materials/Material.ih" #include "math/random.ih" +#include "fb/LocalFB.ih" #define PDF_CULLING 0.0f //#define USE_DGCOLOR -////////////////////////////////////////////////////////////////// -// LightPath -struct LightPath +inline float misHeuristic(float pdf1, float pdf2) { - Ray ray; /*! Last ray in the path. */ - Medium lastMedium; /*! Medium the last ray travels inside. */ - uniform uint32 depth; /*! Recursion depth of path. */ - vec3f throughput; /*! Determines the fraction of - radiance reaches the pixel along - the path. */ - bool ignoreVisibleLights; /*! If the previous shade point used - shadow rays we have to ignore the - emission of geometrical lights to - not double count them. */ - bool unbent; /*! True of the ray path is a straight line. */ -}; - -inline void init_LightPath(LightPath& lp, const Ray &ray) -{ - lp.ray = ray; - lp.lastMedium = make_Medium_Vacuum(); - lp.depth = 0; - lp.throughput = make_vec3f(1.f); - lp.ignoreVisibleLights = false; - lp.unbent = true; + // power heuristic with beta=2 + const float p = sqr(pdf1) * rcp(sqr(pdf1) + sqr(pdf2)); + // guard against high pdf (including Dirac delta) + // using the limit when pdf1 approaches inf + // compare with bit less than sqrt(float_max) (when sqr starts to overflow) + return pdf1 > 1e17f ? 1.0f : p; } -inline void extend_fast(LightPath& lp, - const vec3f nextRay_org, - const vec3f nextRay_dir, - const float nextRay_near, - const float nextRay_far, - const vec3f weight, - const bool ignoreVL) -{ - lp.unbent = lp.unbent & eq(nextRay_dir,lp.ray.dir); - setRay(lp.ray,nextRay_org,nextRay_dir,nextRay_near,nextRay_far); - lp.depth = lp.depth+1; - lp.throughput = mul(lp.throughput,weight); - lp.ignoreVisibleLights = ignoreVL; -} - -////////////////////////////////////////////////////////////////// -// PathTracer - +// TODO use intersection filters vec3f transparentShadow(const uniform PathTracer* uniform self, vec3f lightContrib, Ray &shadowRay, - Medium medium, - varying RandomTEA* uniform rng) + Medium medium) { int max_depth = self->maxDepth; const float org_t_max = shadowRay.t; @@ -125,166 +91,164 @@ vec3f transparentShadow(const uniform PathTracer* uniform self, ScreenSample PathTraceIntegrator_Li(const uniform PathTracer* uniform self, const vec2f &pixel, // normalized, i.e. in [0..1] - LightPath &lightPath, + Ray &ray, varying RandomTEA* uniform rng) { - uniform uint32/*BRDFType*/ directLightingBSDFTypes = (uniform uint32)(BSDF_DIFFUSE | BSDF_GLOSSY); - ScreenSample sample; sample.alpha = 1.f; - vec3f L = make_vec3f(0.f); - vec3f Lw = make_vec3f(1.f); + + vec3f L = make_vec3f(0.f); // accumulated radiance + vec3f Lw = make_vec3f(1.f); // path throughput + Medium currentMedium = make_Medium_vacuum(); + float lastBSDFPdf = inf; // probability density of previous sampled BSDF, for MIS + bool straightPath = true; // path from camera did not change direction, for alpha and backplate + uniform uint32 depth = 0; + // geometric configuration of last surface interaction + DifferentialGeometry lastDg; + // P and N also used by light eval + lastDg.P = ray.org; + lastDg.Ns = ray.dir; + lastDg.Ng = ray.dir; do { - /*! Traverse ray. */ - traceRay(self->super.model, lightPath.ray); + traceRay(self->super.model, ray); - if (lightPath.depth == 0) - sample.z = lightPath.ray.t; + // record depth of primary rays + if (depth == 0) + sample.z = ray.t; - const vec3f wo = neg(lightPath.ray.dir); + const vec3f wo = neg(ray.dir); - /*! Environment shading when nothing hit. */ - if (noHit(lightPath.ray)) { - if (lightPath.unbent) + float maxLightDist = ray.t; // per default virtual lights are occluded by hit geometry + + // environment shading when nothing hit + if (noHit(ray)) { + maxLightDist = inf; // also include envLights (i.e. the ones in infinity) + if (straightPath) sample.alpha = 1.0f - luminance(Lw); - if ((bool)self->backplate & lightPath.unbent) { + if ((bool)self->backplate & straightPath) { L = L + Lw * get3f(self->backplate, clamp2edge(self->backplate, pixel)); - } else if (!lightPath.ignoreVisibleLights) - for (uniform int i = 0; i < self->numLights; i++) { // TODO: self->num_envLights - const uniform Light *uniform l = self->lights[i]; - L = L + Lw * l->evalEnv(l, lightPath.ray.dir); - } + maxLightDist = 1e38; // backplate hides envLights (i.e. the ones in infinity) + } + } - break; + // 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) + L = L + Lw * le.value * misHeuristic(lastBSDFPdf, le.pdf); } + if (noHit(ray)) + break; + + // terminate after evaluation of lights and before next shading to always have both samples for MIS + if (depth >= self->maxDepth) + break; + + //////////////////////////////////// + // handle next surface interaction DifferentialGeometry dg; - postIntersect(self->super.model, dg, lightPath.ray, + postIntersect(self->super.model, dg, ray, DG_MATERIALID| DG_NS|DG_NG|DG_FACEFORWARD|DG_NORMALIZE|DG_TEXCOORD|DG_COLOR|DG_TANGENTS ); - /*! Shade surface. */ + // shade surface uniform ShadingContext ctx; ShadingContext_Constructor(&ctx); const varying BSDF* bsdf = NULL; -#if 1 + uniform PathTraceMaterial* m = (uniform PathTraceMaterial*)dg.material; foreach_unique(mm in m) if (mm != NULL) - bsdf = mm->getBSDF(mm, &ctx, dg, lightPath.ray, lightPath.lastMedium); -#else - foreach_unique(geomID in lightPath.ray.geomID) { - uniform PathTraceMaterial* uniform m - = (uniform PathTraceMaterial*)(self->super.model->geometry[geomID]->material); - print("shading %\n",m); - if (m != NULL) m->shade(m,lightPath.ray, lightPath.lastMedium, dg, brdfs, Ns); - } -#endif - -#if 0 - // iw: disabled because we dont' have per-geometry lights yet - /*! Add light emitted by hit area light source. */ - if (!lightPath.ignoreVisibleLights) { - foreach_unique(geomID in lightPath.ray.geomID) { - const uniform AreaLight* uniform l = self->super.model->geometry[geomID]->light; - if (l != NULL) - // L = add(L, mul(Lw, l->Le(l,dg,wo))); - L = L + Lw * l->Le(l,dg,wo); - } - } -#endif + bsdf = mm->getBSDF(mm, &ctx, dg, ray, currentMedium); - /*! Check if any BSDF component uses direct lighting. */ - bool useDirectLighting = bsdf->type & directLightingBSDFTypes; - - /*! Direct lighting. Shoot shadow rays to all light sources. */ - if (useDirectLighting) + // direct lighting including shadows and MIS + if (bsdf->type & BSDF_SMOOTH) { uniform int numLights = self->lights ? min(MAX_LIGHTS, self->numLights) : 0; for (uniform int i = 0; i < numLights; i++) { const uniform Light *uniform light = self->lights[i]; - /*! Either use precomputed samples for the light or sample light now. */ - LightSample ls = light->sample(light, dg, RandomTEA__getFloats(rng)); + Light_SampleRes ls = light->sample(light, dg, RandomTEA__getFloats(rng)); - /*! Ignore zero radiance or illumination from the back. */ - if (reduce_max(ls.radiance) <= 0.0f | ls.pdf <= PDF_CULLING) //| dot(dg.Ns, ls.direction) <= 1e-8f) + // skip when zero contribution from light + if (reduce_max(ls.weight) <= 0.0f | ls.pdf <= PDF_CULLING) continue; - /*! Evaluate BSDF */ - vec3f bsdfValue; - float lsDirectionPdf; - foreach_unique(b in bsdf) - if (b != NULL) - bsdfValue = b->eval(b, wo, ls.direction, lsDirectionPdf); + // evaluate BSDF + BSDF_EvalRes fe; + foreach_unique(f in bsdf) + if (f != NULL) + fe = f->eval(f, wo, ls.dir); #ifdef USE_DGCOLOR - bsdfValue = bsdfValue * make_vec3f(dg.color); + fe.value = fe.value * make_vec3f(dg.color); #endif - if (reduce_max(bsdfValue) <= 0.0f) + // skip when zero contribution from material + if (reduce_max(fe.value) <= 0.0f) continue; - /*! Test for shadows. */ + // test for shadows Ray shadow_ray; - setRay(shadow_ray, dg.P, ls.direction, - //dg.error* - self->super.epsilon, ls.distance- - //dg.error* - self->super.epsilon); - shadow_ray.time = lightPath.ray.time; - - vec3f unshaded_light_contrib = Lw * ls.radiance * bsdfValue; - L = L + transparentShadow(self, unshaded_light_contrib, shadow_ray, lightPath.lastMedium, rng); + setRay(shadow_ray, dg.P, ls.dir, + self->super.epsilon, ls.dist - self->super.epsilon); + shadow_ray.time = ray.time; + + const vec3f unshaded_light_contrib = Lw * ls.weight * fe.value * misHeuristic(ls.pdf, fe.pdf); + L = L + transparentShadow(self, unshaded_light_contrib, shadow_ray, currentMedium); } } - /*! Global illumination. Pick one BSDF component and sample it. */ - if (lightPath.depth >= self->maxDepth) - break; - - /*! sample brdf */ - Sample3f wi = make_Sample3f(make_vec3f(0.0f),0.0f); uint32 type = 0; + // sample BSDF vec2f s = RandomTEA__getFloats(rng); vec2f ss = RandomTEA__getFloats(rng); // FIXME: should be only one component - vec3f bsdfWeight; - foreach_unique(b in bsdf) - if (b != NULL) - bsdfWeight = b->sample(b, wo, wi.v, wi.pdf, type, s, ss.x); + BSDF_SampleRes fs; + foreach_unique(f in bsdf) + if (f != NULL) + fs = f->sample(f, wo, s, ss.x); #ifdef USE_DGCOLOR if ((type & GLOSSY_REFLECTION) == NONE) // only colorize diffuse component - bsdfWeight = bsdfWeight * make_vec3f(dg.color); + fs.weight = fs.weight * make_vec3f(dg.color); #endif - /*! Continue only if we hit something valid. */ - if (reduce_max(bsdfWeight) <= 0.0f | wi.pdf <= PDF_CULLING) + // terminate path when zero contribution from material + if (reduce_max(fs.weight) <= 0.0f | fs.pdf <= PDF_CULLING) break; - /*! Compute simple volumetric effect. */ - const vec3f transmission = lightPath.lastMedium.transmission; + Lw = Lw * fs.weight; + + // compute simple volumetric effect + const vec3f transmission = currentMedium.transmission; if (ne(transmission,make_vec3f(1.f))) - bsdfWeight = bsdfWeight * powf(transmission,lightPath.ray.t); + Lw = Lw * powf(transmission, ray.t); - /*! Tracking medium if we hit a medium interface. */ - if (type & BSDF_TRANSMISSION) { + // update currentMedium if we hit a medium interface TODO: support nested dielectrics + if (fs.type & BSDF_TRANSMISSION) { foreach_unique(uniMat in dg.material) { uniform PathTraceMaterial* uniform m = (uniform PathTraceMaterial *)uniMat; - if (m != NULL) m->selectNextMedium(m,lightPath.lastMedium); + if (m != NULL) + m->selectNextMedium(m, currentMedium); } } - /*! Continue the path. */ - extend_fast(lightPath, - dg.P,wi.v,//dg.error* - self->super.epsilon,inf, - bsdfWeight*wi.pdf,(type & directLightingBSDFTypes) != BSDF_NONE); + // keep lastBSDFPdf and lastDg when there was a Dirac transmission + // to better combine MIS with transparent shadows + if (fs.type & ~BSDF_SPECULAR_TRANSMISSION) { + lastBSDFPdf = fs.pdf; + lastDg = dg; + } - Lw = Lw * bsdfWeight; - } while (reduce_max(lightPath.throughput) > self->minContribution); + // continue the path + straightPath &= eq(ray.dir, fs.wi); + setRay(ray, dg.P, fs.wi, self->super.epsilon, inf); + depth++; + } while (reduce_max(Lw) > self->minContribution); sample.rgb = L; return sample; @@ -293,7 +257,8 @@ ScreenSample PathTraceIntegrator_Li(const uniform PathTracer* uniform self, inline ScreenSample PathTracer_renderPixel(uniform PathTracer *uniform self, const uint32 ix, - const uint32 iy) + const uint32 iy, + const uint32 accumID) { uniform FrameBuffer *uniform fb = self->super.fb; @@ -308,11 +273,11 @@ inline ScreenSample PathTracer_renderPixel(uniform PathTracer *uniform self, // init RNG RandomTEA rng_state; varying RandomTEA* const uniform rng = &rng_state; - RandomTEA__Constructor(rng, fb->size.x*iy+ix, fb->accumID); + RandomTEA__Constructor(rng, fb->size.x*iy+ix, accumID); const int spp = max(1, self->super.spp); for (uniform int s=0; s < spp; s++) { - screenSample.sampleID.z = fb->accumID*spp + s; + screenSample.sampleID.z = accumID*spp + s; CameraSample cameraSample; const vec2f pixelSample = RandomTEA__getFloats(rng); @@ -324,12 +289,9 @@ inline ScreenSample PathTracer_renderPixel(uniform PathTracer *uniform self, const vec2f timeSample = RandomTEA__getFloats(rng); screenSample.ray.time = timeSample.x; - LightPath lightPath; - init_LightPath(lightPath, screenSample.ray); - ScreenSample sample = PathTraceIntegrator_Li(self, cameraSample.screen, - lightPath, rng); - screenSample.rgb = screenSample.rgb + sample.rgb; + screenSample.ray, rng); + screenSample.rgb = screenSample.rgb + min(sample.rgb, make_vec3f(self->maxRadiance)); screenSample.alpha = screenSample.alpha + sample.alpha; screenSample.z = min(screenSample.z, sample.z); } @@ -342,7 +304,7 @@ inline ScreenSample PathTracer_renderPixel(uniform PathTracer *uniform self, -void *uniform PathTracer_beginFrame(uniform Renderer *uniform _self, +unmasked void *uniform PathTracer_beginFrame(uniform Renderer *uniform _self, uniform FrameBuffer *uniform fb) { _self->fb = fb; @@ -355,10 +317,10 @@ void PathTracer_renderTileJob(uniform PathTracer *uniform self, uniform Tile &tile, uniform int taskIndex) { - uniform FrameBuffer *uniform fb = self->super.fb; - uniform int32 spp = self->super.spp; + uniform FrameBuffer *uniform fb = self->super.fb; - const uniform int blocks = fb->accumID > 0 || spp > 0 ? + uniform int32 spp = self->super.spp; + const uniform int blocks = tile.accumID > 0 || spp > 0 ? 1 : min(1 << -2 * spp, TILE_SIZE*TILE_SIZE); const uniform int begin = taskIndex * RENDERTILE_PIXELS_PER_JOB; @@ -370,7 +332,7 @@ void PathTracer_renderTileJob(uniform PathTracer *uniform self, if (ix >= fb->size.x || iy >= fb->size.y) continue; - ScreenSample screenSample = PathTracer_renderPixel(self, ix, iy); + ScreenSample screenSample = PathTracer_renderPixel(self, ix, iy, tile.accumID); for (uniform int p = 0; p < blocks; p++) { const uint32 pixel = z_order.xs[i*blocks+p] + (z_order.ys[i*blocks+p] * TILE_SIZE); @@ -379,7 +341,7 @@ void PathTracer_renderTileJob(uniform PathTracer *uniform self, } } -void PathTracer_renderTile(uniform Renderer *uniform _self, +unmasked void PathTracer_renderTile(uniform Renderer *uniform _self, void *uniform perFrameData, uniform Tile &tile, uniform int jobID) @@ -396,6 +358,7 @@ void PathTracer_renderTile(uniform Renderer *uniform _self, export void PathTracer_set(void *uniform _self, const uniform int32 maxDepth, const uniform float minContribution, + const uniform float maxRadiance, void *uniform backplate, void **uniform lights, const uniform uint32 numLights) @@ -404,6 +367,7 @@ export void PathTracer_set(void *uniform _self, self->maxDepth = maxDepth; self->minContribution = minContribution; + self->maxRadiance = maxRadiance; self->backplate = (uniform Texture2D *uniform)backplate; self->lights = (const uniform Light *uniform *uniform)lights; self->numLights = numLights; @@ -416,7 +380,7 @@ export void* uniform PathTracer_create(void *uniform cppE) self->super.renderTile = PathTracer_renderTile; self->super.beginFrame = PathTracer_beginFrame; - PathTracer_set(self, 20, 0.01f, NULL, NULL, 0); + PathTracer_set(self, 20, 0.01f, inf, NULL, NULL, 0); precomputeZOrder(); diff --git a/ospray/render/pathtracer/bsdfs/BSDF.ih b/ospray/render/pathtracer/bsdfs/BSDF.ih index b2d7569d7f..c374f51c0c 100644 --- a/ospray/render/pathtracer/bsdfs/BSDF.ih +++ b/ospray/render/pathtracer/bsdfs/BSDF.ih @@ -42,6 +42,9 @@ /*! all possible transmissions */ #define BSDF_TRANSMISSION (BSDF_DIFFUSE_TRANSMISSION | BSDF_GLOSSY_TRANSMISSION | BSDF_SPECULAR_TRANSMISSION) +/*! all non-dirac types */ +#define BSDF_SMOOTH (BSDF_DIFFUSE | BSDF_GLOSSY) + /*! no component set */ #define BSDF_NONE 0 @@ -50,27 +53,53 @@ struct BSDF; -typedef uint32 BSDFType; +typedef uint32 BSDF_Type; + +struct BSDF_EvalRes +{ + vec3f value; //!< radiance multiplied by dot(wi,N) + float pdf; +}; + +inline BSDF_EvalRes make_BSDF_EvalRes_zero() +{ + BSDF_EvalRes res; + res.value = make_vec3f(0.0f); + res.pdf = 0.0f; + return res; +} -/*! Result is multiplied by dot(wi,N). */ -typedef vec3f (*BSDF_EvalFunc)(const varying BSDF* uniform super, - const vec3f& wo, const vec3f& wi, float& pdf); +typedef BSDF_EvalRes (*BSDF_EvalFunc)(const varying BSDF* uniform self, + const vec3f& wo, const vec3f& wi); + +struct BSDF_SampleRes +{ + vec3f weight; //!< radiance multiplied by dot(wi,N)/pdf + vec3f wi; + float pdf; + BSDF_Type type; +}; + +inline BSDF_SampleRes make_BSDF_SampleRes_zero() +{ + BSDF_SampleRes res; + res.weight = make_vec3f(0.0f); + return res; +} -/*! Result is multiplied by dot(wi,N)/pdf. */ -typedef vec3f (*BSDF_SampleFunc)(const varying BSDF* uniform super, - const vec3f& wo, vec3f& wi, float& pdf, BSDFType& type, - const vec2f& s, float ss); +typedef BSDF_SampleRes (*BSDF_SampleFunc)(const varying BSDF* uniform self, + const vec3f& wo, const vec2f& s, float ss); struct BSDF { - uniform BSDFType type; + uniform BSDF_Type type; uniform BSDF_EvalFunc eval; uniform BSDF_SampleFunc sample; const varying linear3f* uniform frame; }; inline void BSDF_Constructor(varying BSDF* uniform self, - uniform BSDFType type, + uniform BSDF_Type type, uniform BSDF_EvalFunc eval, uniform BSDF_SampleFunc sample, const varying linear3f* uniform frame) diff --git a/ospray/render/pathtracer/bsdfs/Conductor.ih b/ospray/render/pathtracer/bsdfs/Conductor.ih index 45df2305e3..a8425de7b6 100644 --- a/ospray/render/pathtracer/bsdfs/Conductor.ih +++ b/ospray/render/pathtracer/bsdfs/Conductor.ih @@ -27,21 +27,22 @@ struct Conductor vec3f k; //!< imaginary part of refraction index }; -inline vec3f Conductor_eval(const varying BSDF* uniform super, - const vec3f& wo, const vec3f& wi, float& pdf) +inline BSDF_EvalRes Conductor_eval(const varying BSDF* uniform super, + const vec3f& wo, const vec3f& wi) { - return make_vec3f(0.0f); + return make_BSDF_EvalRes_zero(); } -inline vec3f Conductor_sample(const varying BSDF* uniform super, - const vec3f& wo, vec3f& wi, float& pdf, BSDFType& type, - const vec2f& s, float ss) +inline BSDF_SampleRes Conductor_sample(const varying BSDF* uniform super, + const vec3f& wo, const vec2f& s, float ss) { const varying Conductor* uniform self = (const varying Conductor* uniform)super; - wi = reflect(wo, getN(super)); - pdf = 1.0f; - type = BSDF_SPECULAR_REFLECTION; - return self->reflectance * fresnelConductor(dot(wo, getN(super)), self->eta, self->k); + BSDF_SampleRes res; + res.wi = reflect(wo, getN(super)); + res.pdf = inf; + res.type = BSDF_SPECULAR_REFLECTION; + res.weight = self->reflectance * fresnelConductor(dot(wo, getN(super)), self->eta, self->k); + return res; } inline void Conductor_Constructor(varying Conductor* uniform self, const varying linear3f* uniform frame, diff --git a/ospray/render/pathtracer/bsdfs/Dielectric.ih b/ospray/render/pathtracer/bsdfs/Dielectric.ih index 2e76f46a26..930497d72b 100644 --- a/ospray/render/pathtracer/bsdfs/Dielectric.ih +++ b/ospray/render/pathtracer/bsdfs/Dielectric.ih @@ -25,41 +25,39 @@ struct Dielectric float eta; }; -inline vec3f Dielectric_eval(const varying BSDF* uniform super, - const vec3f& wo, const vec3f& wi, float& pdf) +inline BSDF_EvalRes Dielectric_eval(const varying BSDF* uniform super, + const vec3f& wo, const vec3f& wi) { - return make_vec3f(0.0f); + return make_BSDF_EvalRes_zero(); } -inline vec3f Dielectric_sample(const varying BSDF* uniform super, - const vec3f& wo, vec3f& wi, float& pdf, BSDFType& type, - const vec2f& s, float ss) +inline BSDF_SampleRes Dielectric_sample(const varying BSDF* uniform super, + const vec3f& wo, const vec2f& s, float ss) { const varying Dielectric* uniform self = (const varying Dielectric* uniform)super; + BSDF_SampleRes res; float cosThetaO = max(dot(wo, getN(super)), 0.0f); // Fresnel term float cosThetaT; // positive float F = fresnelDielectricEx(cosThetaO, cosThetaT, self->eta); + res.pdf = inf; // Sample the reflection or the transmission - if (ss <= F) - { + if (ss <= F) { // Reflection - wi = reflect(wo, getN(super), cosThetaO); - type = BSDF_SPECULAR_REFLECTION; - pdf = F; - return make_vec3f(1.0f); - } - else - { + res.wi = reflect(wo, getN(super), cosThetaO); + res.type = BSDF_SPECULAR_REFLECTION; + res.weight = make_vec3f(1.0f); + } else { // Transmission - wi = refract(wo, getN(super), cosThetaO, cosThetaT, self->eta); - type = BSDF_SPECULAR_TRANSMISSION; - pdf = 1.0f-F; - return make_vec3f(sqrf(rcp(self->eta))); // solid angle compression + res.wi = refract(wo, getN(super), cosThetaO, cosThetaT, self->eta); + res.type = BSDF_SPECULAR_TRANSMISSION; + res.weight = make_vec3f(rsqrt(self->eta)); // solid angle compression } + + return res; } inline void Dielectric_Constructor(varying Dielectric* uniform self, const varying linear3f* uniform frame, diff --git a/ospray/render/pathtracer/bsdfs/DielectricLayer.ih b/ospray/render/pathtracer/bsdfs/DielectricLayer.ih index 451aee1f65..f07960ad7b 100644 --- a/ospray/render/pathtracer/bsdfs/DielectricLayer.ih +++ b/ospray/render/pathtracer/bsdfs/DielectricLayer.ih @@ -28,18 +28,15 @@ struct DielectricLayer float thickness; }; -inline vec3f DielectricLayer_eval(const varying BSDF* uniform super, - const vec3f& wo, const vec3f& wi, float& pdf) +inline BSDF_EvalRes DielectricLayer_eval(const varying BSDF* uniform super, + const vec3f& wo, const vec3f& wi) { const varying DielectricLayer* uniform self = (const varying DielectricLayer* uniform)super; + BSDF_EvalRes res; float cosThetaO = dot(wo, getN(super)); float cosThetaI = dot(wi, getN(super)); - if (cosThetaO <= 0.0f || cosThetaI <= 0.0f) - { - pdf = 0.0f; - return make_vec3f(0.0f); - } + if (cosThetaO <= 0.0f || cosThetaI <= 0.0f) return make_BSDF_EvalRes_zero(); // Fresnel term float cosThetaO1; // positive @@ -47,59 +44,55 @@ inline vec3f DielectricLayer_eval(const varying BSDF* uniform super, // Evaluate the substrate BRDF // Ignore refraction - float substratePdf; - vec3f substrateValue = self->substrate->eval(self->substrate, wo, wi, substratePdf); + BSDF_EvalRes substrate = self->substrate->eval(self->substrate, wo, wi); // Apply the coating transmittance // Computing the path length from the original angles would result in too much absorption, so instead use the refracted angles float cosThetaI1 = refract(cosThetaI, self->eta); // positive - substrateValue = substrateValue * pow(self->transmittance, self->thickness * (rcp(cosThetaO1) + rcp(cosThetaI1))); + substrate.value = substrate.value * pow(self->transmittance, self->thickness * (rcp(cosThetaO1) + rcp(cosThetaI1))); // Compute the final subtrate reflection // Ignore Fresnel for the exiting ray - pdf = (1.0f-F) * substratePdf; - return (1.0f-F) * substrateValue; + res.pdf = (1.0f-F) * substrate.pdf; + res.value = (1.0f-F) * substrate.value; + return res; } -inline vec3f DielectricLayer_sample(const varying BSDF* uniform super, - const vec3f& wo, vec3f& wi, float& pdf, BSDFType& type, - const vec2f& s, float ss) +inline BSDF_SampleRes DielectricLayer_sample(const varying BSDF* uniform super, + const vec3f& wo, const vec2f& s, float ss) { const varying DielectricLayer* uniform self = (const varying DielectricLayer* uniform)super; + BSDF_SampleRes res; float cosThetaO = dot(wo, getN(super)); - if (cosThetaO <= 0.0f) return make_vec3f(0.0f); + if (cosThetaO <= 0.0f) return make_BSDF_SampleRes_zero(); // Fresnel term float cosThetaO1; // positive float F = fresnelDielectricEx(cosThetaO, cosThetaO1, self->eta); - // Sample the coating or the substrate reflection - if (ss < F) - { + if (ss < F) { // Sample the coating reflection - type = BSDF_SPECULAR_REFLECTION; - wi = reflect(wo, getN(super), cosThetaO); - pdf = F; - return make_vec3f(1.0f); - } - else - { + res.type = BSDF_SPECULAR_REFLECTION; + res.wi = reflect(wo, getN(super), cosThetaO); + res.pdf = inf; + res.weight = make_vec3f(1.0f); + } else { // Sample the substrate BRDF float ss1 = (ss - F) * rcp(1.0f-F); // reallocate sample - float substratePdf; - vec3f substrateWeight = self->substrate->sample(self->substrate, wo, wi, substratePdf, type, s, ss1); - if (reduce_max(substrateWeight) <= 0.0f) return make_vec3f(0.0f); - float cosThetaI = max(dot(wi, getN(super)), 0.0f); // should be positive + res = self->substrate->sample(self->substrate, wo, s, ss1); + if (reduce_max(res.weight) <= 0.0f) return res; + float cosThetaI = max(dot(res.wi, getN(super)), 0.0f); // should be positive // Apply the coating transmittance float cosThetaI1 = refract(cosThetaI, self->eta); // positive - substrateWeight = substrateWeight * pow(self->transmittance, self->thickness * (rcp(cosThetaO1) + rcp(cosThetaI1))); + res.weight = res.weight * pow(self->transmittance, self->thickness * (rcp(cosThetaO1) + rcp(cosThetaI1))); - // Compute the final base reflection - pdf = (1.0f-F) * substratePdf; - return substrateWeight; + // Compute the final reflection + res.pdf = (1.0f-F) * res.pdf; } + + return res; } inline void DielectricLayer_Constructor(varying DielectricLayer* uniform self, const varying linear3f* uniform frame, diff --git a/ospray/render/pathtracer/bsdfs/GGXDistribution.ih b/ospray/render/pathtracer/bsdfs/GGXDistribution.ih index 442f0372fb..6c2617530b 100644 --- a/ospray/render/pathtracer/bsdfs/GGXDistribution.ih +++ b/ospray/render/pathtracer/bsdfs/GGXDistribution.ih @@ -38,6 +38,7 @@ inline float eval(const GGXDistribution& self, return alpha2 * rcp(pi*sqr(tmp)); } +// TODO: remove dup, or return pdf inline float eval(const GGXDistribution& self, float cosTheta, float& pdf) { diff --git a/ospray/render/pathtracer/bsdfs/Lambert.ih b/ospray/render/pathtracer/bsdfs/Lambert.ih index 9a4838147c..6d7e41c979 100644 --- a/ospray/render/pathtracer/bsdfs/Lambert.ih +++ b/ospray/render/pathtracer/bsdfs/Lambert.ih @@ -25,24 +25,27 @@ struct Lambert vec3f R; }; -inline vec3f Lambert_eval(const varying BSDF* uniform super, - const vec3f& wo, const vec3f& wi, float& pdf) +inline BSDF_EvalRes Lambert_eval(const varying BSDF* uniform super, + const vec3f& wo, const vec3f& wi) { const varying Lambert* uniform self = (const varying Lambert* uniform)super; - pdf = clamp(dot(wi, getN(super))) * one_over_pi; - return self->R/pi * clamp(dot(wi, getN(super))); + BSDF_EvalRes res; + res.pdf = clamp(dot(wi, getN(super))) * one_over_pi; + res.value = self->R/pi * clamp(dot(wi, getN(super))); + return res; } -inline vec3f Lambert_sample(const varying BSDF* uniform super, - const vec3f& wo, vec3f& wi, float& pdf, BSDFType& type, - const vec2f& s, float ss) +inline BSDF_SampleRes Lambert_sample(const varying BSDF* uniform super, + const vec3f& wo, const vec2f& s, float ss) { const varying Lambert* uniform self = (const varying Lambert* uniform)super; const vec3f localDir = cosineSampleHemisphere(s); - wi = getFrame(super) * localDir; - pdf = cosineSampleHemispherePDF(localDir); - type = BSDF_DIFFUSE_REFLECTION; - return self->R; + BSDF_SampleRes res; + res.wi = getFrame(super) * localDir; + res.pdf = cosineSampleHemispherePDF(localDir); + res.type = BSDF_DIFFUSE_REFLECTION; + res.weight = self->R; + return res; } inline void Lambert_Constructor(varying Lambert* uniform self, const varying linear3f* uniform frame, diff --git a/ospray/render/pathtracer/bsdfs/MicrofacetConductor.ih b/ospray/render/pathtracer/bsdfs/MicrofacetConductor.ih index 570555059f..7384dc8db2 100644 --- a/ospray/render/pathtracer/bsdfs/MicrofacetConductor.ih +++ b/ospray/render/pathtracer/bsdfs/MicrofacetConductor.ih @@ -29,18 +29,15 @@ struct MicrofacetConductor GGXDistribution distribution; }; -inline vec3f MicrofacetConductor_eval(const varying BSDF* uniform super, - const vec3f& wo, const vec3f& wi, float& pdf) +inline BSDF_EvalRes MicrofacetConductor_eval(const varying BSDF* uniform super, + const vec3f& wo, const vec3f& wi) { const varying MicrofacetConductor* uniform self = (const varying MicrofacetConductor* uniform)super; + BSDF_EvalRes res; float cosThetaO = dot(wo, getN(super)); float cosThetaI = dot(wi, getN(super)); - if (cosThetaO <= 0.0f || cosThetaI <= 0.0f) - { - pdf = 0.0f; - return make_vec3f(0.0f); - } + if (cosThetaO <= 0.0f || cosThetaI <= 0.0f) return make_BSDF_EvalRes_zero(); vec3f wh = normalize(wi + wo); float cosThetaH = dot(wh, getN(super)); @@ -53,37 +50,39 @@ inline vec3f MicrofacetConductor_eval(const varying BSDF* uniform super, float D = evalVisible(self->distribution, cosThetaH, cosThetaO, cosThetaOH, whPdf); float G = G2(self->distribution, cosThetaO, cosThetaI, cosThetaOH, cosThetaIH); - pdf = whPdf * rcp(4.0f*abs(cosThetaOH)); - return F * (D * G * rcp(4.0f*cosThetaO)); + res.pdf = whPdf * rcp(4.0f*abs(cosThetaOH)); + res.value = F * (D * G * rcp(4.0f*cosThetaO)); + return res; } -inline vec3f MicrofacetConductor_sample(const varying BSDF* uniform super, - const vec3f& wo, vec3f& wi, float& pdf, BSDFType& type, - const vec2f& s, float ss) +inline BSDF_SampleRes MicrofacetConductor_sample(const varying BSDF* uniform super, + const vec3f& wo, const vec2f& s, float ss) { const varying MicrofacetConductor* uniform self = (const varying MicrofacetConductor* uniform)super; + BSDF_SampleRes res; float cosThetaO = dot(wo, getN(super)); - if (cosThetaO <= 0.0f) return make_vec3f(0.0f); + if (cosThetaO <= 0.0f) return make_BSDF_SampleRes_zero(); float whPdf; //vec3f wh = getFrame(super) * sample(self->distribution, whPdf, s); vec3f wh = getFrame(super) * sampleVisible(self->distribution, transposed(getFrame(super)) * wo, whPdf, s); - wi = reflect(wo, wh); - float cosThetaI = dot(wi, getN(super)); - if (cosThetaI <= 0.0f) return make_vec3f(0.0f); + res.wi = reflect(wo, wh); + float cosThetaI = dot(res.wi, getN(super)); + if (cosThetaI <= 0.0f) return make_BSDF_SampleRes_zero(); //float cosThetaH = dot(wh, getN(super)); float cosThetaOH = dot(wo, wh); - float cosThetaIH = dot(wi, wh); + float cosThetaIH = dot(res.wi, wh); vec3f F = fresnelConductor(cosThetaOH, self->eta, self->k); float G = G2(self->distribution, cosThetaO, cosThetaI, cosThetaOH, cosThetaIH); - type = BSDF_GLOSSY_REFLECTION; - pdf = whPdf * rcp(4.0f*abs(cosThetaOH)); - //return F * (G * abs(cosThetaOH * rcp(cosThetaO*cosThetaH))); - return F * (G * rcp_safe(G1(self->distribution, cosThetaO, cosThetaOH))); + res.type = BSDF_GLOSSY_REFLECTION; + res.pdf = whPdf * rcp(4.0f*abs(cosThetaOH)); + //res.weight = F * (G * abs(cosThetaOH * rcp(cosThetaO*cosThetaH))); + res.weight = F * (G * rcp_safe(G1(self->distribution, cosThetaO, cosThetaOH))); + return res; } inline void MicrofacetConductor_Constructor(varying MicrofacetConductor* uniform self, const varying linear3f* uniform frame, diff --git a/ospray/render/pathtracer/bsdfs/MicrofacetDielectricLayer.ih b/ospray/render/pathtracer/bsdfs/MicrofacetDielectricLayer.ih index ab8dc1bd5f..ac276106da 100644 --- a/ospray/render/pathtracer/bsdfs/MicrofacetDielectricLayer.ih +++ b/ospray/render/pathtracer/bsdfs/MicrofacetDielectricLayer.ih @@ -30,18 +30,15 @@ struct MicrofacetDielectricLayer GGXDistribution distribution; }; -inline vec3f MicrofacetDielectricLayer_eval(const varying BSDF* uniform super, - const vec3f& wo, const vec3f& wi, float& pdf) +inline BSDF_EvalRes MicrofacetDielectricLayer_eval(const varying BSDF* uniform super, + const vec3f& wo, const vec3f& wi) { const varying MicrofacetDielectricLayer* uniform self = (const varying MicrofacetDielectricLayer* uniform)super; + BSDF_EvalRes res; float cosThetaO = dot(wo, getN(super)); float cosThetaI = dot(wi, getN(super)); - if (cosThetaO <= 0.0f || cosThetaI <= 0.0f) - { - pdf = 0.0f; - return make_vec3f(0.0f); - } + if (cosThetaO <= 0.0f || cosThetaI <= 0.0f) return make_BSDF_EvalRes_zero(); // Compute the microfacet normal vec3f wh = normalize(wi + wo); @@ -59,46 +56,46 @@ inline vec3f MicrofacetDielectricLayer_eval(const varying BSDF* uniform super, float D = evalVisible(self->distribution, cosThetaH, cosThetaO, cosThetaOH, whPdf); float G = G2(self->distribution, cosThetaO, cosThetaI, cosThetaOH, cosThetaIH); - float coatingPdf = whPdf * rcp(4.0f*cosThetaOH); - float coatingValue = F * D * G * rcp(4.0f*cosThetaO); + BSDF_EvalRes coating; + coating.pdf = whPdf * rcp(4.0f*cosThetaOH); + coating.value = make_vec3f(F * D * G * rcp(4.0f*cosThetaO)); // Evaluate the substrate // Ignore refraction - float substratePdf; - vec3f substrateValue = self->substrate->eval(self->substrate, wo, wi, substratePdf); + BSDF_EvalRes substrate = self->substrate->eval(self->substrate, wo, wi); // Apply the coating transmittance // Computing the path length from the original angles would result in too much absorption, so instead use the refracted angles float cosThetaO1 = refract(cosThetaO, self->eta); // positive float cosThetaI1 = refract(cosThetaI, self->eta); // positive - substrateValue = substrateValue * pow(self->transmittance, self->thickness * (rcp(cosThetaO1) + rcp(cosThetaI1))); + substrate.value = substrate.value * pow(self->transmittance, self->thickness * (rcp(cosThetaO1) + rcp(cosThetaI1))); // Compute the final substrate reflection // Ignore Fresnel for the exiting ray float Ft = 1.0f-fresnelDielectric(cosThetaO, self->eta); - substrateValue = substrateValue * Ft; + substrate.value = substrate.value * Ft; // Compute the total reflection float coatingPickProb = 1.0f-Ft; float substratePickProb = Ft; - pdf = coatingPickProb * coatingPdf + substratePickProb * substratePdf; - return coatingValue + substrateValue; + res.pdf = coatingPickProb * coating.pdf + substratePickProb * substrate.pdf; + res.value = coating.value + substrate.value; + return res; } -inline vec3f MicrofacetDielectricLayer_sample(const varying BSDF* uniform super, - const vec3f& wo, vec3f& wi, float& pdf, BSDFType& type, - const vec2f& s, float ss) +inline BSDF_SampleRes MicrofacetDielectricLayer_sample(const varying BSDF* uniform super, + const vec3f& wo, const vec2f& s, float ss) { const varying MicrofacetDielectricLayer* uniform self = (const varying MicrofacetDielectricLayer* uniform)super; + BSDF_SampleRes res; float cosThetaO = dot(wo, getN(super)); - if (cosThetaO <= 0.0f) return make_vec3f(0.0f); + if (cosThetaO <= 0.0f) return make_BSDF_SampleRes_zero(); // Sample the coating or the substrate reflection vec3f wh; - float substratePdf; - vec3f substrateValue; + BSDF_EvalRes substrate; float Ft = 1.0f-fresnelDielectric(cosThetaO, self->eta); float coatingPickProb = 1.0f-Ft; @@ -112,26 +109,27 @@ inline vec3f MicrofacetDielectricLayer_sample(const varying BSDF* uniform super, wh = getFrame(super) * sampleVisible(self->distribution, transposed(getFrame(super)) * wo, whPdf, s); float cosThetaOH = dot(wo, wh); - type = BSDF_GLOSSY_REFLECTION; - wi = reflect(wo, wh, cosThetaOH); + res.type = BSDF_GLOSSY_REFLECTION; + res.wi = reflect(wo, wh, cosThetaOH); // Evaluate the substrate - substrateValue = self->substrate->eval(self->substrate, wo, wi, substratePdf); + substrate = self->substrate->eval(self->substrate, wo, res.wi); } else { // Sample the substrate float ss1 = (ss - coatingPickProb) * rcp(substratePickProb); // reallocate sample - vec3f substrateWeight = self->substrate->sample(self->substrate, wo, wi, substratePdf, type, s, ss1); - if (reduce_max(substrateWeight) <= 0.0f) return make_vec3f(0.0f); - substrateValue = substrateWeight * substratePdf; + res = self->substrate->sample(self->substrate, wo, s, ss1); + if (reduce_max(res.weight) <= 0.0f) return res; + substrate.pdf = res.pdf; + substrate.value = res.weight * res.pdf; // Compute the microfacet normal - wh = normalize(wi + wo); + wh = normalize(res.wi + wo); } - float cosThetaI = dot(wi, getN(super)); - if (cosThetaI <= 0.0f) return make_vec3f(0.0f); + float cosThetaI = dot(res.wi, getN(super)); + if (cosThetaI <= 0.0f) return make_BSDF_SampleRes_zero(); float cosThetaOH = dot(wo, wh); // Fresnel term @@ -139,27 +137,29 @@ inline vec3f MicrofacetDielectricLayer_sample(const varying BSDF* uniform super, // Evaluate the coating reflection float cosThetaH = dot(wh, getN(super)); - float cosThetaIH = dot(wi, wh); + float cosThetaIH = dot(res.wi, wh); float whPdf; //float D = eval(self->distribution, cosThetaH, whPdf); float D = evalVisible(self->distribution, cosThetaH, cosThetaO, cosThetaOH, whPdf); float G = G2(self->distribution, cosThetaO, cosThetaI, cosThetaOH, cosThetaIH); - float coatingPdf = whPdf * rcp(4.0f*cosThetaOH); - float coatingValue = F * D * G * rcp(4.0f*cosThetaO); + BSDF_EvalRes coating; + coating.pdf = whPdf * rcp(4.0f*cosThetaOH); + coating.value = make_vec3f(F * D * G * rcp(4.0f*cosThetaO)); // Apply the coating transmittance float cosThetaO1 = refract(cosThetaO, self->eta); // positive float cosThetaI1 = refract(cosThetaI, self->eta); // positive - substrateValue = substrateValue * pow(self->transmittance, self->thickness * (rcp(cosThetaO1) + rcp(cosThetaI1))); + substrate.value = substrate.value * pow(self->transmittance, self->thickness * (rcp(cosThetaO1) + rcp(cosThetaI1))); - // Compute the final base reflection - substrateValue = substrateValue * Ft; + // Compute the final substrate reflection + substrate.value = substrate.value * Ft; // Compute the total reflection - pdf = coatingPickProb * coatingPdf + substratePickProb * substratePdf; - return (coatingValue + substrateValue) * rcp(pdf); + res.pdf = coatingPickProb * coating.pdf + substratePickProb * substrate.pdf; + res.weight = (coating.value + substrate.value) * rcp(res.pdf); + return res; } inline void MicrofacetDielectricLayer_Constructor(varying MicrofacetDielectricLayer* uniform self, const varying linear3f* uniform frame, diff --git a/ospray/render/pathtracer/bsdfs/Minneart.ih b/ospray/render/pathtracer/bsdfs/Minneart.ih index 93fe0da5fc..41c2865794 100644 --- a/ospray/render/pathtracer/bsdfs/Minneart.ih +++ b/ospray/render/pathtracer/bsdfs/Minneart.ih @@ -31,27 +31,32 @@ struct Minneart float b; }; -inline vec3f Minneart_eval(const varying BSDF* uniform super, - const vec3f& wo, const vec3f& wi, float& pdf) +inline BSDF_EvalRes Minneart_eval(const varying BSDF* uniform super, + const vec3f& wo, const vec3f& wi) { const varying Minneart* uniform self = (const varying Minneart* uniform)super; + BSDF_EvalRes res; const float cosThetaI = clamp(dot(wi,getN(super))); const float backScatter = pow(clamp(dot(wo,wi)), self->b); - pdf = cosineSampleHemispherePDF(cosThetaI); - return mul(backScatter * cosThetaI * one_over_pi, self->R); + res.pdf = cosineSampleHemispherePDF(cosThetaI); + res.value = mul(backScatter * cosThetaI * one_over_pi, self->R); + return res; } -inline vec3f Minneart_sample(const varying BSDF* uniform super, - const vec3f& wo, vec3f& wi, float& pdf, BSDFType& type, - const vec2f& s, float ss) +inline BSDF_SampleRes Minneart_sample(const varying BSDF* uniform super, + const vec3f& wo, const vec2f& s, float ss) { const varying Minneart* uniform self = (const varying Minneart* uniform)super; + BSDF_SampleRes res; const vec3f localDir = cosineSampleHemisphere(s); - wi = getFrame(super) * localDir; - type = BSDF_DIFFUSE_REFLECTION; - return Minneart_eval(super, wo, wi, pdf) * rcp(pdf); + res.wi = getFrame(super) * localDir; + res.type = BSDF_DIFFUSE_REFLECTION; + BSDF_EvalRes eval = Minneart_eval(super, wo, res.wi); + res.pdf = eval.pdf; + res.weight = eval.value * rcp(eval.pdf); + return res; } inline void Minneart_Constructor(varying Minneart* uniform self, const varying linear3f* uniform frame, diff --git a/ospray/render/pathtracer/bsdfs/MultiBSDF.ih b/ospray/render/pathtracer/bsdfs/MultiBSDF.ih index 2748b5c4a7..be01ec7899 100644 --- a/ospray/render/pathtracer/bsdfs/MultiBSDF.ih +++ b/ospray/render/pathtracer/bsdfs/MultiBSDF.ih @@ -49,45 +49,43 @@ inline void MultiBSDF_add(varying BSDF* uniform super, } /*! Evaluates all BSDF components. */ -inline vec3f MultiBSDF_eval(const varying BSDF* uniform super, - const vec3f& wo, const vec3f& wi, float& pdf) +inline BSDF_EvalRes MultiBSDF_eval(const varying BSDF* uniform super, + const vec3f& wo, const vec3f& wi) { const varying MultiBSDF* uniform self = (const varying MultiBSDF* uniform)super; - vec3f value = make_vec3f(0.0f); - pdf = 0.0f; + BSDF_EvalRes res = make_BSDF_EvalRes_zero(); for (uniform int i = 0; i < self->numBsdfs; ++i) { if (self->importances[i] > 0.0f) { const varying BSDF* uniform curBsdf = self->bsdfs[i]; - float curPdf = 0.0f; - value = value + curBsdf->eval(curBsdf, wo, wi, curPdf); - pdf = pdf + curPdf * self->importances[i]; + BSDF_EvalRes cur = curBsdf->eval(curBsdf, wo, wi); + res.value = res.value + cur.value; + res.pdf = res.pdf + cur.pdf * self->importances[i]; } } - pdf *= rcp(self->importanceSum); - return value; + res.pdf *= rcp(self->importanceSum); + return res; } /*! Sample the multi-BSDF. */ -inline vec3f MultiBSDF_sample(const varying BSDF* uniform super, - const vec3f& wo, vec3f& wi, float& pdf, BSDFType& type, - const vec2f& s, float ss) +inline BSDF_SampleRes MultiBSDF_sample(const varying BSDF* uniform super, + const vec3f& wo, const vec2f& s, float ss) { const varying MultiBSDF* uniform self = (const varying MultiBSDF* uniform)super; - if (self->importanceSum == 0.0f) - return make_vec3f(0.0f); + if (self->importanceSum == 0.0f) // also handles case self->numBsdfs == 0 + return make_BSDF_SampleRes_zero(); if (self->numBsdfs == 1) { const varying BSDF* uniform bsdf = self->bsdfs[0]; - return bsdf->sample(bsdf, wo, wi, pdf, type, s, ss); + return bsdf->sample(bsdf, wo, s, ss); } - else if (self->numBsdfs > 1) + else { // choose which BSDF to sample float x = ss * self->importanceSum; @@ -100,40 +98,41 @@ inline vec3f MultiBSDF_sample(const varying BSDF* uniform super, ss = (x + self->importances[choice] - prefixSum) * rcp(self->importances[choice]); // sample chosen BSDF - vec3f weight; + BSDF_SampleRes res; foreach_unique (i in choice) { const varying BSDF* uniform bsdf = self->bsdfs[i]; - weight = bsdf->sample(bsdf, wo, wi, pdf, type, s, ss); + res = bsdf->sample(bsdf, wo, s, ss); } - if (eq(weight, make_vec3f(0.0f)) | (pdf == 0.0f)) - return make_vec3f(0.0f); + if (eq(res.weight, make_vec3f(0.0f)) | (res.pdf == 0.0f)) + return make_BSDF_SampleRes_zero(); + + if (res.type & BSDF_SPECULAR) + { + // scale by rcp(selection pdf) + res.weight = res.weight * (self->importanceSum * rcp(self->importances[choice])); + return res; + } // compute overall weight and pdf - vec3f value = weight * pdf; - pdf *= self->importances[choice]; + vec3f value = res.weight * res.pdf; + res.pdf *= self->importances[choice]; - if (!(type & BSDF_SPECULAR)) + for (uniform int i = 0; i < self->numBsdfs; ++i) { - for (uniform int i = 0; i < self->numBsdfs; ++i) + if ((i != choice) & (self->importances[i] > 0.0f)) { - if ((i != choice) & (self->importances[i] > 0.0f)) - { - const varying BSDF* uniform curBsdf = self->bsdfs[i]; - float curPdf = 0.0f; - value = value + curBsdf->eval(curBsdf, wo, wi, curPdf); - pdf = pdf + curPdf * self->importances[i]; - } + const varying BSDF* uniform curBsdf = self->bsdfs[i]; + BSDF_EvalRes cur = curBsdf->eval(curBsdf, wo, res.wi); + value = value + cur.value; + res.pdf = res.pdf + cur.pdf * self->importances[i]; } } - pdf *= rcp(self->importanceSum); - return value * rcp(pdf); - } - else - { - return make_vec3f(0.0f); + res.pdf *= rcp(self->importanceSum); + res.weight = value * rcp(res.pdf); + return res; } } diff --git a/ospray/render/pathtracer/bsdfs/Optics.ih b/ospray/render/pathtracer/bsdfs/Optics.ih index ba24d98056..e3d4f2e393 100644 --- a/ospray/render/pathtracer/bsdfs/Optics.ih +++ b/ospray/render/pathtracer/bsdfs/Optics.ih @@ -20,18 +20,23 @@ #include "ospray/math/sampling.ih" #include "ospray/math/LinearSpace.ih" +/*! Reflects a viewing vector I at a normal N. Cosine between I + * and N is given as input. */ +inline vec3f reflect(const vec3f& I, const vec3f& N, float cosI) +{ + return (2.0f*cosI) * N - I; +} + /*! Reflects a viewing vector I at a normal N. */ inline vec3f reflect(const vec3f& I, const vec3f& N) { - float cosI = dot(I,N); - return (2.0f*cosI) * N - I; + return reflect(I, N, dot(I, N)); } -/*! Reflects a viewing vector I at a normal N. Cosine between I - * and N is given as input. */ -inline vec3f reflect(const vec3f& I, const vec3f& N, float cosI) +// helper function which computes cosT^2 from cosI and eta +inline float sqrCosT(const float cosI, const float eta) { - return (2.0f*cosI) * N - I; + return 1.0f - sqr(eta)*(1.0f - sqr(cosI)); } //! \brief Refracts a viewing vector I at a normal N @@ -39,26 +44,24 @@ inline vec3f reflect(const vec3f& I, const vec3f& N, float cosI) * relative refraction index eta. Eta is refraction index of outside * medium (where N points into) divided by refraction index of the * inside medium. The vectors I and N have to point towards the same - * side of the surface. The cosine between I and N is given as input - * and the cosine of -N and transmission ray is computed as - * output. */ -inline vec3f refract(const vec3f& I, const vec3f& N, float cosI, float eta) + * side of the surface. The cosine between I and N, and the cosine of -N and + * the refracted ray is given as input */ +inline vec3f refract(const vec3f& I, const vec3f& N, float cosI, float cosT, float eta) { - const float k = 1.0f-eta*eta*(1.0f-cosI*cosI); - if (k < 0.0f) return make_vec3f(0.f); - const float cosT = sqrtf(k); - return sub(mul(eta,sub(mul(cosI,N),I)),mul(cosT,N)); + return eta*(cosI*N - I) - cosT*N; } -inline vec3f refract(const vec3f& I, const vec3f& N, float cosI, float cosT, float eta) +inline vec3f refract(const vec3f& I, const vec3f& N, float cosI, float eta) { - return sub(mul(eta,sub(mul(cosI,N),I)),mul(cosT,N)); + const float sqrCosT = sqrCosT(cosI, eta); + if (sqrCosT < 0.0f) return make_vec3f(0.f); + return refract(I, N, cosI, sqrt(sqrCosT), eta); } inline float refract(float cosI, float eta) { - float k = 1.0f - eta*eta*(1.0f-cosI*cosI); - return sqrt(max(k, 0.0f)); + const float sqrCosT = sqrCosT(cosI, eta); + return sqrt(max(sqrCosT, 0.0f)); } //! \brief Computes fresnel coefficient for dielectric medium @@ -70,7 +73,7 @@ inline float fresnelDielectric(float cosI, float cosT, float eta) { const float Rper = (eta*cosI - cosT) * rcpf(eta*cosI + cosT); const float Rpar = ( cosI - eta*cosT) * rcpf( cosI + eta*cosT); - return 0.5f*(Rpar*Rpar + Rper*Rper); + return 0.5f*(sqr(Rpar) + sqr(Rper)); } /*! Computes fresnel coefficient for media interface with relative @@ -79,35 +82,33 @@ inline float fresnelDielectric(float cosI, float cosT, float eta) * positive. */ inline float fresnelDielectric(float cosI, float eta) { - const float k = 1.0f-eta*eta*(1.0f-cosI*cosI); - if (k < 0.0f) return 1.0f; - const float cosT = sqrtf(k); - return fresnelDielectric(cosI, cosT, eta); + const float sqrCosT = sqrCosT(cosI, eta); + if (sqrCosT < 0.0f) return 1.0f; + return fresnelDielectric(cosI, sqrt(sqrCosT), eta); } inline float fresnelDielectricEx(float cosI, float& cosT, float eta) { - const float k = 1.0f-eta*eta*(1.0f-cosI*cosI); - if (k < 0.0f) + const float sqrCosT = sqrCosT(cosI, eta); + if (sqrCosT < 0.0f) { cosT = 0.0f; return 1.0f; } - cosT = sqrtf(k); - return fresnelDielectric(cosI, cosT, eta); + return fresnelDielectric(cosI, sqrt(sqrCosT), eta); } /*! Computes fresnel coefficient for conductor medium with complex * refraction index (eta,k). The cosine has to be positive. */ inline vec3f fresnelConductor(float cosI, vec3f eta, vec3f k) { - vec3f tmp = eta*eta + k*k; + vec3f tmp = sqr(eta) + sqr(k); vec3f Rpar - = (tmp * cosI*cosI - 2.0f*eta*cosI + make_vec3f(1.f)) - * rcp(tmp * cosI*cosI + 2.0f*eta*cosI + make_vec3f(1.f)); + = (tmp * sqr(cosI) - 2.0f*eta*cosI + make_vec3f(1.f)) + * rcp(tmp * sqr(cosI) + 2.0f*eta*cosI + make_vec3f(1.f)); vec3f Rper - = (tmp - 2.0f*eta*cosI + make_vec3f(cosI*cosI)) - * rcp(tmp + 2.0f*eta*cosI + make_vec3f(cosI*cosI)); + = (tmp - 2.0f*eta*cosI + make_vec3f(sqr(cosI))) + * rcp(tmp + 2.0f*eta*cosI + make_vec3f(sqr(cosI))); return 0.5f * (Rpar + Rper); } diff --git a/ospray/render/pathtracer/bsdfs/Reflection.ih b/ospray/render/pathtracer/bsdfs/Reflection.ih index f09ed9e480..09b21e71ca 100644 --- a/ospray/render/pathtracer/bsdfs/Reflection.ih +++ b/ospray/render/pathtracer/bsdfs/Reflection.ih @@ -25,22 +25,23 @@ struct Reflection vec3f reflectance; }; -inline vec3f Reflection_eval(const varying BSDF* uniform super, - const vec3f& wo, const vec3f& wi, float& pdf) +inline BSDF_EvalRes Reflection_eval(const varying BSDF* uniform super, + const vec3f& wo, const vec3f& wi) { - return make_vec3f(0.0f); + return make_BSDF_EvalRes_zero(); } -inline vec3f Reflection_sample(const varying BSDF* uniform super, - const vec3f& wo, vec3f& wi, float& pdf, BSDFType& type, - const vec2f& s, float ss) +inline BSDF_SampleRes Reflection_sample(const varying BSDF* uniform super, + const vec3f& wo, const vec2f& s, float ss) { const varying Reflection* uniform self = (const varying Reflection* uniform)super; + BSDF_SampleRes res; - wi = reflect(wo, getN(super)); - pdf = 1.0f; - type = BSDF_SPECULAR_REFLECTION; - return self->reflectance; + res.wi = reflect(wo, getN(super)); + res.pdf = inf; + res.type = BSDF_SPECULAR_REFLECTION; + res.weight = self->reflectance; + return res; } inline void Reflection_Constructor(varying Reflection* uniform self, const varying linear3f* uniform frame, diff --git a/ospray/render/pathtracer/bsdfs/Specular.ih b/ospray/render/pathtracer/bsdfs/Specular.ih index 65948bd3a1..f33906081e 100644 --- a/ospray/render/pathtracer/bsdfs/Specular.ih +++ b/ospray/render/pathtracer/bsdfs/Specular.ih @@ -32,26 +32,32 @@ struct Specular float exp; }; -inline vec3f Specular_eval(const varying BSDF* uniform super, - const vec3f& wo, const vec3f& wi, float& pdf) +inline BSDF_EvalRes Specular_eval(const varying BSDF* uniform super, + const vec3f& wo, const vec3f& wi) { const varying Specular* uniform self = (const varying Specular* uniform)super; + BSDF_EvalRes res; + const vec3f refl = reflect(wo, getN(super)); - if (dot(refl,wi) < 0.0f) return make_vec3f(0.0f); - pdf = powerCosineSampleHemispherePDF(dot(refl,wi), self->exp); - return mul(self->R, (self->exp+2) * one_over_two_pi * pow(dot(refl,wi),self->exp) * clamp(dot(wi, getN(super)))); + if (dot(refl,wi) < 0.0f) return make_BSDF_EvalRes_zero(); + res.pdf = powerCosineSampleHemispherePDF(dot(refl,wi), self->exp); + res.value = self->R * ((self->exp+2.f) * one_over_two_pi * pow(dot(refl,wi),self->exp) * clamp(dot(wi, getN(super)))); + return res; } -inline vec3f Specular_sample(const varying BSDF* uniform super, - const vec3f& wo, vec3f& wi, float& pdf, BSDFType& type, - const vec2f& s, float ss) +inline BSDF_SampleRes Specular_sample(const varying BSDF* uniform super, + const vec3f& wo, const vec2f& s, float ss) { const varying Specular* uniform self = (const varying Specular* uniform)super; + BSDF_SampleRes res; + const vec3f refl = reflect(wo, getN(super)); const vec3f localDir = powerCosineSampleHemisphere(self->exp, s); - wi = frame(refl) * localDir; - pdf = powerCosineSampleHemispherePDF(localDir, self->exp); - return mul(self->R, (self->exp+2) * rcp(self->exp+1) * clamp(dot(wi, getN(super)))); + res.wi = frame(refl) * localDir; + res.pdf = powerCosineSampleHemispherePDF(localDir, self->exp); + res.type = BSDF_GLOSSY_REFLECTION; + res.weight = self->R * ((self->exp+2.f) * rcp(self->exp+1.f) * clamp(dot(res.wi, getN(super)))); + return res; } inline void Specular_Constructor(varying Specular* uniform self, diff --git a/ospray/render/pathtracer/bsdfs/ThinDielectric.ih b/ospray/render/pathtracer/bsdfs/ThinDielectric.ih index f6d540a1df..4a7c455334 100644 --- a/ospray/render/pathtracer/bsdfs/ThinDielectric.ih +++ b/ospray/render/pathtracer/bsdfs/ThinDielectric.ih @@ -27,41 +27,41 @@ struct ThinDielectric uniform float thickness; /*! thickness of the medium */ }; -inline vec3f ThinDielectric_eval(const varying BSDF* uniform super, - const vec3f& wo, const vec3f& wi, float& pdf) +inline BSDF_EvalRes ThinDielectric_eval(const varying BSDF* uniform super, + const vec3f& wo, const vec3f& wi) { - return make_vec3f(0.0f); + return make_BSDF_EvalRes_zero(); } -inline vec3f ThinDielectric_sample(const varying BSDF* uniform super, - const vec3f& wo, vec3f& wi, float& pdf, BSDFType& type, - const vec2f& s, float ss) + +// TODO: account for multiple internal reflections with geometric sum +inline BSDF_SampleRes ThinDielectric_sample(const varying BSDF* uniform super, + const vec3f& wo, const vec2f& s, float ss) { const varying ThinDielectric* uniform self = (const varying ThinDielectric* uniform)super; + BSDF_SampleRes res; float cosThetaO = max(dot(wo, getN(super)), 0.0f); // Fresnel term float F = fresnelDielectric(cosThetaO, self->eta); + res.pdf = inf; // Sample the reflection or the transmission - if (ss <= F) - { + if (ss <= F) { // Reflection - wi = reflect(wo, getN(super), cosThetaO); - type = BSDF_SPECULAR_REFLECTION; - pdf = F; - return make_vec3f(1.0f); - } - else - { + res.wi = reflect(wo, getN(super), cosThetaO); + res.type = BSDF_SPECULAR_REFLECTION; + res.weight = make_vec3f(1.0f); + } else { // Transmission - wi = neg(wo); - type = BSDF_SPECULAR_TRANSMISSION; - pdf = 1.0f-F; + res.wi = neg(wo); + res.type = BSDF_SPECULAR_TRANSMISSION; float alpha = self->thickness * rcp(cosThetaO); - return powf(self->transmission, alpha); + res.weight = powf(self->transmission, alpha); } + + return res; } inline void ThinDielectric_Constructor(varying ThinDielectric* uniform self, const varying linear3f* uniform frame, diff --git a/ospray/render/pathtracer/bsdfs/Transmission.ih b/ospray/render/pathtracer/bsdfs/Transmission.ih index 019dfe3d12..37e77c0082 100644 --- a/ospray/render/pathtracer/bsdfs/Transmission.ih +++ b/ospray/render/pathtracer/bsdfs/Transmission.ih @@ -28,21 +28,23 @@ struct Transmission vec3f T; }; -inline vec3f Transmission_eval(const varying BSDF* uniform super, - const vec3f& wo, const vec3f& wi, float& pdf) +inline BSDF_EvalRes Transmission_eval(const varying BSDF* uniform super, + const vec3f& wo, const vec3f& wi) { - return make_vec3f(0.0f); + return make_BSDF_EvalRes_zero(); } -inline vec3f Transmission_sample(const varying BSDF* uniform super, - const vec3f& wo, vec3f& wi, float& pdf, BSDFType& type, - const vec2f& s, float ss) +inline BSDF_SampleRes Transmission_sample(const varying BSDF* uniform super, + const vec3f& wo, const vec2f& s, float ss) { const varying Transmission* uniform self = (const varying Transmission* uniform)super; - wi = neg(wo); - pdf = 1.0f; - type = BSDF_SPECULAR_TRANSMISSION; - return self->T; + BSDF_SampleRes res; + + res.wi = neg(wo); + res.pdf = inf; + res.type = BSDF_SPECULAR_TRANSMISSION; + res.weight = self->T; + return res; } inline void Transmission_Constructor(varying Transmission* uniform self, const varying linear3f* uniform frame, diff --git a/ospray/render/pathtracer/bsdfs/Velvety.ih b/ospray/render/pathtracer/bsdfs/Velvety.ih index 41bc8aa2c8..ace28dc0cf 100644 --- a/ospray/render/pathtracer/bsdfs/Velvety.ih +++ b/ospray/render/pathtracer/bsdfs/Velvety.ih @@ -31,29 +31,34 @@ struct Velvety float f; }; -inline vec3f Velvety_eval(const varying BSDF* uniform super, - const vec3f& wo, const vec3f& wi, float& pdf) +inline BSDF_EvalRes Velvety_eval(const varying BSDF* uniform super, + const vec3f& wo, const vec3f& wi) { const varying Velvety* uniform self = (const varying Velvety* uniform)super; + BSDF_EvalRes res; const float cosThetaO = clamp(dot(wo,getN(super))); const float cosThetaI = clamp(dot(wi,getN(super))); const float sinThetaO = sqrt(1.0f - cosThetaO * cosThetaO); const float horizonScatter = pow(sinThetaO, self->f); - pdf = cosineSampleHemispherePDF(cosThetaI); - return mul(horizonScatter * cosThetaI * one_over_pi, self->R); + res.pdf = cosineSampleHemispherePDF(cosThetaI); + res.value = mul(horizonScatter * cosThetaI * one_over_pi, self->R); + return res; } -inline vec3f Velvety_sample(const varying BSDF* uniform super, - const vec3f& wo, vec3f& wi, float& pdf, BSDFType& type, - const vec2f& s, float ss) +inline BSDF_SampleRes Velvety_sample(const varying BSDF* uniform super, + const vec3f& wo, const vec2f& s, float ss) { const varying Velvety* uniform self = (const varying Velvety* uniform)super; + BSDF_SampleRes res; const vec3f localDir = cosineSampleHemisphere(s); - wi = getFrame(super) * localDir; - type = BSDF_DIFFUSE_REFLECTION; - return Velvety_eval(super, wo, wi, pdf) * rcp(pdf); + res.wi = getFrame(super) * localDir; + res.type = BSDF_DIFFUSE_REFLECTION; + BSDF_EvalRes eval = Velvety_eval(super, wo, res.wi); + res.pdf = eval.pdf; + res.weight = eval.value * rcp(eval.pdf); + return res; } inline void Velvety_Constructor(varying Velvety* uniform self, const varying linear3f* uniform frame, diff --git a/ospray/render/pathtracer/materials/Glass.cpp b/ospray/render/pathtracer/materials/Glass.cpp index 1d054bc5c6..eecd01d2b9 100644 --- a/ospray/render/pathtracer/materials/Glass.cpp +++ b/ospray/render/pathtracer/materials/Glass.cpp @@ -33,10 +33,8 @@ namespace ospray { const vec3f& transmissionOutside = getParam3f("transmissionOutside",vec3f(1.f)); - const float etaInside - = getParamf("etaInside",getParamf("eta",1.4f)); - const float etaOutside - = getParamf("etaOutside",1.f); + const float etaInside = getParamf("etaInside", getParamf("eta", 1.5f)); + const float etaOutside = getParamf("etaOutside", 1.f); ispcEquivalent = ispc::PathTracer_Glass_create (etaInside, (const ispc::vec3f&)transmissionInside, diff --git a/ospray/render/pathtracer/materials/Glass.ispc b/ospray/render/pathtracer/materials/Glass.ispc index 7d2dd495be..eb070bfae5 100644 --- a/ospray/render/pathtracer/materials/Glass.ispc +++ b/ospray/render/pathtracer/materials/Glass.ispc @@ -52,12 +52,12 @@ vec3f Glass_getTransparency(const uniform PathTraceMaterial* uniform material, float eta = eq(currentMedium, self->mediumOutside) ? self->mediumOutside.ior*rcp(self->mediumInside.ior) : self->mediumInside.ior*rcp(self->mediumOutside.ior); - float cosThetaO = max(dot(ray.dir, dg.Ns), 0.0f); + float cosThetaO = max(-dot(ray.dir, dg.Ns), 0.0f); return make_vec3f(1.0f-fresnelDielectric(cosThetaO, eta)); } void Glass_selectNextMedium(const uniform PathTraceMaterial* uniform super, - varying Medium& currentMedium) + Medium& currentMedium) { const uniform Glass* uniform self = (const uniform Glass* uniform)super; diff --git a/ospray/render/pathtracer/materials/Material.ih b/ospray/render/pathtracer/materials/Material.ih index fa8097f85e..876d6e122f 100644 --- a/ospray/render/pathtracer/materials/Material.ih +++ b/ospray/render/pathtracer/materials/Material.ih @@ -26,7 +26,7 @@ struct PathTraceMaterial; -typedef const varying BSDF* uniform (*PathTraceMaterial_GetBSDFFunc)(const uniform PathTraceMaterial* uniform material, +typedef const varying BSDF* uniform (*PathTraceMaterial_GetBSDFFunc)(const uniform PathTraceMaterial* uniform self, uniform ShadingContext* uniform ctx, /*! The point to shade on a surface. */ const DifferentialGeometry& dg, @@ -35,7 +35,7 @@ typedef const varying BSDF* uniform (*PathTraceMaterial_GetBSDFFunc)(const unifo /*! The medium this ray travels inside. */ const Medium& currentMedium); -typedef vec3f (*PathTraceMaterial_GetTransparencyFunc)(const uniform PathTraceMaterial* uniform material, +typedef vec3f (*PathTraceMaterial_GetTransparencyFunc)(const uniform PathTraceMaterial* uniform self, /*! The point to shade on a surface. */ const DifferentialGeometry& dg, /*! The ray arriving at the point to shade. */ @@ -43,8 +43,8 @@ typedef vec3f (*PathTraceMaterial_GetTransparencyFunc)(const uniform PathTraceMa /*! The medium this ray travels inside. */ const Medium& currentMedium); -typedef void (*PathTraceMaterial_SelectNextMediumFunc)(const uniform PathTraceMaterial *uniform self, - varying Medium& currentMedium); +typedef void (*PathTraceMaterial_SelectNextMediumFunc)(const uniform PathTraceMaterial* uniform self, + Medium& currentMedium); struct PathTraceMaterial { @@ -54,7 +54,7 @@ struct PathTraceMaterial PathTraceMaterial_SelectNextMediumFunc selectNextMedium; }; -void PathTraceMaterial_Constructor(uniform PathTraceMaterial *uniform self, +void PathTraceMaterial_Constructor(uniform PathTraceMaterial* uniform self, uniform PathTraceMaterial_GetBSDFFunc getBSDF, uniform PathTraceMaterial_GetTransparencyFunc getTransparency, uniform PathTraceMaterial_SelectNextMediumFunc selectNextMedium); diff --git a/ospray/render/pathtracer/materials/Material.ispc b/ospray/render/pathtracer/materials/Material.ispc index 541ab6ec47..e8df0cbf26 100644 --- a/ospray/render/pathtracer/materials/Material.ispc +++ b/ospray/render/pathtracer/materials/Material.ispc @@ -25,7 +25,7 @@ vec3f PathTraceMaterial_getTransparency(const uniform PathTraceMaterial* uniform } void PathTraceMaterial_selectNextMedium(const uniform PathTraceMaterial* uniform self, - varying Medium& currentMedium) + Medium& currentMedium) { /* do nothing by default */ } void PathTraceMaterial_Constructor(uniform PathTraceMaterial* uniform self, diff --git a/ospray/render/pathtracer/materials/Medium.ih b/ospray/render/pathtracer/materials/Medium.ih index d80d9f669a..427b5e55a5 100644 --- a/ospray/render/pathtracer/materials/Medium.ih +++ b/ospray/render/pathtracer/materials/Medium.ih @@ -30,7 +30,7 @@ inline Medium make_Medium(const vec3f transmission, const float ior) return m; } -inline Medium make_Medium_Vacuum() { +inline Medium make_Medium_vacuum() { return make_Medium(make_vec3f(1.0f),1.0f); } diff --git a/ospray/render/pathtracer/materials/ThinGlass.cpp b/ospray/render/pathtracer/materials/ThinGlass.cpp index b0e1cf54d5..abf23b9b9e 100644 --- a/ospray/render/pathtracer/materials/ThinGlass.cpp +++ b/ospray/render/pathtracer/materials/ThinGlass.cpp @@ -29,9 +29,9 @@ namespace ospray { if (getIE() != NULL) return; const vec3f& transmission - = getParam3f("transmission",vec3f(1.f)); //vec3f(0.19,0.45,1.5)); + = getParam3f("transmission", vec3f(1.f)); const float eta - = getParamf("eta",1.4f); //vec3f(.4f,0.f,0.f)); + = getParamf("eta", 1.5f); const float thickness = getParamf("thickness",1.f); diff --git a/ospray/render/pathtracer/materials/ThinGlass.ispc b/ospray/render/pathtracer/materials/ThinGlass.ispc index 91e8e577ff..f6bf8ef2ba 100644 --- a/ospray/render/pathtracer/materials/ThinGlass.ispc +++ b/ospray/render/pathtracer/materials/ThinGlass.ispc @@ -47,8 +47,7 @@ vec3f ThinGlass_getTransparency(const uniform PathTraceMaterial* uniform materia { const uniform ThinGlass* uniform self = (const uniform ThinGlass* uniform)material; - float cosThetaO = max(dot(ray.dir, dg.Ns), 0.0f); - vec3f transmission = self->transmission; + float cosThetaO = max(-dot(ray.dir, dg.Ns), 0.0f); float alpha = self->thickness * rcp(cosThetaO); return powf(self->transmission, alpha) * (1.0f-fresnelDielectric(cosThetaO, self->eta)); } diff --git a/ospray/render/raycast/RaycastRenderer.cpp b/ospray/render/raycast/RaycastRenderer.cpp index 158904eb79..159208cf33 100644 --- a/ospray/render/raycast/RaycastRenderer.cpp +++ b/ospray/render/raycast/RaycastRenderer.cpp @@ -111,5 +111,11 @@ namespace ospray { RaycastRenderer_testFrame; OSP_REGISTER_RENDERER(RaycastRenderer_testFrame,testFrame); + /*! \brief Instantion of Ray Cast Renderer that renders a simple + test frame, without even calling postIntersct */ + typedef RaycastRenderer + RaycastRenderer_rayDir; + OSP_REGISTER_RENDERER(RaycastRenderer_rayDir,rayDir); + } // ::ospray diff --git a/ospray/render/raycast/RaycastRenderer.ispc b/ospray/render/raycast/RaycastRenderer.ispc index e9b216bc98..e0d35a7944 100644 --- a/ospray/render/raycast/RaycastRenderer.ispc +++ b/ospray/render/raycast/RaycastRenderer.ispc @@ -35,9 +35,9 @@ struct RaycastRenderer // int shadeMode; unused }; -//! a simple test-frame renderer that doesn't even trace a ray, just -//! returns a well-defined test frame (mostly useful for debugging -//! whether frame buffers are properly set up etcpp +/*! a simple test-frame renderer that doesn't even trace a ray, just + returns a well-defined test frame (mostly useful for debugging + whether frame buffers are properly set up etcpp */ void RaycastRenderer_renderSample_testFrame(uniform Renderer *uniform _self, void *uniform perFrameData, varying ScreenSample &sample) @@ -49,6 +49,17 @@ void RaycastRenderer_renderSample_testFrame(uniform Renderer *uniform _self, sample.z = 1.f; } +/*! a simple test-frame renderer that doesn't even trace a ray, just + returns the absolute of the ray direction */ +void RaycastRenderer_renderSample_rayDir(uniform Renderer *uniform _self, + void *uniform perFrameData, + varying ScreenSample &sample) +{ + sample.rgb = absf(sample.ray.dir); + sample.alpha = 1.f; + sample.z = 1.f; +} + void RaycastRenderer_renderSample_eyeLight(uniform Renderer *uniform _self, void *uniform perFrameData, varying ScreenSample &sample) @@ -286,6 +297,7 @@ void RaycastRenderer_renderSample_backfacing_Ns(uniform Renderer *uniform _self, } \ DEFINE_RAYCAST_RENDERER(testFrame); +DEFINE_RAYCAST_RENDERER(rayDir); DEFINE_RAYCAST_RENDERER(eyeLight); DEFINE_RAYCAST_RENDERER(Ng); DEFINE_RAYCAST_RENDERER(Ns); diff --git a/ospray/render/scivis/SciVisMaterial.cpp b/ospray/render/scivis/SciVisMaterial.cpp index f0a7958438..2a5100ed64 100644 --- a/ospray/render/scivis/SciVisMaterial.cpp +++ b/ospray/render/scivis/SciVisMaterial.cpp @@ -58,6 +58,7 @@ namespace ospray { } OSP_REGISTER_MATERIAL(SciVisMaterial, SciVisMaterial); + OSP_REGISTER_MATERIAL(SciVisMaterial, OBJMaterial); } // ::ospray::scivis } // ::ospray diff --git a/ospray/render/scivis/SciVisRenderer.cpp b/ospray/render/scivis/SciVisRenderer.cpp index 81582bc36e..26b6078bfa 100644 --- a/ospray/render/scivis/SciVisRenderer.cpp +++ b/ospray/render/scivis/SciVisRenderer.cpp @@ -43,11 +43,11 @@ namespace ospray { void **lightPtr = lightArray.empty() ? NULL : &lightArray[0]; - const bool shadowsEnabled = bool(getParam1i("shadowsEnabled", 1)); + const bool shadowsEnabled = getParam1i("shadowsEnabled", 0); const int32 maxDepth = getParam1i("maxDepth", 10); - int numAOSamples = getParam1i("aoSamples", 4); + int numAOSamples = getParam1i("aoSamples", 0); float rayLength = getParam1f("aoOcclusionDistance", 1e20f); float aoWeight = getParam1f("aoWeight", 0.25f); @@ -76,6 +76,8 @@ namespace ospray { OSP_REGISTER_RENDERER(SciVisRenderer, rt); OSP_REGISTER_RENDERER(SciVisRenderer, scivis); OSP_REGISTER_RENDERER(SciVisRenderer, sv); + OSP_REGISTER_RENDERER(SciVisRenderer, obj); + OSP_REGISTER_RENDERER(SciVisRenderer, OBJ); } // ::ospray::scivis } // ::ospray diff --git a/ospray/render/scivis/SciVisRenderer.ispc b/ospray/render/scivis/SciVisRenderer.ispc index 4cdcd0c3e0..01f03017a6 100644 --- a/ospray/render/scivis/SciVisRenderer.ispc +++ b/ospray/render/scivis/SciVisRenderer.ispc @@ -30,8 +30,7 @@ #define ALPHA_THRESHOLD (.05f) -// Data types -////////////////////////////////////////////////////////////////////////////// +// Data types ///////////////////////////////////////////////////////////////// struct SciVisRenderer { @@ -61,17 +60,7 @@ struct SciVisShadingInfo vec3f geometryColor; }; -struct PassInfo { - // region to integrate over in this pass - varying region1f region; - // block to use in this pass - NULL for 'everything other than blocks' - DDBVolumeBlock *uniform block; - // blend in background color when ray misses - uniform bool useBG; -}; - -// Function definitions -/////////////////////////////////////////////////////////////////////////////// +// Function definitions /////////////////////////////////////////////////////// inline void initShadingInfo(varying SciVisShadingInfo &info) { @@ -118,6 +107,9 @@ inline void shadeMaterials(const varying DifferentialGeometry &dg, } } } + // BRDF normalization + info.Kd = info.Kd * one_over_pi; + info.Ks = info.Ks * ((info.Ns + 2.f) * one_over_two_pi); } // AO functions // @@ -150,6 +142,7 @@ inline float calculateAO(const uniform SciVisRenderer *uniform self, hits++; } + // the cosTheta of cosineSampleHemispherePDF and dot(dg.Ns, ao_dir) cancel return 1.0f - (float)hits/self->aoSamples; } @@ -223,7 +216,7 @@ inline void shadeLights(const uniform SciVisRenderer *uniform self, const varying Ray &ray, const varying DifferentialGeometry &dg, const varying SciVisShadingInfo &info, - const varying float depth, + const varying int path_depth, varying vec3f &color) { const vec3f R = ray.dir - ((2.f * dot(ray.dir, dg.Ns)) * dg.Ns); @@ -233,24 +226,24 @@ inline void shadeLights(const uniform SciVisRenderer *uniform self, for (uniform int i = 0; self->lights && i < self->numLights; i++) { const uniform Light *uniform l = self->lights[i]; const vec2f s = make_vec2f(0.5f); - const LightSample light = l->sample(l, dg, s); + const Light_SampleRes light = l->sample(l, dg, s); - if (reduce_max(light.radiance) > 0.f) { // any potential contribution? - const float cosNL = abs(dot(light.direction, dg.Ns)); - const float cosLR = max(0.f, dot(light.direction, R)); + if (reduce_max(light.weight) > 0.f) { // any potential contribution? + const float cosNL = abs(dot(light.dir, dg.Ns)); + const float cosLR = max(0.f, dot(light.dir, R)); const vec3f brdf = info.Kd * cosNL + info.Ks * powf(cosLR, info.Ns); const vec3f light_contrib = info.local_opacity - * brdf * light.radiance; + * brdf * light.weight; if (self->shadowsEnabled) { const float max_contrib = reduce_max(light_contrib); if (max_contrib > .01f) { Ray shadowRay; - setRay(shadowRay, P, light.direction); + setRay(shadowRay, P, light.dir); const float light_alpha = lightAlpha(shadowRay, self->super.model, max_contrib, - self->maxDepth - depth, + self->maxDepth - path_depth, self->super.epsilon); color = color + light_alpha * light_contrib; } @@ -294,14 +287,15 @@ inline void SciVisRenderer_computeVolumeSample(SciVisRenderer *uniform renderer, const vec2f s = make_vec2f(0.5f); for (uniform uint32 i=0; inumLights; i++) { - const LightSample light = renderer->lights[i]->sample(renderer->lights[i], dg, s); + const Light_SampleRes light = + renderer->lights[i]->sample(renderer->lights[i], dg, s); const float cosNL = (gradient.x == 0.f && gradient.y == 0.f && gradient.z == 0.f) ? - 1.f : abs(dot(safe_normalize(light.direction), + 1.f : abs(dot(safe_normalize(light.dir), gradient)); - shadedColor = shadedColor + sampleColor * cosNL * light.radiance; + shadedColor = shadedColor + sampleColor * cosNL * light.weight; } sampleColor = shadedColor; @@ -326,46 +320,74 @@ void SciVisRenderer_computeGeometrySample(SciVisRenderer *uniform self, varying Ray &ray, varying vec4f &out_color) { - //NOTE(jda) - no geometry opacity handled here... + vec3f color = make_vec3f(0.f); + float path_opacity = 1.f; + int path_depth = 0; + float ray_t_depth = 0.f; - // We compute intersections on the model and provide the contribution for the - // closest hit. - traceRay(self->super.model, ray); + while (1) { - // No hit found. - if(ray.geomID < 0) { - ray.t = infinity; - return; - } + traceRay(self->super.model, ray); + + // Check if we missed, if so we are done // + if (ray.geomID < 0) { + out_color = make_vec4f(color.x, color.y, color.z, 1.f - path_opacity); + return; + } - // Calculate material information from DG // - DifferentialGeometry dg; - postIntersect(self->super.model, dg, ray, - DG_NG|DG_NS|DG_NORMALIZE|DG_FACEFORWARD| - DG_MATERIALID|DG_COLOR|DG_TEXCOORD); + // Record depth of first hit for depth output // + if (path_depth == 0) { + ray_t_depth = ray.t; + } - SciVisShadingInfo info; - initShadingInfo(info); + // Start shading // - shadeMaterials(dg, info); + // Calculate material information from DG // + DifferentialGeometry dg; + postIntersect(self->super.model, + dg, + ray, + DG_NG|DG_NS|DG_NORMALIZE|DG_FACEFORWARD| + DG_MATERIALID|DG_COLOR|DG_TEXCOORD); - info.local_opacity = info.d; + SciVisShadingInfo info; + initShadingInfo(info); - vec3f color = make_vec3f(0.f); + shadeMaterials(dg, info); - shadeAO(self, sampleID, dg, info, color); - shadeLights(self, ray, dg, info, 0/*depth*/, color); + info.local_opacity = path_opacity * info.d; - out_color = make_vec4f(color.x, color.y, color.z, 1.f); + if (info.local_opacity > 0.01f) { // worth shading? + shadeAO(self, sampleID, dg, info, color); + shadeLights(self, ray, dg, info, path_depth, color); + } + + // Kill path when reached max depth or if remaining contribution too low + path_opacity = path_opacity * (1.f - info.d); + path_depth++; + if (path_depth >= self->maxDepth || path_opacity < 0.01f ) { + out_color = make_vec4f(color.x, color.y, color.z, 1.f - path_opacity); + ray.t = ray_t_depth; + return; + } + + // Reset ray + ray.t0 = ray.t + self->super.epsilon; + ray.t = infinity; + ray.primID = -1; + ray.geomID = -1; + ray.instID = -1; + } } -/*! Returns the first hit volume for the provided ray and sets the ray bounds t0 and t, - considering the provided ray offset and any clipping. If no volume is found, the - returned volume is NULL and ray.t0 will be set to infinity. */ +/*! Returns the first hit volume for the provided ray and sets the ray bounds + * t0 and t, considering the provided ray offset and any clipping. If no + * volume is found, the returned volume is NULL and ray.t0 will be set to + * infinity. + */ inline Volume * SciVisRenderer_intersectVolumes(uniform SciVisRenderer *uniform renderer, varying Ray &ray, - const uniform PassInfo &passInfo, const varying float &rayOffset) { // The first intersected volume. @@ -384,7 +406,8 @@ SciVisRenderer_intersectVolumes(uniform SciVisRenderer *uniform renderer, intersectBox(ray, volume_i->boundingBox, t0, t1); // Clip against volume clipping box (if specified). - if(ne(volume_i->volumeClippingBox.lower, volume_i->volumeClippingBox.upper)) { + if(ne(volume_i->volumeClippingBox.lower, + volume_i->volumeClippingBox.upper)) { float tClip0, tClip1; intersectBox(ray, volume_i->volumeClippingBox, tClip0, tClip1); @@ -415,19 +438,11 @@ SciVisRenderer_intersectVolumes(uniform SciVisRenderer *uniform renderer, /*! This function intersects the volume and geometries. */ void SciVisRenderer_intersect(uniform SciVisRenderer *uniform renderer, varying Ray &ray, - const uniform PassInfo &passInfo, const varying float &rayOffset, const varying vec3i &sampleID, varying vec4f &color, varying float &depth) { - const region1f clipRange = passInfo.region; - - if (clipRange.lower != 0.f) { - ray.t0 = max(ray.t0,clipRange.lower); - ray.t = min(ray.t,clipRange.upper); - } - // Original tMax for ray interval const float tMax = ray.t; @@ -457,8 +472,7 @@ void SciVisRenderer_intersect(uniform SciVisRenderer *uniform renderer, geometryRay.instID = -1; // Get first intersected volume for each ray and set the ray bounds. - Volume *volume = SciVisRenderer_intersectVolumes(renderer, ray, - passInfo, rayOffset); + Volume *volume = SciVisRenderer_intersectVolumes(renderer, ray, rayOffset); // Provide ray offset for use with isosurface geometries (this value // ignored elsewhere). @@ -480,8 +494,15 @@ void SciVisRenderer_intersect(uniform SciVisRenderer *uniform renderer, // Trace the ray through the volume and geometries. float firstHit; - while ((firstHit = min(ray.t0, geometryRay.t)) < min(tMax,clipRange.upper) - && min(min(color.x, color.y), color.z) < 1.0f && color.w < 0.99f) { + if(geometryRay.t < ray.t0 || volume == NULL) { + // Geometry contribution. + color = color + (1.0f - color.w) * geometryColor; + } + + while ((firstHit = min(ray.t0, geometryRay.t)) < tMax + /*&& min(min(color.x, color.y), color.z) < 1.0f*///<--why is this here? + && color.w < 0.99f) { + if (firstHit == ray.t0) { // Check to see if we've exited the current volume. @@ -489,8 +510,8 @@ void SciVisRenderer_intersect(uniform SciVisRenderer *uniform renderer, ray.t0 = ray.t + epsilon; ray.t = tMax; - volume = SciVisRenderer_intersectVolumes(renderer, ray, - passInfo, rayOffset); + volume = SciVisRenderer_intersectVolumes(renderer, ray, rayOffset); + } else { if (any(volume == NULL)) @@ -505,7 +526,8 @@ void SciVisRenderer_intersect(uniform SciVisRenderer *uniform renderer, color = color + (1.0f - color.w) * volumeColor; } - } else if (firstHit == geometryRay.t) { + + } else {// firstHit == geometryRay.t // Geometry contribution. color = color + (1.0f - color.w) * geometryColor; @@ -531,96 +553,13 @@ void SciVisRenderer_intersect(uniform SciVisRenderer *uniform renderer, } } -// Main shading function // - -inline -void SciVisRenderer_shadeRay(const uniform SciVisRenderer *uniform self, - varying ScreenSample &sample) -{ - Ray &ray = sample.ray; - // ISPC issue #703. Switch to 'nice' code once ISPC #703 is fixed. - // print("ray.dir % % %\n",ray.dir.x,ray.dir.y,ray.dir.z); - vec3f color = make_vec3f(0.f); - float path_opacity = 1.f; - int depth = 0; - - while (1) { - - traceRay(self->super.model, ray); - - // Record depth of first hit in z buffer // - if (depth == 0) { - sample.z = ray.t; - } - - // Check if we missed, if so we are done // - if (ray.geomID < 0) { - sample.rgb = self->super.backgroundEnabled ? - color + path_opacity * self->super.bgColor : - color; - sample.alpha = 1.f - path_opacity; - return; - } - - // Start shading // - - // Calculate material information from DG // - DifferentialGeometry dg; - postIntersect(self->super.model, - dg, - ray, - DG_NG|DG_NS|DG_NORMALIZE|DG_FACEFORWARD| - DG_MATERIALID|DG_COLOR|DG_TEXCOORD); - - SciVisShadingInfo info; - initShadingInfo(info); - - shadeMaterials(dg, info); - - info.local_opacity = path_opacity * info.d; - - if (info.local_opacity > 0.01f) { // worth shading? - shadeAO(self, sample.sampleID, dg, info, color); - shadeLights(self, ray, dg, info, depth, color); - } - - // kill path when reached max depth or if remaining contribution too low - path_opacity = path_opacity * (1.f - info.d); - depth++; - if (depth >= self->maxDepth | path_opacity < 0.01f ) { - sample.rgb = color; - sample.alpha = 1.f - path_opacity; - return; - } - - ray.t0 = ray.t + self->super.epsilon; - ray.t = infinity; - ray.primID = -1; - ray.geomID = -1; - ray.instID = -1; - } -} - void SciVisRenderer_renderSample(uniform Renderer *uniform _self, void *uniform perFrameData, varying ScreenSample &sample) { - //NOTE(jda) - Eliminate #if'd out code path when satisfied with surface only - // scene performance and features -#if 0 - uniform SciVisRenderer *uniform self = - (uniform SciVisRenderer *uniform)_self; - SciVisRenderer_shadeRay(self, sample); -#else SciVisRenderer *uniform renderer = (SciVisRenderer *uniform) _self; - PassInfo *uniform passInfo - = (PassInfo *uniform)perFrameData; - - // Background color. - const uniform bool useBG = ((passInfo == NULL) || passInfo->useBG); - // Ray offset for this sample, as a fraction of the nominal step size. float rayOffset = precomputedHalton2(sample.sampleID.z); int ix = sample.sampleID.x % 4; @@ -632,23 +571,14 @@ void SciVisRenderer_renderSample(uniform Renderer *uniform _self, // Provide the renderer to the intersector as it contains all // volumes, geometries, etc. - vec4f color = make_vec4f(0.0f,0.f,0.f,0.f); + vec4f color = make_vec4f(0.0f); float depth = infinity; - if (passInfo != NULL) { - SciVisRenderer_intersect(renderer, sample.ray, *passInfo, - rayOffset, sample.sampleID, color, depth); - } else { - uniform PassInfo dummyPassInfo; - dummyPassInfo.region = make_region1f(0.f,inf); - dummyPassInfo.useBG = true; - dummyPassInfo.block = NULL; - SciVisRenderer_intersect(renderer, sample.ray, dummyPassInfo, - rayOffset, sample.sampleID, color, depth); - } + SciVisRenderer_intersect(renderer, sample.ray, rayOffset, + sample.sampleID, color, depth); // Attenuate the foreground and background colors by the opacity. - if (useBG && renderer->super.backgroundEnabled) { + if (renderer->super.backgroundEnabled) { const vec4f background = make_vec4f(renderer->super.bgColor, 1.f); color = color.w * color + (1.0f - color.w) * background; } @@ -659,7 +589,6 @@ void SciVisRenderer_renderSample(uniform Renderer *uniform _self, sample.rgb.z = color.z; sample.alpha = color.w; sample.z = depth; -#endif } // Exports (called from C++) @@ -681,7 +610,10 @@ export void SciVisRenderer_set(void *uniform _self, self->maxDepth = maxDepth; self->aoSamples = aoSamples; self->aoRayLength = aoRayLength; - self->aoWeight = aoWeight; + + // already factor in parts of cosineSampleHemispherePDF + self->aoWeight = aoWeight * pi; + self->lights = (const uniform Light *uniform *uniform)lights; self->numLights = numLights; } @@ -691,7 +623,7 @@ export void *uniform SciVisRenderer_create(void *uniform cppE) uniform SciVisRenderer *uniform self = uniform new uniform SciVisRenderer; Renderer_Constructor(&self->super,cppE); self->super.renderSample = SciVisRenderer_renderSample; - SciVisRenderer_set(self, true, 10, 4, infinity, 1.f, NULL, 0); + SciVisRenderer_set(self, true, 10, 4, infinity, 0.25f, NULL, 0); return self; } diff --git a/ospray/render/simpleAO/SimpleAO.h b/ospray/render/simpleAO/SimpleAO.h index 4a978b6bad..212d102cf3 100644 --- a/ospray/render/simpleAO/SimpleAO.h +++ b/ospray/render/simpleAO/SimpleAO.h @@ -33,7 +33,7 @@ // ospray #include "ospray/render/Renderer.h" -#include "ospray/texture/Texture.h" +#include "ospray/texture/Texture2D.h" namespace ospray { diff --git a/ospray/render/simpleAO/SimpleAO.ispc b/ospray/render/simpleAO/SimpleAO.ispc index 12ab56c592..c1fad7ba46 100644 --- a/ospray/render/simpleAO/SimpleAO.ispc +++ b/ospray/render/simpleAO/SimpleAO.ispc @@ -82,12 +82,13 @@ inline vec3f getRandomDir(varying RandomTEA* uniform rng, inline void shade_ao(uniform SimpleAO *uniform self, varying vec3f &color, varying float &alpha, - int sampleCnt, + const uniform int sampleCnt, + const uniform int accumID, const Ray &ray, const int32 pixel_x, const int32 pixel_y, - const float rot_x, - const float rot_y) + const uniform float rot_x, + const uniform float rot_y) { if (ray.geomID < 0) { color = self->super.backgroundEnabled ? self->super.bgColor : @@ -119,7 +120,7 @@ inline void shade_ao(uniform SimpleAO *uniform self, uniform FrameBuffer *uniform fb = self->super.fb; RandomTEA rng_state; varying RandomTEA* const uniform rng = &rng_state; - RandomTEA__Constructor(rng, (fb->size.x * pixel_y) + pixel_x, fb->accumID); + RandomTEA__Constructor(rng, (fb->size.x * pixel_y) + pixel_x, accumID); int hits = 0; vec3f biNormU,biNormV; @@ -153,16 +154,15 @@ void SimpleAO_renderSample(uniform Renderer *uniform _self, traceRay(self->super.model, sample.ray); sample.z = sample.ray.t; - uniform int samplesPerFrame = self->samplesPerFrame; - uniform int framesPer16 = 16 / samplesPerFrame; - int accumID = sample.sampleID.z / framesPer16; - float rot_x = 1.f - precomputedHalton3(accumID); - float rot_y = 1.f - precomputedHalton5(accumID); + const uniform int accumID = reduce_max(sample.sampleID.z) * self->samplesPerFrame; + const uniform float rot_x = 1.f - precomputedHalton3(accumID); + const uniform float rot_y = 1.f - precomputedHalton5(accumID); shade_ao(self, sample.rgb, sample.alpha, - samplesPerFrame, + self->samplesPerFrame, + accumID, sample.ray, sample.sampleID.x, sample.sampleID.y, diff --git a/ospray/render/simpleAO/SimpleAOMaterial.h b/ospray/render/simpleAO/SimpleAOMaterial.h index dc05f75e9c..5e0944d509 100644 --- a/ospray/render/simpleAO/SimpleAOMaterial.h +++ b/ospray/render/simpleAO/SimpleAOMaterial.h @@ -43,7 +43,7 @@ namespace ospray { vec3f Kd; //! \brief diffuse texture, if available - Ref map_Kd; + Ref map_Kd; }; }//namespace ospray::simpleao }//namespace ospray diff --git a/ospray/render/util.ih b/ospray/render/util.ih index d1134f26f1..2d4ed645fd 100644 --- a/ospray/render/util.ih +++ b/ospray/render/util.ih @@ -49,6 +49,25 @@ inline float precomputedHalton5(uint32 sampleID) } +inline uniform float precomputedHalton2(uniform uint32 sampleID) +{ + if (!precomputedHalton_initialized) precomputedHalton_create(); + return precomputedHalton[0][sampleID & (NUM_PRECOMPUTED_HALTON_VALUES-1)]; +} + +inline uniform float precomputedHalton3(uniform uint32 sampleID) +{ + if (!precomputedHalton_initialized) precomputedHalton_create(); + return precomputedHalton[1][sampleID & (NUM_PRECOMPUTED_HALTON_VALUES-1)]; +} + +inline uniform float precomputedHalton5(uniform uint32 sampleID) +{ + if (!precomputedHalton_initialized) precomputedHalton_create(); + return precomputedHalton[2][sampleID & (NUM_PRECOMPUTED_HALTON_VALUES-1)]; +} + + inline vec3f make_random_color(const int i) { diff --git a/ospray/render/volume/RaycastVolumeRenderer.cpp b/ospray/render/volume/RaycastVolumeRenderer.cpp index d98df69f60..35056d5f6f 100644 --- a/ospray/render/volume/RaycastVolumeRenderer.cpp +++ b/ospray/render/volume/RaycastVolumeRenderer.cpp @@ -18,7 +18,7 @@ #include "ospray/lights/Light.h" #include "ospray/common/Data.h" #include "ospray/common/Core.h" -#include "ospray/common/parallel_for.h" +#include "ospray/common/tasking/parallel_for.h" #include "ospray/render/volume/RaycastVolumeRenderer.h" #include "RaycastVolumeMaterial.h" @@ -46,24 +46,26 @@ namespace ospray { CacheForBlockTiles(size_t numBlocks) : numBlocks(numBlocks), blockTile(new Tile *[numBlocks]) { - for (int i=0;i::infinity(); Tile *tile = new Tile; - for (int i=0;ir[i] = 0.f; - for (int i=0;ig[i] = 0.f; - for (int i=0;ib[i] = 0.f; - for (int i=0;ia[i] = 0.f; - for (int i=0;iz[i] = std::numeric_limits::infinity(); + for (int i = 0; i < TILE_SIZE*TILE_SIZE; i++) tile->r[i] = 0.f; + for (int i = 0; i < TILE_SIZE*TILE_SIZE; i++) tile->g[i] = 0.f; + for (int i = 0; i < TILE_SIZE*TILE_SIZE; i++) tile->b[i] = 0.f; + for (int i = 0; i < TILE_SIZE*TILE_SIZE; i++) tile->a[i] = 0.f; + for (int i = 0; i < TILE_SIZE*TILE_SIZE; i++) tile->z[i] = infinity; return tile; } @@ -72,17 +74,17 @@ namespace ospray { #if TILE_CACHE_SAFE_MUTEX mutex.lock(); Tile *tile = blockTile[blockID]; - if (tile == NULL) { + if (tile == nullptr) { blockTile[blockID] = tile = allocTile(); } mutex.unlock(); return tile; #else Tile *tile = blockTile[blockID]; - if (tile != NULL) return tile; + if (tile != nullptr) return tile; mutex.lock(); tile = blockTile[blockID]; - if (tile == NULL) { + if (tile == nullptr) { blockTile[blockID] = tile = allocTile(); } mutex.unlock(); @@ -115,7 +117,7 @@ namespace ospray { DPRenderTask(int workerRank); - void run(size_t taskIndex) const; + void operator()(int taskIndex) const; }; DPRenderTask::DPRenderTask(int workerRank) @@ -123,35 +125,27 @@ namespace ospray { { } - void DPRenderTask::run(size_t taskIndex) const + void DPRenderTask::operator()(int taskIndex) const { const size_t tileID = taskIndex; - Tile bgTile, fgTile; const size_t tile_y = taskIndex / numTiles_x; const size_t tile_x = taskIndex - tile_y*numTiles_x; - bgTile.region.lower.x = tile_x * TILE_SIZE; - bgTile.region.lower.y = tile_y * TILE_SIZE; - bgTile.region.upper.x = std::min(bgTile.region.lower.x+TILE_SIZE,fb->size.x); - bgTile.region.upper.y = std::min(bgTile.region.lower.y+TILE_SIZE,fb->size.y); - bgTile.fbSize = fb->size; - bgTile.rcp_fbSize = rcp(vec2f(bgTile.fbSize)); - bgTile.generation = 0; - bgTile.children = 0; - - fgTile.region = bgTile.region; - fgTile.fbSize = bgTile.fbSize; - fgTile.rcp_fbSize = bgTile.rcp_fbSize; - fgTile.generation = 0; - fgTile.children = 0; + const vec2i tileId(tile_x, tile_y); + const int32 accumID = fb->accumID(tileID); + Tile bgTile(tileId, fb->size, accumID); + Tile fgTile(bgTile); size_t numBlocks = dpv->numDDBlocks; CacheForBlockTiles blockTileCache(numBlocks); // for (int i=0;iddBlock[i].bounds); bool *blockWasVisible = (bool*)alloca(numBlocks*sizeof(bool)); - for (int i=0;isetTile(fgTile); - // all other tiles for gen #1 will be set below, no matter whether it's mine or not + // all other tiles for gen #1 will be set below, no matter whether + // it's mine or not } // now, send all block cache tiles that were generated on this @@ -206,37 +203,36 @@ 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;blockIDregion = bgTile.region; tile->fbSize = bgTile.fbSize; tile->rcp_fbSize = bgTile.rcp_fbSize; tile->generation = 1; tile->children = 0; //nextGenTile-1; - // for (int i=0;ir[i] = float((blockID*3*7) % 11) / 11.f; - fb->setTile(*tile); } } /*! try if we are running in data-parallel mode, and if data-parallel is even required. if not (eg, if there's no - data-parallel volumes in the scene) return NULL and render only + data-parallel volumes in the scene) return nullptr and render only in regular mode; otherwise, compute some precomputations and return pointer to that (which'll switch the main renderframe fct to render data parallel) */ - void RaycastVolumeRenderer::renderFrame(FrameBuffer *fb, const uint32 channelFlags) + float RaycastVolumeRenderer::renderFrame(FrameBuffer *fb, + const uint32 channelFlags) { int workerRank = ospray::core::getWorkerRank(); - std::vector ddVolumeVec; - for (int volumeID=0;volumeIDvolume.size();volumeID++) { - const DataDistributedBlockedVolume *ddv - = dynamic_cast(model->volume[volumeID].ptr); + using DDBV = DataDistributedBlockedVolume; + std::vector ddVolumeVec; + for (int volumeID = 0; volumeID < model->volume.size(); volumeID++) { + const DDBV* ddv = dynamic_cast(model->volume[volumeID].ptr); if (!ddv) continue; ddVolumeVec.push_back(ddv); } @@ -244,12 +240,12 @@ namespace ospray { if (ddVolumeVec.empty()) { static bool printed = false; if (!printed) { - cout << "no data parallel volumes, rendering in traditional raycast_volume_render mode" << endl; + cout << "no data parallel volumes, rendering in traditional" + << " raycast_volume_render mode" << endl; printed = true; } - Renderer::renderFrame(fb,channelFlags); - return; + return Renderer::renderFrame(fb,channelFlags); } // ======================================================= @@ -263,18 +259,20 @@ namespace ospray { // check if we're even in mpi parallel mode (can't do // data-parallel otherwise) - if (!ospray::core::isMpiParallel()) + if (!ospray::core::isMpiParallel()) { throw std::runtime_error("#dvr: need data-parallel rendering, " "but not running in mpi mode!?"); + } // switch (distributed) frame buffer into compositing mode DistributedFrameBuffer *dfb = dynamic_cast(fb); - if (!dfb) + if (!dfb) { throw std::runtime_error("OSPRay data parallel rendering error. " "this is a data-parallel scene, but we're " "not using the distributed frame buffer!?"); - dfb->setFrameMode(DistributedFrameBuffer::ALPHA_BLENDING); + } + dfb->setFrameMode(DistributedFrameBuffer::ALPHA_BLENDING); // note: we can NEVER be the master, since the master doesn't even // have an instance of this renderer class - @@ -299,16 +297,17 @@ namespace ospray { DPRenderTask renderTask(workerRank); renderTask.fb = fb; renderTask.renderer = this; - renderTask.numTiles_x = divRoundUp(dfb->size.x,TILE_SIZE); - renderTask.numTiles_y = divRoundUp(dfb->size.y,TILE_SIZE); + renderTask.numTiles_x = divRoundUp(dfb->size.x, TILE_SIZE); + renderTask.numTiles_y = divRoundUp(dfb->size.y, TILE_SIZE); renderTask.channelFlags = channelFlags; renderTask.dpv = ddVolumeVec[0]; size_t NTASKS = renderTask.numTiles_x * renderTask.numTiles_y; - parallel_for(NTASKS, [&](int taskIndex){renderTask.run(taskIndex);}); + parallel_for(NTASKS, renderTask); dfb->waitUntilFinished(); - Renderer::endFrame(NULL,channelFlags); + Renderer::endFrame(nullptr, channelFlags); + return fb->endFrame(0.f); } #endif @@ -316,21 +315,22 @@ namespace ospray { void RaycastVolumeRenderer::commit() { // Create the equivalent ISPC RaycastVolumeRenderer object. - if (ispcEquivalent == NULL) { + if (ispcEquivalent == nullptr) { ispcEquivalent = ispc::RaycastVolumeRenderer_createInstance(); } // Set the lights if any. - Data *lightsData = (Data *)getParamData("lights", NULL); + Data *lightsData = (Data *)getParamData("lights", nullptr); lights.clear(); - if (lightsData) + if (lightsData) { for (size_t i=0; isize(); i++) lights.push_back(((Light **)lightsData->data)[i]->getIE()); + } ispc::RaycastVolumeRenderer_setLights(ispcEquivalent, - lights.empty() ? NULL : &lights[0], + lights.empty() ? nullptr : &lights[0], lights.size()); // Initialize state in the parent class, must be called after the ISPC diff --git a/ospray/render/volume/RaycastVolumeRenderer.h b/ospray/render/volume/RaycastVolumeRenderer.h index fd79e1123a..ca7791df21 100644 --- a/ospray/render/volume/RaycastVolumeRenderer.h +++ b/ospray/render/volume/RaycastVolumeRenderer.h @@ -34,18 +34,18 @@ namespace ospray { ~RaycastVolumeRenderer(); //! Create a material of the given type. - Material* createMaterial(const char *type); + Material* createMaterial(const char *type) override; //! Initialize the renderer state, and create the equivalent ISPC volume //! renderer object. - void commit(); + void commit() override; //! A string description of this class. - std::string toString() const; + std::string toString() const override; #if EXP_DATA_PARALLEL /*! per-frame data to describe the data-parallel components */ - void renderFrame(FrameBuffer *fb, const uint32 channelFlags); + float renderFrame(FrameBuffer *fb, const uint32 channelFlags) override; #endif private: diff --git a/ospray/render/volume/RaycastVolumeRenderer.ih b/ospray/render/volume/RaycastVolumeRenderer.ih index bc604010bc..f3c8645b3f 100644 --- a/ospray/render/volume/RaycastVolumeRenderer.ih +++ b/ospray/render/volume/RaycastVolumeRenderer.ih @@ -33,8 +33,3 @@ struct RaycastVolumeRenderer Light **uniform lights; uint32 numLights; }; - -void RaycastVolumeRenderer_renderFramePostamble(Renderer *uniform renderer, - const uniform int32 accumID); -void RaycastVolumeRenderer_renderFramePreamble(Renderer *uniform renderer, - FrameBuffer *uniform framebuffer); diff --git a/ospray/render/volume/RaycastVolumeRenderer.ispc b/ospray/render/volume/RaycastVolumeRenderer.ispc index 7c99148ba8..3512c2e4e5 100644 --- a/ospray/render/volume/RaycastVolumeRenderer.ispc +++ b/ospray/render/volume/RaycastVolumeRenderer.ispc @@ -25,18 +25,6 @@ #include "ospray/camera/Camera.ih" #include "ospray/common/Model.ih" -#if 0//Cannot enable here b/c RENDERTILE_PIXELS_PER_JOB doesn't match C++ side? -#ifdef RENDERTILE_PIXELS_PER_JOB -# undef RENDERTILE_PIXELS_PER_JOB -#endif - -/*! number of pixels that each job in a parallel rendertile task - executes together. Must be a multipel of the maximum possible - programCount (16), and must be smaller than TILE_SIZE (in one - dimension) */ -#define RENDERTILE_PIXELS_PER_JOB 32 -#endif - struct PassInfo { // region to integrate over in this pass varying region1f region; @@ -46,37 +34,19 @@ struct PassInfo { uniform bool useBG; }; -void RaycastVolumeRenderer_endFrame(Renderer *uniform self, - void *uniform perFrameData, - const uniform int32 accumID) -{ - if (self->fb) - self->fb->accumID = accumID; - - self->fb = NULL; -} - -void *uniform RaycastVolumeRenderer_beginFrame(Renderer *uniform self, - FrameBuffer *uniform framebuffer) -{ - self->fb = framebuffer; - return NULL; -} - inline void RaycastVolumeRenderer_computeVolumeSample(RaycastVolumeRenderer *uniform self, Volume *uniform volume, varying Ray &ray, varying vec4f &color) { - // if (!volume) { print("NULL VOLUME IN VOLUMESAMPLE()\n"); } - // if (!volume->computeSample) { print("trying to sample volume w/o sample function!!!!\n"); } - // 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); + TransferFunction *uniform xf = volume->transferFunction; + // Look up the color associated with the volume sample. - vec3f sampleColor = volume->transferFunction->getColorForValue(volume->transferFunction, sample); + vec3f sampleColor = xf->getColorForValue(xf, sample); // Compute gradient shading, if enabled. if(volume->gradientShadingEnabled) { @@ -94,21 +64,23 @@ inline void RaycastVolumeRenderer_computeVolumeSample(RaycastVolumeRenderer *uni const vec2f s = make_vec2f(0.5f); for (uniform uint32 i=0; inumLights; i++) { - const LightSample light = self->lights[i]->sample(self->lights[i], dg, s); + const Light_SampleRes light = self->lights[i]->sample(self->lights[i], dg, s); const float cosNL = (gradient.x == 0.f && gradient.y == 0.f && gradient.z == 0.f) ? - 1.f : abs(dot(safe_normalize(light.direction), gradient)); + 1.f : abs(dot(safe_normalize(light.dir), gradient)); - shadedColor = shadedColor + sampleColor * cosNL * light.radiance; + shadedColor = shadedColor + sampleColor * cosNL * light.weight; } sampleColor = shadedColor; } // Look up the opacity associated with the volume sample. - const float sampleOpacity = volume->transferFunction->getOpacityForValue(volume->transferFunction, sample); + const float sampleOpacity = xf->getOpacityForValue(xf, sample); // Set the color contribution for this sample only (do not accumulate). - color = clamp(sampleOpacity / volume->samplingRate) * make_vec4f(sampleColor.x, sampleColor.y, sampleColor.z, 1.0f); + color + = clamp(sampleOpacity / volume->samplingRate) + * make_vec4f(sampleColor.x, sampleColor.y, sampleColor.z, 1.0f); // Advance the ray for the next sample. volume->intersect(volume, ray); @@ -173,10 +145,10 @@ inline void RaycastVolumeRenderer_computeGeometrySample(RaycastVolumeRenderer *u const vec2f s = make_vec2f(0.5f); for (uniform uint32 i=0; inumLights; i++) { - const LightSample light = self->lights[i]->sample(self->lights[i], dg, s); - const float cosNL = abs(dot(safe_normalize(light.direction), dg.Ns)); + const Light_SampleRes light = self->lights[i]->sample(self->lights[i], dg, s); + const float cosNL = abs(dot(safe_normalize(light.dir), dg.Ns)); - shadedColor = shadedColor + geometryColor * cosNL * light.radiance; + shadedColor = shadedColor + geometryColor * cosNL * light.weight; } // Set the color contribution for this sample only (do not accumulate). @@ -204,18 +176,6 @@ RaycastVolumeRenderer_intersectVolumes(uniform RaycastVolumeRenderer *uniform se // Intersect volume bounding box. float t0, t1; Volume *uniform volume_i = passInfo.block->ispcVolume; -#if 0 - print("bb %\n % % %\n % % %\n", - volume_i, - volume_i->boundingBox.lower.x, - volume_i->boundingBox.lower.y, - volume_i->boundingBox.lower.z, - volume_i->boundingBox.upper.x, - volume_i->boundingBox.upper.y, - volume_i->boundingBox.upper.z); - if (eq(volume_i->boundingBox.lower,volume_i->boundingBox.upper)) - print("EMPTY BBOX!!!!\n"); -#endif intersectBox(ray, volume_i->boundingBox, t0, t1); t0 = max(t0,passInfo.region.lower); t1 = min(t1,passInfo.region.upper); @@ -230,17 +190,7 @@ RaycastVolumeRenderer_intersectVolumes(uniform RaycastVolumeRenderer *uniform se // If we intersected a volume, offset ray by a fraction of the nominal ray step. -#if 0 - if (volume) { - float dt = volume->samplingStep * rcpf(volume->samplingRate); - float t0 = ray.t0; - int i0 = (int)(ray.t0 / dt); - ray.t0 = (i0 + rayOffset)*dt; - if (ray.t0 < t0) ray.t0 += dt; - } -#else if (volume) ray.t0 += rayOffset * volume->samplingStep * rcpf(volume->samplingRate); -#endif // Return the first intersected volume. return volume; @@ -464,21 +414,11 @@ void RaycastVolumeRenderer_renderSample(Renderer *uniform pointer, export void *uniform RaycastVolumeRenderer_createInstance() { - // The self object. RaycastVolumeRenderer *uniform self = uniform new uniform RaycastVolumeRenderer; - // Constructor of the parent class. Renderer_Constructor(&self->super, NULL); - - // Function to compute the color and opacity for a screen space sample. self->super.renderSample = RaycastVolumeRenderer_renderSample; - // Function to perform per-frame state initialization. - self->super.beginFrame = RaycastVolumeRenderer_beginFrame; - - // Function to perform per-frame state completion. - self->super.endFrame = RaycastVolumeRenderer_endFrame; - return self; } @@ -642,7 +582,7 @@ export void DDDVRRenderer_renderTile(void*uniform _self, const uniform int begin = taskIndex * RENDERTILE_PIXELS_PER_JOB; const uniform int end = begin + RENDERTILE_PIXELS_PER_JOB; - const uniform int startSampleID = max(fb->accumID,0); + const uniform int startSampleID = max(fgTile.accumID,0); for (uniform uint32 i=begin;iget = get; -} diff --git a/ospray/texture/Texture2D.cpp b/ospray/texture/Texture2D.cpp index 9c494da5dc..6d1f9fd55e 100644 --- a/ospray/texture/Texture2D.cpp +++ b/ospray/texture/Texture2D.cpp @@ -21,20 +21,21 @@ namespace ospray { Texture2D::~Texture2D() { - if (!(flags & OSP_TEXTURE_SHARED_BUFFER)) delete[] (unsigned char *)data; + if (!(flags & OSP_TEXTURE_SHARED_BUFFER)) + delete[] (unsigned char *)data; } - Texture2D *Texture2D::createTexture(int sx, int sy, OSPDataType type, void *data, int flags) + Texture2D *Texture2D::createTexture(const vec2i &size, + const OSPTextureFormat type, void *data, const int flags) { Texture2D *tx = new Texture2D; - tx->width = sx; - tx->height = sy; + tx->size = size; tx->type = type; tx->flags = flags; tx->managedObjectType = OSP_TEXTURE; - const size_t bytes = size_t(sx) * sy * sizeOf(type); + const size_t bytes = sizeOf(type) * size.x * size.y; assert(data); @@ -45,24 +46,7 @@ namespace ospray { memcpy(tx->data, data, bytes); } - switch (type) { - case OSP_UCHAR4: - tx->ispcEquivalent = ispc::Texture2D_4uc_create(sx,sy,tx->data,flags); - break; - case OSP_UCHAR3: - tx->ispcEquivalent = ispc::Texture2D_3uc_create(sx,sy,tx->data,flags); - break; - case OSP_FLOAT: - tx->ispcEquivalent = ispc::Texture2D_1f_create(sx,sy,tx->data,flags); - break; - case OSP_FLOAT3: - tx->ispcEquivalent = ispc::Texture2D_3f_create(sx,sy,tx->data,flags); - break; - case OSP_FLOAT3A: - tx->ispcEquivalent = ispc::Texture2D_4f_create(sx,sy,tx->data,flags); - break; - default: throw std::runtime_error("Could not determine bytes per pixel in " __FILE__); - } + tx->ispcEquivalent = ispc::Texture2D_create((ispc::vec2i&)size, tx->data, type, flags); return tx; } diff --git a/ospray/texture/Texture2D.h b/ospray/texture/Texture2D.h index 862883e66b..6862ffc5a2 100644 --- a/ospray/texture/Texture2D.h +++ b/ospray/texture/Texture2D.h @@ -16,13 +16,13 @@ #pragma once -#include "Texture.h" -#include "../include/ospray/ospray.h" +#include "ospray/common/Managed.h" +#include "ospray/OSPTexture.h" namespace ospray { /*! \brief A Texture defined through a 2D Image. */ - struct Texture2D : public Texture { + struct Texture2D : public ManagedObject { //! \brief common function to help printf-debugging /*! Every derived class should overrride this! */ @@ -31,12 +31,11 @@ namespace ospray { virtual ~Texture2D(); /*! \brief creates a Texture2D object with the given parameter */ - static Texture2D *createTexture(int width, int height, OSPDataType type, - void *data, int flags); + static Texture2D *createTexture(const vec2i &size, const OSPTextureFormat, + void *data, const int flags); - int width; - int height; - OSPDataType type; + vec2i size; + OSPTextureFormat type; void *data; int flags; }; diff --git a/ospray/texture/Texture2D.ih b/ospray/texture/Texture2D.ih index dba5c7e235..e9102755a4 100644 --- a/ospray/texture/Texture2D.ih +++ b/ospray/texture/Texture2D.ih @@ -16,8 +16,7 @@ #pragma once -#include "Texture.ih" -#include "ospray/common/default.ih" +#include "ospray/OSPTexture.h" #include "ospray/math/vec.ih" struct Texture2D; diff --git a/ospray/texture/Texture2D.ispc b/ospray/texture/Texture2D.ispc index 35d15095e7..61e40769ec 100644 --- a/ospray/texture/Texture2D.ispc +++ b/ospray/texture/Texture2D.ispc @@ -20,18 +20,20 @@ // Low-level texel accessors ////////////////////////////////////////////////////////////////////////////// -inline vec4f getTexel4uc(const uniform Texture2D *uniform self, const vec2i i) +// TODO blocking + +inline vec4f getTexel_RGBA8(const uniform Texture2D *uniform self, const vec2i i) { assert(self); - const uint32 c = ((uniform uint32 *uniform)self->data)[i.y*self->size.x + i.x]; - const uint32 r = c & 255; - const uint32 g = (c >> 8) & 255; - const uint32 b = (c >> 16) & 255; + const uint32 c = ((const uniform uint32 *uniform)self->data)[i.y*self->size.x + i.x]; + const uint32 r = c & 0xff; + const uint32 g = (c >> 8) & 0xff; + const uint32 b = (c >> 16) & 0xff; const uint32 a = c >> 24; return make_vec4f(r, g, b, a)*(1.f/255.f); } -inline vec4f getTexel3uc(const uniform Texture2D *uniform self, const vec2i i) +inline vec4f getTexel_RGB8(const uniform Texture2D *uniform self, const vec2i i) { assert(self); const uniform uint8 *uniform texel = (const uniform uint8 *uniform)self->data; @@ -42,25 +44,40 @@ inline vec4f getTexel3uc(const uniform Texture2D *uniform self, const vec2i i) return make_vec4f(make_vec3f(r, g, b)*(1.f/255.f), 1.f); } -// TODO: getTexel1uc, getTexel[34]uc_sRGB +inline vec4f getTexel_R8(const uniform Texture2D *uniform self, const vec2i i) +{ + assert(self); + const uint8 c = ((const uniform uint8 *uniform)self->data)[i.y*self->size.x + i.x]; + return make_vec4f(c*(1.f/255.f), 0.0f, 0.0f, 1.f); +} + +inline vec4f getTexel_SRGBA(const uniform Texture2D *uniform self, const vec2i i) +{ + return srgba_to_linear(getTexel_RGBA8(self, i)); +} + +inline vec4f getTexel_SRGB(const uniform Texture2D *uniform self, const vec2i i) +{ + return srgba_to_linear(getTexel_RGB8(self, i)); +} -inline vec4f getTexel4f(const uniform Texture2D *uniform self, const vec2i i) +inline vec4f getTexel_RGBA32F(const uniform Texture2D *uniform self, const vec2i i) { assert(self); - return ((uniform vec4f *uniform)self->data)[i.y*self->size.x + i.x]; + return ((const uniform vec4f *uniform)self->data)[i.y*self->size.x + i.x]; } -inline vec4f getTexel3f(const uniform Texture2D *uniform self, const vec2i i) +inline vec4f getTexel_RGB32F(const uniform Texture2D *uniform self, const vec2i i) { assert(self); - vec3f v = ((uniform vec3f*uniform )self->data)[i.y*self->size.x + i.x]; + vec3f v = ((const uniform vec3f*uniform )self->data)[i.y*self->size.x + i.x]; return make_vec4f(v, 1.f); } -inline vec4f getTexel1f(const uniform Texture2D *uniform self, const vec2i i) +inline vec4f getTexel_R32F(const uniform Texture2D *uniform self, const vec2i i) { assert(self); - float v = ((uniform float*uniform)self->data)[i.y*self->size.x + i.x]; + float v = ((const uniform float*uniform)self->data)[i.y*self->size.x + i.x]; return make_vec4f(v, 0.f, 0.f, 1.f); } @@ -122,175 +139,73 @@ inline vec4f bilerp(const vec2f frac, const vec4f c00, const vec4f c01, const ve // Implementations of Texture2D_get for different formats and filter modi ////////////////////////////////////////////////////////////////////////////// -static varying vec4f Texture2D_4uc_bilinear(const uniform Texture2D *uniform self, - const varying vec2f &p) -{ - assert(self); - BilinCoords coords = bilinear_coords(self, p); - - const vec4f c00 = getTexel4uc(self, make_vec2i(coords.st0.x, coords.st0.y)); - const vec4f c01 = getTexel4uc(self, make_vec2i(coords.st1.x, coords.st0.y)); - const vec4f c10 = getTexel4uc(self, make_vec2i(coords.st0.x, coords.st1.y)); - const vec4f c11 = getTexel4uc(self, make_vec2i(coords.st1.x, coords.st1.y)); - - return bilerp(coords.frac, c00, c01, c10, c11); -} - -static varying vec4f Texture2D_4uc_nearest(const uniform Texture2D *uniform self, - const varying vec2f &p) -{ - assert(self); - - return getTexel4uc(self, nearest_coords(self, p)); -} - -static varying vec4f Texture2D_3uc_bilinear(const uniform Texture2D *uniform self, - const varying vec2f &p) -{ - assert(self); - BilinCoords coords = bilinear_coords(self, p); - - const vec4f c00 = getTexel3uc(self, make_vec2i(coords.st0.x, coords.st0.y)); - const vec4f c01 = getTexel3uc(self, make_vec2i(coords.st1.x, coords.st0.y)); - const vec4f c10 = getTexel3uc(self, make_vec2i(coords.st0.x, coords.st1.y)); - const vec4f c11 = getTexel3uc(self, make_vec2i(coords.st1.x, coords.st1.y)); - - return bilerp(coords.frac, c00, c01, c10, c11); -} - -static varying vec4f Texture2D_3uc_nearest(const uniform Texture2D *uniform self, - const varying vec2f &p) -{ - assert(self); - - return getTexel3uc(self, nearest_coords(self, p)); -} - - -static varying vec4f Texture2D_4f_bilinear(const uniform Texture2D *uniform self, - const varying vec2f &p) -{ - assert(self); - BilinCoords coords = bilinear_coords(self, p); - - const vec4f c00 = getTexel4f(self, make_vec2i(coords.st0.x, coords.st0.y)); - const vec4f c01 = getTexel4f(self, make_vec2i(coords.st1.x, coords.st0.y)); - const vec4f c10 = getTexel4f(self, make_vec2i(coords.st0.x, coords.st1.y)); - const vec4f c11 = getTexel4f(self, make_vec2i(coords.st1.x, coords.st1.y)); - - return bilerp(coords.frac, c00, c01, c10, c11); -} - -static varying vec4f Texture2D_4f_nearest(const uniform Texture2D *uniform self, - const varying vec2f &p) -{ - assert(self); - - return getTexel4f(self, nearest_coords(self, p)); -} - - -static varying vec4f Texture2D_3f_bilinear(const uniform Texture2D *uniform self, - const varying vec2f &p) -{ - assert(self); - - BilinCoords coords = bilinear_coords(self, p); - - const vec4f c00 = getTexel3f(self, make_vec2i(coords.st0.x, coords.st0.y)); - const vec4f c01 = getTexel3f(self, make_vec2i(coords.st1.x, coords.st0.y)); - const vec4f c10 = getTexel3f(self, make_vec2i(coords.st0.x, coords.st1.y)); - const vec4f c11 = getTexel3f(self, make_vec2i(coords.st1.x, coords.st1.y)); - - return bilerp(coords.frac, c00, c01, c10, c11); -} - -static varying vec4f Texture2D_3f_nearest(const uniform Texture2D *uniform self, - const varying vec2f &p) -{ - assert(self); - - return getTexel3f(self, nearest_coords(self, p)); -} - - -static varying vec4f Texture2D_1f_bilinear(const uniform Texture2D *uniform self, - const varying vec2f &p) -{ - assert(self); - BilinCoords coords = bilinear_coords(self, p); - - const vec4f c00 = getTexel1f(self, make_vec2i(coords.st0.x, coords.st0.y)); - const vec4f c01 = getTexel1f(self, make_vec2i(coords.st1.x, coords.st0.y)); - const vec4f c10 = getTexel1f(self, make_vec2i(coords.st0.x, coords.st1.y)); - const vec4f c11 = getTexel1f(self, make_vec2i(coords.st1.x, coords.st1.y)); - - return bilerp(coords.frac, c00, c01, c10, c11); -} - -static varying vec4f Texture2D_1f_nearest(const uniform Texture2D *uniform self, - const varying vec2f &p) -{ - assert(self); - - return getTexel1f(self, nearest_coords(self, p)); -} - +#define __define_tex_get(FMT) \ + \ +static vec4f Texture2D_nearest_##FMT(const uniform Texture2D *uniform self, \ + const vec2f &p) \ +{ \ + return getTexel_##FMT(self, nearest_coords(self, p)); \ +} \ + \ +static vec4f Texture2D_bilinear_##FMT(const uniform Texture2D *uniform self, \ + const vec2f &p) \ +{ \ + BilinCoords cs = bilinear_coords(self, p); \ + \ + const vec4f c00 = getTexel_##FMT(self, make_vec2i(cs.st0.x, cs.st0.y)); \ + const vec4f c01 = getTexel_##FMT(self, make_vec2i(cs.st1.x, cs.st0.y)); \ + const vec4f c10 = getTexel_##FMT(self, make_vec2i(cs.st0.x, cs.st1.y)); \ + const vec4f c11 = getTexel_##FMT(self, make_vec2i(cs.st1.x, cs.st1.y)); \ + \ + return bilerp(cs.frac, c00, c01, c10, c11); \ +} + +#define __define_tex_get_case(FMT) \ + case OSP_TEXTURE_##FMT: return filter_nearest ? &Texture2D_nearest_##FMT : \ + &Texture2D_bilinear_##FMT; + +#define __foreach_fetcher(FCT) \ + FCT(RGBA8) \ + FCT(SRGBA) \ + FCT(RGBA32F) \ + FCT(RGB8) \ + FCT(SRGB) \ + FCT(RGB32F) \ + FCT(R8) \ + FCT(R32F) + +__foreach_fetcher(__define_tex_get) + +static uniform Texture2D_get Texture2D_get_addr(const uniform uint32 type, + const uniform bool filter_nearest) +{ + switch (type) { + __foreach_fetcher(__define_tex_get_case) + } +}; -uniform Texture2D *uniform Texture2D_create(uniform uint32 sizeX, - uniform uint32 sizeY, - void *uniform data, - uniform Texture2D_get get) -{ - uniform Texture2D *uniform self = uniform new uniform Texture2D; - self->size = make_vec2i(sizeX, sizeY); - self->sizef = make_vec2f(sizeX, sizeY) - 1e-12f; - self->halfTexel = make_vec2f(0.5f/sizeX, 0.5f/sizeY); - self->data = data; - self->get = get; - return self; -} +#undef __define_tex_get +#undef __define_tex_get_addr +#undef __foreach_fetcher // Exports (called from C++) ////////////////////////////////////////////////////////////////////////////// -export void *uniform Texture2D_4uc_create(uniform uint32 sizeX, - uniform uint32 sizeY, - void *uniform data, - uniform int flags) -{ - return Texture2D_create(sizeX,sizeY,data,flags & OSP_TEXTURE_FILTER_NEAREST ? &Texture2D_4uc_nearest : &Texture2D_4uc_bilinear); -} - -export void *uniform Texture2D_3uc_create(uniform uint32 sizeX, - uniform uint32 sizeY, - void *uniform data, - uniform int flags) +export void *uniform Texture2D_create(uniform vec2i &size, void *uniform data, + uniform uint32 type, uniform uint32 flags) { - return Texture2D_create(sizeX,sizeY,data,flags & OSP_TEXTURE_FILTER_NEAREST ? &Texture2D_3uc_nearest : &Texture2D_3uc_bilinear); -} + uniform Texture2D *uniform self = uniform new uniform Texture2D; + self->size = size; -export void *uniform Texture2D_4f_create(uniform uint32 sizeX, - uniform uint32 sizeY, - void *uniform data, - uniform int flags) -{ - return Texture2D_create(sizeX,sizeY,data,flags & OSP_TEXTURE_FILTER_NEAREST ? &Texture2D_4f_nearest : &Texture2D_4f_bilinear); -} + // Due to float rounding frac(x) can be exactly 1.0f (e.g. for very small + // negative x), although it should be strictly smaller than 1.0f. We handle + // this case by having sizef slightly smaller than size, such that + // frac(x)*sizef is always < size. + self->sizef = make_vec2f(nextafter(size.x, -1.0f), nextafter(size.y, -1.0f)); + self->halfTexel = make_vec2f(0.5f/size.x, 0.5f/size.y); + self->data = data; + self->get = Texture2D_get_addr(type, flags & OSP_TEXTURE_FILTER_NEAREST); -export void *uniform Texture2D_3f_create(uniform uint32 sizeX, - uniform uint32 sizeY, - void *uniform data, - uniform int flags) -{ - return Texture2D_create(sizeX,sizeY,data,flags & OSP_TEXTURE_FILTER_NEAREST ? &Texture2D_3f_nearest : &Texture2D_3f_bilinear); -} - -export void *uniform Texture2D_1f_create(uniform uint32 sizeX, - uniform uint32 sizeY, - void *uniform data, - uniform int flags) -{ - return Texture2D_create(sizeX,sizeY,data,flags & OSP_TEXTURE_FILTER_NEAREST ? &Texture2D_1f_nearest : &Texture2D_1f_bilinear); + return self; } diff --git a/ospray/transferFunction/LinearTransferFunction.cpp b/ospray/transferFunction/LinearTransferFunction.cpp index 67f3623ae2..6d113c8312 100644 --- a/ospray/transferFunction/LinearTransferFunction.cpp +++ b/ospray/transferFunction/LinearTransferFunction.cpp @@ -21,22 +21,39 @@ namespace ospray { + //! Destructor. + LinearTransferFunction::~LinearTransferFunction() + { + if (ispcEquivalent != NULL) + ispc::LinearTransferFunction_destroy(ispcEquivalent); + } + void LinearTransferFunction::commit() { // Create the equivalent ISPC transfer function. if (ispcEquivalent == NULL) createEquivalentISPC(); // Retrieve the color and opacity values. - colorValues = getParamData("colors", NULL); opacityValues = getParamData("opacities", NULL); + colorValues = getParamData("colors", NULL); + opacityValues = getParamData("opacities", NULL); // Set the color values. - if (colorValues) ispc::LinearTransferFunction_setColorValues(ispcEquivalent, colorValues->numItems, (ispc::vec3f *) colorValues->data); + if (colorValues) + ispc::LinearTransferFunction_setColorValues(ispcEquivalent, + colorValues->numItems, + (ispc::vec3f *) colorValues->data); // Set the opacity values. - if (opacityValues) ispc::LinearTransferFunction_setOpacityValues(ispcEquivalent, opacityValues->numItems, (float *) opacityValues->data); + if (opacityValues) { + float *alpha = (float *)opacityValues->data; + ispc::LinearTransferFunction_setOpacityValues(ispcEquivalent, + opacityValues->numItems, + (float *)opacityValues->data); + } // Set the value range that the transfer function covers. - vec2f valueRange = getParam2f("valueRange", vec2f(0.0f, 1.0f)); ispc::TransferFunction_setValueRange(ispcEquivalent, (const ispc::vec2f &) valueRange); + vec2f valueRange = getParam2f("valueRange", vec2f(0.0f, 1.0f)); + ispc::TransferFunction_setValueRange(ispcEquivalent, (const ispc::vec2f &) valueRange); // Notify listeners that the transfer function has changed. notifyListenersThatObjectGotChanged(); diff --git a/ospray/transferFunction/LinearTransferFunction.h b/ospray/transferFunction/LinearTransferFunction.h index 1cb569f888..ac890c2a10 100644 --- a/ospray/transferFunction/LinearTransferFunction.h +++ b/ospray/transferFunction/LinearTransferFunction.h @@ -25,17 +25,18 @@ namespace ospray { - //! \brief A concrete implementation of the TransferFunction class for - //! piecewise linear transfer functions. - //! - class LinearTransferFunction : public TransferFunction { + /*! \brief A concrete implementation of the TransferFunction class for + piecewise linear transfer functions. + */ + class LinearTransferFunction : public TransferFunction + { public: //! Constructor. LinearTransferFunction() {} //! Destructor. - virtual ~LinearTransferFunction() { if (ispcEquivalent != NULL) ispc::LinearTransferFunction_destroy(ispcEquivalent); } + virtual ~LinearTransferFunction(); //! Allocate storage and populate the transfer function. virtual void commit(); diff --git a/ospray/transferFunction/LinearTransferFunction.ih b/ospray/transferFunction/LinearTransferFunction.ih index 4cefd7b7e0..40971cfa0b 100644 --- a/ospray/transferFunction/LinearTransferFunction.ih +++ b/ospray/transferFunction/LinearTransferFunction.ih @@ -26,10 +26,12 @@ struct LinearTransferFunction { TransferFunction super; //! Transfer function opacity values and count. - float *uniform opacityValues; uniform int opacityValueCount; + uniform float *uniform opacityValues; + uniform int opacityValueCount; //! Transfer function color values and count. - vec3f *uniform colorValues; uniform int colorValueCount; + uniform vec3f *uniform colorValues; + uniform int colorValueCount; //! 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 84f65546ff..b2f4dcd6d8 100644 --- a/ospray/transferFunction/LinearTransferFunction.ispc +++ b/ospray/transferFunction/LinearTransferFunction.ispc @@ -17,29 +17,34 @@ #include "ospray/transferFunction/LinearTransferFunction.ih" inline varying vec3f -LinearTransferFunction_getColorForValue(const void *uniform pointer, +LinearTransferFunction_getColorForValue(const void *uniform _self, varying float value) { // Return (0,0,0) for NaN values. - if (isnan(value)) return(make_vec3f(0.0f)); + if (isnan(value)) + return make_vec3f(0.0f); // Cast to the actual TransferFunction subtype. - const LinearTransferFunction *uniform transferFunction = (const LinearTransferFunction *uniform) pointer; + const LinearTransferFunction *uniform self + = (const LinearTransferFunction *uniform) _self; // No color values may be available. - if (transferFunction->colorValueCount == 0) return(make_vec3f(1.0f)); + if (self->colorValueCount == 0) + return make_vec3f(1.0f); // Clamp the value to the lower bound of the value range. - if (value <= transferFunction->super.valueRange.x) return(transferFunction->colorValues[0]); + if (value <= self->super.valueRange.x) + return self->colorValues[0]; // Clamp the value to the upper bound of the value range. - if (value >= transferFunction->super.valueRange.y) return(transferFunction->colorValues[transferFunction->colorValueCount - 1]); + if (value >= self->super.valueRange.y) + return self->colorValues[self->colorValueCount - 1]; // Map the value into the range [0.0, 1.0]. value - = (value - transferFunction->super.valueRange.x) - / (transferFunction->super.valueRange.y - transferFunction->super.valueRange.x) - * (transferFunction->colorValueCount - 1.0f); + = (value - self->super.valueRange.x) + / (self->super.valueRange.y - self->super.valueRange.x) + * (self->colorValueCount - 1.0f); // Compute the color index and fractional offset. int index = floor(value); @@ -47,97 +52,113 @@ LinearTransferFunction_getColorForValue(const void *uniform pointer, // The interpolated color. return - ((1.0f - remainder) * transferFunction->colorValues[index] - + remainder * transferFunction->colorValues[min(index + 1, transferFunction->colorValueCount - 1)]); + ((1.0f - remainder) * self->colorValues[index] + + remainder * self->colorValues[min(index + 1, self->colorValueCount - 1)]); } uniform vec2f -LinearTransferFunction_getMinMaxOpacityInRange(void *uniform pointer, +LinearTransferFunction_getMinMaxOpacityInRange(void *uniform _self, const uniform vec2f &range) { - uniform LinearTransferFunction *uniform transferFunction = (uniform LinearTransferFunction *uniform) pointer; + uniform LinearTransferFunction *uniform self = (uniform LinearTransferFunction *uniform) _self; const uniform int maxDim = PRECOMPUTED_OPACITY_SUBRANGE_COUNT - 1; - const uniform float denom = transferFunction->super.valueRange.y - transferFunction->super.valueRange.x; - const uniform int i = floor(clamp((range.x - transferFunction->super.valueRange.x) / denom) * maxDim); - const uniform int j = ceil(clamp((range.y - transferFunction->super.valueRange.x) / denom) * maxDim); - return(transferFunction->minMaxOpacityInRange[min(i,maxDim)][min(j,maxDim)]); + const uniform float denom = self->super.valueRange.y - self->super.valueRange.x; + const uniform int i = floor(clamp((range.x - self->super.valueRange.x) / denom) * maxDim); + const uniform int j = ceil(clamp((range.y - self->super.valueRange.x) / denom) * maxDim); + return self->minMaxOpacityInRange[min(i,maxDim)][min(j,maxDim)]; } varying float -LinearTransferFunction_getMaxOpacityInRange(void *uniform pointer, +LinearTransferFunction_getMaxOpacityInRange(void *uniform _self, const varying vec2f &range) { - uniform LinearTransferFunction *uniform transferFunction = (uniform LinearTransferFunction *uniform) pointer; + uniform LinearTransferFunction *uniform self = (uniform LinearTransferFunction *uniform) _self; const uniform int maxDim = PRECOMPUTED_OPACITY_SUBRANGE_COUNT - 1; - const uniform float denom = transferFunction->super.valueRange.y - transferFunction->super.valueRange.x; - const varying int i = floor(clamp((range.x - transferFunction->super.valueRange.x) / denom) * maxDim); - const varying int j = ceil(clamp((range.y - transferFunction->super.valueRange.x) / denom) * maxDim); - return(transferFunction->minMaxOpacityInRange[min(i,maxDim)][min(j,maxDim)].y); + const uniform float denom = self->super.valueRange.y - self->super.valueRange.x; + const varying int i = floor(clamp((range.x - self->super.valueRange.x) / denom) * maxDim); + const varying int j = ceil(clamp((range.y - self->super.valueRange.x) / denom) * maxDim); + return self->minMaxOpacityInRange[min(i,maxDim)][min(j,maxDim)].y; } inline varying float -LinearTransferFunction_getOpacityForValue(const void *uniform pointer, +LinearTransferFunction_getOpacityForValue(const void *uniform _self, varying float value) { // Return 0 for NaN values. - if (isnan(value)) return(0.0f); + if (isnan(value)) return 0.0f; // Cast to the actual TransferFunction subtype. - const LinearTransferFunction *uniform transferFunction = (const LinearTransferFunction *uniform) pointer; + const LinearTransferFunction *uniform self + = (const LinearTransferFunction *uniform) _self; // No opacity values may be available. - if (transferFunction->opacityValueCount == 0) return(1.0f); + if (self->opacityValueCount == 0) + return 1.0f; // Clamp the value to the lower bound of the value range. - if (value <= transferFunction->super.valueRange.x) return(transferFunction->opacityValues[0]); + if (value <= self->super.valueRange.x) + return self->opacityValues[0]; // Clamp the value to the upper bound of the value range. - if (value >= transferFunction->super.valueRange.y) return(transferFunction->opacityValues[transferFunction->opacityValueCount - 1]); + if (value >= self->super.valueRange.y) + return self->opacityValues[self->opacityValueCount - 1]; - // Map the value into the range [0.0, 1.0]. - value = (value - transferFunction->super.valueRange.x) / (transferFunction->super.valueRange.y - transferFunction->super.valueRange.x) * (transferFunction->opacityValueCount - 1.0f); + // Map the value into the range [0.0, numValues). + const float remapped + = (value - self->super.valueRange.x) + / (self->super.valueRange.y - self->super.valueRange.x) + * (self->opacityValueCount - 1.0f); // Compute the opacity index and fractional offset. - int index = floor(value); float remainder = value - index; + int index = floor(remapped); + float remainder = remapped - index; // The interpolated opacity. - return((1.0f - remainder) * transferFunction->opacityValues[index] + remainder * transferFunction->opacityValues[min(index + 1, transferFunction->opacityValueCount - 1)]); - + float ret = + (1.0f - remainder) * self->opacityValues[index] + + remainder * self->opacityValues[min(index + 1, self->opacityValueCount - 1)]; + return ret; } -void LinearTransferFunction_precomputeMinMaxOpacityRanges(void *uniform pointer) +void LinearTransferFunction_precomputeMinMaxOpacityRanges(void *uniform _self) { - uniform LinearTransferFunction *uniform transferFunction = (uniform LinearTransferFunction *uniform) pointer; + uniform LinearTransferFunction *uniform self + = (uniform LinearTransferFunction *uniform) _self; // Compute the diagonal. - for (uniform int i=0 ; i < PRECOMPUTED_OPACITY_SUBRANGE_COUNT ; i++) { + for (uniform int i=0; i < PRECOMPUTED_OPACITY_SUBRANGE_COUNT; i++) { // Figure out the range of values in the array we are going to compare. - const uniform int checkRangeLow = transferFunction->opacityValueCount * (((float) i) / PRECOMPUTED_OPACITY_SUBRANGE_COUNT); - const uniform int checkRangeHigh = transferFunction->opacityValueCount * (((float) i + 1) / PRECOMPUTED_OPACITY_SUBRANGE_COUNT); - - uniform vec2f range = make_vec2f(transferFunction->opacityValues[checkRangeLow], transferFunction->opacityValues[checkRangeLow]); - for (uniform int opacityIDX = checkRangeLow + 1 ; opacityIDX < checkRangeHigh ; opacityIDX++) - range = make_vec2f(min(range.x, transferFunction->opacityValues[opacityIDX]), max(range.y, transferFunction->opacityValues[opacityIDX])); - - transferFunction->minMaxOpacityInRange[i][i] = range; - + const uniform int checkRangeLow + = self->opacityValueCount * (((float) i) / PRECOMPUTED_OPACITY_SUBRANGE_COUNT); + const uniform int checkRangeHigh + = self->opacityValueCount * (((float)i + 1) / PRECOMPUTED_OPACITY_SUBRANGE_COUNT); + + uniform vec2f range = make_vec2f(self->opacityValues[checkRangeLow]); + for (uniform int opacityIDX = checkRangeLow + 1; + opacityIDX < checkRangeHigh; + opacityIDX++) + range = make_vec2f(min(range.x, self->opacityValues[opacityIDX]), + max(range.y, self->opacityValues[opacityIDX])); + + self->minMaxOpacityInRange[i][i] = range; } // Fill out each column from the diagonal up. - for (uniform int i=0 ; i < PRECOMPUTED_OPACITY_SUBRANGE_COUNT ; i++) { - for (uniform int j = i + 1 ; j < PRECOMPUTED_OPACITY_SUBRANGE_COUNT ; j++) { + for (uniform int i=0; i < PRECOMPUTED_OPACITY_SUBRANGE_COUNT; i++) { + for (uniform int j = i + 1; j < PRECOMPUTED_OPACITY_SUBRANGE_COUNT; j++) { // Figure out the range of values in the array we are going to compare. - const uniform int checkRangeLow = transferFunction->opacityValueCount * (((float) i) / PRECOMPUTED_OPACITY_SUBRANGE_COUNT); - const uniform int checkRangeHigh = transferFunction->opacityValueCount * (((float) j + 1) / PRECOMPUTED_OPACITY_SUBRANGE_COUNT); + const uniform int checkRangeLow = self->opacityValueCount * (((float) i) / PRECOMPUTED_OPACITY_SUBRANGE_COUNT); + const uniform int checkRangeHigh = self->opacityValueCount * (((float) j + 1) / PRECOMPUTED_OPACITY_SUBRANGE_COUNT); - uniform vec2f range = transferFunction->minMaxOpacityInRange[i][i]; - for (uniform int opacityIDX = checkRangeLow + 1 ; opacityIDX < checkRangeHigh ; opacityIDX++) - range = make_vec2f(min(range.x, transferFunction->opacityValues[opacityIDX]), max(range.y, transferFunction->opacityValues[opacityIDX])); + uniform vec2f range = self->minMaxOpacityInRange[i][i]; + for (uniform int opacityIDX = checkRangeLow + 1; opacityIDX < checkRangeHigh; opacityIDX++) + range = make_vec2f(min(range.x, self->opacityValues[opacityIDX]), + max(range.y, self->opacityValues[opacityIDX])); - transferFunction->minMaxOpacityInRange[i][j] = range; + self->minMaxOpacityInRange[i][j] = range; } @@ -148,84 +169,95 @@ void LinearTransferFunction_precomputeMinMaxOpacityRanges(void *uniform pointer) export void *uniform LinearTransferFunction_createInstance() { // The transfer function. - LinearTransferFunction *uniform transferFunction = uniform new uniform LinearTransferFunction; + LinearTransferFunction *uniform self = uniform new uniform LinearTransferFunction; // Function to get the interpolated color for a given value. - transferFunction->super.getColorForValue = LinearTransferFunction_getColorForValue; + self->super.getColorForValue = LinearTransferFunction_getColorForValue; // Function to get the interpolated opacity for a given value. - transferFunction->super.getOpacityForValue = LinearTransferFunction_getOpacityForValue; + self->super.getOpacityForValue = LinearTransferFunction_getOpacityForValue; // Virtual function to look up the maximum opacity based on an input range. - transferFunction->super.getMaxOpacityInRange = LinearTransferFunction_getMaxOpacityInRange; + self->super.getMaxOpacityInRange = LinearTransferFunction_getMaxOpacityInRange; // Virtual function to look up the min/max opacity based on an input range. - transferFunction->super.getMinMaxOpacityInRange = LinearTransferFunction_getMinMaxOpacityInRange; + self->super.getMinMaxOpacityInRange = LinearTransferFunction_getMinMaxOpacityInRange; // Transfer function colors and count. - transferFunction->colorValues = NULL; transferFunction->colorValueCount = 0; + self->colorValues = NULL; + self->colorValueCount = 0; // Transfer function opacity values and count. - transferFunction->opacityValues = NULL; transferFunction->opacityValueCount = 0; + self->opacityValues = NULL; + self->opacityValueCount = 0; // The default transfer function value range. - transferFunction->super.valueRange = make_vec2f(0.0f, 1.0f); + self->super.valueRange = make_vec2f(0.0f, 1.0f); // Freshly baked transfer function. - return(transferFunction); - + return self; } -export void LinearTransferFunction_destroy(void *uniform pointer) +export void LinearTransferFunction_destroy(void *uniform _self) { // Cast to the actual TransferFunction subtype. - LinearTransferFunction *uniform transferFunction = (LinearTransferFunction *uniform) pointer; + LinearTransferFunction *uniform self = (LinearTransferFunction *uniform) _self; - // Free memory for the color values. - if (transferFunction->colorValues != NULL) delete[] transferFunction->colorValues; + // // Free memory for the color values. + // if (self->colorValues != NULL) delete[] self->colorValues; - // Free memory for the opacity values. - if (transferFunction->opacityValues != NULL) delete[] transferFunction->opacityValues; + // // Free memory for the opacity values. + // if (self->opacityValues != NULL) delete[] self->opacityValues; // Container is deallocated by ~ManagedObject } -export void LinearTransferFunction_setColorValues(void *uniform pointer, +export void LinearTransferFunction_setColorValues(void *uniform _self, const uniform size_t &count, vec3f *uniform source) { // Cast to the actual TransferFunction subtype. - LinearTransferFunction *uniform transferFunction = (LinearTransferFunction *uniform) pointer; + LinearTransferFunction *uniform self + = (LinearTransferFunction *uniform) _self; // Free memory for any existing color values. - if (transferFunction->colorValues != NULL) delete[] transferFunction->colorValues; + if (self->colorValues != NULL) + delete[] self->colorValues; // Allocate memory for the incoming color values. - transferFunction->colorValueCount = count; transferFunction->colorValues = uniform new uniform vec3f[count]; + self->colorValueCount = count; + self->colorValues = uniform new uniform vec3f[count]; // Copy the color values into the transfer function. - for (uniform size_t i=0 ; i < count ; i++) transferFunction->colorValues[i] = source[i]; + for (uniform size_t i=0; i < count; i++) + self->colorValues[i] = source[i]; } -export void LinearTransferFunction_setOpacityValues(void *uniform pointer, +export void LinearTransferFunction_setOpacityValues(void *uniform _self, const uniform size_t &count, float *uniform source) { // Cast to the actual TransferFunction subtype. - LinearTransferFunction *uniform transferFunction = (LinearTransferFunction *uniform) pointer; + LinearTransferFunction *uniform self + = (LinearTransferFunction *uniform) _self; - // Free memory for any existing opacity values. - if (transferFunction->opacityValues != NULL) delete[] transferFunction->opacityValues; + self->opacityValues = source; + self->opacityValueCount = count; - // Allocate memory for the incoming opacity values. - transferFunction->opacityValueCount = count; transferFunction->opacityValues = uniform new uniform float[count]; + // // Free memory for any existing opacity values. + // if (self->opacityValues != NULL) + // delete[] self->opacityValues; - // Copy the opacity values into the transfer function. - for (uniform size_t i=0 ; i < count ; i++) transferFunction->opacityValues[i] = source[i]; + // // Allocate memory for the incoming opacity values. + // self->opacityValueCount = count; + // self->opacityValues = uniform new uniform float[count]; + + // // Copy the opacity values into the transfer function. + // for (uniform size_t i=0; i < count; i++) + // selfy->opacityValues[i] = source[i]; // Precompute the min / max opacity ranges. - LinearTransferFunction_precomputeMinMaxOpacityRanges(pointer); + LinearTransferFunction_precomputeMinMaxOpacityRanges(_self); } - diff --git a/ospray/transferFunction/TransferFunction.cpp b/ospray/transferFunction/TransferFunction.cpp index 21062d48f9..4c2b92b64b 100644 --- a/ospray/transferFunction/TransferFunction.cpp +++ b/ospray/transferFunction/TransferFunction.cpp @@ -22,16 +22,19 @@ namespace ospray { - TransferFunction *TransferFunction::createInstance(std::string type) { - - // Function pointer type for creating a concrete instance of a subtype of this class. + TransferFunction *TransferFunction::createInstance(const std::string &type) + { + // Function pointer type for creating a concrete instance of a + // subtype of this class. typedef TransferFunction *(*creationFunctionPointer)(); // Function pointers corresponding to each subtype. - std::map symbolRegistry; + static std::map symbolRegistry; - // Return a concrete instance of the requested subtype if the creation function is already known. - if (symbolRegistry.count(type) > 0 && symbolRegistry[type] != NULL) return((*symbolRegistry[type])()); + // Return a concrete instance of the requested subtype if the + // creation function is already known. + if (symbolRegistry.count(type) > 0 && symbolRegistry[type] != NULL) + return((*symbolRegistry[type])()); // Otherwise construct the name of the creation function to look for. std::string creationFunctionName = "ospray_create_transfer_function_" + type; @@ -40,17 +43,20 @@ namespace ospray { symbolRegistry[type] = (creationFunctionPointer) getSymbol(creationFunctionName); // The named function may not be found if the requested subtype is not known. - if (!symbolRegistry[type] && ospray::logLevel >= 1) std::cerr << " ospray::TransferFunction WARNING: unrecognized subtype '" + type + "'." << std::endl; + if (!symbolRegistry[type] && ospray::logLevel >= 1) + std::cerr << " ospray::TransferFunction WARNING: unrecognized subtype '" + << type << "'." << std::endl; // Create a concrete instance of the requested subtype. - TransferFunction *transferFunction = (symbolRegistry[type]) ? (*symbolRegistry[type])() : NULL; + TransferFunction *transferFunction + = (symbolRegistry[type]) ? (*symbolRegistry[type])() : NULL; // Denote the subclass type in the ManagedObject base class. - if (transferFunction) transferFunction->managedObjectType = OSP_TRANSFER_FUNCTION; + if (transferFunction) + transferFunction->managedObjectType = OSP_TRANSFER_FUNCTION; // The initialized transfer function. - return(transferFunction); - + return transferFunction; } } // ::ospray diff --git a/ospray/transferFunction/TransferFunction.h b/ospray/transferFunction/TransferFunction.h index f666846588..98d12ea333 100644 --- a/ospray/transferFunction/TransferFunction.h +++ b/ospray/transferFunction/TransferFunction.h @@ -18,31 +18,32 @@ #include "ospray/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. -//! +/*! \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 { + /*! \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 + { public: //! Constructor. @@ -55,28 +56,13 @@ namespace ospray { virtual void commit() = 0; //! Create a transfer function of the given type. - static TransferFunction *createInstance(std::string type); + static TransferFunction *createInstance(const std::string &type); //! A string description of this class. virtual std::string toString() const { return("ospray::TransferFunction"); } protected: - //! Create the equivalent ISPC transfer function. - virtual void createEquivalentISPC() = 0; - - //! Print an error message. - void emitMessage(const std::string &kind, const std::string &message) const - { std::cerr << " " + toString() + " " + kind + ": " + message + "." << std::endl; } - - //! Error checking. - void exitOnCondition(bool condition, const std::string &message) const - { if (!condition) return; emitMessage("ERROR", message); exit(1); } - - //! Warning condition. - void warnOnCondition(bool condition, const std::string &message) const - { if (!condition) return; emitMessage("WARNING", message); } - }; } // ::ospray diff --git a/ospray/volume/BlockBrickedVolume.cpp b/ospray/volume/BlockBrickedVolume.cpp index 0a6021a1a2..391257cab9 100644 --- a/ospray/volume/BlockBrickedVolume.cpp +++ b/ospray/volume/BlockBrickedVolume.cpp @@ -16,10 +16,8 @@ //ospray #include "ospray/volume/BlockBrickedVolume.h" -#include "ospray/common/parallel_for.h" +#include "ospray/common/tasking/parallel_for.h" #include "BlockBrickedVolume_ispc.h" -// std -#include namespace ospray { @@ -50,24 +48,21 @@ namespace ospray { StructuredVolume::commit(); } - int BlockBrickedVolume::setRegion(// points to the first voxel to be copies. - // The voxels at 'source' MUST have - // dimensions 'regionSize', must be - // organized in 3D-array order, and must - // have the same voxel type as the volume. - const void *source, - // coordinates of the lower, - // left, front corner of the target - // region. - const vec3i ®ionCoords, - // size of the region that we're writing to - // MUST be the same as the dimensions of - // source[][][] - const vec3i ®ionSize) + int BlockBrickedVolume::setRegion( + // points to the first voxel to be copied. The voxels at 'source' MUST + // have dimensions 'regionSize', must be organized in 3D-array order, and + // must have the same voxel type as the volume. + const void *source, + // coordinates of the lower, left, front corner of the target region + const vec3i ®ionCoords, + // size of the region that we're writing to, MUST be the same as the + // dimensions of source[][][] + const vec3i ®ionSize) { // Create the equivalent ISPC volume container and allocate memory for voxel // data. - if (ispcEquivalent == nullptr) createEquivalentISPC(); + if (ispcEquivalent == nullptr) + createEquivalentISPC(); /*! \todo check if we still need this 'computevoxelrange' - in theory we need this only if the app is allowed to query these @@ -87,6 +82,8 @@ namespace ospray { + (size_t)regionSize.z; if (voxelType == "uchar") computeVoxelRange((unsigned char *)source, numVoxelsInRegion); + else if (voxelType == "ushort") + computeVoxelRange((unsigned short *)source, numVoxelsInRegion); else if (voxelType == "float") computeVoxelRange((float *)source, numVoxelsInRegion); else if (voxelType == "double") @@ -101,11 +98,11 @@ namespace ospray { // Copy voxel data into the volume. const int NTASKS = regionSize.y * regionSize.z; parallel_for(NTASKS, [&](int taskIndex){ - ispc::BlockBrickedVolume_setRegion(ispcEquivalent, - source, - (const ispc::vec3i &) regionCoords, - (const ispc::vec3i &) regionSize, - taskIndex); + ispc::BlockBrickedVolume_setRegion(ispcEquivalent, + source, + (const ispc::vec3i &)regionCoords, + (const ispc::vec3i &)regionSize, + taskIndex); }); return true; @@ -139,5 +136,6 @@ namespace ospray { // A volume type with 64-bit addressing and multi-level bricked storage order. OSP_REGISTER_VOLUME(BlockBrickedVolume, block_bricked_volume); #endif + } // ::ospray diff --git a/ospray/volume/BlockBrickedVolume.h b/ospray/volume/BlockBrickedVolume.h index 0f488a7431..b8e7896a39 100644 --- a/ospray/volume/BlockBrickedVolume.h +++ b/ospray/volume/BlockBrickedVolume.h @@ -30,21 +30,21 @@ namespace ospray { ~BlockBrickedVolume(); //! A string description of this class. - std::string toString() const; + std::string toString() const override; //! Allocate storage and populate the volume, called through the OSPRay API. - void commit(); + void commit() override; //! Copy voxels into the volume at the given index (non-zero return value //! indicates success). int setRegion(const void *source, const vec3i &index, - const vec3i &count); + const vec3i &count) override; private: //! Create the equivalent ISPC volume container. - void createEquivalentISPC(); + void createEquivalentISPC() override; }; diff --git a/ospray/volume/BlockBrickedVolume.ih b/ospray/volume/BlockBrickedVolume.ih index 0d7f3dd548..e6f12286c2 100644 --- a/ospray/volume/BlockBrickedVolume.ih +++ b/ospray/volume/BlockBrickedVolume.ih @@ -16,7 +16,7 @@ #pragma once -#include "ospray/common/OSPDataType.h" +#include "ospray/OSPDataType.h" #include "ospray/volume/StructuredVolume.ih" //! \brief ISPC variables and functions for the BlockBrickedVolume class @@ -44,8 +44,8 @@ struct BlockBrickedVolume { /*! copy given block of voxels into the volume, where source[0] will be written to volume[targetCoord000] */ - void (*uniform setRegion)(BlockBrickedVolume *uniform _volume, - const void *uniform _source, + void (*uniform setRegion)(BlockBrickedVolume *uniform self, + const void *uniform source, const uniform vec3i ®ionSize, const uniform vec3i &targetCoord000, const uniform int taskIndex); diff --git a/ospray/volume/BlockBrickedVolume.ispc b/ospray/volume/BlockBrickedVolume.ispc index eb2486d589..ddba87a98b 100644 --- a/ospray/volume/BlockBrickedVolume.ispc +++ b/ospray/volume/BlockBrickedVolume.ispc @@ -82,68 +82,35 @@ inline void BlockBrickedVolume_getVoxelAddress(BlockBrickedVolume *uniform volum | voxelOffset.x; } -inline void BlockBrickedVolumeUChar_getVoxel(void *uniform _volume, - const varying vec3i &index, - varying float &value) -{ - // Cast to the actual Volume subtype. - BlockBrickedVolume *uniform volume = (BlockBrickedVolume *uniform) _volume; - - // Cast to the actual voxel type. - uint8 *uniform blockMem = (uint8 *uniform) volume->blockMem; - // Compute the 1D address of the block in the volume and the voxel in the block. - Address address; - BlockBrickedVolume_getVoxelAddress(volume, index, address); - // The voxel value at the 1D address. - foreach_unique(blockID in address.block) { - uint8 *uniform blockPtr = blockMem + (BLOCK_VOXEL_COUNT * (uint64)blockID); - value = blockPtr[address.voxel]; - } +#define template_getVoxel(type) \ +inline void BlockBrickedVolume_getVoxel_##type(void *uniform _self, \ + const varying vec3i &index, \ + varying float &value) \ +{ \ + /* Cast to the actual volume subtype. */ \ + BlockBrickedVolume *uniform self = (BlockBrickedVolume *uniform)_self; \ + \ + /* Compute the 1D address of the block in the volume \ + and the voxel in the block. */ \ + Address address; \ + BlockBrickedVolume_getVoxelAddress(self, index, address); \ + \ + /* The voxel value at the 1D address. */ \ + foreach_unique(blockID in address.block) { \ + type *uniform blockPtr = (type *uniform)self->blockMem + \ + (BLOCK_VOXEL_COUNT * (uint64)blockID); \ + value = blockPtr[address.voxel]; \ + } \ } -inline void BlockBrickedVolumeFloat_getVoxel(void *uniform _volume, - const varying vec3i &index, - varying float &value) -{ - // Cast to the actual Volume subtype. - BlockBrickedVolume *uniform volume = (BlockBrickedVolume *uniform) _volume; - - // Cast to the actual voxel type. - float *uniform blockMem = (float *uniform) volume->blockMem; - - // Compute the 1D address of the block in the volume and the voxel in the block. - Address address; - BlockBrickedVolume_getVoxelAddress(volume, index, address); +template_getVoxel(uint8); +template_getVoxel(uint16); +template_getVoxel(float); +template_getVoxel(double); +#undef template_getVoxel - // The voxel value at the 1D address. - foreach_unique(blockID in address.block) { - float *uniform blockPtr = blockMem + (BLOCK_VOXEL_COUNT * (uint64)blockID); - value = blockPtr[address.voxel]; - } -} - -inline void BlockBrickedVolumeDouble_getVoxel(void *uniform _volume, - const varying vec3i &index, - varying float &value) -{ - // Cast to the actual Volume subtype. - BlockBrickedVolume *uniform volume = (BlockBrickedVolume *uniform) _volume; - - // Cast to the actual voxel type. - double *uniform blockMem = (double *uniform) volume->blockMem; - - // Compute the 1D address of the block in the volume and the voxel in the block. - Address address; - BlockBrickedVolume_getVoxelAddress(volume, index, address); - - // The voxel value at the 1D address. - foreach_unique(blockID in address.block) { - double *uniform blockPtr = blockMem + (BLOCK_VOXEL_COUNT * (uint64)blockID); - value = blockPtr[address.voxel]; - } -} inline void BlockBrickedVolume_allocateMemory(BlockBrickedVolume *uniform volume) { @@ -168,109 +135,46 @@ inline void BlockBrickedVolume_allocateMemory(BlockBrickedVolume *uniform volume /*! copy given block of voxels into the volume, where source[0] will be written to volume[targetCoord000] */ -void BlockBrickedVolumeUChar_setRegion(BlockBrickedVolume *uniform self, - const void *uniform _source, - const uniform vec3i &targetCoord000, - const uniform vec3i ®ionSize, - const uniform int taskIndex) -{ - const uint8 *uniform source = (const uint8 *uniform)_source; - const uniform uint32 region_y = taskIndex % regionSize.y; - const uniform uint32 region_z = taskIndex / regionSize.y; - const uniform uint64 runOfs = (uint64)regionSize.x * (region_y + (uint64)regionSize.y * region_z); - const uint8 *uniform run = source + runOfs; - vec3i coord = targetCoord000 + make_vec3i(0,region_y,region_z); - foreach (x = 0 ... regionSize.x) { - Address address; - coord.x = targetCoord000.x + x; - if (coord.x < 0 || - coord.y < 0 || - coord.z < 0 || - coord.x >= self->super.dimensions.x || - coord.y >= self->super.dimensions.y || - coord.z >= self->super.dimensions.z - ) - continue; - BlockBrickedVolume_getVoxelAddress(self, coord, address); - foreach_unique(blockID in address.block) { - uint8 *uniform blockPtr - = ((uint8*uniform)self->blockMem) - + blockID * (uint64)BLOCK_VOXEL_COUNT; - blockPtr[address.voxel] = run[x]; - } - } +#define template_setRegion(type) \ +void BlockBrickedVolume_setRegion_##type(BlockBrickedVolume *uniform self, \ + const void *uniform _source, \ + const uniform vec3i &targetCoord000, \ + const uniform vec3i ®ionSize, \ + const uniform int taskIndex) \ +{ \ + const uniform uint32 region_y = taskIndex % regionSize.y; \ + const uniform uint32 region_z = taskIndex / regionSize.y; \ + const uniform uint64 runOfs = (uint64)regionSize.x * \ + (region_y + (uint64)regionSize.y * region_z); \ + const type *uniform run = (const type *uniform)_source + runOfs; \ + vec3i coord = targetCoord000 + make_vec3i(0,region_y,region_z); \ + foreach (x = 0 ... regionSize.x) { \ + Address address; \ + coord.x = targetCoord000.x + x; \ + if (coord.x < 0 || \ + coord.y < 0 || \ + coord.z < 0 || \ + coord.x >= self->super.dimensions.x || \ + coord.y >= self->super.dimensions.y || \ + coord.z >= self->super.dimensions.z \ + ) \ + continue; \ + \ + BlockBrickedVolume_getVoxelAddress(self, coord, address); \ + foreach_unique(blockID in address.block) { \ + type *uniform blockPtr = ((type *uniform)self->blockMem) \ + + blockID * (uint64)BLOCK_VOXEL_COUNT; \ + blockPtr[address.voxel] = run[x]; \ + } \ + } \ } -/*! copy given block of voxels into the volume, where source[0] will - be written to volume[targetCoord000] */ -void BlockBrickedVolumeFloat_setRegion(BlockBrickedVolume *uniform self, - const void *uniform _source, - const uniform vec3i &targetCoord000, - const uniform vec3i ®ionSize, - const uniform int taskIndex) -{ - const float *uniform source = (const float *uniform)_source; - const uniform uint32 region_y = taskIndex % regionSize.y; - const uniform uint32 region_z = taskIndex / regionSize.y; - const uniform uint64 runOfs = (uint64)regionSize.x * (region_y + (uint64)regionSize.y * region_z); - const float *uniform run = source + runOfs; - vec3i coord = targetCoord000 + make_vec3i(0,region_y,region_z); - foreach (x = 0 ... regionSize.x) { - Address address; - coord.x = targetCoord000.x + x; - if (coord.x < 0 || - coord.y < 0 || - coord.z < 0 || - coord.x >= self->super.dimensions.x || - coord.y >= self->super.dimensions.y || - coord.z >= self->super.dimensions.z - ) - continue; - - BlockBrickedVolume_getVoxelAddress(self, coord, address); - foreach_unique(blockID in address.block) { - float *uniform blockPtr - = ((float*uniform)self->blockMem) - + blockID * (uint64)BLOCK_VOXEL_COUNT; - blockPtr[address.voxel] = run[x]; - } - } -} +template_setRegion(uint8); +template_setRegion(uint16); +template_setRegion(float); +template_setRegion(double); +#undef template_setRegion -/*! copy given block of voxels into the volume, where source[0] will - be written to volume[targetCoord000] */ -void BlockBrickedVolumeDouble_setRegion(BlockBrickedVolume *uniform self, - const void *uniform _source, - const uniform vec3i &targetCoord000, - const uniform vec3i ®ionSize, - const uniform int taskIndex) -{ - const double *uniform source = (const double *uniform)_source; - const uniform uint32 region_y = taskIndex % regionSize.y; - const uniform uint32 region_z = taskIndex / regionSize.y; - const uniform uint64 runOfs = (uint64)regionSize.x * (region_y + (uint64)regionSize.y * region_z); - const double *uniform run = source + runOfs; - vec3i coord = targetCoord000 + make_vec3i(0,region_y,region_z); - foreach (x = 0 ... regionSize.x) { - Address address; - coord.x = targetCoord000.x + x; - if (coord.x < 0 || - coord.y < 0 || - coord.z < 0 || - coord.x >= self->super.dimensions.x || - coord.y >= self->super.dimensions.y || - coord.z >= self->super.dimensions.z - ) - continue; - BlockBrickedVolume_getVoxelAddress(self, coord, address); - foreach_unique(blockID in address.block) { - double *uniform blockPtr - = ((double*uniform)self->blockMem) - + blockID * (uint64)BLOCK_VOXEL_COUNT; - blockPtr[address.voxel] = run[x]; - } - } -} void BlockBrickedVolume_Constructor(BlockBrickedVolume *uniform volume, /*! pointer to the c++-equivalent class of this entity */ @@ -285,18 +189,23 @@ void BlockBrickedVolume_Constructor(BlockBrickedVolume *uniform volume, if (volume->voxelType == OSP_UCHAR) { volume->voxelSize = sizeof(uniform uint8); - volume->super.getVoxel = BlockBrickedVolumeUChar_getVoxel; - volume->setRegion = &BlockBrickedVolumeUChar_setRegion; + volume->super.getVoxel = BlockBrickedVolume_getVoxel_uint8; + volume->setRegion = &BlockBrickedVolume_setRegion_uint8; + } + else if (volume->voxelType == OSP_USHORT) { + volume->voxelSize = sizeof(uniform uint16); + volume->super.getVoxel = BlockBrickedVolume_getVoxel_uint16; + volume->setRegion = &BlockBrickedVolume_setRegion_uint16; } else if (volume->voxelType == OSP_FLOAT) { volume->voxelSize = sizeof(uniform float); - volume->super.getVoxel = BlockBrickedVolumeFloat_getVoxel; - volume->setRegion = &BlockBrickedVolumeFloat_setRegion; + volume->super.getVoxel = BlockBrickedVolume_getVoxel_float; + volume->setRegion = &BlockBrickedVolume_setRegion_float; } else if (volume->voxelType == OSP_DOUBLE) { volume->voxelSize = sizeof(uniform double); - volume->super.getVoxel = BlockBrickedVolumeDouble_getVoxel; - volume->setRegion = &BlockBrickedVolumeDouble_setRegion; + volume->super.getVoxel = BlockBrickedVolume_getVoxel_double; + volume->setRegion = &BlockBrickedVolume_setRegion_double; } else { print("#osp:block_bricked_volume: unknown voxel type\n"); @@ -307,56 +216,6 @@ void BlockBrickedVolume_Constructor(BlockBrickedVolume *uniform volume, BlockBrickedVolume_allocateMemory(volume); } -inline varying float BlockBrickedVolumeFloat_computeSample(void *uniform _volume, const varying vec3f &worldCoordinates) -{ - // Cast to the actual Volume subtype. - StructuredVolume *uniform volume = (StructuredVolume *uniform) _volume; - - // Transform the sample location into the local coordinate system. - vec3f localCoordinates; - volume->transformWorldToLocal(volume, worldCoordinates, localCoordinates); - - // Coordinates outside the volume are clamped to the volume bounds. - const vec3f clampedLocalCoordinates = clamp(localCoordinates, make_vec3f(0.0f), - volume->localCoordinatesUpperBound); - - // Lower and upper corners of the box straddling the voxels to be interpolated. - const vec3i voxelIndex_0 = integer_cast(clampedLocalCoordinates); - const vec3i voxelIndex_1 = voxelIndex_0 + 1; - - // Fractional coordinates within the lower corner voxel used during interpolation. - const vec3f fractionalLocalCoordinates = clampedLocalCoordinates - float_cast(voxelIndex_0); - - // Look up the voxel values to be interpolated. - float voxelValue_000; - float voxelValue_001; - float voxelValue_010; - float voxelValue_011; - float voxelValue_100; - float voxelValue_101; - float voxelValue_110; - float voxelValue_111; - BlockBrickedVolumeFloat_getVoxel(volume, make_vec3i(voxelIndex_0.x, voxelIndex_0.y, voxelIndex_0.z), voxelValue_000); - BlockBrickedVolumeFloat_getVoxel(volume, make_vec3i(voxelIndex_1.x, voxelIndex_0.y, voxelIndex_0.z), voxelValue_001); - BlockBrickedVolumeFloat_getVoxel(volume, make_vec3i(voxelIndex_0.x, voxelIndex_1.y, voxelIndex_0.z), voxelValue_010); - BlockBrickedVolumeFloat_getVoxel(volume, make_vec3i(voxelIndex_1.x, voxelIndex_1.y, voxelIndex_0.z), voxelValue_011); - BlockBrickedVolumeFloat_getVoxel(volume, make_vec3i(voxelIndex_0.x, voxelIndex_0.y, voxelIndex_1.z), voxelValue_100); - BlockBrickedVolumeFloat_getVoxel(volume, make_vec3i(voxelIndex_1.x, voxelIndex_0.y, voxelIndex_1.z), voxelValue_101); - BlockBrickedVolumeFloat_getVoxel(volume, make_vec3i(voxelIndex_0.x, voxelIndex_1.y, voxelIndex_1.z), voxelValue_110); - BlockBrickedVolumeFloat_getVoxel(volume, make_vec3i(voxelIndex_1.x, voxelIndex_1.y, voxelIndex_1.z), voxelValue_111); - - // Interpolate the voxel values. - const float voxelValue_00 = voxelValue_000 + fractionalLocalCoordinates.x * (voxelValue_001 - voxelValue_000); - const float voxelValue_01 = voxelValue_010 + fractionalLocalCoordinates.x * (voxelValue_011 - voxelValue_010); - const float voxelValue_10 = voxelValue_100 + fractionalLocalCoordinates.x * (voxelValue_101 - voxelValue_100); - const float voxelValue_11 = voxelValue_110 + fractionalLocalCoordinates.x * (voxelValue_111 - voxelValue_110); - const float voxelValue_0 = voxelValue_00 + fractionalLocalCoordinates.y * (voxelValue_01 - voxelValue_00 ); - const float voxelValue_1 = voxelValue_10 + fractionalLocalCoordinates.y * (voxelValue_11 - voxelValue_10 ); - const float volumeSample = voxelValue_0 + fractionalLocalCoordinates.z * (voxelValue_1 - voxelValue_0 ); - - return volumeSample; -} - export void *uniform BlockBrickedVolume_createInstance(void *uniform cppEquivalent, const uniform int voxelType, @@ -364,30 +223,22 @@ export void *uniform BlockBrickedVolume_createInstance(void *uniform cppEquivale { // The volume container. BlockBrickedVolume *uniform volume = uniform new uniform BlockBrickedVolume; - BlockBrickedVolume_Constructor(volume, cppEquivalent, voxelType, dimensions); - // if (voxelType == OSP_FLOAT) { - // print("using hand-inlined computesample fct for block-bricked\n"); - // volume->super.super.computeSample = BlockBrickedVolumeFloat_computeSample; - // } + return volume; } -export void -BlockBrickedVolume_setRegion(void *uniform _self, - /* points to the first voxel to be copies. The - voxels at 'soruce' MUST have dimensions - 'regionSize', must be organized in 3D-array - order, and must have the same voxel type as the - volume.*/ - const void *uniform _source, - /*! coordinates of the lower, left, front corner of - the target region.*/ - const uniform vec3i ®ionCoords, - /*! size of the region that we're writing to; MUST - be the same as the dimensions of source[][][] */ - const uniform vec3i ®ionSize, - const uniform int taskIndex) +export void BlockBrickedVolume_setRegion(void *uniform _self, + // points to the first voxel to be copied. The voxels at 'source' MUST have + // dimensions 'regionSize', must be organized in 3D-array order, and must + // have the same voxel type as the volume. + const void *uniform _source, + // coordinates of the lower, left, front corner of the target region + const uniform vec3i ®ionCoords, + // size of the region that we're writing to, MUST be the same as the + // dimensions of source[][][] + const uniform vec3i ®ionSize, + const uniform int taskIndex) { // Cast to the actual Volume subtype. BlockBrickedVolume *uniform self = (BlockBrickedVolume *uniform)_self; diff --git a/ospray/volume/DataDistributedBlockedVolume.cpp b/ospray/volume/DataDistributedBlockedVolume.cpp index 06be4a2448..b43b61acaa 100644 --- a/ospray/volume/DataDistributedBlockedVolume.cpp +++ b/ospray/volume/DataDistributedBlockedVolume.cpp @@ -85,7 +85,7 @@ namespace ospray { void DataDistributedBlockedVolume::buildAccelerator() { std::cout << "intentionally SKIP building an accelerator for data parallel " - << "volume" << std::endl; + << "volume (this'll be done on the brick level)" << std::endl; } std::string DataDistributedBlockedVolume::toString() const @@ -154,7 +154,6 @@ namespace ospray { "ospSetRegion())"); ddBlocks = getParam3i("num_dp_blocks",vec3i(4,4,4)); - PRINT(ddBlocks); blockSize = divRoundUp(dimensions,ddBlocks); std::cout << "#osp:dp: using data parallel volume of " << ddBlocks << " blocks, blockSize is " << blockSize << std::endl; @@ -170,7 +169,7 @@ namespace ospray { // Set the grid spacing, default to (1,1,1). this->gridSpacing = getParam3f("gridSpacing", vec3f(1.f)); - numDDBlocks = embree::reduce_mul(ddBlocks); + numDDBlocks = ospcommon::reduce_mul(ddBlocks); ddBlock = new DDBlock[numDDBlocks]; printf("=======================================================\n"); @@ -183,64 +182,63 @@ namespace ospray { "mode..."); } int64 numWorkers = ospray::core::getWorkerCount(); - PRINT(numDDBlocks); - PRINT(numWorkers); + // PRINT(numDDBlocks); + // PRINT(numWorkers); voxelType = getParamString("voxelType", "unspecified"); // if (numDDBlocks >= numWorkers) { - // we have more workers than blocks - use one owner per block, - // meaning we'll end up with multiple blocks per worker - int blockID = 0; - for (int iz=0;iz= numWorkers) { - block->firstOwner = blockID % numWorkers; - block->numOwners = 1; - } else { - block->firstOwner = (blockID * numWorkers) / numDDBlocks; - int nextBlockFirstOwner = ((blockID+1)*numWorkers) / numDDBlocks; - block->numOwners = nextBlockFirstOwner - block->firstOwner + 1; - } - block->isMine - = (ospray::core::getWorkerRank() >= block->firstOwner) - && (ospray::core::getWorkerRank() < - (block->firstOwner + block->numOwners)); - block->domain.lower = vec3i(ix,iy,iz) * blockSize; - block->domain.upper = min(block->domain.lower+blockSize,dimensions); - block->bounds.lower = gridOrigin + - (gridSpacing * vec3f(block->domain.lower)); - block->bounds.upper = gridOrigin + - (gridSpacing * vec3f(block->domain.upper)); - - // XXX?? 1 overlap? - block->domain.upper = min(block->domain.upper+vec3i(1),dimensions); - + // we have more workers than blocks - use one owner per block, + // meaning we'll end up with multiple blocks per worker + int blockID = 0; + for (int iz=0;iz= numWorkers) { + block->firstOwner = blockID % numWorkers; + block->numOwners = 1; + } else { + block->firstOwner = (blockID * numWorkers) / numDDBlocks; + int nextBlockFirstOwner = ((blockID+1)*numWorkers) / numDDBlocks; + block->numOwners = nextBlockFirstOwner - block->firstOwner; // + 1; + } + block->isMine + = (ospray::core::getWorkerRank() >= block->firstOwner) + && (ospray::core::getWorkerRank() < + (block->firstOwner + block->numOwners)); + block->domain.lower = vec3i(ix,iy,iz) * blockSize; + block->domain.upper = min(block->domain.lower+blockSize,dimensions); + block->bounds.lower = gridOrigin + + (gridSpacing * vec3f(block->domain.lower)); + block->bounds.upper = gridOrigin + + (gridSpacing * vec3f(block->domain.upper)); + + // iw: add one voxel overlap, so we can properly interpolate + // even across block boundaries (we need the full *cell* on + // the right side, not just the last *voxel*!) + block->domain.upper = min(block->domain.upper+vec3i(1),dimensions); + + + if (block->isMine) { + Ref volume = new BlockBrickedVolume; + vec3i blockDims = block->domain.upper - block->domain.lower; + volume->findParam("dimensions",1)->set(blockDims); + volume->findParam("gridOrigin",1)->set(block->bounds.lower); + volume->findParam("gridSpacing",1)->set(gridSpacing); + volume->findParam("voxelType",1)->set(voxelType.c_str()); - if (block->isMine) { - Ref volume = new BlockBrickedVolume; - vec3i blockDims = block->domain.upper - block->domain.lower; - volume->findParam("dimensions",1)->set(blockDims); - volume->findParam("gridOrigin",1)->set(block->bounds.lower); - volume->findParam("gridSpacing",1)->set(gridSpacing); - volume->findParam("voxelType",1)->set(voxelType.c_str()); - - printf("rank %li owns block %i,%i,%i (ID %i), dims %i %i %i\n", - (size_t)core::getWorkerRank(),ix,iy,iz, - blockID,blockDims.x,blockDims.y,blockDims.z); - block->cppVolume = volume; - block->ispcVolume = NULL; //volume->getIE(); - } else { - block->ispcVolume = NULL; - block->cppVolume = NULL; - } + printf("rank %li owns block %i,%i,%i (ID %i), dims %i %i %i\n", + (size_t)core::getWorkerRank(),ix,iy,iz, + blockID,blockDims.x,blockDims.y,blockDims.z); + block->cppVolume = volume; + block->ispcVolume = NULL; //volume->getIE(); + } else { + block->ispcVolume = NULL; + block->cppVolume = NULL; } - // } else { - // FATAL("not implemented yet - more workers than blocks ...");//TODO - // } - + } + // Create an ISPC BlockBrickedVolume object and assign type-specific // function pointers. ispcEquivalent = ispc::DDBVolume_create(this, diff --git a/ospray/volume/DataDistributedBlockedVolume.h b/ospray/volume/DataDistributedBlockedVolume.h index d611431cf8..f1a3a197b4 100644 --- a/ospray/volume/DataDistributedBlockedVolume.h +++ b/ospray/volume/DataDistributedBlockedVolume.h @@ -64,10 +64,10 @@ namespace ospray { //! A string description of this class. std::string toString() const override; - + //! Allocate storage and populate the volume, called through the OSPRay API. void commit() override; - + //! Copy voxels into the volume at the given index (non-zero return value //! indicates success). int setRegion(const void *source, @@ -78,7 +78,7 @@ namespace ospray { //private: //! Create the equivalent ISPC volume container. - void createEquivalentISPC(); + void createEquivalentISPC() override; /*! size of each block, in voxels, WITHOUT padding (in practice the blocks * WILL be padded) */ diff --git a/ospray/volume/DataDistributedBlockedVolume.ih b/ospray/volume/DataDistributedBlockedVolume.ih index 928c38277e..2ab56a962b 100644 --- a/ospray/volume/DataDistributedBlockedVolume.ih +++ b/ospray/volume/DataDistributedBlockedVolume.ih @@ -14,27 +14,8 @@ // limitations under the License. // // ======================================================================== // -#include "ospray/volume/BlockBrickedVolume.ih" - -// ======================================================================== // -// 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 "ospray/common/OSPDataType.h" #include "ospray/volume/StructuredVolume.ih" diff --git a/ospray/volume/GhostBlockBrickedVolume.cpp b/ospray/volume/GhostBlockBrickedVolume.cpp index c70a0ed494..66b8247fa0 100644 --- a/ospray/volume/GhostBlockBrickedVolume.cpp +++ b/ospray/volume/GhostBlockBrickedVolume.cpp @@ -16,18 +16,15 @@ //ospray #include "ospray/volume/GhostBlockBrickedVolume.h" +#include "ospray/common/tasking/parallel_for.h" #include "GhostBlockBrickedVolume_ispc.h" -// std -#include - -bool g_dbg = 0; namespace ospray { GhostBlockBrickedVolume::~GhostBlockBrickedVolume() { if (ispcEquivalent) { - ispc::GGBV_freeVolume(ispcEquivalent); + ispc::GBBV_freeVolume(ispcEquivalent); } } @@ -43,7 +40,7 @@ namespace ospray { // to 'setRegion', and only a final commit at the // end. 'dimensions' etc may/will _not_ be committed before // setregion. - exitOnCondition(ispcEquivalent == NULL, + exitOnCondition(ispcEquivalent == nullptr, "the volume data must be set via ospSetRegion() " "prior to commit for this volume type"); @@ -51,30 +48,29 @@ namespace ospray { StructuredVolume::commit(); } - int GhostBlockBrickedVolume::setRegion(/* points to the first voxel to be copies. The - voxels at 'source' MUST have dimensions - 'regionSize', must be organized in 3D-array - order, and must have the same voxel type as the - volume.*/ - const void *source, - /*! coordinates of the lower, - left, front corner of the target - region.*/ - const vec3i ®ionCoords, - /*! size of the region that we're writing to; MUST - be the same as the dimensions of source[][][] */ + int GhostBlockBrickedVolume::setRegion( + // points to the first voxel to be copied. The voxels at 'source' MUST + // have dimensions 'regionSize', must be organized in 3D-array order, and + // must have the same voxel type as the volume. + const void *source, + // coordinates of the lower, left, front corner of the target region + const vec3i ®ionCoords, + // size of the region that we're writing to, MUST be the same as the + // dimensions of source[][][] const vec3i ®ionSize) { - if (g_dbg) PING; - // Create the equivalent ISPC volume container and allocate memory for voxel data. - if (ispcEquivalent == NULL) createEquivalentISPC(); + // Create the equivalent ISPC volume container and allocate memory for voxel + // data. + if (ispcEquivalent == nullptr) + createEquivalentISPC(); /*! \todo check if we still need this 'computevoxelrange' - in theory we need this only if the app is allowed to query these values, and they're not being set in sharedstructuredvolume, either, so should we actually set them at all!? */ - // Compute the voxel value range for unsigned byte voxels if none was previously specified. - Assert2(source,"NULL source in GhostBlockBrickedVolume::setRegion()"); + // Compute the voxel value range for unsigned byte voxels if none was + // previously specified. + Assert2(source,"nullptr source in GhostBlockBrickedVolume::setRegion()"); #ifndef OSPRAY_VOLUME_VOXELRANGE_IN_APP if (findParam("voxelRange") == NULL) { @@ -84,39 +80,52 @@ namespace ospray { = (size_t)regionSize.x * + (size_t)regionSize.y * + (size_t)regionSize.z; - if (voxelType == "uchar") + if (voxelType == "uchar") computeVoxelRange((unsigned char *)source, numVoxelsInRegion); - else if (voxelType == "float") + else if (voxelType == "ushort") + computeVoxelRange((unsigned short *)source, numVoxelsInRegion); + else if (voxelType == "float") computeVoxelRange((float *)source, numVoxelsInRegion); - else if (voxelType == "double") + else if (voxelType == "double") computeVoxelRange((double *) source, numVoxelsInRegion); - else - throw std::runtime_error("invalid voxelType in GhostBlockBrickedVolume::setRegion()"); + else { + throw std::runtime_error("invalid voxelType in " + "GhostBlockBrickedVolume::setRegion()"); + } } #endif // Copy voxel data into the volume. - ispc::GGBV_setRegion(ispcEquivalent, source, - (const ispc::vec3i &) regionCoords, - (const ispc::vec3i &) regionSize); + const int NTASKS = regionSize.y * regionSize.z; + parallel_for(NTASKS, [&](int taskIndex){ + ispc::GBBV_setRegion(ispcEquivalent, + source, + (const ispc::vec3i &)regionCoords, + (const ispc::vec3i &)regionSize, + taskIndex); + }); + return true; } - void GhostBlockBrickedVolume::createEquivalentISPC() + void GhostBlockBrickedVolume::createEquivalentISPC() { // Get the voxel type. - voxelType = getParamString("voxelType", "unspecified"); - exitOnCondition(getVoxelType() == OSP_UNKNOWN, - "unrecognized voxel type (must be set before calling ospSetRegion())"); + voxelType = getParamString("voxelType", "unspecified"); + exitOnCondition(getVoxelType() == OSP_UNKNOWN, + "unrecognized voxel type (must be set before calling " + "ospSetRegion())"); // Get the volume dimensions. this->dimensions = getParam3i("dimensions", vec3i(0)); - exitOnCondition(reduce_min(this->dimensions) <= 0, - "invalid volume dimensions (must be set before calling ospSetRegion())"); - - // Create an ISPC GhostBlockBrickedVolume object and assign type-specific function pointers. - ispcEquivalent = ispc::GGBV_createInstance(this, - (int)getVoxelType(), - (const ispc::vec3i &)this->dimensions); + exitOnCondition(reduce_min(this->dimensions) <= 0, + "invalid volume dimensions (must be set before calling " + "ospSetRegion())"); + + // Create an ISPC GhostBlockBrickedVolume object and assign type-specific + // function pointers. + ispcEquivalent = ispc::GBBV_createInstance(this, + (int)getVoxelType(), + (const ispc::vec3i &)this->dimensions); } #ifdef EXP_NEW_BB_VOLUME_KERNELS diff --git a/ospray/volume/GhostBlockBrickedVolume.h b/ospray/volume/GhostBlockBrickedVolume.h index 618ed9d605..d2965d84e1 100644 --- a/ospray/volume/GhostBlockBrickedVolume.h +++ b/ospray/volume/GhostBlockBrickedVolume.h @@ -27,7 +27,6 @@ namespace ospray { class GhostBlockBrickedVolume : public StructuredVolume { public: - //! Destructor. ~GhostBlockBrickedVolume(); //! A string description of this class. diff --git a/ospray/volume/GhostBlockBrickedVolume.ih b/ospray/volume/GhostBlockBrickedVolume.ih index f340fd1878..f5b9b3889f 100644 --- a/ospray/volume/GhostBlockBrickedVolume.ih +++ b/ospray/volume/GhostBlockBrickedVolume.ih @@ -16,7 +16,7 @@ #pragma once -#include "ospray/common/OSPDataType.h" +#include "ospray/OSPDataType.h" #include "ospray/volume/StructuredVolume.ih" //! \brief ISPC variables and functions for the GhostBlockBrickedVolume class @@ -44,14 +44,15 @@ struct GhostBlockBrickedVolume { /*! copy given block of voxels into the volume, where source[0] will be written to volume[targetCoord000] */ - void (*uniform setRegion)(void *uniform _volume, - const void *uniform _source, - const uniform vec3i ®ionSize, - const uniform vec3i &targetCoord000); + void (*uniform setRegion)(GhostBlockBrickedVolume *uniform self, + const void *uniform source, + const uniform vec3i ®ionSize, + const uniform vec3i &targetCoord000, + const uniform int taskIndex); }; -void GhostBlockBrickedVolume_Constructor(GhostBlockBrickedVolume *uniform volume, +void GhostBlockBrickedVolume_Constructor(GhostBlockBrickedVolume *uniform volume, /*! pointer to the c++-equivalent class of this entity */ void *uniform cppEquivalent, - const uniform int voxelType, + const uniform int voxelType, const uniform vec3i &dimensions); diff --git a/ospray/volume/GhostBlockBrickedVolume.ispc b/ospray/volume/GhostBlockBrickedVolume.ispc index b9adaf959a..34a7dacab4 100644 --- a/ospray/volume/GhostBlockBrickedVolume.ispc +++ b/ospray/volume/GhostBlockBrickedVolume.ispc @@ -19,7 +19,7 @@ /*! total number of bits per block dimension. '6' would mean 18 bits = 1/4million voxels per block, which for alots would be 1MB, so should all fit into a single 2M page (assuming we do 2M allocs, of course) */ -#define BLOCK_BITS (6) +#define BLOCK_BITS (6) #define BRICK_BITS (2) /*! @{ number of voxels per block per dimension */ @@ -34,7 +34,7 @@ /*! size of one block, in voxels */ #define VOXELS_PER_BLOCK (BLOCK_WIDTH*BLOCK_WIDTH*BLOCK_WIDTH) -/*! @{ start bit for given section of address in bricked offset field +/*! @{ start bit for given section of address in bricked offset field lo is the address part for inside a brick, hi is the remaining part inside the blcok ex the brick part @@ -60,6 +60,7 @@ /*! @{ number of bits we have to SHIFT addresses for given type */ #define shift_per_uint8 0 +#define shift_per_uint16 1 #define shift_per_float 2 #define shift_per_double 3 /*! @} */ @@ -67,21 +68,22 @@ /*! @{ number of bits we have to MULTIPLY offsets with for given type */ #define scale_per_uint8 1 +#define scale_per_uint16 2 #define scale_per_float 4 #define scale_per_double 8 /*! @} */ /*! do a simple type rename/abbreviation, to we have shorter type names */ -typedef GhostBlockBrickedVolume GGBV; +typedef GhostBlockBrickedVolume GBBV; /*! structure that encodes a block:offset style address for a single - sample */ + sample */ struct Address { - + //! The 1D address of the block in the volume containing the voxel. varying uint32 block; - + //! The 1D offset of the voxel in the enclosing block. varying uint32 voxel; }; @@ -91,10 +93,10 @@ struct Address { ID, base of the lower-left, and offset's to the +1's in x,y,and z. Deltas fully contain the effet of bricking */ struct Address8 { - + //! The 1D address of the block in the volume containing the voxel. varying uint32 block; - + //! The 1D offset (in bytes!) of the voxel in the enclosing block. varying uint32 voxelOfs; /*! the offset we have to add to voxelofs to go to the next voxel in @@ -155,13 +157,14 @@ inline int intDiv(float x) } template_brickTranslation(uint8); +template_brickTranslation(uint16); template_brickTranslation(float); template_brickTranslation(double); #define template_getAddress(type) \ /* IMPORTANT: this function computes RAW adresses that are to be */ \ /* directy added to "unsigned char *" pointers */ \ - inline void GGBV_getAddress_##type(GGBV *uniform volume, \ + inline void GBBV_getAddress_##type(GBBV *uniform volume, \ const vec3f &voxelIdxInVolume_f, \ const vec3i &voxelIdxInVolume, \ varying Address8 &address) \ @@ -186,7 +189,7 @@ template_brickTranslation(double); /* IMPORTANT: this function computes type-relative offsets, so */ \ /* values returned from this function should only be added to */ \ /* "type *" pointers */ \ - inline void GGBV_getIndices_##type(GGBV *uniform volume, \ + inline void GBBV_getIndices_##type(GBBV *uniform volume, \ const varying vec3i &voxelIdxInVolume, \ varying Address &address) \ { \ @@ -222,6 +225,7 @@ template_brickTranslation(double); } template_getAddress(uint8); +template_getAddress(uint16); template_getAddress(float); template_getAddress(double); @@ -242,7 +246,7 @@ template_getAddress(double); because certain values will get recomputed for each of the 7 direction (plus the original cell itself) but this is the easiest (I could find). */ -inline bool GGBV_getGhostIndices(GGBV *uniform volume, +inline bool GBBV_getGhostIndices(GBBV *uniform volume, const varying vec3i &voxelIdxInVolume, const uniform vec3i delta, varying Address &address) @@ -250,7 +254,7 @@ inline bool GGBV_getGhostIndices(GGBV *uniform volume, // do not set offset value for original sample if ((delta.x == 0) && (delta.y == 0) && (delta.z == 0)) return false; - + // Compute the 3D index of the block containing the brick containing the voxel. // vec3i blockIndex = voxelIdxInVolume / make_vec3i(BLOCK_WIDTH-1); vec3i blockIndex = make_vec3i(intDiv(voxelIdxInVolume.x), @@ -278,24 +282,24 @@ inline bool GGBV_getGhostIndices(GGBV *uniform volume, --blockIndex.z; valid = true; } - + // Compute the 1D address of the block in the volume. address.block = blockIndex.x + volume->blockCount.x * (blockIndex.y + volume->blockCount.y * blockIndex.z); - + const vec3i brickIdxInBlock = voxelIdxInBlock >> BRICK_BITS; const vec3i voxelIdxInBrick = bitwise_AND(voxelIdxInBlock,BRICK_MASK); - + // Compute the 1D address of the voxel in the block. address.voxel = - (voxelIdxInBrick.x << (BRICK_BIT_X_LO)) | - (voxelIdxInBrick.y << (BRICK_BIT_Y_LO)) | - (voxelIdxInBrick.z << (BRICK_BIT_Z_LO)) | - (brickIdxInBlock.x << (BRICK_BIT_X_HI)) | - (brickIdxInBlock.y << (BRICK_BIT_Y_HI)) | - (brickIdxInBlock.z << (BRICK_BIT_Z_HI)); + (voxelIdxInBrick.x << (BRICK_BIT_X_LO)) | + (voxelIdxInBrick.y << (BRICK_BIT_Y_LO)) | + (voxelIdxInBrick.z << (BRICK_BIT_Z_LO)) | + (brickIdxInBlock.x << (BRICK_BIT_X_HI)) | + (brickIdxInBlock.y << (BRICK_BIT_Y_HI)) | + (brickIdxInBlock.z << (BRICK_BIT_Z_HI)); return valid && (blockIndex.x >=0) && (blockIndex.y >= 0) && (blockIndex.z >= 0); } @@ -313,21 +317,22 @@ inline bool GGBV_getGhostIndices(GGBV *uniform volume, uniform uint8 *uniform base = (uniform uint8 *uniform)basePtr; \ return *((uniform type *)(base+offset)); \ } \ - + template_accessArray(uint8); +template_accessArray(uint16); template_accessArray(float); template_accessArray(double); #undef template_accessArray - + #define template_getVoxel(type) \ /*! get a single voxel. careful - THIS function operates on */ \ /* typed offsets, not byte-offsets */ \ - inline void GGBV_getVoxel_##type(void *uniform _volume, \ + inline void GBBV_getVoxel_##type(void *uniform _volume, \ const varying vec3i &index, \ varying float &value) \ { \ /* Cast to the actual Volume subtype. */ \ - GGBV *uniform volume = (GGBV *uniform) _volume; \ + GBBV *uniform volume = (GBBV *uniform) _volume; \ \ /* Cast to the actual voxel type.*/ \ const type *uniform blockMem \ @@ -335,7 +340,7 @@ template_accessArray(double); \ /* Compute the 1D address of the block in the volume and the voxel in the block. */ \ Address address; \ - GGBV_getIndices_##type(volume, index, address); \ + GBBV_getIndices_##type(volume, index, address); \ \ /* The voxel value at the 1D address.*/ \ foreach_unique(blockID in address.block) { \ @@ -347,198 +352,66 @@ template_accessArray(double); } template_getVoxel(uint8) +template_getVoxel(uint16) template_getVoxel(float) template_getVoxel(double) #undef template_getVoxel -inline void GGBV_allocateMemory(GGBV *uniform volume) -{ - // Memory may already have been allocated. - if (volume->blockMem != NULL) return; - - // Volume size in blocks per dimension with padding to the nearest block. - volume->blockCount = (volume->super.dimensions + (BLOCK_WIDTH-1) - 1) / (BLOCK_WIDTH-1); - - // Volume size in blocks with padding. - const uniform size_t blockCount = volume->blockCount.x * volume->blockCount.y * volume->blockCount.z; - - // allocate the large array of blocks - uniform uint64 blockSize = VOXELS_PER_BLOCK * volume->voxelSize; - volume->blockMem = malloc64(blockSize * (uint64)blockCount); - - if (volume->blockMem == NULL) { - print("failed to allocate block memory!"); - return; - } +#define template_setRegion(type) \ +void GBBV_setRegionTask_##type(GBBV *uniform self, \ + const void *uniform _source, \ + const uniform vec3i &targetCoord000, \ + const uniform vec3i ®ionSize, \ + const uniform int taskIndex) \ +{ \ + const type *uniform source = (const type *uniform)_source; \ + const uniform uint32 region_y = taskIndex % regionSize.y; \ + const uniform uint32 region_z = taskIndex / regionSize.y; \ + const uniform uint64 runOfs \ + = (uint64)regionSize.x * (region_y + (uint64)regionSize.y * region_z); \ + const type *uniform run = source + runOfs; \ + vec3i coord = targetCoord000 + make_vec3i(0,region_y,region_z); \ + foreach (x = 0 ... regionSize.x) { \ + Address address; \ + coord.x = targetCoord000.x + x; \ + if (coord.x < 0 || \ + coord.y < 0 || \ + coord.z < 0 || \ + coord.x >= self->super.dimensions.x || \ + coord.y >= self->super.dimensions.y || \ + coord.z >= self->super.dimensions.z \ + ) \ + continue; \ + \ + GBBV_getIndices_##type(self, coord, address); \ + /* set voxel itself */ \ + foreach_unique(blockID in address.block) { \ + type *uniform blockPtr \ + = ((type*uniform)self->blockMem) \ + + blockID * (uint64)VOXELS_PER_BLOCK; \ + blockPtr[address.voxel] = run[x]; \ + } \ + /* copy voxel to end of lower/left/front block if it's on the boundary */ \ + for (uniform int32 iz=0;iz<2;iz++) \ + for (uniform int32 iy=0;iy<2;iy++) \ + for (uniform int32 ix=0;ix<2;ix++) { \ + if (GBBV_getGhostIndices(self, coord, make_vec3i(ix,iy,iz),address)) { \ + foreach_unique(blockID in address.block) { \ + type *uniform blockPtr \ + = ((type*uniform)self->blockMem) \ + + (uint64)blockID * (uint64)VOXELS_PER_BLOCK; \ + blockPtr[address.voxel] = run[x]; \ + } \ + } \ + } \ + } \ } -task void PBBVUChar_setRegionTask(GGBV *uniform self, - const uint8 *uniform source, - const uniform vec3i &targetCoord000, - const uniform vec3i ®ionSize) -{ - const uniform uint32 region_y = taskIndex % regionSize.y; - const uniform uint32 region_z = taskIndex / regionSize.y; - const uniform uint64 runOfs - = (uint64)regionSize.x * (region_y + (uint64)regionSize.y * region_z); - const uint8 *uniform run = source + runOfs; - vec3i coord = targetCoord000 + make_vec3i(0,region_y,region_z); - foreach (x = 0 ... regionSize.x) { - Address address; - coord.x = targetCoord000.x + x; - if (coord.x < 0 || - coord.y < 0 || - coord.z < 0 || - coord.x >= self->super.dimensions.x || - coord.y >= self->super.dimensions.y || - coord.z >= self->super.dimensions.z - ) - continue; - - GGBV_getIndices_uint8(self, coord, address); - foreach_unique(blockID in address.block) { - uint8 *uniform blockPtr - = ((uint8*uniform)self->blockMem) - + blockID * (uint64)VOXELS_PER_BLOCK; - blockPtr[address.voxel] = run[x]; - } - for (uniform int32 iz=0;iz<2;iz++) - for (uniform int32 iy=0;iy<2;iy++) - for (uniform int32 ix=0;ix<2;ix++) { - if (GGBV_getGhostIndices(self, coord, make_vec3i(ix,iy,iz),address)) { - foreach_unique(blockID in address.block) { - uint8 *uniform blockPtr - = ((uint8*uniform)self->blockMem) - + (uint64)blockID * (uint64)VOXELS_PER_BLOCK; - blockPtr[address.voxel] = run[x]; - } - } - } - } -} - -task void PBBVFloat_setRegionTask(GGBV *uniform self, - const float *uniform source, - const uniform vec3i &targetCoord000, - const uniform vec3i ®ionSize) -{ - const uniform uint32 region_y = taskIndex % regionSize.y; - const uniform uint32 region_z = taskIndex / regionSize.y; - const uniform uint64 runOfs - = (uint64)regionSize.x * (region_y + (uint64)regionSize.y * region_z); - const float *uniform run = source + runOfs; - vec3i coord = targetCoord000 + make_vec3i(0,region_y,region_z); - foreach (x = 0 ... regionSize.x) { - Address address; - coord.x = targetCoord000.x + x; - if (coord.x < 0 || - coord.y < 0 || - coord.z < 0 || - coord.x >= self->super.dimensions.x || - coord.y >= self->super.dimensions.y || - coord.z >= self->super.dimensions.z - ) - continue; - - GGBV_getIndices_float(self, coord, address); - // set voxel itself - foreach_unique(blockID in address.block) { - float *uniform blockPtr - = ((float*uniform)self->blockMem) - + blockID * (uint64)VOXELS_PER_BLOCK; - blockPtr[address.voxel] = run[x]; - } - // copy voxel to end of lower/left/front block if it's on the boundary - for (uniform int32 iz=0;iz<2;iz++) - for (uniform int32 iy=0;iy<2;iy++) - for (uniform int32 ix=0;ix<2;ix++) { - if (GGBV_getGhostIndices(self, coord, make_vec3i(ix,iy,iz),address)) { - foreach_unique(blockID in address.block) { - float *uniform blockPtr - = ((float*uniform)self->blockMem) - + blockID * (uint64)VOXELS_PER_BLOCK; - blockPtr[address.voxel] = run[x]; - } - } - } - } -} - -task void PBBVDouble_setRegionTask(GGBV *uniform self, - const double *uniform source, - const uniform vec3i &targetCoord000, - const uniform vec3i ®ionSize) -{ - const uniform uint32 region_y = taskIndex % regionSize.y; - const uniform uint32 region_z = taskIndex / regionSize.y; - const uniform uint64 runOfs = (uint64)regionSize.x * (region_y + (uint64)regionSize.y * region_z); - const double *uniform run = source + runOfs; - vec3i coord = targetCoord000 + make_vec3i(0,region_y,region_z); - foreach (x = 0 ... regionSize.x) { - Address address; - coord.x = targetCoord000.x + x; - if (coord.x < 0 || - coord.y < 0 || - coord.z < 0 || - coord.x >= self->super.dimensions.x || - coord.y >= self->super.dimensions.y || - coord.z >= self->super.dimensions.z - ) - continue; - GGBV_getIndices_double(self, coord, address); - foreach_unique(blockID in address.block) { - double *uniform blockPtr - = ((double*uniform)self->blockMem) - + blockID * (uint64)VOXELS_PER_BLOCK; - blockPtr[address.voxel] = run[x]; - } - } -} - -/*! copy given block of voxels into the volume, where source[0] will - be written to volume[targetCoord000] */ -void GGBVUChar_setRegion(void *uniform _volume, - const void *uniform _source, - const uniform vec3i &targetCoord000, - const uniform vec3i ®ionSize) -{ - // a 'run' is sequence of connected voxels in x direction - uniform uint32 numRuns = regionSize.y * regionSize.z; - launch[numRuns] PBBVUChar_setRegionTask((GGBV*uniform)_volume, - (const uint8*uniform)_source, - targetCoord000, - regionSize); -} - -/*! copy given block of voxels into the volume, where source[0] will - be written to volume[targetCoord000] */ -void GGBVFloat_setRegion(void *uniform _volume, - const void *uniform _source, - const uniform vec3i &targetCoord000, - const uniform vec3i ®ionSize) -{ - // a 'run' is sequence of connected voxels in x direction - uniform uint32 numRuns = regionSize.y * regionSize.z; - launch[numRuns] PBBVFloat_setRegionTask((GGBV*uniform)_volume, - (const float*uniform)_source, - targetCoord000, - regionSize); -} - -/*! copy given block of voxels into the volume, where source[0] will - be written to volume[targetCoord000] */ -void GGBVDouble_setRegion(void *uniform _volume, - const void *uniform _source, - const uniform vec3i &targetCoord000, - const uniform vec3i ®ionSize) -{ - // a 'run' is sequence of connected voxels in x direction - uniform uint32 numRuns = regionSize.y * regionSize.z; - launch[numRuns] PBBVDouble_setRegionTask((GGBV*uniform)_volume, - (const double*uniform)_source, - targetCoord000, - regionSize); -} +template_setRegion(uint8) +template_setRegion(uint16) +template_setRegion(float) +template_setRegion(double) +#undef template_setRegion /*! perform trilinear interpolation for given sample. unlike old way of doing this (a single computesample on the StructuredVolume level @@ -547,11 +420,11 @@ void GGBVDouble_setRegion(void *uniform _volume, (inlined), and thus be about 50% faster (wall-time, meaning even much faster in pure sample speed) */ #define template_computeSample(type) \ - inline float GGBV_computeSample_##type(void *uniform _volume, \ + inline float GBBV_computeSample_##type(void *uniform _volume, \ const vec3f &worldCoordinates) \ { \ /* Cast to the actual Volume subtype. */ \ - GGBV *uniform volume = (GGBV *uniform) _volume; \ + GBBV *uniform volume = (GBBV *uniform) _volume; \ \ /* Transform the sample location into the local coordinate system. */ \ vec3f localCoordinates; \ @@ -572,7 +445,7 @@ void GGBVDouble_setRegion(void *uniform _volume, \ /* Compute the 1D address of the block in the volume and the voxel in the block. */ \ Address8 address8; \ - GGBV_getAddress_##type(volume, clampedLocalCoordinates, \ + GBBV_getAddress_##type(volume, clampedLocalCoordinates, \ voxelIndex_0, address8); \ /* split block into 24+8 bits; we'll have to do a foreach_unique */ \ /* over the upper 24 bits to satify 64-bit addressing, but at */ \ @@ -625,38 +498,67 @@ void GGBVDouble_setRegion(void *uniform _volume, } template_computeSample(uint8) +template_computeSample(uint16) template_computeSample(float) template_computeSample(double) #undef template_computeSample -void GGBV_Constructor(GGBV *uniform volume, + +inline void GBBV_allocateMemory(GBBV *uniform volume) +{ + // Memory may already have been allocated. + if (volume->blockMem != NULL) return; + + // Volume size in blocks per dimension with padding to the nearest block. + volume->blockCount = (volume->super.dimensions + (BLOCK_WIDTH-1) - 1) / (BLOCK_WIDTH-1); + + // Volume size in blocks with padding. + const uniform size_t blockCount = volume->blockCount.x * volume->blockCount.y * volume->blockCount.z; + + // allocate the large array of blocks + uniform uint64 blockSize = VOXELS_PER_BLOCK * volume->voxelSize; + volume->blockMem = malloc64(blockSize * (uint64)blockCount); + + if (volume->blockMem == NULL) { + print("failed to allocate block memory!"); + return; + } +} + +void GBBV_Constructor(GBBV *uniform volume, /*! pointer to the c++-equivalent class of this entity */ void *uniform cppEquivalent, - const uniform int voxelType, + const uniform int voxelType, const uniform vec3i &dimensions) { StructuredVolume_Constructor(&volume->super, cppEquivalent, dimensions); - + volume->blockMem = NULL; volume->voxelType = (OSPDataType) voxelType; - + if (volume->voxelType == OSP_UCHAR) { volume->voxelSize = sizeof(uniform uint8); - volume->super.getVoxel = GGBV_getVoxel_uint8; - volume->setRegion = &GGBVUChar_setRegion; - volume->super.super.computeSample = GGBV_computeSample_uint8; + volume->super.getVoxel = GBBV_getVoxel_uint8; + volume->setRegion = &GBBV_setRegionTask_uint8; + volume->super.super.computeSample = GBBV_computeSample_uint8; + } + else if (volume->voxelType == OSP_USHORT) { + volume->voxelSize = sizeof(uniform uint16); + volume->super.getVoxel = GBBV_getVoxel_uint16; + volume->setRegion = &GBBV_setRegionTask_uint16; + volume->super.super.computeSample = GBBV_computeSample_uint16; } else if (volume->voxelType == OSP_FLOAT) { volume->voxelSize = sizeof(uniform float); - volume->super.getVoxel = GGBV_getVoxel_float; - volume->setRegion = &GGBVFloat_setRegion; - volume->super.super.computeSample = GGBV_computeSample_float; + volume->super.getVoxel = GBBV_getVoxel_float; + volume->setRegion = &GBBV_setRegionTask_float; + volume->super.super.computeSample = GBBV_computeSample_float; } else if (volume->voxelType == OSP_DOUBLE) { - volume->voxelSize = sizeof(uniform double); - volume->super.getVoxel = GGBV_getVoxel_double; - volume->setRegion = &GGBVDouble_setRegion; - volume->super.super.computeSample = GGBV_computeSample_double; + volume->voxelSize = sizeof(uniform double); + volume->super.getVoxel = GBBV_getVoxel_double; + volume->setRegion = &GBBV_setRegionTask_double; + volume->super.super.computeSample = GBBV_computeSample_double; } else { print("#osp:block_bricked_volume: unknown voxel type\n"); @@ -664,43 +566,41 @@ void GGBV_Constructor(GGBV *uniform volume, } // Allocate memory. - GGBV_allocateMemory(volume); + GBBV_allocateMemory(volume); } -export void *uniform GGBV_createInstance(void *uniform cppEquivalent, - const uniform int voxelType, +export void *uniform GBBV_createInstance(void *uniform cppEquivalent, + const uniform int voxelType, const uniform vec3i &dimensions) { // create instance of actual volume type ... - GGBV *uniform volume = uniform new uniform GGBV; + GBBV *uniform volume = uniform new uniform GBBV; // ... call constructor to initialize it ... - GGBV_Constructor(volume, cppEquivalent, voxelType, dimensions); + GBBV_Constructor(volume, cppEquivalent, voxelType, dimensions); // ... and return object to caller return volume; } - -export void GGBV_setRegion(void *uniform _self, - /* points to the first voxel to be copies. The - voxels at 'soruce' MUST have dimensions - 'regionSize', must be organized in 3D-array - order, and must have the same voxel type as the - volume.*/ - const void *uniform _source, - /*! coordinates of the lower, left, front corner of - the target region.*/ - const uniform vec3i ®ionCoords, - /*! size of the region that we're writing to; MUST - be the same as the dimensions of source[][][] */ - const uniform vec3i ®ionSize) + +export void GBBV_setRegion(void *uniform _self, + // points to the first voxel to be copied. The voxels at 'source' MUST have + // dimensions 'regionSize', must be organized in 3D-array order, and must + // have the same voxel type as the volume. + const void *uniform _source, + // coordinates of the lower, left, front corner of the target region + const uniform vec3i ®ionCoords, + // size of the region that we're writing to, MUST be the same as the + // dimensions of source[][][] + const uniform vec3i ®ionSize, + const uniform int taskIndex) { // Cast to the actual Volume subtype. - GGBV *uniform self = (GGBV *uniform)_self; - self->setRegion(_self,_source,regionCoords,regionSize); + GBBV *uniform self = (GBBV *uniform)_self; + self->setRegion(self, _source, regionCoords, regionSize, taskIndex); } - -export void GGBV_freeVolume(void *uniform _self) + +export void GBBV_freeVolume(void *uniform _self) { - GGBV *uniform self = (GGBV *uniform)_self; + GBBV *uniform self = (GBBV *uniform)_self; if (self->blockMem) { free64(self->blockMem); } diff --git a/ospray/volume/SharedStructuredVolume.cpp b/ospray/volume/SharedStructuredVolume.cpp index 0bb50da881..c198c88b53 100644 --- a/ospray/volume/SharedStructuredVolume.cpp +++ b/ospray/volume/SharedStructuredVolume.cpp @@ -19,12 +19,10 @@ #include "SharedStructuredVolume_ispc.h" #include "StructuredVolume_ispc.h" #include "ospray/common/Data.h" -// std -#include namespace ospray { -SharedStructuredVolume::SharedStructuredVolume() : voxelData(NULL) {} +SharedStructuredVolume::SharedStructuredVolume() : voxelData(nullptr) {} SharedStructuredVolume::~SharedStructuredVolume() { @@ -40,7 +38,7 @@ SharedStructuredVolume::~SharedStructuredVolume() void SharedStructuredVolume::commit() { // Create the equivalent ISPC volume container. - if (ispcEquivalent == NULL) createEquivalentISPC(); + if (ispcEquivalent == nullptr) createEquivalentISPC(); // StructuredVolume commit actions. StructuredVolume::commit(); @@ -50,7 +48,7 @@ SharedStructuredVolume::~SharedStructuredVolume() const vec3i &index, const vec3i &count) { - if (getIE() == NULL) + if (getIE() == nullptr) createEquivalentISPC(); switch (getVoxelType()) { case OSP_UCHAR: @@ -58,6 +56,11 @@ SharedStructuredVolume::~SharedStructuredVolume() (const ispc::vec3i&)index, (const ispc::vec3i&)count); break; + case OSP_USHORT: + ispc::SharedStructuredVolume_setRegion_uint16(getIE(),source, + (const ispc::vec3i&)index, + (const ispc::vec3i&)count); + break; case OSP_FLOAT: ispc::SharedStructuredVolume_setRegion_float(getIE(),source, (const ispc::vec3i&)index, @@ -70,10 +73,9 @@ SharedStructuredVolume::~SharedStructuredVolume() break; default: throw std::runtime_error("SharedStructuredVolume::setRegion() not " - "support for volumes of voxel type '"+voxelType+"'"); + "support for volumes of voxel type '" + + voxelType + "'"); } - // exitOnCondition(true, "setRegion() not allowed on this volume type; " - // "volume data must be provided via the voxelData parameter"); return 0; } @@ -89,20 +91,22 @@ SharedStructuredVolume::~SharedStructuredVolume() exitOnCondition(reduce_min(dimensions) <= 0, "invalid volume dimensions"); // Get the voxel data. - voxelData = (Data *)getParamObject("voxelData", NULL); + voxelData = (Data *)getParamObject("voxelData", nullptr); - // exitOnCondition(voxelData == NULL, "no voxel data provided"); - if (voxelData) + if (voxelData) { warnOnCondition(!(voxelData->flags & OSP_DATA_SHARED_BUFFER), - "the voxel data buffer was not created with the OSP_DATA_SHARED_BUFFER flag; " - "use another volume type (e.g. BlockBrickedVolume) for better performance"); + "The voxel data buffer was not created with the " + "OSP_DATA_SHARED_BUFFER flag; " + "Use another volume type (e.g. BlockBrickedVolume) for " + "better performance"); + } // The voxel count. - size_t voxelCount = (size_t)dimensions.x * (size_t)dimensions.y * (size_t)dimensions.z; - allocatedVoxelData - = (voxelData == NULL) - ? malloc(voxelCount*sizeOf(ospVoxelType)) - : NULL; + size_t voxelCount = (size_t)dimensions.x * + (size_t)dimensions.y * + (size_t)dimensions.z; + allocatedVoxelData = (voxelData == nullptr) ? + malloc(voxelCount*sizeOf(ospVoxelType)) : nullptr; // Create an ISPC SharedStructuredVolume object and assign // type-specific function pointers. @@ -123,7 +127,8 @@ SharedStructuredVolume::~SharedStructuredVolume() StructuredVolume::buildAccelerator(); } - // A volume type with XYZ storage order. The voxel data is provided by the application via a shared data buffer. + // A volume type with XYZ storage order. The voxel data is provided by the + // application via a shared data buffer. OSP_REGISTER_VOLUME(SharedStructuredVolume, shared_structured_volume); } // ::ospray diff --git a/ospray/volume/SharedStructuredVolume.h b/ospray/volume/SharedStructuredVolume.h index f6d92be19b..e28ec635b0 100644 --- a/ospray/volume/SharedStructuredVolume.h +++ b/ospray/volume/SharedStructuredVolume.h @@ -34,27 +34,30 @@ namespace ospray { ~SharedStructuredVolume(); //! A string description of this class. - std::string toString() const; + std::string toString() const override; //! Allocate storage and populate the volume, called through the OSPRay API. - void commit(); + void commit() override; //! Copy voxels into the volume at the given index; not allowed on //! SharedStructuredVolume. - int setRegion(const void *source, const vec3i &index, const vec3i &count); + int setRegion(const void *source, + const vec3i &index, + const vec3i &count) override; private: //! Create the equivalent ISPC volume container. - void createEquivalentISPC(); + void createEquivalentISPC() override; //! Called when a dependency of this object changes. - void dependencyGotChanged(ManagedObject *object); + void dependencyGotChanged(ManagedObject *object) override; //! The voxelData object upon commit(). Data *voxelData; - //! the pointer to allocated data if the user did _not_ specify a shared buffer + //! the pointer to allocated data if the user did _not_ specify a shared + //! buffer void *allocatedVoxelData; }; diff --git a/ospray/volume/SharedStructuredVolume.ih b/ospray/volume/SharedStructuredVolume.ih index 547e6c2ac9..a1f77667d5 100644 --- a/ospray/volume/SharedStructuredVolume.ih +++ b/ospray/volume/SharedStructuredVolume.ih @@ -16,7 +16,7 @@ #pragma once -#include "ospray/common/OSPDataType.h" +#include "ospray/OSPDataType.h" #include "ospray/volume/StructuredVolume.ih" //! \brief ISPC variables and functions for the SharedStructuredVolume class diff --git a/ospray/volume/SharedStructuredVolume.ispc b/ospray/volume/SharedStructuredVolume.ispc index 11e8273ba5..a9b6ea2e15 100644 --- a/ospray/volume/SharedStructuredVolume.ispc +++ b/ospray/volume/SharedStructuredVolume.ispc @@ -16,186 +16,81 @@ #include "ospray/volume/SharedStructuredVolume.ih" -// ----------------------------------------------------------------------------- -// versions for pure 32-bit addressing. volume *MUST* be smaller than 2G -// ----------------------------------------------------------------------------- - -/*! get a voxel from given volume type, assuming we can use 32-bit addressing */ -inline void SharedStructuredVolumeUChar_getVoxel_32(void *uniform _volume, - const varying vec3i &index, - varying float &value) -{ - // Cast to the actual Volume subtype. - SharedStructuredVolume *uniform volume = (SharedStructuredVolume *uniform) _volume; - - // Cast to the actual voxel type. - const uint8 *uniform voxelData = (const uint8 *uniform) volume->voxelData; - - // The voxel value at the given index. - value = voxelData[index.x + volume->super.dimensions.x * (index.y + volume->super.dimensions.y * index.z)]; -} - -/*! get a voxel from given volume type, assuming we can use 32-bit addressing */ -inline void SharedStructuredVolumeFloat_getVoxel_32(void *uniform _volume, - const varying vec3i &index, - varying float &value) -{ - // Cast to the actual Volume subtype. - SharedStructuredVolume *uniform volume = (SharedStructuredVolume *uniform) _volume; - - // Cast to the actual voxel type. - const float *uniform voxelData = (const float *uniform) volume->voxelData; - const uint32 addr = index.x + volume->super.dimensions.x * (index.y + volume->super.dimensions.y * index.z); - - // The voxel value at the given index. - value = voxelData[addr]; -} - -/*! get a voxel from given volume type, assuming we can use 32-bit addressing */ -inline void SharedStructuredVolumeDouble_getVoxel_32(void *uniform _volume, - const varying vec3i &index, - varying float &value) -{ - // Cast to the actual Volume subtype. - SharedStructuredVolume *uniform volume = (SharedStructuredVolume *uniform) _volume; - - // Cast to the actual voxel type. - const double *uniform voxelData = (const double *uniform) volume->voxelData; - const uint32 addr = index.x + volume->super.dimensions.x * (index.y + volume->super.dimensions.y * index.z); - - // The voxel value at the given index. - value = voxelData[addr]; -} - - -// ----------------------------------------------------------------------------- -// versions for 64/32-bit addressing. volume itself can be larger than -// 2G, but each slice must be within the 2G limit. -// ----------------------------------------------------------------------------- - -/*! get a voxel from given volume type, assuming we need proper 64-bit addressing */ -inline void SharedStructuredVolumeUChar_getVoxel_64_32(void *uniform _volume, - const varying vec3i &index, - varying float &value) -{ - // Cast to the actual Volume subtype. - SharedStructuredVolume *uniform volume = (SharedStructuredVolume *uniform) _volume; - - - const uniform uint8 *uniform basePtr = (const uniform uint8 *uniform)volume->voxelData; - - // iterate over slices, then do 32-bit gather in slice - const uint32 ofs = index.x + volume->super.dimensions.x * index.y; - foreach_unique (z in index.z) { - const uniform uint64 byteOffset = z * volume->bytesPerSlice; - const uniform uint8 *uniform sliceData - = (const uniform uint8 *uniform )(basePtr + byteOffset); - value = sliceData[ofs]; - } -} - -/*! get a voxel from given volume type, assuming we need proper 64-bit addressing */ -inline void SharedStructuredVolumeFloat_getVoxel_64_32(void *uniform _volume, - const varying vec3i &index, - varying float &value) -{ - // Cast to the actual Volume subtype. - SharedStructuredVolume *uniform volume = (SharedStructuredVolume *uniform) _volume; - - const uniform uint8 *uniform basePtr = (const uniform uint8 *uniform)volume->voxelData; - - // iterate over slices, then do 32-bit gather in slice - const uint32 ofs = index.x + volume->super.dimensions.x * index.y; - foreach_unique (z in index.z) { - const uniform uint64 byteOffset = z * volume->bytesPerSlice; - const uniform float *uniform sliceData - = (const uniform float *uniform )(basePtr + byteOffset); - value = sliceData[ofs]; - } -} - -/*! get a voxel from given volume type, assuming we need proper 64-bit addressing */ -inline void SharedStructuredVolumeDouble_getVoxel_64_32(void *uniform _volume, - const varying vec3i &index, - varying float &value) -{ - // Cast to the actual Volume subtype. - SharedStructuredVolume *uniform volume = (SharedStructuredVolume *uniform) _volume; - - const uniform uint8 *uniform basePtr = (const uniform uint8 *uniform)volume->voxelData; - - // iterate over slices, then do 32-bit gather in slice - const uint32 ofs = index.x + volume->super.dimensions.x * index.y; - foreach_unique (z in index.z) { - const uniform uint64 byteOffset = z * volume->bytesPerSlice; - const uniform double *uniform sliceData - = (const uniform double *uniform )(basePtr + byteOffset); - value = sliceData[ofs]; - } -} - - -// ----------------------------------------------------------------------------- -// versions for full 64-bit addressing, no matter what the dimensions or slice size -// ----------------------------------------------------------------------------- - -/*! get a voxel from given volume type, assuming we need proper 64-bit addressing */ -inline void SharedStructuredVolumeUChar_getVoxel_64(void *uniform _volume, - const varying vec3i &index, - varying float &value) -{ - // Cast to the actual Volume subtype. - SharedStructuredVolume *uniform volume = (SharedStructuredVolume *uniform) _volume; - - const uint64 index64 = - (uint64)index.x + volume->super.dimensions.x * ((int64)index.y + volume->super.dimensions.y * ((uint64)index.z)); - const uint32 hi28 = index64 >> 28; - const uint32 lo28 = index64 & ((1<<28)-1); - - foreach_unique (hi in hi28) { - const uniform uint64 hi64 = hi; - const uint8 *uniform base = ((const uint8 *)volume->voxelData) + (hi64<<28); - value = base[lo28]; - } -} - -/*! get a voxel from given volume type, assuming we need proper 64-bit addressing */ -inline void SharedStructuredVolumeFloat_getVoxel_64(void *uniform _volume, - const varying vec3i &index, - varying float &value) -{ - // Cast to the actual Volume subtype. - SharedStructuredVolume *uniform volume = (SharedStructuredVolume *uniform) _volume; - - const uint64 index64 = (uint64)index.x + volume->super.dimensions.x * ((int64)index.y + volume->super.dimensions.y * ((uint64)index.z)); - const uint32 hi28 = index64 >> 28; - const uint32 lo28 = index64 & ((1<<28)-1); - - foreach_unique (hi in hi28) { - const uniform uint64 hi64 = hi; - const float *uniform base = ((const float *)volume->voxelData) + (hi64<<28); - value = base[lo28]; - } +/*! get a voxel from given volume type */ + +#define template_getVoxel(type) \ +/* --------------------------------------------------------------------------\ +// versions for pure 32-bit addressing. volume *MUST* be smaller than 2G \ +// ------------------------------------------------------------------------*/\ +inline void SSV_getVoxel_##type##_32(void *uniform _self, \ + const varying vec3i &index, \ + varying float &value) \ +{ \ + /* Cast to the actual Volume subtype. */ \ + SharedStructuredVolume *uniform self \ + = (SharedStructuredVolume *uniform)_self; \ + \ + /* Cast to the actual voxel type. */ \ + const type *uniform voxelData = (const type *uniform)self->voxelData; \ + const uint32 addr = index.x + \ + self->super.dimensions.x*(index.y + self->super.dimensions.y*index.z); \ + \ + /* The voxel value at the given index. */ \ + value = voxelData[addr]; \ +} \ +/* --------------------------------------------------------------------------\ +// versions for 64/32-bit addressing. volume itself can be larger than \ +// 2G, but each slice must be within the 2G limit. \ +// ------------------------------------------------------------------------*/\ +inline void SSV_getVoxel_##type##_64_32(void *uniform _self, \ + const varying vec3i &index, \ + varying float &value) \ +{ \ + /* Cast to the actual Volume subtype. */ \ + SharedStructuredVolume *uniform self \ + = (SharedStructuredVolume *uniform)_self; \ + \ + const uniform uint8 *uniform basePtr = \ + (const uniform uint8 *uniform)self->voxelData; \ + \ + /* iterate over slices, then do 32-bit gather in slice */ \ + const uint32 ofs = index.x + self->super.dimensions.x * index.y; \ + foreach_unique (z in index.z) { \ + const uniform uint64 byteOffset = z * self->bytesPerSlice; \ + const uniform type *uniform sliceData \ + = (const uniform type *uniform )(basePtr + byteOffset); \ + value = sliceData[ofs]; \ + } \ +} \ +/* --------------------------------------------------------------------------\ +// versions for full 64-bit addressing, for all dimensions or slice size \ +// ------------------------------------------------------------------------*/\ +inline void SSV_getVoxel_##type##_64(void *uniform _self, \ + const varying vec3i &index, \ + varying float &value) \ +{ \ + /* Cast to the actual Volume subtype. */ \ + SharedStructuredVolume *uniform self \ + = (SharedStructuredVolume *uniform)_self; \ + \ + const uint64 index64 = (uint64)index.x + self->super.dimensions.x * \ + ((int64)index.y + self->super.dimensions.y * ((uint64)index.z)); \ + const uint32 hi28 = index64 >> 28; \ + const uint32 lo28 = index64 & ((1<<28)-1); \ + \ + foreach_unique (hi in hi28) { \ + const uniform uint64 hi64 = hi; \ + const type *uniform base = ((const type *)self->voxelData) + (hi64<<28); \ + value = base[lo28]; \ + } \ } -/*! get a voxel from given volume type, assuming we need proper 64-bit addressing */ -inline void SharedStructuredVolumeDouble_getVoxel_64(void *uniform _volume, - const varying vec3i &index, - varying float &value) -{ - // Cast to the actual Volume subtype. - SharedStructuredVolume *uniform volume = (SharedStructuredVolume *uniform) _volume; - - const uint64 index64 = (uint64)index.x + volume->super.dimensions.x * ((int64)index.y + volume->super.dimensions.y * ((uint64)index.z)); - const uint32 hi28 = index64 >> 28; - const uint32 lo28 = index64 & ((1<<28)-1); +template_getVoxel(uint8); +template_getVoxel(uint16); +template_getVoxel(float); +template_getVoxel(double); +#undef template_getVoxel - foreach_unique (hi in hi28) { - const uniform uint64 hi64 = hi; - const double *uniform base = ((const double *)volume->voxelData) + (hi64<<28); - value = base[lo28]; - } -} /*! read a _typed_ value from an address that's given by an *BYTE*-offset relative to a base array. note that even though we @@ -203,23 +98,23 @@ inline void SharedStructuredVolumeDouble_getVoxel_64(void *uniform _volume, the width of the array data type), the the base pointer must *STILL* be of the proper type for this macro to figure out the type of data it's reading from this address */ -#define template_accessArray(type) \ - inline float accessArrayWithOffset(const type *uniform basePtr, \ - const varying uint32 offset) \ - { \ - uniform uint8 *uniform base = (uniform uint8 *uniform)basePtr; \ - return *((uniform type *)(base+offset)); \ - } \ - inline float accessArrayWithOffset(const type *uniform basePtr, \ - const uniform uint64 baseOfs, \ - const varying uint32 offset) \ - { \ - uniform uint8 *uniform base \ - = (uniform uint8 *uniform)(basePtr); \ - return *((uniform type *)((base+baseOfs)+offset)); \ - } \ +#define template_accessArray(type) \ +inline float accessArrayWithOffset(const type *uniform basePtr, \ + const varying uint32 offset) \ +{ \ + uniform uint8 *uniform base = (uniform uint8 *uniform)basePtr; \ + return *((uniform type *)(base+offset)); \ +} \ +inline float accessArrayWithOffset(const type *uniform basePtr, \ + const uniform uint64 baseOfs, \ + const varying uint32 offset) \ +{ \ + uniform uint8 *uniform base = (uniform uint8 *uniform)(basePtr); \ + return *((uniform type *)((base+baseOfs)+offset)); \ +} \ template_accessArray(uint8); +template_accessArray(uint16); template_accessArray(float); template_accessArray(double); #undef template_accessArray @@ -231,136 +126,135 @@ template_accessArray(double); function will directly do all the addressing for the getSample (inlined), and thus be about 50% faster (wall-time, meaning even much faster in pure sample speed) */ -#define template_computeSample(type) \ - inline float SSV_computeSample_##type##_32(void *uniform _self, \ - const vec3f &worldCoordinates) \ - { \ - /* Cast to the actual Volume subtype. */ \ - SharedStructuredVolume *uniform self \ - = (SharedStructuredVolume *uniform) _self; \ - \ - /* Transform the sample location into the local coordinate system. */ \ - vec3f localCoordinates; \ - self->super.transformWorldToLocal(&self->super, \ - worldCoordinates, \ - localCoordinates); \ - \ - /* Coordinates outside the volume are clamped to the volume bounds. */ \ - const vec3f clampedLocalCoordinates \ - = clamp(localCoordinates, make_vec3f(0.0f), \ - self->super.localCoordinatesUpperBound); \ - \ - /* Lower and upper corners of the box straddling the voxels to be interpolated. */ \ - const vec3i voxelIndex_0 = integer_cast(clampedLocalCoordinates); \ - \ - /* Fractional coordinates within the lower corner voxel used during interpolation. */ \ - const vec3f frac = clampedLocalCoordinates - float_cast(voxelIndex_0); \ - \ - const uint32 voxelOfs \ - = voxelIndex_0.x * self->voxelOfs_dx \ - + voxelIndex_0.y * self->voxelOfs_dy \ - + voxelIndex_0.z * self->voxelOfs_dz; \ - const type *uniform voxelData \ - = (const type *uniform)self->voxelData; \ - const uniform uint64 ofs000 = 0; \ - const uniform uint64 ofs001 = self->bytesPerVoxel; \ - const float val000 = accessArrayWithOffset(voxelData,ofs000,voxelOfs); \ - const float val001 = accessArrayWithOffset(voxelData,ofs001,voxelOfs); \ - const float val00 = val000 + frac.x * (val001 - val000); \ - \ - const uniform uint64 ofs010 = self->bytesPerLine; \ - const uniform uint64 ofs011 = self->bytesPerLine+self->bytesPerVoxel; \ - const float val010 = accessArrayWithOffset(voxelData,ofs010,voxelOfs); \ - const float val011 = accessArrayWithOffset(voxelData,ofs011,voxelOfs); \ - const float val01 = val010 + frac.x * (val011 - val010); \ - \ - const uniform uint64 ofs100 = self->bytesPerSlice; \ - const uniform uint64 ofs101 = ofs100 + ofs001; \ - const float val100 = accessArrayWithOffset(voxelData,ofs100,voxelOfs); \ - const float val101 = accessArrayWithOffset(voxelData,ofs101,voxelOfs); \ - const float val10 = val100 + frac.x * (val101 - val100); \ - \ - const uniform uint64 ofs110 = ofs100 + ofs010; \ - const uniform uint64 ofs111 = ofs100 + ofs011; \ - const float val110 = accessArrayWithOffset(voxelData,ofs110,voxelOfs); \ - const float val111 = accessArrayWithOffset(voxelData,ofs111,voxelOfs); \ - const float val11 = val110 + frac.x * (val111 - val110); \ - \ - /* Interpolate the voxel values. */ \ - const float val0 = val00 + frac.y * (val01 - val00 ); \ - const float val1 = val10 + frac.y * (val11 - val10 ); \ - const float val = val0 + frac.z * (val1 - val0 ); \ - \ - return val; \ - } \ - \ - inline float SSV_computeSample_##type##_64_32(void *uniform _self, \ - const vec3f &worldCoordinates) \ - { \ - /* Cast to the actual Volume subtype. */ \ - SharedStructuredVolume *uniform self \ - = (SharedStructuredVolume *uniform) _self; \ - \ - /* Transform the sample location into the local coordinate system. */ \ - vec3f localCoordinates; \ - self->super.transformWorldToLocal(&self->super, \ - worldCoordinates, \ - localCoordinates); \ - \ - /* Coordinates outside the volume are clamped to the volume bounds. */ \ - const vec3f clampedLocalCoordinates \ - = clamp(localCoordinates, make_vec3f(0.0f), \ - self->super.localCoordinatesUpperBound); \ - \ - /* Lower and upper corners of the box straddling the voxels to be interpolated. */ \ - const vec3i voxelIndex_0 = integer_cast(clampedLocalCoordinates); \ - \ - /* Fractional coordinates within the lower corner voxel used during interpolation. */ \ - const vec3f frac = clampedLocalCoordinates - float_cast(voxelIndex_0); \ - \ - varying float ret = 0.f; \ - foreach_unique (sliceID in voxelIndex_0.z) { \ - const uint32 voxelOfs \ - = voxelIndex_0.x * self->voxelOfs_dx \ - + voxelIndex_0.y * self->voxelOfs_dy; \ - const type *uniform voxelData \ - = (const type *uniform)((uniform uint8*uniform)self->voxelData \ - +sliceID*self->bytesPerSlice); \ - const uniform uint64 ofs000 = 0; \ - const uniform uint64 ofs001 = self->bytesPerVoxel; \ - const float val000 = accessArrayWithOffset(voxelData,ofs000,voxelOfs); \ - const float val001 = accessArrayWithOffset(voxelData,ofs001,voxelOfs); \ - const float val00 = val000 + frac.x * (val001 - val000); \ - \ - const uniform uint64 ofs010 = self->bytesPerLine; \ - const uniform uint64 ofs011 = self->bytesPerLine+self->bytesPerVoxel; \ - const float val010 = accessArrayWithOffset(voxelData,ofs010,voxelOfs); \ - const float val011 = accessArrayWithOffset(voxelData,ofs011,voxelOfs); \ - const float val01 = val010 + frac.x * (val011 - val010); \ - \ - const uniform uint64 ofs100 = self->bytesPerSlice; \ - const uniform uint64 ofs101 = ofs100 + ofs001; \ - const float val100 = accessArrayWithOffset(voxelData,ofs100,voxelOfs); \ - const float val101 = accessArrayWithOffset(voxelData,ofs101,voxelOfs); \ - const float val10 = val100 + frac.x * (val101 - val100); \ - \ - const uniform uint64 ofs110 = ofs100 + ofs010; \ - const uniform uint64 ofs111 = ofs100 + ofs011; \ - const float val110 = accessArrayWithOffset(voxelData,ofs110,voxelOfs); \ - const float val111 = accessArrayWithOffset(voxelData,ofs111,voxelOfs); \ - const float val11 = val110 + frac.x * (val111 - val110); \ - \ - /* Interpolate the voxel values. */ \ - const float val0 = val00 + frac.y * (val01 - val00 ); \ - const float val1 = val10 + frac.y * (val11 - val10 ); \ - const float val = val0 + frac.z * (val1 - val0 ); \ - ret = val; \ - } \ - return ret; \ - } - +#define template_computeSample(type) \ +inline float SSV_computeSample_##type##_32(void *uniform _self, \ + const vec3f &worldCoordinates) \ +{ \ + /* Cast to the actual Volume subtype. */ \ + SharedStructuredVolume *uniform self \ + = (SharedStructuredVolume *uniform)_self; \ + \ + /* Transform the sample location into the local coordinate system. */ \ + vec3f localCoordinates; \ + self->super.transformWorldToLocal(&self->super, \ + worldCoordinates, \ + localCoordinates); \ + \ + /* Coordinates outside the volume are clamped to the volume bounds. */ \ + const vec3f clampedLocalCoordinates \ + = clamp(localCoordinates, make_vec3f(0.0f), \ + self->super.localCoordinatesUpperBound); \ + \ + /* Lower and upper corners of the box straddling the voxels to be interpolated. */\ + const vec3i voxelIndex_0 = integer_cast(clampedLocalCoordinates); \ + \ + /* Fractional coordinates within the lower corner voxel used during interpolation. */\ + const vec3f frac = clampedLocalCoordinates - float_cast(voxelIndex_0); \ + \ + const uint32 voxelOfs \ + = voxelIndex_0.x * self->voxelOfs_dx \ + + voxelIndex_0.y * self->voxelOfs_dy \ + + voxelIndex_0.z * self->voxelOfs_dz; \ + const type *uniform voxelData = (const type *uniform)self->voxelData; \ + const uniform uint64 ofs000 = 0; \ + const uniform uint64 ofs001 = self->bytesPerVoxel; \ + const float val000 = accessArrayWithOffset(voxelData,ofs000,voxelOfs); \ + const float val001 = accessArrayWithOffset(voxelData,ofs001,voxelOfs); \ + const float val00 = val000 + frac.x * (val001 - val000); \ + \ + const uniform uint64 ofs010 = self->bytesPerLine; \ + const uniform uint64 ofs011 = self->bytesPerLine+self->bytesPerVoxel; \ + const float val010 = accessArrayWithOffset(voxelData,ofs010,voxelOfs); \ + const float val011 = accessArrayWithOffset(voxelData,ofs011,voxelOfs); \ + const float val01 = val010 + frac.x * (val011 - val010); \ + \ + const uniform uint64 ofs100 = self->bytesPerSlice; \ + const uniform uint64 ofs101 = ofs100 + ofs001; \ + const float val100 = accessArrayWithOffset(voxelData,ofs100,voxelOfs); \ + const float val101 = accessArrayWithOffset(voxelData,ofs101,voxelOfs); \ + const float val10 = val100 + frac.x * (val101 - val100); \ + \ + const uniform uint64 ofs110 = ofs100 + ofs010; \ + const uniform uint64 ofs111 = ofs100 + ofs011; \ + const float val110 = accessArrayWithOffset(voxelData,ofs110,voxelOfs); \ + const float val111 = accessArrayWithOffset(voxelData,ofs111,voxelOfs); \ + const float val11 = val110 + frac.x * (val111 - val110); \ + \ + /* Interpolate the voxel values. */ \ + const float val0 = val00 + frac.y * (val01 - val00); \ + const float val1 = val10 + frac.y * (val11 - val10); \ + const float val = val0 + frac.z * (val1 - val0 ); \ + \ + return val; \ +} \ + \ +inline float SSV_computeSample_##type##_64_32(void *uniform _self, \ + const vec3f &worldCoordinates) \ +{ \ + /* Cast to the actual Volume subtype. */ \ + SharedStructuredVolume *uniform self \ + = (SharedStructuredVolume *uniform)_self; \ + \ + /* Transform the sample location into the local coordinate system. */ \ + vec3f localCoordinates; \ + self->super.transformWorldToLocal(&self->super, \ + worldCoordinates, \ + localCoordinates); \ + \ + /* Coordinates outside the volume are clamped to the volume bounds. */ \ + const vec3f clampedLocalCoordinates \ + = clamp(localCoordinates, make_vec3f(0.0f), \ + self->super.localCoordinatesUpperBound); \ + \ + /* Lower and upper corners of the box straddling the voxels to be interpolated. */\ + const vec3i voxelIndex_0 = integer_cast(clampedLocalCoordinates); \ + \ + /* Fractional coordinates within the lower corner voxel used during interpolation. */\ + const vec3f frac = clampedLocalCoordinates - float_cast(voxelIndex_0); \ + \ + varying float ret = 0.f; \ + foreach_unique (sliceID in voxelIndex_0.z) { \ + const uint32 voxelOfs \ + = voxelIndex_0.x * self->voxelOfs_dx \ + + voxelIndex_0.y * self->voxelOfs_dy; \ + const type *uniform voxelData \ + = (const type *uniform)((uniform uint8*uniform)self->voxelData \ + +sliceID*self->bytesPerSlice); \ + const uniform uint64 ofs000 = 0; \ + const uniform uint64 ofs001 = self->bytesPerVoxel; \ + const float val000 = accessArrayWithOffset(voxelData,ofs000,voxelOfs); \ + const float val001 = accessArrayWithOffset(voxelData,ofs001,voxelOfs); \ + const float val00 = val000 + frac.x * (val001 - val000); \ + \ + const uniform uint64 ofs010 = self->bytesPerLine; \ + const uniform uint64 ofs011 = self->bytesPerLine+self->bytesPerVoxel; \ + const float val010 = accessArrayWithOffset(voxelData,ofs010,voxelOfs); \ + const float val011 = accessArrayWithOffset(voxelData,ofs011,voxelOfs); \ + const float val01 = val010 + frac.x * (val011 - val010); \ + \ + const uniform uint64 ofs100 = self->bytesPerSlice; \ + const uniform uint64 ofs101 = ofs100 + ofs001; \ + const float val100 = accessArrayWithOffset(voxelData,ofs100,voxelOfs); \ + const float val101 = accessArrayWithOffset(voxelData,ofs101,voxelOfs); \ + const float val10 = val100 + frac.x * (val101 - val100); \ + \ + const uniform uint64 ofs110 = ofs100 + ofs010; \ + const uniform uint64 ofs111 = ofs100 + ofs011; \ + const float val110 = accessArrayWithOffset(voxelData,ofs110,voxelOfs); \ + const float val111 = accessArrayWithOffset(voxelData,ofs111,voxelOfs); \ + const float val11 = val110 + frac.x * (val111 - val110); \ + \ + /* Interpolate the voxel values. */ \ + const float val0 = val00 + frac.y * (val01 - val00); \ + const float val1 = val10 + frac.y * (val11 - val10); \ + const float val = val0 + frac.z * (val1 - val0 ); \ + ret = val; \ + } \ + return ret; \ +} template_computeSample(uint8) +template_computeSample(uint16) template_computeSample(float) template_computeSample(double) #undef template_computeSample @@ -378,6 +272,8 @@ void SharedStructuredVolume_Constructor(SharedStructuredVolume *uniform self, if (voxelType == OSP_UCHAR) bytesPerVoxel = sizeof(uniform uint8); + if (voxelType == OSP_USHORT) + bytesPerVoxel = sizeof(uniform uint16); else if (voxelType == OSP_FLOAT) bytesPerVoxel = sizeof(uniform float); else if (voxelType == OSP_DOUBLE) @@ -405,13 +301,16 @@ void SharedStructuredVolume_Constructor(SharedStructuredVolume *uniform self, // in this case, we know ALL addressing can be 32-bit. if (voxelType == OSP_UCHAR) { - self->super.getVoxel = SharedStructuredVolumeUChar_getVoxel_32; + self->super.getVoxel = SSV_getVoxel_uint8_32; self->super.super.computeSample = SSV_computeSample_uint8_32; + } else if (voxelType == OSP_USHORT) { + self->super.getVoxel = SSV_getVoxel_uint16_32; + self->super.super.computeSample = SSV_computeSample_float_32; } else if (voxelType == OSP_FLOAT) { - self->super.getVoxel = SharedStructuredVolumeFloat_getVoxel_32; + self->super.getVoxel = SSV_getVoxel_float_32; self->super.super.computeSample = SSV_computeSample_float_32; } else if (voxelType == OSP_DOUBLE) { - self->super.getVoxel = SharedStructuredVolumeDouble_getVoxel_32; + self->super.getVoxel = SSV_getVoxel_double_32; self->super.super.computeSample = SSV_computeSample_double_32; } @@ -421,13 +320,16 @@ void SharedStructuredVolume_Constructor(SharedStructuredVolume *uniform self, // slice, but need 64-bit arithmetic to get slice begins if (voxelType == OSP_UCHAR) { - self->super.getVoxel = SharedStructuredVolumeUChar_getVoxel_64_32; + self->super.getVoxel = SSV_getVoxel_uint8_64_32; self->super.super.computeSample = SSV_computeSample_uint8_64_32; + } else if (voxelType == OSP_USHORT) { + self->super.getVoxel = SSV_getVoxel_uint16_64_32; + self->super.super.computeSample = SSV_computeSample_uint16_64_32; } else if (voxelType == OSP_FLOAT) { - self->super.getVoxel = SharedStructuredVolumeFloat_getVoxel_64_32; + self->super.getVoxel = SSV_getVoxel_float_64_32; self->super.super.computeSample = SSV_computeSample_float_64_32; } else if (voxelType == OSP_DOUBLE) { - self->super.getVoxel = SharedStructuredVolumeDouble_getVoxel_64_32; + self->super.getVoxel = SSV_getVoxel_double_64_32; self->super.super.computeSample = SSV_computeSample_double_64_32; } } else { @@ -436,12 +338,13 @@ void SharedStructuredVolume_Constructor(SharedStructuredVolume *uniform self, // addressing, and we have to do 64-bit throughout if (voxelType == OSP_UCHAR) - self->super.getVoxel = SharedStructuredVolumeUChar_getVoxel_64; + self->super.getVoxel = SSV_getVoxel_uint8_64; + else if (voxelType == OSP_USHORT) + self->super.getVoxel = SSV_getVoxel_uint16_64; else if (voxelType == OSP_FLOAT) - self->super.getVoxel = SharedStructuredVolumeFloat_getVoxel_64; + self->super.getVoxel = SSV_getVoxel_float_64; else if (voxelType == OSP_DOUBLE) - self->super.getVoxel = SharedStructuredVolumeDouble_getVoxel_64; - + self->super.getVoxel = SSV_getVoxel_double_64; } } @@ -460,33 +363,35 @@ export void *uniform SharedStructuredVolume_createInstance(void *uniform cppEqui /*! this is a very simple implementation that does not yet use either vectors OR threads ... should be fixed */ -#define template_setRegion(type) \ - export void SharedStructuredVolume_setRegion_##type \ - (void *uniform _self, \ - const void *uniform source, \ - const uniform vec3i &index, \ - const uniform vec3i &count) \ - { \ - SharedStructuredVolume *uniform self \ - = (SharedStructuredVolume *uniform)_self; \ - uniform type *uniform ptr_out = (uniform type *)self->voxelData; \ - const uniform type *uniform ptr_in = (const uniform type *)source; \ - for (uniform int iz=0;izsuper.dimensions.x \ - * (iiy+self->super.dimensions.y*iiz); \ - *(ptr_out+ofs_out) = ptr_in[ofs_in]; \ - } \ - } \ - } +#define template_setRegion(type) \ +export void SharedStructuredVolume_setRegion_##type \ +(void *uniform _self, \ + const void *uniform source, \ + const uniform vec3i &index, \ + const uniform vec3i &count) \ +{ \ + SharedStructuredVolume *uniform self \ + = (SharedStructuredVolume *uniform)_self; \ + uniform type *uniform ptr_out = (uniform type *)self->voxelData; \ + const uniform type *uniform ptr_in = (const uniform type *)source; \ + for (uniform int iz=0;izsuper.dimensions.x \ + * (iiy+self->super.dimensions.y*iiz); \ + *(ptr_out+ofs_out) = ptr_in[ofs_in]; \ + } \ + } \ +} template_setRegion(uint8); +template_setRegion(uint16); template_setRegion(float); template_setRegion(double); +#undef template_setRegion diff --git a/ospray/volume/StructuredVolume.cpp b/ospray/volume/StructuredVolume.cpp index 954f7c2ad6..1a957a76ef 100644 --- a/ospray/volume/StructuredVolume.cpp +++ b/ospray/volume/StructuredVolume.cpp @@ -114,6 +114,10 @@ namespace ospray { if (!strcmp(kind, "uchar") && width == 1) res = OSP_UCHAR; + // Unsigned 16-bit scalar integer. + if (!strcmp(kind, "ushort") && width == 1) + res = OSP_USHORT; + // Single precision scalar floating point. if (!strcmp(kind, "float") && width == 1) res = OSP_FLOAT; diff --git a/ospray/volume/StructuredVolume.h b/ospray/volume/StructuredVolume.h index bec23a180b..e3d3608cd6 100644 --- a/ospray/volume/StructuredVolume.h +++ b/ospray/volume/StructuredVolume.h @@ -17,7 +17,7 @@ #pragma once // ospray -#include "ospray/common/parallel_for.h" +#include "ospray/common/tasking/parallel_for.h" #include "ospray/volume/Volume.h" // stl #include @@ -54,7 +54,7 @@ namespace ospray { /*! \returns 0 on error, any non-zero value indicates success */ virtual int setRegion(const void *source_pointer, const vec3i &target_index, - const vec3i &source_count) = 0; + const vec3i &source_count) override = 0; protected: diff --git a/ospray/volume/Volume.cpp b/ospray/volume/Volume.cpp index d955464a41..0069cc6db3 100644 --- a/ospray/volume/Volume.cpp +++ b/ospray/volume/Volume.cpp @@ -39,7 +39,7 @@ namespace ospray { return("ospray::Volume"); } - Volume *Volume::createInstance(std::string type) + Volume *Volume::createInstance(const std::string &type) { // Function pointer type for creating a concrete instance of a subtype of // this class. @@ -116,31 +116,6 @@ namespace ospray { vec3f(boundingBox.upper.x, boundingBox.upper.y, boundingBox.upper.z)); } - void Volume::emitMessage(const std::string &kind, - const std::string &message) const - { - std::cerr << " " + toString() - << " " + kind + ": " + message + "." << std::endl; - } - - void Volume::exitOnCondition(bool condition, - const std::string &message) const - { - if (!condition) - return; - emitMessage("ERROR", message); - exit(1); - } - - void Volume::warnOnCondition(bool condition, - const std::string &message) const - { - if (!condition) - return; - - emitMessage("WARNING", message); - } - void Volume::updateEditableParameters() { // Set the gradient shading flag for the renderer. diff --git a/ospray/volume/Volume.h b/ospray/volume/Volume.h index cca919b774..ed711d26b3 100644 --- a/ospray/volume/Volume.h +++ b/ospray/volume/Volume.h @@ -18,15 +18,15 @@ #include "ospray/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. -//! +/*! \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() \ { \ @@ -35,17 +35,18 @@ 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 - //! type string specifies a particular concrete implementation to - //! createInstance(). This type string must be registered either in - //! OSPRay proper, or in a loaded module using OSP_REGISTER_VOLUME. - //! - class Volume : public ManagedObject { + /*! \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 + type string specifies a particular concrete implementation to + createInstance(). This type string must be registered either in + OSPRay proper, or in a loaded module using OSP_REGISTER_VOLUME. + */ + class Volume : public ManagedObject + { public: #if EXP_DATA_PARALLEL @@ -79,7 +80,7 @@ namespace ospray { virtual std::string toString() const; //! Create a volume container of the given type. - static Volume *createInstance(std::string type); + static Volume *createInstance(const std::string &type); //! Allocate storage and populate the volume. virtual void commit() = 0; @@ -101,23 +102,9 @@ namespace ospray { protected: - //! Create the equivalent ISPC volume container. - virtual void createEquivalentISPC() = 0; - //! Complete volume initialization (only on first commit). virtual void finish(); - - //! Print an error message. - void emitMessage(const std::string &kind, - const std::string &message) const; - - //! Error checking. - void exitOnCondition(bool condition, - const std::string &message) const; - - //! Warning condition. - void warnOnCondition(bool condition, - const std::string &message) const; }; + } // ::ospray diff --git a/ospray/volume/Volume.ih b/ospray/volume/Volume.ih index b28cd8ebe6..c933c84620 100644 --- a/ospray/volume/Volume.ih +++ b/ospray/volume/Volume.ih @@ -58,23 +58,19 @@ struct Volume { //! Bounding box for the volume in world coordinates. uniform box3f boundingBox; -// #if EXP_DATA_PARALLEL -// // uniform DataParallelInfo dataParallel; -// #endif - //! The value at the given sample location in world coordinates. - varying float (*uniform computeSample)(void *uniform volume, + varying float (*uniform computeSample)(void *uniform _self, const varying vec3f &worldCoordinates); //! The gradient at the given sample location in world coordinates. - varying vec3f (*uniform computeGradient)(void *uniform volume, + varying vec3f (*uniform computeGradient)(void *uniform _self, const varying vec3f &worldCoordinates); //! Find the next hit point in the volume for ray casting based renderers. - void (*uniform intersect)(void *uniform volume, varying Ray &ray); + void (*uniform intersect)(void *uniform _self, varying Ray &ray); //! Find the next isosurface hit point in the volume for ray casting based renderers. - void (*uniform intersectIsosurface)(void *uniform volume, + void (*uniform intersectIsosurface)(void *uniform _self, uniform float *uniform isovalues, uniform int numIsovalues, varying Ray &ray); diff --git a/scripts/build_gitlab/linux.sh b/scripts/build_gitlab/linux.sh new file mode 100755 index 0000000000..86d4d92ed4 --- /dev/null +++ b/scripts/build_gitlab/linux.sh @@ -0,0 +1,28 @@ +## ======================================================================== ## +## Copyright 2015-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. ## +## ======================================================================== ## + +#!/bin/sh + +mkdir build +cd build + +cmake \ + -D OSPRAY_BUILD_ISA=ALL \ + -D OSPRAY_APPS_PARTICLEVIEWER=ON \ + -D OSPRAY_MODULE_TACHYON=ON \ +.. + +make -j`nproc` diff --git a/scripts/build_gitlab/osx.sh b/scripts/build_gitlab/osx.sh new file mode 100755 index 0000000000..8881e493d3 --- /dev/null +++ b/scripts/build_gitlab/osx.sh @@ -0,0 +1,12 @@ +#/bin/sh + +mkdir build +cd build +rm -rf * + +# NOTE(jda) - using Internal tasking system here temporarily to avoid installing TBB +cmake \ +-D OSPRAY_TASKING_SYSTEM=Internal \ +.. + +make -j 4 diff --git a/scripts/build_gitlab/win.bat b/scripts/build_gitlab/win.bat new file mode 100755 index 0000000000..e7ccf0a98b --- /dev/null +++ b/scripts/build_gitlab/win.bat @@ -0,0 +1,37 @@ +@echo off +rem ======================================================================== rem +rem Copyright 2015-2016 Intel Corporation rem +rem rem +rem Licensed under the Apache License, Version 2.0 (the "License"); rem +rem you may not use this file except in compliance with the License. rem +rem You may obtain a copy of the License at rem +rem rem +rem http://www.apache.org/licenses/LICENSE-2.0 rem +rem rem +rem Unless required by applicable law or agreed to in writing, software rem +rem distributed under the License is distributed on an "AS IS" BASIS, rem +rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. rem +rem See the License for the specific language governing permissions and rem +rem limitations under the License. rem +rem ======================================================================== rem + +setlocal + +md build +cd build + +cmake -L ^ +-G "Visual Studio 12 2013 Win64" ^ +-T "Intel C++ Compiler 16.0" ^ +-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 ^ +.. + +cmake --build . --config Release --target ALL_BUILD -- /m /nologo + +:abort +endlocal +:end diff --git a/scripts/build_gitlab/win.sh b/scripts/build_gitlab/win.sh new file mode 100755 index 0000000000..9b5781bd18 --- /dev/null +++ b/scripts/build_gitlab/win.sh @@ -0,0 +1,32 @@ +## ======================================================================== ## +## Copyright 2015-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. ## +## ======================================================================== ## + +#!/bin/sh + +mkdir build +cd build + +cmake -L \ +-G "Visual Studio 12 2013 Win64" \ +-T "Intel C++ Compiler 16.0" \ +-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 \ +.. + +cmake --build . --config Release --target ALL_BUILD -- -m -nologo diff --git a/scripts/release_linux.sh b/scripts/release/linux.sh similarity index 58% rename from scripts/release_linux.sh rename to scripts/release/linux.sh index 92456eeb77..7e9440c6ca 100755 --- a/scripts/release_linux.sh +++ b/scripts/release/linux.sh @@ -16,11 +16,7 @@ #!/bin/bash -# to make sure we do not include nor link against wrong TBB -export CPATH= -export LIBRARY_PATH= -export LD_LIBRARY_PATH= -TBB_PATH_LOCAL=$PWD/tbb +#### Helper functions #### # check version of symbols function check_symbols @@ -43,20 +39,80 @@ function check_symbols done } +#### Set variables for script #### + +export ROOT_DIR=$PWD + +DEP_LOCATION=http://sdvis.org/~jdamstut/ospray_deps/linux +EMBREE_TARBALL=embree-2.9.0.x86_64.linux.tar.gz +ISPC_TARBALL=ispc-v1.9.0-linux.tar.gz +TBB_TARBALL=tbb44_20160413oss_lin.tgz + +# set compiler if the user hasn't explicitly set CC and CXX +if [ -z $CC ]; then + echo "***NOTE: Defaulting to use icc/icpc!" + echo -n " Please set env variables 'CC' and 'CXX' to" + echo " a different supported compiler (gcc/clang) if desired." + export CC=icc + export CXX=icpc +fi + +# to make sure we do not include nor link against wrong TBB +# NOTE: if we are not verifying CentOS6 defaults, we are likely using +# a different compiler which requires LD_LIBRARY_PATH! +if [ -n $OSPRAY_RELEASE_NO_VERIFY ]; then + unset CPATH + unset LIBRARY_PATH + unset LD_LIBRARY_PATH +fi + +#### Fetch dependencies (TBB+Embree+ISPC) #### + +if [ ! -d deps ]; then + mkdir deps + rm -rf deps/* + cd deps + + # Embree + wget $DEP_LOCATION/$EMBREE_TARBALL + tar -xaf $EMBREE_TARBALL + rm $EMBREE_TARBALL + + # ISPC + wget $DEP_LOCATION/$ISPC_TARBALL + tar -xaf $ISPC_TARBALL + rm $ISPC_TARBALL + + # TBB + wget $DEP_LOCATION/$TBB_TARBALL + tar -xaf $TBB_TARBALL + rm $TBB_TARBALL + + cd $ROOT_DIR + ln -snf deps/embree* embree + ln -snf deps/ispc* ispc + ln -snf deps/tbb* tbb +fi + +TBB_PATH_LOCAL=$ROOT_DIR/tbb +export embree_DIR=$ROOT_DIR/embree +export PATH=$ROOT_DIR/ispc:$PATH + +#### Build OSPRay #### + mkdir -p build_release cd build_release -# make sure to use default settings -rm -f CMakeCache.txt -rm -f ospray/version.h + +# Clean out build directory to be sure we are doing a fresh build +rm -rf * # set release and RPM settings cmake \ --D CMAKE_C_COMPILER:FILEPATH=icc \ --D CMAKE_CXX_COMPILER:FILEPATH=icpc \ -D OSPRAY_BUILD_ISA=ALL \ --D OSPRAY_BUILD_MIC_SUPPORT=ON \ --D OSPRAY_BUILD_COI_DEVICE=ON \ --D OSPRAY_BUILD_MPI_DEVICE=ON \ +-D OSPRAY_BUILD_MIC_SUPPORT=OFF \ +-D OSPRAY_BUILD_COI_DEVICE=OFF \ +-D OSPRAY_BUILD_MPI_DEVICE=OFF \ +-D OSPRAY_USE_EXTERNAL_EMBREE=ON \ -D USE_IMAGE_MAGICK=OFF \ -D OSPRAY_ZIP_MODE=OFF \ -D CMAKE_INSTALL_PREFIX=/usr \ @@ -66,10 +122,15 @@ cmake \ # create RPM files make -j `nproc` preinstall -check_symbols libospray.so GLIBC 2 4 -check_symbols libospray.so GLIBCXX 3 4 -check_symbols libospray.so CXXABI 1 3 -make package +# if we define 'OSPRAY_RELEASE_NO_VERIFY' to anything, then we +# don't verify link dependencies for CentOS6 +if [ -z $OSPRAY_RELEASE_NO_VERIFY ]; then + check_symbols libospray.so GLIBC 2 4 + check_symbols libospray.so GLIBCXX 3 4 + check_symbols libospray.so CXXABI 1 3 +fi + +make -j `nproc` package # read OSPRay version OSPRAY_VERSION=`sed -n 's/#define OSPRAY_VERSION "\(.*\)"/\1/p' ospray/version.h` @@ -94,4 +155,3 @@ cmake \ # create tar.gz files make -j `nproc` package -cd .. diff --git a/scripts/release_macosx.sh b/scripts/release/macosx.sh similarity index 57% rename from scripts/release_macosx.sh rename to scripts/release/macosx.sh index c978bb5992..65a2359239 100755 --- a/scripts/release_macosx.sh +++ b/scripts/release/macosx.sh @@ -16,26 +16,85 @@ #!/bin/bash +#### Helper functions #### + +umask=`umask` +function onexit { + umask $umask +} +trap onexit EXIT +umask 002 + +#### Set variables for script #### + +export ROOT_DIR=$PWD + +DEP_LOCATION=http://sdvis.org/~jdamstut/ospray_deps/osx +EMBREE_TARBALL=embree-2.9.0.x86_64.macosx.tar.gz +ISPC_TARBALL=ispc-v1.9.0-osx.tar.gz +TBB_TARBALL=tbb44_20160413oss_osx.tgz + +# set compiler if the user hasn't explicitly set CC and CXX +if [ -z $CC ]; then + echo "***NOTE: Defaulting to use clang!" + echo -n " Please set env variables 'CC' and 'CXX' to" + echo " a different supported compiler (gcc/icc) if desired." + export CC=clang + export CXX=clang++ +fi + # to make sure we do not include nor link against wrong TBB export CPATH= export LIBRARY_PATH= export DYLD_LIBRARY_PATH= TBB_PATH_LOCAL=$PWD/tbb +#### Fetch dependencies (TBB+Embree+ISPC) #### + +if [ ! -d deps ]; then + mkdir deps + rm -rf deps/* + cd deps + + # Embree + wget $DEP_LOCATION/$EMBREE_TARBALL + tar -xf $EMBREE_TARBALL + rm $EMBREE_TARBALL + + # ISPC + wget $DEP_LOCATION/$ISPC_TARBALL + tar -xf $ISPC_TARBALL + rm $ISPC_TARBALL + + # TBB + wget $DEP_LOCATION/$TBB_TARBALL + tar -xf $TBB_TARBALL + rm $TBB_TARBALL + + cd $ROOT_DIR + ln -snf deps/embree* embree + ln -snf deps/ispc* ispc + ln -snf deps/tbb* tbb +fi + +TBB_PATH_LOCAL=$ROOT_DIR/tbb +export embree_DIR=$ROOT_DIR/embree +export PATH=$ROOT_DIR/ispc:$PATH + +#### Build OSPRay #### + mkdir -p build_release cd build_release -# make sure to use default settings -rm -f CMakeCache.txt -rm -f ospray/version.h + +# Clean out build directory to be sure we are doing a fresh build +rm -rf * # set release and installer settings cmake \ --D CMAKE_C_COMPILER:FILEPATH=icc \ --D CMAKE_CXX_COMPILER:FILEPATH=icpc \ -D OSPRAY_BUILD_ISA=ALL \ --D OSPRAY_BUILD_MIC_SUPPORT=ON \ --D OSPRAY_BUILD_COI_DEVICE=ON \ --D OSPRAY_BUILD_MPI_DEVICE=ON \ +-D OSPRAY_BUILD_MIC_SUPPORT=OFF \ +-D OSPRAY_BUILD_COI_DEVICE=OFF \ +-D OSPRAY_BUILD_MPI_DEVICE=OFF \ -D USE_IMAGE_MAGICK=OFF \ -D OSPRAY_ZIP_MODE=OFF \ -D CMAKE_INSTALL_PREFIX=/opt/local \ @@ -43,8 +102,8 @@ cmake \ -D CMAKE_INSTALL_LIBDIR=lib \ -D CMAKE_INSTALL_DOCDIR=../../Applications/OSPRay/doc \ -D CMAKE_INSTALL_BINDIR=../../Applications/OSPRay/bin \ +-D TBB_ROOT=$TBB_PATH_LOCAL \ .. -#-D TBB_ROOT=/opt/local \ # create installers make -j 4 package @@ -56,10 +115,9 @@ cmake \ -D CMAKE_INSTALL_LIBDIR=lib \ -D CMAKE_INSTALL_DOCDIR=doc \ -D CMAKE_INSTALL_BINDIR=bin \ +-D TBB_ROOT=$TBB_PATH_LOCAL \ .. -#-D TBB_ROOT=$TBB_PATH_LOCAL \ # create ZIP files make -j 4 package -cd .. diff --git a/scripts/release_win.bat b/scripts/release/win.bat similarity index 89% rename from scripts/release_win.bat rename to scripts/release/win.bat index 771387c683..b729ee414e 100755 --- a/scripts/release_win.bat +++ b/scripts/release/win.bat @@ -20,8 +20,6 @@ rem set TBB_PATH_LOCAL=%cd%\tbb md build_release cd build_release -del CMakeCache.txt -del ospray\version.h rem set release settings cmake -L ^ @@ -30,6 +28,8 @@ cmake -L ^ -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 +40,8 @@ cmake -L ^ rem -D TBB_ROOT=%TBB_PATH_LOCAL% ^ rem compile and create installers -cmake --clean-first --build . --config Release --target PACKAGE -- /m /nologo +# option '--clean-first' somehow conflicts with options after '--' for msbuild +cmake --build . --config Release --target PACKAGE -- /m /nologo rem create ZIP files cmake -D OSPRAY_ZIP_MODE=ON .. diff --git a/scripts/release_win.sh b/scripts/release/win.sh similarity index 92% rename from scripts/release_win.sh rename to scripts/release/win.sh index 55277d6ec1..0d27a32f42 100755 --- a/scripts/release_win.sh +++ b/scripts/release/win.sh @@ -22,11 +22,8 @@ export LIBRARY_PATH= export LD_LIBRARY_PATH= #TBB_PATH_LOCAL=$PWD/tbb -#rm -rf build_release mkdir -p build_release cd build_release -rm -f CMakeCache.txt -rm -f ospray/version.h # set release settings cmake -L \ @@ -35,6 +32,8 @@ cmake -L \ -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 \ @@ -45,7 +44,7 @@ cmake -L \ # -D TBB_ROOT=%TBB_PATH_LOCAL% \ # compile and create installers -# option --clean-first' somehow conflicts with options after '--' for msbuild +# option '--clean-first' somehow conflicts with options after '--' for msbuild cmake --build . --config Release --target PACKAGE -- -m -nologo # create ZIP files diff --git a/scripts/trigger_gitlab_ci.sh b/scripts/trigger_gitlab_ci.sh new file mode 100755 index 0000000000..5a3c506a65 --- /dev/null +++ b/scripts/trigger_gitlab_ci.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +REF_NAME=${1} + +if [[ -n "${REF_NAME}" ]]; then + echo "Triggering CI build of branch '${REF_NAME}'" +else + echo "No branch name specified, defaulting to 'devel'" + REF_NAME="devel" +fi + +curl -X POST \ + -F token=32b3258c799f57f1c6159585ce133b \ + -F ref=${REF_NAME} \ + https://gitlab.com/api/v3/projects/998314/trigger/builds