Home

Awesome

OWL: A Productivity Library for OptiX 7

<!--- ------------------------------------------------------- -->

What is OWL?

OWL is a convenience/productivity-oriented library on top of OptiX 7.x, and aims at making it easier to write OptiX programs by taking some of the more arcane arts (like knowing what a Shader Binding Table is, and how to actually build it), and doing that for the user. For example, assuming the node graph (ie, the programs, geometries, and acceleration structures) have already been built, the shader binding table (SBT) can be built and properly populated by a single call owlBuildSBT(context).

In addition, OWL also allows for somewhat higher-level abstractions than native OptiX+CUDA for operations such as creating device buffers, uploading data, building shader programs and pipelines, building acceleration structures, etc.

Who is OWL designed/intended for?

OWL is particularly targetted at two groups of users: First, those that do want to use GPU Ray Tracing and RTX hardware acceleration, and that are comfortable with typical GPU concepts such as GPU memory vs device memory, ray tracing pipeline, shader programs, and some CUDA programming - but that are not "Ninja" OptiX/Vulkan/DirectX users, and might not be 100% sure about the most nitty-bitty grits of details on SBT data layout and order, or on just how exactly to do the BVH compaction, how exactly to deal with async launches or refitting, etc.

Second, it targets those that do know all these concepts, but would rather spent their time on the actual shader programs and functionality of the program, rather than on doing and all the low-level steps themselves; ie, those that are willing to trade a bit of low-level control (and maybe some tiny amount of performance) for higher developing productivity.

Simple Example

As an example of how easy it is to use OWL to build OptiX data strucutres, the following example code snippet takes a host-based triangle mesh and:

Note how this little example will do these step: including data upload, set-up of build inputs, BVH construction, BVH compaction, and everything else that's required for this. Though still a relatively benign example, doing the same in low-level CUDA and OptiX code would result in significantly more code that the user would have to write, debug, and maintain.

/* simple sample of setting up a full geometry, BLAS and
   IAS for a simple single-triangle mesh model */
