OpenSubdiv/documentation/osd_overview.rst
2015-04-06 22:09:14 -07:00

208 lines
7.5 KiB
ReStructuredText

..
Copyright 2013 Pixar
Licensed under the Apache License, Version 2.0 (the "Apache License")
with the following modification; you may not use this file except in
compliance with the Apache License and the following modification to it:
Section 6. Trademarks. is deleted and replaced with:
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor
and its affiliates, except as required to comply with Section 4(c) of
the License and to reproduce the content of the NOTICE file.
You may obtain a copy of the Apache License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the Apache License with the above modification is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the Apache License for the specific
language governing permissions and limitations under the Apache License.
OSD Overview
------------
.. contents::
:local:
:backlinks: none
.. image:: images/api_layers_3_0.png
:width: 100px
:target: images/api_layers_3_0.png
OpenSubdiv (Osd)
================
**Osd** contains client-level code that uses *Far* to create concrete instances of
meshes. These meshes use precomputed tables from *Far* to perform table-driven
subdivision steps with a variety of massively parallel computational backend
technologies. **Osd** supports both `uniform subdivision <subdivision_surfaces.html#uniform-subdivision>`__
and `adaptive refinement <subdivision_surfaces.html#feature-adaptive-subdivision>`__
with cubic patches.
----
Modular Architecture
====================
With uniform subdivision the computational backend code performs Catmull-Clark
splitting and averaging on each face.
With adaptive subdivision, the Catmull/Clark steps are used to compute the CVs
of cubic Bezier patches. On modern GPU architectures, bicubic patches can be
drawn directly on screen at very high resolution using optimized tessellation
shader paths.
.. image:: images/osd_layers.png
Finally, the general manipulation of high-order surfaces also requires functionality
outside of the scope of pure drawing.
Following this pattern of general use, **Osd** can be broken down into 3 main
modules : **Compute**, **Draw** and **Eval**.
.. image:: images/osd_modules.png
:align: center
The modules are designed so that the data being manipulated can be shared and
interoperated between modules (although not all paths are possible).
These modules are identified by their name spaces (**Compute**, **Draw**,
**Eval**) and encapsulate atomic functationality. The vertex data is carried
in interoperable buffers that can be exchanged between modules.
The typical use pattern is to pose the coarse vertices of a mesh for a given frame.
The buffer is submitted to the **Refine** module which applies the subdivision rules
and produces refined control vertices. This new buffer can be passed to the **Draw**
module which will draw them on screen.
However, the same buffer of refined control vertices could be passed instead to
the **Eval** module (and be projected onto another surface for instance) before
being sent for display to the **Draw** module.
----
OsdCompute
**********
The Compute module contains the code paths that manage the application of the
subdivision rules to the vertex data. This module is sufficient for uniform
subdivision applications.
----
OsdDraw
*******
The Draw module manages interactions with discrete display devices and provide
support for interactive drawing of the subdivision surfaces.
----
OsdEval
*******
The Eval module provides computational APIs for the evaluation of vertex data at
the limit, ray intersection and point projection.
OpenSubdiv enforces the same results for the different computation backends with
a series of regression tests that compare the methods to each other.
.. container:: impnotip
* **Beta Issues**
Face-varying smooth data interpolation is currently only supported in
**Osd** through refinement and limit points but not in the PatchTables.
----
Cross-Platform Implementation
=============================
One of the key goals of OpenSubdiv is to achieve as much cross-platform flexibility
as possible and leverage all optimized hardware paths where available. This can
be very challenging however, as there is a very large variety of plaftorms and
matching APIs available, with very distinct capabilities. The following chart
illustrates the matrix of back-end APIs supported for each module.
.. image:: images/osd_backends.png
:align: center
Since the **Compute** module performs mostly specialized interpolation
computations, most GP-GPU and multi-core APIs can be deployed. If the end-goal
is to draw the surface on screen, it can be very beneficial to move as much of
these computations to the same GPU device in order to minimize data transfers.
For instance: pairing a CUDA **Compute** back-end to an OpenGL **Draw** backend
could be a good choice on hardware and OS that supports both. Similarly, a DX11
HLSL-Compute **Compute** back-end can be paired effectively with a DX11
HLSL-Shading **Draw** back-end. Some pairings however are not possible, as
there may be no data inter-operation paths available (ex: transferring DX11
compute SRVs to GL texture buffers).
----
Contexts & Controllers
======================
At the core of **Osd** modularization is the need for inter-operating vertex buffer
data between different APIs. This is achieved through a *"binding"* mechanism.
Binding Vertex Buffers
**********************
Each back-end manages data of 2 types: specific to each primitive manipulated
(topology, vertex data...), and general state data that is shared by all the
primitives (compute kernels, device ID...). The first type is contained in a
"Context" object, the latter manipulated through a singleton "Controller".
.. image:: images/osd_context_controller.png
:align: center
The Context itself holds the data that is specific to both the primitive and
the operation that needs to be appled (ex: *"drawing"*). It also owns multiple
buffers of vertex data. Contexts and Controller each have a specific back-end
API, so only matching back-ends can be paired (ex: an OpenCL Context cannot be
paired with a CUDA Controller).
Vertex Buffer Inter-Op
**********************
When a Controller needs to perform an operation, it *"binds"* the Context, which
is the trigger to move the vertex data into the appropriate device memory pool
(CPU to GPU, GPU to GPU...).
.. image:: images/osd_controllers.png
:align: center
In practice, a given application will maintain singletons of the controllers for
each of the modules that it uses, and pair them with the Contexts associated with
each primitive. A given primitive will use one Context for each of the modules that
it uses.
Example
*******
Here is an example of client code implementation for drawing surfaces using a
CUDA **Compute** module and an OpenGL **Draw** module.
.. image:: images/osd_controllers_example1.png
:align: center
The client code will construct a CudaComputeController and CudaComputeContext
for the **Compute** stage, along with an GLDrawController and a GLDrawContext.
The critical components are the vertex buffers, which must be of type
CudaGLVertexBuffer. The Contexts and Controllers classes all are
specializations of a templated *"Bind"* function which will leverage API
specific code responsible for the inter-operation of the data between the
API-specific back-ends.