OWLGroup buildBlasAndIas(max3x4f             &instXfm,
                         std::vector<float3> &vtx,
                         std::vector<int3>   &idx,
						 float3               color)
{
   /* upload the buffers */
   OWLBuffer vtxBuffer
      = owlDeviceBufferCreate(ctx,OWL_FLOAT3,
	                          vtx.size(),vtx.data());
   OWLBuffer idxBuffer
      = owlDeviceBufferCreate(ctx,OWL_INT3,
	                          idx.size(),idx.data());

   /* create triangle mesh geometry */
   OWLGeom mesh = owlGeomCreate(ctx,myMeshGT);
   owlTrianglesSetVertices(mesh,vtxBuffer,vtx.size(),
                          /*stride+ofs*/sizeof(vtx[0],0);
   owlTrianglesSetIndices(mesh,vtxBuffer,vtx.size(),
                          /*stride+ofs*/sizeof(idx[0]),0);

   /* create and build triangle BLAS */
   OWLGroup blas = owlTrianglesGroupCreate(ctx,1,&mesh);
   owlGroupBuildAccel(blas);

   /* create and build instance accel struct (IAS) */
   OWLGroup ias = owlInstanceGroupCreate(ctx,1,
       /* instantiated BLASes */&blas,
       /* instance IDs:       */nullptr,
	   /* instance transforms */&instXfm);
   owlGroupBuildAccel(ias);
   return blas; // that's it!
}

Of course, even with OWL there's still much more that needs to be done for a full renderer: For example, in this code we assumed that a context (ctx) and a geometry type for this mesh (myMeshGT) have already been created; the user also still has to set up the programs, create frame buffer and launch data, build the programs (owlBuildPrograms()), the pipline (owlBuildPipeline()), and the SBT (owlBuildSBT(ctx)), etc.

What about Advanced Users?

As stated above, OWL explicitly aims for helping entry-level or casual RTX users get started, and get working productively with OptiX and RTX without having to first become an OptiX "Ninja".

However, that is not to mean that it is only useful for beginners. In fact, OWL currently supports lots of rather advanced features as well, including, for example:

In particular for advanced users, OWL is explicitly intended to allow advanced users to mix OWL code and data structures with other, manually written CUDA code if and whenever so desired. For example, OWL offers functions to easily query the CUDA device-addresses of buffers, OptixTraversableHandle's from groups, CUDA streams from launches, etc. As such, it is absolutely possible to mix OWL and CUDA code by, for example, having a multi-pass renderer in which CUDA does all the shading code and set-up of ray streams, and OWL doing the acceleration structure build and (RTX hardware-accelerated) tracing of these ray streams, even in multi-threaded and multi-GPU settings, with proper CUDA streams, etc (in fact, I do that in several of my own OWL applications).

<!--- ------------------------------------------------------- -->

Current State of Development

OWL was first publicly released early 2019, and has been used in several research/paper projects (see below). OWL initially targetted a much smaller scope of work - initially it was supposed to be only a "wrapper" around things like building acceleration structures (hence the name "OptiX Wrapper Library"), but the need for a higher abstraction level soon became evident, primarily due to the need to help users build and populate the SBT - which needs more "global" information than a single acceleration structure.

Despite these significant changes after the initial release, the current abstraction level and API have remained stable over roughly a year now, with only relatively minor additions such as buffers of buffers, refitting, textures, or motion blur. Some features will still need adding (e.g., curves, which got added to OptiX 7.1 but are not yet exposed in OWL); however, we consider the current release to be sufficiently stable to finally have given it the long-awaited "version 1.x".

<!--- ------------------------------------------------------- -->

Sample Use Cases

Some sample use projects/papers that recently used OWL:

(http://www.sci.utah.edu/~wald/Publications/2020/dw2/dw2.pdf)

<!--- ------------------------------------------------------- -->

Building OWL / Supported Platforms

General Requirements:

Per-OS Instructions:

<!--- ------------------------------------------------------- -->

Using OWL through CMake

Though you can of course use OWL without CMake, it is highly encouraged to use OWL as a git submodule, using CMake to configure and build this submodule. In particular, the suggested procedure is to first do a add_subdirectory with the owl submodules as such:

set(owl_dir ${PROJECT_SOURCE_DIR}/whereeverYourOWLSubmoduleIs)
add_subdirectory(${owl_dir} EXCLUDE_FROM_ALL)

(the EXCLUDE_FROM_ALL makes sure that your main project won't automatically build any owl samples or test cases unless you explicitly request so).

Once your project has called add_subdirectory on owl, it only has to link the owl::owl target in order to bring in all includes, linked libraries, etc. to fully use it. This might look like:

target_link_libraries(myOwlApp PRIVATE owl::owl)

If your sample uses the owlViewer base class and/or ptx embedding, add those as well:

target_link_libraries(myOwlApp PRIVATE myOwlApp-ptx owl::owl owl_viewer)

OptiX will need to be in a place that can be found by CMake. Point CMake at your OptiX directory by adding it to CMAKE_PREFIX_PATH (where it works on all platforms similar to how LD_LIBRARY_PATH resolves runtime linking on Linux). Note that CMAKE_PREFIX_PATH can be specified as an environment variable or as a CMake variable when you run CMake on your project.

<!--- ------------------------------------------------------- -->

Latest Progress/Revision History

Latest additions, not yet in any release

v1.1 - Switched to "modern cmake" technology (kudos lpisha, and jda)

v.1.1.6:

v.1.1.5: bugfix: various buffer types didn't properly release all memory.

v.1.1.4:

v.1.1.3: bugfix: fixed TBB includes for windows, when sued as submodule

v.1.1.2:

1.1.1: various fixes for the 'modern cmake' version, with a pretty big re-vamp of the entire build system. projects using owl as a submodule need to update how they use cmake accordingly; pls consult the samples for how to cleanly do that.

1.1.0: first release with louis pisha's 'modern cmake' version of the build system. Also includes several new samples, including the voxel renderer from the "ray tracing gems2" article.

v1.0.x - First "considered to be complete" version

1.0.4: fixed issue #68 - now compiles with optix 7.2, and newewst intel tbb

1.0.3: bugfix: no longer fatally failing when memadvise optimization didn't work

1.0.2: (finally) fixed long-standing bug in owlViewer that caused samples to crash when forcing OWL to run on a GPU that's different from the GPU that held the OpenGL graphics context for the viewer. Fixed.

*1.0.1: bugfix for missing owlSet4{}() functions

v0.9.x - Elimination of LL layer, and support for motion blur

v0.9.1: added support for more texture formats, access to the raw texture objects

v0.9.0: initial motion blur, and inital elimination of ll layer

v0.8.x - Revamped build system, owl viewer, interative samples, and textures

v0.8.3: fixes, github issues, and naming

v0.8.2: double types, interactive sample

v0.8.1: first light of textures

v0.8.0: build system, glfw, and owl viewer

v0.7.x - Unifiction of ng and ll APIs into one single owl API

v0.7.4: major cleanups of "low-level" and "api" layer abstractions

v0.7.3: performance "guiding"

v0.7.3: bug hotfix

v0.7.2: various feature extensions and bug fixes

v0.7.1: bugfix release.

v0.7.0: merged ng and ll APIs into one single API

v0.6.x - Buffer updates, launch params, first interactive example, ...

v0.6.1: cleanup/flesh-out of instance transform API

v0.6.0: Buffer updates, launch params, first interactive example, ...

Process of adding this sample also required, among others, the following feature changes/additions

v0.5.x - First Public Release Cleanups

v0.5.4: First external windows-app

v0.5.3: First serious node graph sample

v0.5.2: First (partial) node graph sample

v0.5.1: First "c-api" version

v0.5.0: First public release

v0.4.x - Instances

v0.4.5: ll08-sierpinski now uses path tracing

v0.4.4: multi-level instancing

v0.4.3: new api fcts to set transforms and children for instance groups

v0.4.2: bugfix - all samples working in multi-device again

v0.4.1: example ll06-rtow-mixedGeometries.png working w/ manual sucessive traced into two different accels

v0.4.0: new way of building SBT now based on groups

v0.3.x - User Geometries

v0.3.4: bugfix: adding bounds prog broke bounds buffer variant. fixed.

v0.3.4: first 'serious' example: RTOW-finalChapter on OWL

v0.3.3: major bugfix in bounds program for geoms w/ more than 128 prims.

v0.3.2: added two explicit examples for uesr geom - one with host-generation of bounds passed thrugh buffer, and one with bounds program

v0.3.1: First draft of device-side user prim bounds generation

v0.3.0: First example of user geometry working

v0.2.x

v0.2.1: multiple triangle meshes working

v0.2.0: first triangle mesh with trace and SBT data working

v0.1.x

Contributors