Merge branch 'release/v2_2_0'
@ -131,6 +131,12 @@ if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANGCC OR CMAKE_COMPILER_IS_ICC
|
||||
|
||||
foreach (ICC_LIB iomp5 irng intlc)
|
||||
|
||||
if(CMAKE_SIZEOF_VOID_P MATCHES "8")
|
||||
list(APPEND ICC_LIB_ARCH "intel64")
|
||||
elseif(CMAKE_SIZEOF_VOID_P MATCHES "4")
|
||||
list(APPEND ICC_LIB_ARCH "ia32")
|
||||
endif()
|
||||
|
||||
find_library( ICC_${ICC_LIB}
|
||||
NAMES
|
||||
${ICC_LIB}
|
||||
@ -138,9 +144,7 @@ if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANGCC OR CMAKE_COMPILER_IS_ICC
|
||||
${ICC_LOCATION}/lib
|
||||
/opt/intel/lib/
|
||||
PATH_SUFFIXES
|
||||
intel64/
|
||||
ia32/
|
||||
mic/
|
||||
${ICC_LIB_ARCH}
|
||||
)
|
||||
|
||||
if (ICC_${ICC_LIB})
|
||||
|
@ -71,6 +71,7 @@ if (DOCUTILS_FOUND AND PYTHONINTERP_FOUND)
|
||||
far_overview.rst
|
||||
getting_started.rst
|
||||
glviewer.rst
|
||||
glstencilviewer.rst
|
||||
glbatchviewer.rst
|
||||
hbr_overview.rst
|
||||
intro.rst
|
||||
|
@ -1,4 +1,4 @@
|
||||
..
|
||||
..
|
||||
Copyright 2013 Pixar
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -21,7 +21,7 @@
|
||||
either express or implied. See the License for the specific
|
||||
language governing permissions and limitations under the
|
||||
License.
|
||||
|
||||
|
||||
|
||||
Code Examples
|
||||
-------------
|
||||
@ -29,7 +29,7 @@ Code Examples
|
||||
Standalone Viewers
|
||||
==================
|
||||
|
||||
OpenSubdiv builds a number of standalone viewers that demonstrate various aspects
|
||||
OpenSubdiv builds a number of standalone viewers that demonstrate various aspects
|
||||
of the software.
|
||||
|
||||
----
|
||||
@ -37,17 +37,18 @@ of the software.
|
||||
.. list-table:: **OpenGL examples**
|
||||
:class: quickref
|
||||
:widths: 50 50
|
||||
|
||||
|
||||
* - | `glViewer <glviewer.html>`_
|
||||
| `glBatchViewer <glbatchviewer.html>`_
|
||||
| `glStencilViewer <glstencilviewer.html>`_
|
||||
- | `limitEval <limiteval.html>`_
|
||||
| `paintTest <painttest.html>`_
|
||||
| `ptexViewer <ptexviewer.html>`_
|
||||
- | `paintTest <painttest.html>`_
|
||||
| `limitEval <limiteval.html>`_
|
||||
|
||||
.. list-table:: **DirectX examples**
|
||||
:class: quickref
|
||||
:widths: 50 50
|
||||
|
||||
|
||||
* - | `dxViewer <dxviewer.html>`_
|
||||
- |
|
||||
|
||||
@ -64,8 +65,8 @@ of the software.
|
||||
|
||||
**Note:**
|
||||
the Maya plugins are currently unsupported and they may fail to compile
|
||||
or work with current versions of OpenSubdiv. These were originally written for
|
||||
the sole purpose of live demonstrations and the code is provided only as an
|
||||
or work with current versions of OpenSubdiv. These were originally written for
|
||||
the sole purpose of live demonstrations and the code is provided only as an
|
||||
implementation example.
|
||||
|
||||
|
|
||||
@ -76,13 +77,13 @@ Common Keyboard Controls
|
||||
========================
|
||||
|
||||
.. code:: c++
|
||||
|
||||
|
||||
Left mouse button drag : orbit camera
|
||||
Middle mouse button drag : pan camera
|
||||
Right mouse button : dolly camera
|
||||
n, p : next/prev model
|
||||
1, 2, 3, ..., 9, 0 : specify adaptive isolation or uniform refinment level
|
||||
+, - : increase / decrease tessellation
|
||||
+, - : increase / decrease tessellation
|
||||
Tab : toggle full-screen
|
||||
Esc : turn on / off the HUD
|
||||
w : switch display mode
|
||||
|
@ -65,6 +65,7 @@ SEE ALSO
|
||||
`Code Examples <code_examples.html>`__, \
|
||||
`glViewer <glviewer.html>`__, \
|
||||
`glBatchViewer <glbatchviewer.html>`__, \
|
||||
`glStencilViewer <glstencilviewer.html>`__, \
|
||||
`ptexViewer <ptexviewer.html>`__, \
|
||||
`paintTest <painttest.html>`__, \
|
||||
`limitEval <limiteval.html>`__, \
|
||||
|
@ -1,4 +1,4 @@
|
||||
..
|
||||
..
|
||||
Copyright 2013 Pixar
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -21,7 +21,7 @@
|
||||
either express or implied. See the License for the specific
|
||||
language governing permissions and limitations under the
|
||||
License.
|
||||
|
||||
|
||||
|
||||
FAR Overview
|
||||
------------
|
||||
@ -33,13 +33,13 @@ FAR Overview
|
||||
Feature Adaptive Representation (Far)
|
||||
=====================================
|
||||
|
||||
Far is a serialized topoloigcal data representation.Far uses hbr to create and
|
||||
cache fast run time data structures for table driven subdivision of vertices and
|
||||
cubic patches for limit surface evaluation. `Feature-adaptive <subdivision_surfaces.html#feature-adaptive-subdivision>`__
|
||||
refinement logic is used to adaptively refine coarse topology near features like
|
||||
extraordinary vertices and creases in order to make the topology amenable to
|
||||
cubic patch evaluation. Far is also a generic, templated algorithmic base API
|
||||
that clients in higher levels instantiate and use by providing an implementation
|
||||
Far is a serialized topoloigcal data representation.Far uses hbr to create and
|
||||
cache fast run time data structures for table driven subdivision of vertices and
|
||||
cubic patches for limit surface evaluation. `Feature-adaptive <subdivision_surfaces.html#feature-adaptive-subdivision>`__
|
||||
refinement logic is used to adaptively refine coarse topology near features like
|
||||
extraordinary vertices and creases in order to make the topology amenable to
|
||||
cubic patch evaluation. Far is also a generic, templated algorithmic base API
|
||||
that clients in higher levels instantiate and use by providing an implementation
|
||||
of a vertex class. It supports these subdivision schemes:
|
||||
|
||||
Factories & Tables
|
||||
@ -50,3 +50,146 @@ Subdivision Tables
|
||||
|
||||
Patch Tables
|
||||
============
|
||||
|
||||
|
||||
Stencil Tables
|
||||
==============
|
||||
|
||||
|
||||
Stencils are the most direct method of evaluation of specific locations on the
|
||||
limit of a subdivision surface starting from the coarse vertices of the control
|
||||
cage.
|
||||
|
||||
.. image:: images/far_stencil0.png
|
||||
:align: center
|
||||
|
||||
Sample Location
|
||||
***************
|
||||
|
||||
Each stencil is associated with a singular parametric location on the coarse
|
||||
mesh. The paramatric location is defined as face location and local [0.0 - 1.0]
|
||||
(u,v) triplet:
|
||||
|
||||
In the case of a non-coarse quad face, the parametric sub-face quadrant needs to
|
||||
be identified. This can be done either explicitly or implicitly by using the
|
||||
unique ptex face indices for instance.
|
||||
|
||||
.. image:: images/far_stencil6.png
|
||||
:align: center
|
||||
|
||||
|
||||
Principles
|
||||
**********
|
||||
|
||||
Iterative subdivision algorithms such as the one used in `FarSubdivisionTables <#subdivision-tables>`__
|
||||
converge towards the limit surface by sucessively refining the vertices of the
|
||||
coarse control cage.
|
||||
|
||||
.. image:: images/far_stencil4.png
|
||||
:align: center
|
||||
|
||||
Each step is dependent upon the previous subidivion step being completed, and a
|
||||
substantial number of steps may be required in order approximate the limit. Since
|
||||
each subdivision step incurs an O(4 :superscript:`n`) growing amount of
|
||||
computations, the accrued number of interpolations can be quite large.
|
||||
|
||||
However, every intermediate subdivided vertex can be expressed as a linear
|
||||
interpolation of vertice from the previous step. So, eventually, every point at
|
||||
on the limit surface can be expressed as a weighted average of the set of coarse
|
||||
control vertices from the one-ring surrounding the face that the point is in:
|
||||
|
||||
.. image:: images/far_stencil3.png
|
||||
:align: center
|
||||
|
||||
Where:
|
||||
|
||||
.. image:: images/far_stencil2.png
|
||||
:align: center
|
||||
|
||||
Stencils are created by combining the list of control vertices of the 1-ring
|
||||
to a set of interpolation weights obtained by successive accumulation of
|
||||
subdivision interpolation weights.
|
||||
|
||||
The weight accumulation process is made efficient by adaptively subdividing the
|
||||
control cage only around extraordinary locations, and otherwise reverting to fast
|
||||
bi-cubic bspline patch evaluation. The use of bi-cubic patches also allows the
|
||||
accumulation of analytical derivatives.
|
||||
|
||||
API Architecture
|
||||
****************
|
||||
|
||||
The base container for stencil data is the FarStencilTables class. As with most
|
||||
other Far entities, it has an associated FarStencilTablesFactory that requires
|
||||
an HbrMesh:
|
||||
|
||||
.. image:: images/far_stencil5.png
|
||||
:align: center
|
||||
|
||||
Assuming a properly qualified HbrMesh:
|
||||
|
||||
.. code:: c++
|
||||
|
||||
HMesh<OpenSubdiv::FarStencilFactoryVertex> * mesh;
|
||||
|
||||
FarStencilTables controlStencils;
|
||||
|
||||
OpenSubdiv::FarStencilTablesFactory<> factory(mesh);
|
||||
|
||||
for (int i=0; i<nfaces; ++i) {
|
||||
|
||||
HFace * f = mesh->GetFace(i);
|
||||
|
||||
int nv = f->GetNumVertices();
|
||||
|
||||
if (nv!=4) {
|
||||
|
||||
// if the face is not a quad, we have to iterate over sub-quad(rants)
|
||||
for (int j=0; j<f->GetNumVertices(); ++j) {
|
||||
|
||||
factory.SetCurrentFace(i,j);
|
||||
|
||||
factory.AppendStencils( &controlStencils, nsamples/nv, u, v, reflevel );
|
||||
}
|
||||
} else {
|
||||
|
||||
factory.SetCurrentFace(i);
|
||||
|
||||
factory.AppendStencils( &controlStencils, g_nsamples, u, v, reflevel );
|
||||
}
|
||||
}
|
||||
|
||||
When the control vertices (controlPoints) move in space, the limit locations can
|
||||
be very efficiently recomputed simply by applying the blending weights to the
|
||||
series of coarse control vertices:
|
||||
|
||||
.. code:: c++
|
||||
|
||||
class StencilType {
|
||||
public:
|
||||
|
||||
void Clear() {
|
||||
memset( &x, 0, sizeof(StencilType));
|
||||
}
|
||||
|
||||
void AddWithWeight( StencilType const & cv, float weight ) {
|
||||
x += cv.x * weight;
|
||||
y += cv.y * weight;
|
||||
z += cv.z * weight;
|
||||
}
|
||||
|
||||
float x,y,z;
|
||||
};
|
||||
|
||||
std::vector<StencilType> controlPoints,
|
||||
points,
|
||||
utan,
|
||||
vtan;
|
||||
|
||||
// Uppdate points by applying stencils
|
||||
controlStencils.UpdateValues<StencilType>( reinterpret_cast<StencilType const *>(
|
||||
&controlPoints[0]), &points[0] );
|
||||
|
||||
// Uppdate tangents by applying derivative stencils
|
||||
controlStencils.UpdateDerivs<StencilType>( reinterpret_cast<StencilType const *>(
|
||||
&controlPoints[0]), &utan[0], &vtan[0] );
|
||||
|
||||
|
@ -81,7 +81,7 @@ SEE ALSO
|
||||
|
||||
`Code Examples <code_examples.html>`__, \
|
||||
`glViewer <glviewer.html>`__, \
|
||||
`glBatchViewer <glbatchviewer.html>`__, \
|
||||
`glStencilViewer <glstencilviewer.html>`__, \
|
||||
`ptexViewer <ptexviewer.html>`__, \
|
||||
`paintTest <painttest.html>`__, \
|
||||
`limitEval <limiteval.html>`__, \
|
||||
|
74
documentation/glstencilviewer.rst
Normal file
@ -0,0 +1,74 @@
|
||||
..
|
||||
Copyright 2013 Pixar
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License
|
||||
and the following modification to it: Section 6 Trademarks.
|
||||
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 for reproducing
|
||||
the content of the NOTICE file.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
glStencilViewer
|
||||
---------------
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
:backlinks: none
|
||||
|
||||
SYNOPSIS
|
||||
========
|
||||
|
||||
.. parsed-literal::
|
||||
:class: codefhead
|
||||
|
||||
**glStencilViewer** [**-d** *isolation level*] [**-f**] *objfile(s)*
|
||||
|
||||
DESCRIPTION
|
||||
===========
|
||||
|
||||
``glStencilViewer`` is a stand-alone application that showcases the application of
|
||||
pre-computed stencil tables to a collection of geometric test shapes. Multiple
|
||||
controls are available to experiment with the algorithms.
|
||||
|
||||
.. image:: images/glstencilviewer.png
|
||||
:width: 400px
|
||||
:align: center
|
||||
:target: images/glstencilviewer.png
|
||||
|
||||
OPTIONS
|
||||
=======
|
||||
|
||||
**-d** *isolation level*
|
||||
Select the desired isolation level of adaptive feature isolation. This can be
|
||||
useful when trying to load large pieces of geometry.
|
||||
|
||||
**-f**
|
||||
Launches the application in full-screen mode (if is supported by GLFW on the
|
||||
OS)
|
||||
|
||||
SEE ALSO
|
||||
========
|
||||
|
||||
`Code Examples <code_examples.html>`__, \
|
||||
`glViewer <glviewer.html>`__, \
|
||||
`glBatchViewer <glbatchviewer.html>`__, \
|
||||
`ptexViewer <ptexviewer.html>`__, \
|
||||
`paintTest <painttest.html>`__, \
|
||||
`limitEval <limiteval.html>`__, \
|
||||
`dxViewer <dxviewer.html>`__, \
|
||||
|
@ -69,6 +69,7 @@ SEE ALSO
|
||||
|
||||
`Code Examples <code_examples.html>`__, \
|
||||
`glBatchViewer <glbatchviewer.html>`__, \
|
||||
`glStencilViewer <glstencilviewer.html>`__, \
|
||||
`ptexViewer <ptexviewer.html>`__, \
|
||||
`paintTest <painttest.html>`__, \
|
||||
`limitEval <limiteval.html>`__, \
|
||||
|
BIN
documentation/images/far_stencil0.png
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
documentation/images/far_stencil1.png
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
documentation/images/far_stencil2.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
documentation/images/far_stencil3.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
documentation/images/far_stencil4.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
documentation/images/far_stencil5.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
documentation/images/far_stencil6.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
documentation/images/glstencilviewer.png
Normal file
After Width: | Height: | Size: 331 KiB |
@ -51,6 +51,11 @@
|
||||
<ul>
|
||||
<li><a href="hbr_overview.html">Hbr</a></li>
|
||||
<li><a href="far_overview.html">Far</a></li>
|
||||
<ul>
|
||||
<li><a href="far_overview.html#subdivision-tables">Subdivision Tables</a></li>
|
||||
<li><a href="far_overview.html#patch-tables">Patch Tables</a></li>
|
||||
<li><a href="far_overview.html#stencil-tables">Stencil Tables</a></li>
|
||||
</ul>
|
||||
<li><a href="osd_overview.html">Osd</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
@ -79,6 +79,7 @@ SEE ALSO
|
||||
`Code Examples <code_examples.html>`__, \
|
||||
`glViewer <glviewer.html>`__, \
|
||||
`glBatchViewer <glbatchviewer.html>`__, \
|
||||
`glStencilViewer <glstencilviewer.html>`__, \
|
||||
`ptexViewer <ptexviewer.html>`__, \
|
||||
`limitEval <limiteval.html>`__, \
|
||||
`dxViewer <dxviewer.html>`__, \
|
||||
|
@ -134,6 +134,7 @@ SEE ALSO
|
||||
`Code Examples <code_examples.html>`__, \
|
||||
`glViewer <glviewer.html>`__, \
|
||||
`glBatchViewer <glbatchviewer.html>`__, \
|
||||
`glStencilViewer <glstencilviewer.html>`__, \
|
||||
`paintTest <painttest.html>`__, \
|
||||
`limitEval <limiteval.html>`__, \
|
||||
`dxViewer <dxviewer.html>`__, \
|
||||
|
@ -32,6 +32,18 @@ Release Notes
|
||||
|
||||
----
|
||||
|
||||
Release 2.2.0
|
||||
=============
|
||||
|
||||
**New Features**
|
||||
- Added subdivision stencil functionality (Far & OsdEval)
|
||||
|
||||
**Bug Fixes**
|
||||
- Fix D3D11DrawContext to check for NULL pointers
|
||||
- Fix cpuEvalLimitController crash bug
|
||||
- Fixed search path suffixes for ICC libs
|
||||
- Fixed invalid initialization of glslTransformFeedback kernel.
|
||||
|
||||
Release 2.1.0
|
||||
=============
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
||||
if( OPENGL_FOUND AND (GLEW_FOUND AND GLFW_FOUND) OR (APPLE AND GLFW_FOUND))
|
||||
add_subdirectory(glViewer)
|
||||
add_subdirectory(glBatchViewer)
|
||||
add_subdirectory(glStencilViewer)
|
||||
add_subdirectory(simpleCpu)
|
||||
add_subdirectory(limitEval)
|
||||
if(OPENGL_4_3_FOUND AND (NOT APPLE))
|
||||
|
@ -27,6 +27,13 @@
|
||||
|
||||
#include <cmath>
|
||||
|
||||
inline void
|
||||
cross(float *n, const float *v1, const float *v2) {
|
||||
n[0] = v1[1]*v2[2]-v1[2]*v2[1];
|
||||
n[1] = v1[2]*v2[0]-v1[0]*v2[2];
|
||||
n[2] = v1[0]*v2[1]-v1[1]*v2[0];
|
||||
}
|
||||
|
||||
inline void
|
||||
cross(float *n, const float *p0, const float *p1, const float *p2) {
|
||||
|
||||
|
56
examples/glStencilViewer/CMakeLists.txt
Normal file
@ -0,0 +1,56 @@
|
||||
#
|
||||
# Copyright 2013 Pixar
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License
|
||||
# and the following modification to it: Section 6 Trademarks.
|
||||
# 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 for reproducing
|
||||
# the content of the NOTICE file.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
# *** glStencilViewer ***
|
||||
|
||||
set(PLATFORM_LIBRARIES
|
||||
${OSD_LINK_TARGET}
|
||||
${GLFW_LIBRARIES}
|
||||
)
|
||||
|
||||
include_directories(
|
||||
${PROJECT_SOURCE_DIR}/opensubdiv
|
||||
${PROJECT_SOURCE_DIR}/regression
|
||||
${GLFW_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
if ( GLEW_FOUND )
|
||||
include_directories(${GLEW_INCLUDE_DIR})
|
||||
list(APPEND PLATFORM_LIBRARIES ${GLEW_LIBRARY})
|
||||
endif()
|
||||
|
||||
_add_possibly_cuda_executable(glStencilViewer
|
||||
main.cpp
|
||||
../common/font_image.cpp
|
||||
../common/hud.cpp
|
||||
../common/gl_hud.cpp
|
||||
${INC_FILES}
|
||||
)
|
||||
|
||||
target_link_libraries(glStencilViewer
|
||||
${PLATFORM_LIBRARIES}
|
||||
)
|
||||
|
||||
install(TARGETS glStencilViewer DESTINATION ${CMAKE_BINDIR_BASE})
|
1256
examples/glStencilViewer/main.cpp
Normal file
@ -41,6 +41,8 @@ set(PUBLIC_HEADER_FILES
|
||||
patchMap.h
|
||||
patchTables.h
|
||||
patchTablesFactory.h
|
||||
stencilTablesFactory.h
|
||||
stencilTables.h
|
||||
subdivisionTables.h
|
||||
subdivisionTablesFactory.h
|
||||
vertexEditTables.h
|
||||
|
249
opensubdiv/far/stencilTables.h
Normal file
@ -0,0 +1,249 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License
|
||||
// and the following modification to it: Section 6 Trademarks.
|
||||
// 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 for reproducing
|
||||
// the content of the NOTICE file.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#ifndef FAR_STENCILTABLES_H
|
||||
#define FAR_STENCILTABLES_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
|
||||
/// \brief Stencil descriptor
|
||||
///
|
||||
/// Allows access and manipulation of a single stencil in a FarStencilTables.
|
||||
///
|
||||
class FarStencil {
|
||||
public:
|
||||
|
||||
/// Returns the size of the stencil (number of control vertices)
|
||||
int GetSize() const {
|
||||
return *_size;
|
||||
}
|
||||
|
||||
/// Returns the control vertices indices
|
||||
int const * GetVertexIndices() const {
|
||||
return _indices;
|
||||
}
|
||||
|
||||
/// Returns the interpolation weights
|
||||
float const * GetValueWeights() const {
|
||||
return _point;
|
||||
}
|
||||
|
||||
/// Returns U derivative interpolation weights
|
||||
float const * GetUDerivWeights() const {
|
||||
return _uderiv;
|
||||
}
|
||||
|
||||
/// Returns V derivative interpolation weights
|
||||
float const * GetVDerivWeights() const {
|
||||
return _vderiv;
|
||||
}
|
||||
|
||||
/// Increment to the next stencil in the array
|
||||
/// Note : there is no array boundary check !
|
||||
void Increment() {
|
||||
int stride = *_size;
|
||||
++_size;
|
||||
_indices += stride;
|
||||
_point += stride;
|
||||
_uderiv += stride;
|
||||
_vderiv += stride;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
FarStencil( int * size,
|
||||
int * indices,
|
||||
float * point,
|
||||
float * uderiv,
|
||||
float * vderiv )
|
||||
: _size(size),
|
||||
_indices(indices),
|
||||
_point(point),
|
||||
_uderiv(uderiv),
|
||||
_vderiv(vderiv) {
|
||||
}
|
||||
|
||||
friend class FarStencilTables;
|
||||
template <class T> friend class FarStencilTablesFactory;
|
||||
|
||||
int * _size,
|
||||
* _indices;
|
||||
|
||||
float * _point,
|
||||
* _uderiv,
|
||||
* _vderiv;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/// \brief Table of subdivision stencils.
|
||||
///
|
||||
/// Stencils are the most direct methods of evaluation of locations on the limit
|
||||
/// of a surface. Every point of a limit surface can be computed by linearly
|
||||
/// blending a collection of coarse control vertices.
|
||||
///
|
||||
/// A stencil assigns a series of control vertex indices with a blending weight
|
||||
/// that corresponds to a unique parametric location of the limit surface. When
|
||||
/// the control vertices move in space, the limit location can be very efficiently
|
||||
/// recomputed simply by applying the blending weights to the series of coarse
|
||||
/// control vertices.
|
||||
///
|
||||
class FarStencilTables {
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Clears the stencils from the table
|
||||
void Clear() {
|
||||
_sizes.clear();
|
||||
_offsets.clear();
|
||||
_indices.clear();
|
||||
_point.clear();
|
||||
_uderiv.clear();
|
||||
_vderiv.clear();
|
||||
}
|
||||
|
||||
/// \brief Returns the number of stencils in the tables
|
||||
int GetNumStencils() const {
|
||||
return (int)_sizes.size();
|
||||
}
|
||||
|
||||
/// \brief Updates point values based on the control values
|
||||
///
|
||||
/// \note The values array is assumed to be at least as big as the
|
||||
/// result of \c GetNumStencils().
|
||||
template <class T>
|
||||
void UpdateValues( T const *controlValues, T *values, int stride=0 ) const {
|
||||
_Update( controlValues, &_point.at(0), values, stride );
|
||||
}
|
||||
|
||||
/// \brief Updates derivative values based on the control values
|
||||
///
|
||||
/// \note The values array is assumed to be at least as big as the
|
||||
/// result of \c GetNumStencils().
|
||||
template <class T>
|
||||
void UpdateDerivs( T const *controlValues, T *uderivs,
|
||||
T *vderivs, int stride=0 ) const {
|
||||
_Update( controlValues, &_uderiv.at(0), uderivs, stride );
|
||||
_Update( controlValues, &_vderiv.at(0), vderivs, stride );
|
||||
}
|
||||
|
||||
/// \brief Returns a FarStencil at index i in the tables
|
||||
FarStencil GetStencil(int i) const;
|
||||
|
||||
/// \brief Returns the number of control vertices of each stencil in the table
|
||||
std::vector<int> const & GetSizes() const {
|
||||
return _sizes;
|
||||
}
|
||||
|
||||
/// \brief Returns the offset to a given stencil
|
||||
std::vector<int> const & GetOffsets() const {
|
||||
return _offsets;
|
||||
}
|
||||
|
||||
/// \brief Returns the indices of the control vertices
|
||||
std::vector<int> const & GetControlIndices() const {
|
||||
return _indices;
|
||||
}
|
||||
|
||||
/// \brief Returns the stencils interpolation weights
|
||||
std::vector<float> const & GetWeights() const {
|
||||
return _point;
|
||||
}
|
||||
|
||||
/// \brief Returns the stencils U deriv weights
|
||||
std::vector<float> const & GetDuWeights() const {
|
||||
return _uderiv;
|
||||
}
|
||||
|
||||
/// \brief Returns the stencils U deriv weights
|
||||
std::vector<float> const & GetDvWeights() const {
|
||||
return _vderiv;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
template <class T> friend class FarStencilTablesFactory;
|
||||
|
||||
// Update values by appling cached stencil weights to new control values
|
||||
template <class T> void _Update( T const *controlValues,
|
||||
float const * weights,
|
||||
T *values,
|
||||
int stride ) const;
|
||||
|
||||
std::vector<int> _sizes; // number of coeffiecient for each stencil
|
||||
std::vector<int> _offsets; // offset to the start of each stencil
|
||||
std::vector<int> _indices;
|
||||
|
||||
std::vector<float> _point, // weight coefficients (value & derivatives)
|
||||
_uderiv,
|
||||
_vderiv;
|
||||
|
||||
};
|
||||
|
||||
template <class T> void
|
||||
FarStencilTables::_Update( T const *controlValues,
|
||||
float const * weights,
|
||||
T *values,
|
||||
int stride ) const {
|
||||
|
||||
int const * index = &_indices.at(0);
|
||||
|
||||
for (int i=0; i<GetNumStencils(); ++i) {
|
||||
|
||||
// Zero out the result accumulators
|
||||
values[i].Clear();
|
||||
|
||||
// For each element in the array, add the coefs contribution
|
||||
for (int j=0; j<_sizes[i]; ++j, ++index, ++weights) {
|
||||
values[i].AddWithWeight( controlValues[*index], *weights );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline FarStencil
|
||||
FarStencilTables::GetStencil(int i) const {
|
||||
|
||||
int ofs = _offsets[i];
|
||||
|
||||
return FarStencil( const_cast<int *>(&_sizes[i]),
|
||||
const_cast<int *>(&_indices[ofs]),
|
||||
const_cast<float *>(&_point[ofs]),
|
||||
const_cast<float *>(&_uderiv[ofs]),
|
||||
const_cast<float *>(&_vderiv[ofs]) );
|
||||
}
|
||||
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif // FAR_STENCILTABLES_H
|
1678
opensubdiv/far/stencilTablesFactory.h
Normal file
@ -258,19 +258,16 @@ public:
|
||||
bool HasCreaseEdits() const { return hasCreaseEdits; }
|
||||
|
||||
void Unrefine(int numCoarseVerts, int numCoarseFaces) {
|
||||
static int oldMaxFaceID = 0;
|
||||
if(oldMaxFaceID == 0) {
|
||||
oldMaxFaceID = numCoarseFaces;
|
||||
}
|
||||
|
||||
for (int i = numCoarseFaces; i < maxFaceID; ++i) {
|
||||
HbrFace<T>* f = GetFace(i);
|
||||
if(f and not f->IsCoarse())
|
||||
DeleteFace(f);
|
||||
}
|
||||
//oldMaxFaceID = maxFaceID;
|
||||
|
||||
maxFaceID = numCoarseFaces;
|
||||
|
||||
for(int i=numCoarseVerts; (int)vertices.size(); ++i ) {
|
||||
for(int i=numCoarseVerts; i<(int)vertices.size(); ++i ) {
|
||||
HbrVertex<T>* v = GetVertex(i);
|
||||
if(v and not v->IsReferenced())
|
||||
DeleteVertex(v);
|
||||
|
@ -53,6 +53,8 @@ set(CPU_SOURCE_FILES
|
||||
cpuEvalLimitContext.cpp
|
||||
cpuEvalLimitController.cpp
|
||||
cpuEvalLimitKernel.cpp
|
||||
cpuEvalStencilsContext.cpp
|
||||
cpuEvalStencilsController.cpp
|
||||
cpuVertexBuffer.cpp
|
||||
error.cpp
|
||||
evalLimitContext.cpp
|
||||
@ -81,6 +83,8 @@ set(PUBLIC_HEADER_FILES
|
||||
cpuComputeController.h
|
||||
cpuEvalLimitContext.h
|
||||
cpuEvalLimitController.h
|
||||
cpuEvalStencilsContext.h
|
||||
cpuEvalStencilsController.h
|
||||
cpuVertexBuffer.h
|
||||
error.h
|
||||
evalLimitContext.h
|
||||
@ -148,12 +152,14 @@ list(APPEND DOXY_HEADER_FILES
|
||||
set(OPENMP_PUBLIC_HEADERS
|
||||
ompKernel.h
|
||||
ompComputeController.h
|
||||
ompEvalStencilsController.h
|
||||
)
|
||||
|
||||
if( OPENMP_FOUND )
|
||||
list(APPEND CPU_SOURCE_FILES
|
||||
ompKernel.cpp
|
||||
ompComputeController.cpp
|
||||
ompEvalStencilsController.cpp
|
||||
)
|
||||
|
||||
list(APPEND PUBLIC_HEADER_FILES ${OPENMP_PUBLIC_HEADERS})
|
||||
@ -175,10 +181,12 @@ if( TBB_FOUND )
|
||||
list(APPEND CPU_SOURCE_FILES
|
||||
tbbKernel.cpp
|
||||
tbbComputeController.cpp
|
||||
tbbEvalStencilsController.cpp
|
||||
)
|
||||
list(APPEND PUBLIC_HEADER_FILES
|
||||
tbbKernel.h
|
||||
tbbComputeController.h
|
||||
tbbEvalStencilsController.h
|
||||
)
|
||||
if (CMAKE_COMPILER_IS_GNUCXX)
|
||||
list(APPEND PLATFORM_CPU_LIBRARIES
|
||||
|
@ -66,69 +66,62 @@ OsdCpuEvalLimitController::_EvalLimitSample( OpenSubdiv::OsdEvalCoords const & c
|
||||
|
||||
int offset = vertexData.outDesc.stride * index;
|
||||
|
||||
// Based on patch type - go execute interpolation
|
||||
switch( parray.GetDescriptor().GetType() ) {
|
||||
|
||||
if (vertexData.IsBound()) {
|
||||
|
||||
float * out = vertexData.out.GetData()+offset,
|
||||
* outDu = vertexData.outDu.IsBound() ? vertexData.outDu.GetData()+offset : 0,
|
||||
* outDv = vertexData.outDv.IsBound() ? vertexData.outDv.GetData()+offset : 0;
|
||||
|
||||
// Based on patch type - go execute interpolation
|
||||
switch( parray.GetDescriptor().GetType() ) {
|
||||
|
||||
case FarPatchTables::REGULAR : if (vertexData.IsBound()) {
|
||||
evalBSpline( v, u, cvs,
|
||||
case FarPatchTables::REGULAR : evalBSpline( v, u, cvs,
|
||||
vertexData.inDesc,
|
||||
vertexData.in.GetData(),
|
||||
vertexData.outDesc,
|
||||
vertexData.out.GetData()+offset,
|
||||
vertexData.outDu.GetData()+offset,
|
||||
vertexData.outDv.GetData()+offset );
|
||||
} break;
|
||||
out, outDu, outDv );
|
||||
break;
|
||||
|
||||
case FarPatchTables::BOUNDARY : if (vertexData.IsBound()) {
|
||||
evalBoundary( v, u, cvs,
|
||||
case FarPatchTables::BOUNDARY : evalBoundary( v, u, cvs,
|
||||
vertexData.inDesc,
|
||||
vertexData.in.GetData(),
|
||||
vertexData.outDesc,
|
||||
vertexData.out.GetData()+offset,
|
||||
vertexData.outDu.GetData()+offset,
|
||||
vertexData.outDv.GetData()+offset );
|
||||
} break;
|
||||
out, outDu, outDv );
|
||||
break;
|
||||
|
||||
case FarPatchTables::CORNER : if (vertexData.IsBound()) {
|
||||
evalCorner( v, u, cvs,
|
||||
case FarPatchTables::CORNER : evalCorner( v, u, cvs,
|
||||
vertexData.inDesc,
|
||||
vertexData.in.GetData(),
|
||||
vertexData.outDesc,
|
||||
vertexData.out.GetData()+offset,
|
||||
vertexData.outDu.GetData()+offset,
|
||||
vertexData.outDv.GetData()+offset );
|
||||
} break;
|
||||
out, outDu, outDv );
|
||||
break;
|
||||
|
||||
|
||||
case FarPatchTables::GREGORY : if (vertexData.IsBound()) {
|
||||
evalGregory( v, u, cvs,
|
||||
case FarPatchTables::GREGORY : evalGregory( v, u, cvs,
|
||||
&context->GetVertexValenceTable()[0],
|
||||
&context->GetQuadOffsetTable()[ parray.GetQuadOffsetIndex() + handle->vertexOffset ],
|
||||
&context->GetQuadOffsetTable()[ parray.GetQuadOffsetIndex() + handle->vertexOffset ],
|
||||
context->GetMaxValence(),
|
||||
vertexData.inDesc,
|
||||
vertexData.in.GetData(),
|
||||
vertexData.outDesc,
|
||||
vertexData.out.GetData()+offset,
|
||||
vertexData.outDu.GetData()+offset,
|
||||
vertexData.outDv.GetData()+offset );
|
||||
} break;
|
||||
out, outDu, outDv );
|
||||
break;
|
||||
|
||||
case FarPatchTables::GREGORY_BOUNDARY :
|
||||
if (vertexData.IsBound()) {
|
||||
evalGregoryBoundary(v, u, cvs,
|
||||
&context->GetVertexValenceTable()[0],
|
||||
&context->GetQuadOffsetTable()[ parray.GetQuadOffsetIndex() + handle->vertexOffset ],
|
||||
context->GetMaxValence(),
|
||||
vertexData.inDesc,
|
||||
vertexData.in.GetData(),
|
||||
vertexData.outDesc,
|
||||
vertexData.out.GetData()+offset,
|
||||
vertexData.outDu.GetData()+offset,
|
||||
vertexData.outDv.GetData()+offset );
|
||||
} break;
|
||||
case FarPatchTables::GREGORY_BOUNDARY :
|
||||
evalGregoryBoundary( v, u, cvs,
|
||||
&context->GetVertexValenceTable()[0],
|
||||
&context->GetQuadOffsetTable()[ parray.GetQuadOffsetIndex() + handle->vertexOffset ],
|
||||
context->GetMaxValence(),
|
||||
vertexData.inDesc,
|
||||
vertexData.in.GetData(),
|
||||
vertexData.outDesc,
|
||||
out, outDu, outDv );
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
45
opensubdiv/osd/cpuEvalStencilsContext.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License
|
||||
// and the following modification to it: Section 6 Trademarks.
|
||||
// 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 for reproducing
|
||||
// the content of the NOTICE file.
|
||||
//
|
||||
// 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 "../osd/cpuEvalStencilsContext.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
OsdCpuEvalStencilsContext::OsdCpuEvalStencilsContext(FarStencilTables const *stencils) :
|
||||
_stencils(stencils),
|
||||
_controlData(0),
|
||||
_outputData(0),
|
||||
_outputUDeriv(0),
|
||||
_outputVDeriv(0) {
|
||||
}
|
||||
|
||||
OsdCpuEvalStencilsContext *
|
||||
OsdCpuEvalStencilsContext::Create(FarStencilTables const *stencils) {
|
||||
return new OsdCpuEvalStencilsContext(stencils);
|
||||
}
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
193
opensubdiv/osd/cpuEvalStencilsContext.h
Normal file
@ -0,0 +1,193 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License
|
||||
// and the following modification to it: Section 6 Trademarks.
|
||||
// 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 for reproducing
|
||||
// the content of the NOTICE file.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#ifndef FAR_CPU_EVALSTENCILS_CONTEXT_H
|
||||
#define FAR_CPU_EVALSTENCILS_CONTEXT_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../far/stencilTables.h"
|
||||
|
||||
#include "../osd/vertexDescriptor.h"
|
||||
#include "../osd/nonCopyable.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
///
|
||||
/// \brief CPU stencils evaluation context
|
||||
///
|
||||
///
|
||||
class OsdCpuEvalStencilsContext : OsdNonCopyable<OsdCpuEvalStencilsContext> {
|
||||
|
||||
public:
|
||||
/// \brief Creates an OsdCpuEvalStencilsContext instance
|
||||
///
|
||||
/// @param stencils a pointer to the FarStencilTables
|
||||
///
|
||||
static OsdCpuEvalStencilsContext * Create(FarStencilTables const *stencils);
|
||||
|
||||
/// \brief Binds control vertex data buffer
|
||||
///
|
||||
/// Binding ensures that data buffers are properly inter-operated between
|
||||
/// Contexts and Controllers operating across multiple devices.
|
||||
///
|
||||
/// @param controlDataDesc
|
||||
///
|
||||
/// @param controlData
|
||||
///
|
||||
template<class VERTEX_BUFFER>
|
||||
void BindControlData(OsdVertexBufferDescriptor const & controlDataDesc, VERTEX_BUFFER *controlData ) {
|
||||
|
||||
_controlData = controlData ? controlData->BindCpuBuffer() : 0;
|
||||
_controlDataDesc = controlDataDesc;
|
||||
|
||||
}
|
||||
|
||||
/// \brief Binds output vertex data buffer
|
||||
///
|
||||
/// Binding ensures that data buffers are properly inter-operated between
|
||||
/// Contexts and Controllers operating across multiple devices.
|
||||
///
|
||||
/// @param outputDataDesc
|
||||
///
|
||||
/// @param outputData
|
||||
///
|
||||
template<class VERTEX_BUFFER>
|
||||
void BindOutputData( OsdVertexBufferDescriptor const & outputDataDesc, VERTEX_BUFFER *outputData ) {
|
||||
|
||||
_outputData = outputData ? outputData->BindCpuBuffer() : 0;
|
||||
_outputDataDesc = outputDataDesc;
|
||||
}
|
||||
|
||||
/// \brief Binds output derivative vertex data buffer
|
||||
///
|
||||
/// Binding ensures that data buffers are properly inter-operated between
|
||||
/// Contexts and Controllers operating across multiple devices.
|
||||
///
|
||||
/// @param controlDataDesc
|
||||
///
|
||||
/// @param controlData
|
||||
///
|
||||
/// @param outputDataDesc
|
||||
///
|
||||
/// @param outputData
|
||||
///
|
||||
template<class VERTEX_BUFFER>
|
||||
void BindOutputDerivData( OsdVertexBufferDescriptor const & outputDuDesc, VERTEX_BUFFER *outputDu,
|
||||
OsdVertexBufferDescriptor const & outputDvDesc, VERTEX_BUFFER *outputDv ) {
|
||||
|
||||
_outputUDeriv = outputDu ? outputDu ->BindCpuBuffer() : 0;
|
||||
_outputVDeriv = outputDv ? outputDv->BindCpuBuffer() : 0;
|
||||
_outputDuDesc = outputDuDesc;
|
||||
_outputDvDesc = outputDvDesc;
|
||||
}
|
||||
|
||||
/// \brief Unbinds any previously bound vertex and varying data buffers.
|
||||
void Unbind() {
|
||||
_controlData = 0;
|
||||
_controlDataDesc.Reset();
|
||||
|
||||
_outputData = 0;
|
||||
_outputDataDesc.Reset();
|
||||
|
||||
_outputUDeriv = 0;
|
||||
_outputDuDesc.Reset();
|
||||
|
||||
_outputVDeriv = 0;
|
||||
_outputDvDesc.Reset();
|
||||
}
|
||||
|
||||
/// \brief returns a pointer to the control vertex data
|
||||
float const * GetControlData() const {
|
||||
return _controlData;
|
||||
}
|
||||
|
||||
/// \brief returns a pointer to the output vertex data
|
||||
float * GetOutputData() {
|
||||
return _outputData;
|
||||
}
|
||||
|
||||
/// \brief returns a pointer to the output u-derivative vertex data
|
||||
float * GetOutputUDerivData() {
|
||||
return _outputUDeriv;
|
||||
}
|
||||
|
||||
/// \brief returns a pointer to the output v-derivative vertex data
|
||||
float * GetOutputVDerivData() {
|
||||
return _outputVDeriv;
|
||||
}
|
||||
|
||||
/// \brief Returns the vertex data descriptor for the control vertices buffer
|
||||
OsdVertexBufferDescriptor GetControlDataDescriptor() const {
|
||||
return _controlDataDesc;
|
||||
}
|
||||
|
||||
/// \brief Returns the vertex data descriptor for the output vertices buffer
|
||||
OsdVertexBufferDescriptor GetOutputDataDescriptor() const {
|
||||
return _outputDataDesc;
|
||||
}
|
||||
|
||||
/// \brief Returns the vertex data descriptor for the U derivatives data buffer
|
||||
OsdVertexBufferDescriptor GetDuDataDescriptor() const {
|
||||
return _outputDuDesc;
|
||||
}
|
||||
|
||||
/// \brief Returns the vertex data descriptor for the V derivatives data buffer
|
||||
OsdVertexBufferDescriptor GetDvDataDescriptor() const {
|
||||
return _outputDvDesc;
|
||||
}
|
||||
|
||||
|
||||
/// \brief Returns the FarStencilTables applied
|
||||
FarStencilTables const * GetStencilTables() const {
|
||||
return _stencils;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
OsdCpuEvalStencilsContext(FarStencilTables const *stencils);
|
||||
|
||||
private:
|
||||
|
||||
FarStencilTables const * _stencils;
|
||||
|
||||
OsdVertexBufferDescriptor _controlDataDesc,
|
||||
_outputDataDesc,
|
||||
_outputDuDesc,
|
||||
_outputDvDesc;
|
||||
|
||||
float * _controlData,
|
||||
* _outputData,
|
||||
* _outputUDeriv,
|
||||
* _outputVDeriv;
|
||||
};
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif // FAR_CPU_EVALSTENCILS_CONTEXT_H
|
147
opensubdiv/osd/cpuEvalStencilsController.cpp
Normal file
@ -0,0 +1,147 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License
|
||||
// and the following modification to it: Section 6 Trademarks.
|
||||
// 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 for reproducing
|
||||
// the content of the NOTICE file.
|
||||
//
|
||||
// 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 "../osd/cpuEvalStencilsController.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
OsdCpuEvalStencilsController::OsdCpuEvalStencilsController() {
|
||||
}
|
||||
|
||||
OsdCpuEvalStencilsController::~OsdCpuEvalStencilsController() {
|
||||
}
|
||||
|
||||
int
|
||||
OsdCpuEvalStencilsController::_UpdateValues( OsdCpuEvalStencilsContext * context ) {
|
||||
|
||||
int result=0;
|
||||
|
||||
FarStencilTables const * stencils = context->GetStencilTables();
|
||||
|
||||
int nstencils = stencils->GetNumStencils();
|
||||
if (not nstencils)
|
||||
return result;
|
||||
|
||||
OsdVertexBufferDescriptor ctrlDesc = context->GetControlDataDescriptor(),
|
||||
outDesc = context->GetOutputDataDescriptor();
|
||||
|
||||
// make sure that we have control data to work with
|
||||
if (not ctrlDesc.CanEval(outDesc))
|
||||
return 0;
|
||||
|
||||
float const * ctrl = context->GetControlData() + ctrlDesc.offset;
|
||||
|
||||
float * out = context->GetOutputData() + outDesc.offset;
|
||||
|
||||
if ((not ctrl) or (not out))
|
||||
return result;
|
||||
|
||||
int const * sizes = &stencils->GetSizes().at(0),
|
||||
* index = &stencils->GetControlIndices().at(0);
|
||||
|
||||
float const * weight = &stencils->GetWeights().at(0);
|
||||
|
||||
for (int i=0; i<nstencils; ++i) {
|
||||
|
||||
memset(out, 0, outDesc.length*sizeof(float));
|
||||
|
||||
for (int j=0; j<sizes[i]; ++j, ++index, ++weight) {
|
||||
|
||||
float const * cv = ctrl + (*index)*ctrlDesc.stride;
|
||||
|
||||
for (int k=0; k<outDesc.length; ++k) {
|
||||
out[k] += cv[k] * (*weight);
|
||||
}
|
||||
}
|
||||
out += outDesc.stride;
|
||||
}
|
||||
|
||||
return nstencils;
|
||||
}
|
||||
|
||||
int
|
||||
OsdCpuEvalStencilsController::_UpdateDerivs( OsdCpuEvalStencilsContext * context ) {
|
||||
|
||||
int result=0;
|
||||
|
||||
FarStencilTables const * stencils = context->GetStencilTables();
|
||||
|
||||
int nstencils = stencils->GetNumStencils();
|
||||
if (not nstencils)
|
||||
return result;
|
||||
|
||||
OsdVertexBufferDescriptor ctrlDesc = context->GetControlDataDescriptor(),
|
||||
duDesc = context->GetDuDataDescriptor(),
|
||||
dvDesc = context->GetDvDataDescriptor();
|
||||
|
||||
// make sure that we have control data to work with
|
||||
if (not (ctrlDesc.CanEval(duDesc) and ctrlDesc.CanEval(dvDesc)))
|
||||
return 0;
|
||||
|
||||
float const * ctrl = context->GetControlData() + ctrlDesc.offset;
|
||||
|
||||
float * du = context->GetOutputUDerivData() + duDesc.offset,
|
||||
* dv = context->GetOutputVDerivData() + dvDesc.offset;
|
||||
|
||||
if ((not ctrl) or (not du) or (not dv))
|
||||
return result;
|
||||
|
||||
int const * sizes = &stencils->GetSizes().at(0),
|
||||
* index = &stencils->GetControlIndices().at(0);
|
||||
|
||||
float const * duweight = &stencils->GetDuWeights().at(0),
|
||||
* dvweight = &stencils->GetDvWeights().at(0);
|
||||
|
||||
for (int i=0; i<nstencils; ++i) {
|
||||
|
||||
memset(du, 0, duDesc.length*sizeof(float));
|
||||
memset(dv, 0, dvDesc.length*sizeof(float));
|
||||
|
||||
for (int j=0; j<sizes[i]; ++j, ++index, ++duweight, ++dvweight) {
|
||||
|
||||
float const * cv = ctrl + (*index)*ctrlDesc.stride;
|
||||
|
||||
for (int k=0; k<duDesc.length; ++k) {
|
||||
du[k] += cv[k] * (*duweight);
|
||||
dv[k] += cv[k] * (*dvweight);
|
||||
}
|
||||
}
|
||||
du += duDesc.stride;
|
||||
dv += dvDesc.stride;
|
||||
}
|
||||
|
||||
return nstencils;
|
||||
}
|
||||
|
||||
void
|
||||
OsdCpuEvalStencilsController::Synchronize() {
|
||||
}
|
||||
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
144
opensubdiv/osd/cpuEvalStencilsController.h
Normal file
@ -0,0 +1,144 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License
|
||||
// and the following modification to it: Section 6 Trademarks.
|
||||
// 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 for reproducing
|
||||
// the content of the NOTICE file.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#ifndef FAR_CPU_EVALSTENCILS_CONTROLLER_H
|
||||
#define FAR_CPU_EVALSTENCILS_CONTROLLER_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../osd/cpuEvalStencilsContext.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
///
|
||||
/// \brief CPU stencils evaluation controller
|
||||
///
|
||||
/// OsdCpuStencilsController is a compute controller class to launch
|
||||
/// single threaded CPU stencil evalution kernels.
|
||||
///
|
||||
/// Controller entities execute requests from Context instances that they share
|
||||
/// common interfaces with. Controllers are attached to discrete compute devices
|
||||
/// and share the devices resources with Context entities.
|
||||
///
|
||||
class OsdCpuEvalStencilsController {
|
||||
public:
|
||||
|
||||
/// Constructor.
|
||||
OsdCpuEvalStencilsController();
|
||||
|
||||
/// Destructor.
|
||||
~OsdCpuEvalStencilsController();
|
||||
|
||||
|
||||
/// \brief Applies stencil weights to the control vertex data
|
||||
///
|
||||
/// Applies the stencil weights to the control vertex data to evaluate the
|
||||
/// interpolated limit positions at the parametric locations of the stencils
|
||||
///
|
||||
/// @param context the OsdCpuEvalStencilsContext with the stencil weights
|
||||
///
|
||||
/// @param controlDataDesc vertex buffer descriptor for the control vertex data
|
||||
///
|
||||
/// @param controlVertices vertex buffer with the control vertices data
|
||||
///
|
||||
/// @param outputDataDesc vertex buffer descriptor for the output vertex data
|
||||
///
|
||||
/// @param outputData vertex buffer where the vertex data will be output
|
||||
///
|
||||
template<class CONTROL_BUFFER, class OUTPUT_BUFFER>
|
||||
int UpdateValues( OsdCpuEvalStencilsContext * context,
|
||||
OsdVertexBufferDescriptor const & controlDataDesc, CONTROL_BUFFER *controlVertices,
|
||||
OsdVertexBufferDescriptor const & outputDataDesc, OUTPUT_BUFFER *outputData ) {
|
||||
|
||||
if (not context->GetStencilTables()->GetNumStencils())
|
||||
return 0;
|
||||
|
||||
context->BindControlData( controlDataDesc, controlVertices );
|
||||
|
||||
context->BindOutputData( outputDataDesc, outputData );
|
||||
|
||||
int n = _UpdateValues( context );
|
||||
|
||||
context->Unbind();
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/// \brief Applies derivative stencil weights to the control vertex data
|
||||
///
|
||||
/// Computes the U and V derivative stencils to the control vertex data at
|
||||
/// the parametric locations contained in each stencil
|
||||
///
|
||||
/// @param context the OsdCpuEvalStencilsContext with the stencil weights
|
||||
///
|
||||
/// @param controlDataDesc vertex buffer descriptor for the control vertex data
|
||||
///
|
||||
/// @param controlVertices vertex buffer with the control vertices data
|
||||
///
|
||||
/// @param outputDuDesc vertex buffer descriptor for the U derivative output data
|
||||
///
|
||||
/// @param outputDuData output vertex buffer for the U derivative data
|
||||
///
|
||||
/// @param outputDvDesc vertex buffer descriptor for the V deriv output data
|
||||
///
|
||||
/// @param outputDvData output vertex buffer for the V derivative data
|
||||
///
|
||||
template<class CONTROL_BUFFER, class OUTPUT_BUFFER>
|
||||
int UpdateDerivs( OsdCpuEvalStencilsContext * context,
|
||||
OsdVertexBufferDescriptor const & controlDataDesc, CONTROL_BUFFER *controlVertices,
|
||||
OsdVertexBufferDescriptor const & outputDuDesc, OUTPUT_BUFFER *outputDuData,
|
||||
OsdVertexBufferDescriptor const & outputDvDesc, OUTPUT_BUFFER *outputDvData ) {
|
||||
|
||||
if (not context->GetStencilTables()->GetNumStencils())
|
||||
return 0;
|
||||
|
||||
context->BindControlData( controlDataDesc, controlVertices );
|
||||
|
||||
context->BindOutputDerivData( outputDuDesc, outputDuData, outputDvDesc, outputDvData );
|
||||
|
||||
int n = _UpdateDerivs( context );
|
||||
|
||||
context->Unbind();
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/// Waits until all running subdivision kernels finish.
|
||||
void Synchronize();
|
||||
|
||||
private:
|
||||
|
||||
int _UpdateValues( OsdCpuEvalStencilsContext * context );
|
||||
int _UpdateDerivs( OsdCpuEvalStencilsContext * context );
|
||||
|
||||
};
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif // FAR_CPU_EVALSTENCILS_CONTROLLER_H
|
@ -86,10 +86,11 @@ public:
|
||||
///
|
||||
template<class VERTEX_BUFFER>
|
||||
void UpdateVertexTexture(VERTEX_BUFFER *vbo, ID3D11DeviceContext *pd3d11DeviceContext) {
|
||||
updateVertexTexture(vbo->BindD3D11Buffer(pd3d11DeviceContext),
|
||||
pd3d11DeviceContext,
|
||||
vbo->GetNumVertices(),
|
||||
vbo->GetNumElements());
|
||||
if (vbo)
|
||||
updateVertexTexture(vbo->BindD3D11Buffer(pd3d11DeviceContext),
|
||||
pd3d11DeviceContext,
|
||||
vbo->GetNumVertices(),
|
||||
vbo->GetNumElements());
|
||||
}
|
||||
|
||||
ID3D11Buffer *patchIndexBuffer;
|
||||
|
@ -70,7 +70,8 @@ public:
|
||||
///
|
||||
template<class VERTEX_BUFFER>
|
||||
void UpdateVertexTexture(VERTEX_BUFFER *vbo) {
|
||||
updateVertexTexture(vbo->BindVBO(), vbo->GetNumElements());
|
||||
if (vbo)
|
||||
updateVertexTexture(vbo->BindVBO(), vbo->GetNumElements());
|
||||
}
|
||||
|
||||
/// true if the GL version detected supports shader tessellation
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include "../osd/opengl.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
@ -94,20 +95,30 @@ OsdGLSLTransformFeedbackKernelBundle::Compile(int numVertexElements, int numVary
|
||||
glCompileShader(shader);
|
||||
glAttachShader(_program, shader);
|
||||
|
||||
const char *outputs[4];
|
||||
int nOutputs = 0;
|
||||
std::vector<std::string> outputs;
|
||||
|
||||
// position and custom vertex data are stored same buffer whereas varying data
|
||||
// exists on another buffer. "gl_NextBuffer" identifier helps to split them.
|
||||
if (numVertexElements > 0)
|
||||
outputs[nOutputs++] = "outVertexData";
|
||||
if (numVaryingElements > 0) {
|
||||
if (nOutputs > 0)
|
||||
outputs[nOutputs++] = "gl_NextBuffer";
|
||||
outputs[nOutputs++] = "outVaryingData";
|
||||
for (int i = 0; i < numVertexElements; ++i) {
|
||||
char attrName[32];
|
||||
snprintf(attrName, 32, "outVertexData[%d]", i);
|
||||
outputs.push_back(attrName);
|
||||
}
|
||||
for (int i = 0; i < numVaryingElements; ++i) {
|
||||
if (i == 0 and (not outputs.empty())) {
|
||||
outputs.push_back("gl_NextBuffer");
|
||||
}
|
||||
char attrName[32];
|
||||
snprintf(attrName, 32, "outVaryingData[%d]", i);
|
||||
outputs.push_back(attrName);
|
||||
}
|
||||
std::vector<const char *> pOutputs;
|
||||
for (size_t i = 0; i < outputs.size(); ++i) {
|
||||
pOutputs.push_back(&outputs[i][0]);
|
||||
}
|
||||
|
||||
glTransformFeedbackVaryings(_program, nOutputs, outputs, GL_INTERLEAVED_ATTRIBS);
|
||||
glTransformFeedbackVaryings(_program, (GLsizei)outputs.size(),
|
||||
&pOutputs[0], GL_INTERLEAVED_ATTRIBS);
|
||||
|
||||
OSD_DEBUG_CHECK_GL_ERROR("Transform feedback initialize\n");
|
||||
|
||||
|
152
opensubdiv/osd/ompEvalStencilsController.cpp
Normal file
@ -0,0 +1,152 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License
|
||||
// and the following modification to it: Section 6 Trademarks.
|
||||
// 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 for reproducing
|
||||
// the content of the NOTICE file.
|
||||
//
|
||||
// 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 "../osd/ompEvalStencilsController.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
OsdOmpEvalStencilsController::OsdOmpEvalStencilsController(int numThreads) {
|
||||
|
||||
_numThreads = (numThreads == -1) ? omp_get_num_procs() : numThreads;
|
||||
}
|
||||
|
||||
OsdOmpEvalStencilsController::~OsdOmpEvalStencilsController() {
|
||||
}
|
||||
|
||||
int
|
||||
OsdOmpEvalStencilsController::_UpdateValues( OsdCpuEvalStencilsContext * context ) {
|
||||
|
||||
int result=0;
|
||||
|
||||
FarStencilTables const * stencils = context->GetStencilTables();
|
||||
|
||||
int nstencils = stencils->GetNumStencils();
|
||||
if (not nstencils)
|
||||
return result;
|
||||
|
||||
OsdVertexBufferDescriptor ctrlDesc = context->GetControlDataDescriptor(),
|
||||
outDesc = context->GetOutputDataDescriptor();
|
||||
|
||||
// make sure that we have control data to work with
|
||||
if (not ctrlDesc.CanEval(outDesc))
|
||||
return 0;
|
||||
|
||||
float const * ctrl = context->GetControlData() + ctrlDesc.offset;
|
||||
|
||||
if (not ctrl)
|
||||
return result;
|
||||
|
||||
#pragma omp parallel for
|
||||
for (int i=0; i<nstencils; ++i) {
|
||||
|
||||
int size = stencils->GetSizes()[i],
|
||||
offset = stencils->GetOffsets()[i];
|
||||
|
||||
int const * index = &stencils->GetControlIndices().at(offset);
|
||||
|
||||
float const * weight = &stencils->GetWeights().at(offset);
|
||||
|
||||
float * out = context->GetOutputData() + i * outDesc.stride + outDesc.offset;
|
||||
|
||||
memset(out, 0, outDesc.length*sizeof(float));
|
||||
|
||||
for (int j=0; j<size; ++j, ++index, ++weight) {
|
||||
|
||||
float const * cv = ctrl + (*index)*ctrlDesc.stride;
|
||||
|
||||
for (int k=0; k<outDesc.length; ++k) {
|
||||
out[k] += cv[k] * (*weight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nstencils;
|
||||
}
|
||||
|
||||
int
|
||||
OsdOmpEvalStencilsController::_UpdateDerivs( OsdCpuEvalStencilsContext * context ) {
|
||||
|
||||
int result=0;
|
||||
|
||||
FarStencilTables const * stencils = context->GetStencilTables();
|
||||
|
||||
int nstencils = stencils->GetNumStencils();
|
||||
if (not nstencils)
|
||||
return result;
|
||||
|
||||
OsdVertexBufferDescriptor ctrlDesc = context->GetControlDataDescriptor(),
|
||||
duDesc = context->GetDuDataDescriptor(),
|
||||
dvDesc = context->GetDvDataDescriptor();
|
||||
|
||||
// make sure that we have control data to work with
|
||||
if (not (ctrlDesc.CanEval(duDesc) and ctrlDesc.CanEval(dvDesc)))
|
||||
return 0;
|
||||
|
||||
float const * ctrl = context->GetControlData() + ctrlDesc.offset;
|
||||
|
||||
if (not ctrl)
|
||||
return result;
|
||||
|
||||
#pragma omp parallel for
|
||||
for (int i=0; i<nstencils; ++i) {
|
||||
|
||||
int size = stencils->GetSizes()[i],
|
||||
offset = stencils->GetOffsets()[i];
|
||||
|
||||
int const * index = &stencils->GetControlIndices().at(offset);
|
||||
|
||||
float const * duweight = &stencils->GetDuWeights().at(offset),
|
||||
* dvweight = &stencils->GetDvWeights().at(offset);
|
||||
|
||||
float * du = context->GetOutputUDerivData() + i * duDesc.stride + duDesc.offset,
|
||||
* dv = context->GetOutputVDerivData() + i * dvDesc.stride + dvDesc.offset;
|
||||
|
||||
memset(du, 0, duDesc.length*sizeof(float));
|
||||
memset(dv, 0, dvDesc.length*sizeof(float));
|
||||
|
||||
for (int j=0; j<size; ++j, ++index, ++duweight, ++dvweight) {
|
||||
|
||||
float const * cv = ctrl + (*index)*ctrlDesc.stride;
|
||||
|
||||
for (int k=0; k<duDesc.length; ++k) {
|
||||
du[k] += cv[k] * (*duweight);
|
||||
dv[k] += cv[k] * (*dvweight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nstencils;
|
||||
}
|
||||
|
||||
void
|
||||
OsdOmpEvalStencilsController::Synchronize() {
|
||||
}
|
||||
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
154
opensubdiv/osd/ompEvalStencilsController.h
Normal file
@ -0,0 +1,154 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License
|
||||
// and the following modification to it: Section 6 Trademarks.
|
||||
// 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 for reproducing
|
||||
// the content of the NOTICE file.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#ifndef FAR_OMP_EVALSTENCILS_CONTROLLER_H
|
||||
#define FAR_OMP_EVALSTENCILS_CONTROLLER_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../osd/cpuEvalStencilsContext.h"
|
||||
|
||||
#ifdef OPENSUBDIV_HAS_OPENMP
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
///
|
||||
/// \brief CPU stencils evaluation controller
|
||||
///
|
||||
/// OsdCpuStencilsController is a compute controller class to launch
|
||||
/// single threaded CPU stencil evalution kernels.
|
||||
///
|
||||
/// Controller entities execute requests from Context instances that they share
|
||||
/// common interfaces with. Controllers are attached to discrete compute devices
|
||||
/// and share the devices resources with Context entities.
|
||||
///
|
||||
class OsdOmpEvalStencilsController {
|
||||
public:
|
||||
|
||||
/// \brief Constructor.
|
||||
///
|
||||
/// @param numThreads specifies how many openmp parallel threads to use.
|
||||
/// -1 attempts to use all available processors.
|
||||
///
|
||||
OsdOmpEvalStencilsController(int numThreads=-1);
|
||||
|
||||
/// \brief Destructor.
|
||||
~OsdOmpEvalStencilsController();
|
||||
|
||||
|
||||
/// \brief Applies stencil weights to the control vertex data
|
||||
///
|
||||
/// Applies the stencil weights to the control vertex data to evaluate the
|
||||
/// interpolated limit positions at the parametric locations of the stencils
|
||||
///
|
||||
/// @param context the OsdCpuEvalStencilsContext with the stencil weights
|
||||
///
|
||||
/// @param controlDataDesc vertex buffer descriptor for the control vertex data
|
||||
///
|
||||
/// @param controlVertices vertex buffer with the control vertices data
|
||||
///
|
||||
/// @param outputDataDesc vertex buffer descriptor for the output vertex data
|
||||
///
|
||||
/// @param outputData output vertex buffer for the interpolated data
|
||||
///
|
||||
template<class CONTROL_BUFFER, class OUTPUT_BUFFER>
|
||||
int UpdateValues( OsdCpuEvalStencilsContext * context,
|
||||
OsdVertexBufferDescriptor const & controlDataDesc, CONTROL_BUFFER *controlVertices,
|
||||
OsdVertexBufferDescriptor const & outputDataDesc, OUTPUT_BUFFER *outputData ) {
|
||||
|
||||
if (not context->GetStencilTables()->GetNumStencils())
|
||||
return 0;
|
||||
|
||||
omp_set_num_threads(_numThreads);
|
||||
|
||||
context->BindControlData( controlDataDesc, controlVertices );
|
||||
context->BindOutputData( outputDataDesc, outputData );
|
||||
|
||||
int n = _UpdateValues( context );
|
||||
|
||||
context->Unbind();
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/// \brief Applies derivative stencil weights to the control vertex data
|
||||
///
|
||||
/// Computes the U and V derivative stencils to the control vertex data at
|
||||
/// the parametric locations contained in each stencil
|
||||
///
|
||||
/// @param context the OsdCpuEvalStencilsContext with the stencil weights
|
||||
///
|
||||
/// @param controlDataDesc vertex buffer descriptor for the control vertex data
|
||||
///
|
||||
/// @param controlVertices vertex buffer with the control vertices data
|
||||
///
|
||||
/// @param outputDuDesc vertex buffer descriptor for the U derivative output data
|
||||
///
|
||||
/// @param outputDuData output vertex buffer for the U derivative data
|
||||
///
|
||||
/// @param outputDvDesc vertex buffer descriptor for the V deriv output data
|
||||
///
|
||||
/// @param outputDvData output vertex buffer for the V derivative data
|
||||
///
|
||||
template<class CONTROL_BUFFER, class OUTPUT_BUFFER>
|
||||
int UpdateDerivs( OsdCpuEvalStencilsContext * context,
|
||||
OsdVertexBufferDescriptor const & controlDataDesc, CONTROL_BUFFER *controlVertices,
|
||||
OsdVertexBufferDescriptor const & outputDuDesc, OUTPUT_BUFFER *outputDuData,
|
||||
OsdVertexBufferDescriptor const & outputDvDesc, OUTPUT_BUFFER *outputDvData ) {
|
||||
|
||||
if (not context->GetStencilTables()->GetNumStencils())
|
||||
return 0;
|
||||
|
||||
context->BindControlData( controlDataDesc, controlVertices );
|
||||
|
||||
context->BindOutputDerivData( outputDuDesc, outputDuData, outputDvDesc, outputDvData );
|
||||
|
||||
int n = _UpdateDerivs( context );
|
||||
|
||||
context->Unbind();
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/// Waits until all running subdivision kernels finish.
|
||||
void Synchronize();
|
||||
|
||||
private:
|
||||
|
||||
int _UpdateValues( OsdCpuEvalStencilsContext * context );
|
||||
int _UpdateDerivs( OsdCpuEvalStencilsContext * context );
|
||||
|
||||
int _numThreads;
|
||||
};
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif // FAR_OMP_EVALSTENCILS_CONTROLLER_H
|
197
opensubdiv/osd/tbbEvalStencilsController.cpp
Normal file
@ -0,0 +1,197 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License
|
||||
// and the following modification to it: Section 6 Trademarks.
|
||||
// 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 for reproducing
|
||||
// the content of the NOTICE file.
|
||||
//
|
||||
// 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 "../osd/tbbEvalStencilsController.h"
|
||||
|
||||
#include <tbb/parallel_for.h>
|
||||
#include <tbb/task_scheduler_init.h>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
#define grain_size 200
|
||||
|
||||
OsdTbbEvalStencilsController::OsdTbbEvalStencilsController(int numThreads) {
|
||||
|
||||
_numThreads = numThreads > 0 ? numThreads : tbb::task_scheduler_init::automatic;
|
||||
|
||||
tbb::task_scheduler_init init(numThreads);
|
||||
}
|
||||
|
||||
OsdTbbEvalStencilsController::~OsdTbbEvalStencilsController() {
|
||||
}
|
||||
|
||||
|
||||
class StencilKernel {
|
||||
|
||||
public:
|
||||
enum Mode { UNDEFINED, POINT, U_DERIV, V_DERIV };
|
||||
|
||||
StencilKernel( FarStencilTables const * stencils,
|
||||
OsdVertexBufferDescriptor ctrlDesc,
|
||||
float const * ctrlData ) :
|
||||
_stencils(stencils),
|
||||
_mode(UNDEFINED),
|
||||
_ctrlDesc(ctrlDesc),
|
||||
_length(0),
|
||||
_outStride(0),
|
||||
_outData(0) {
|
||||
|
||||
_ctrlData = ctrlData + ctrlDesc.offset;
|
||||
}
|
||||
|
||||
bool SetOutput(Mode mode, OsdVertexBufferDescriptor outDesc, float * outData) {
|
||||
|
||||
if (_ctrlDesc.CanEval(outDesc)) {
|
||||
_mode = mode;
|
||||
_length = outDesc.length;
|
||||
_outStride = outDesc.stride;
|
||||
_outData = outData + outDesc.offset;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void operator() (tbb::blocked_range<int> const &r) const {
|
||||
|
||||
assert(_stencils and _ctrlData and _length and _outStride and _outData);
|
||||
|
||||
int offset = _stencils->GetOffsets()[r.begin()];
|
||||
|
||||
int const * sizes = &_stencils->GetSizes()[r.begin()],
|
||||
* index = &_stencils->GetControlIndices()[offset];
|
||||
|
||||
float const * weight;
|
||||
|
||||
switch (_mode) {
|
||||
case POINT : weight = &_stencils->GetWeights()[offset]; break;
|
||||
case U_DERIV : weight = &_stencils->GetDuWeights()[offset]; break;
|
||||
case V_DERIV : weight = &_stencils->GetDvWeights()[offset]; break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
assert( weight);
|
||||
|
||||
float * out = _outData + r.begin() * _outStride;
|
||||
|
||||
for (int i=r.begin(); i<r.end(); ++i, ++sizes) {
|
||||
|
||||
memset( out, 0, _length * sizeof(float) );
|
||||
|
||||
for (int j=0; j<(*sizes); ++j, ++index, ++weight) {
|
||||
|
||||
float const * cv = _ctrlData + (*index)*_ctrlDesc.stride;
|
||||
|
||||
for (int k=0; k<_length; ++k) {
|
||||
out[k] += cv[k] * (*weight);
|
||||
}
|
||||
}
|
||||
out+=_outStride;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
FarStencilTables const * _stencils;
|
||||
|
||||
Mode _mode;
|
||||
|
||||
OsdVertexBufferDescriptor _ctrlDesc;
|
||||
float const * _ctrlData;
|
||||
|
||||
int _length,
|
||||
_outStride;
|
||||
|
||||
float * _outData;
|
||||
};
|
||||
|
||||
int
|
||||
OsdTbbEvalStencilsController::_UpdateValues( OsdCpuEvalStencilsContext * context ) {
|
||||
|
||||
FarStencilTables const * stencils = context->GetStencilTables();
|
||||
if (not stencils)
|
||||
return 0;
|
||||
|
||||
int nstencils = stencils->GetNumStencils();
|
||||
if (not nstencils)
|
||||
return 0;
|
||||
|
||||
StencilKernel kernel( stencils, context->GetControlDataDescriptor(),
|
||||
context->GetControlData() );
|
||||
|
||||
|
||||
if (not kernel.SetOutput( StencilKernel::POINT,
|
||||
context->GetOutputDataDescriptor(),
|
||||
context->GetOutputData() ))
|
||||
return 0;
|
||||
|
||||
tbb::blocked_range<int> range(0, nstencils, grain_size);
|
||||
|
||||
tbb::parallel_for(range, kernel);
|
||||
|
||||
return nstencils;
|
||||
}
|
||||
|
||||
int
|
||||
OsdTbbEvalStencilsController::_UpdateDerivs( OsdCpuEvalStencilsContext * context ) {
|
||||
|
||||
FarStencilTables const * stencils = context->GetStencilTables();
|
||||
if (not stencils)
|
||||
return 0;
|
||||
|
||||
int nstencils = stencils->GetNumStencils();
|
||||
if (not nstencils)
|
||||
return 0;
|
||||
|
||||
tbb::blocked_range<int> range(0, nstencils, grain_size);
|
||||
|
||||
StencilKernel kernel( stencils, context->GetControlDataDescriptor(),
|
||||
context->GetControlData() );
|
||||
|
||||
if (not kernel.SetOutput( StencilKernel::U_DERIV,
|
||||
context->GetDuDataDescriptor(),
|
||||
context->GetOutputUDerivData() ) )
|
||||
return 0;
|
||||
|
||||
tbb::parallel_for(range, kernel);
|
||||
|
||||
if (not kernel.SetOutput( StencilKernel::V_DERIV,
|
||||
context->GetDvDataDescriptor(),
|
||||
context->GetOutputVDerivData() ) )
|
||||
return 0;
|
||||
|
||||
tbb::parallel_for(range, kernel);
|
||||
|
||||
return nstencils;
|
||||
}
|
||||
|
||||
void
|
||||
OsdTbbEvalStencilsController::Synchronize() {
|
||||
}
|
||||
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
149
opensubdiv/osd/tbbEvalStencilsController.h
Normal file
@ -0,0 +1,149 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License
|
||||
// and the following modification to it: Section 6 Trademarks.
|
||||
// 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 for reproducing
|
||||
// the content of the NOTICE file.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#ifndef FAR_TBB_EVALSTENCILS_CONTROLLER_H
|
||||
#define FAR_TBB_EVALSTENCILS_CONTROLLER_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../osd/cpuEvalStencilsContext.h"
|
||||
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
///
|
||||
/// \brief CPU stencils evaluation controller
|
||||
///
|
||||
/// OsdCpuStencilsController is a compute controller class to launch
|
||||
/// single threaded CPU stencil evalution kernels.
|
||||
///
|
||||
/// Controller entities execute requests from Context instances that they share
|
||||
/// common interfaces with. Controllers are attached to discrete compute devices
|
||||
/// and share the devices resources with Context entities.
|
||||
///
|
||||
class OsdTbbEvalStencilsController {
|
||||
public:
|
||||
|
||||
/// \brief Constructor.
|
||||
///
|
||||
/// @param numThreads specifies how many openmp parallel threads to use.
|
||||
/// -1 attempts to use all available processors.
|
||||
///
|
||||
OsdTbbEvalStencilsController(int numThreads=-1);
|
||||
|
||||
/// \brief Destructor.
|
||||
~OsdTbbEvalStencilsController();
|
||||
|
||||
|
||||
/// \brief Applies stencil weights to the control vertex data
|
||||
///
|
||||
/// Applies the stencil weights to the control vertex data to evaluate the
|
||||
/// interpolated limit positions at the parametric locations of the stencils
|
||||
///
|
||||
/// @param context the OsdCpuEvalStencilsContext with the stencil weights
|
||||
///
|
||||
/// @param controlDataDesc vertex buffer descriptor for the control vertex data
|
||||
///
|
||||
/// @param controlVertices vertex buffer with the control vertices data
|
||||
///
|
||||
/// @param outputDataDesc vertex buffer descriptor for the output vertex data
|
||||
///
|
||||
/// @param outputData output vertex buffer for the interpolated data
|
||||
///
|
||||
template<class CONTROL_BUFFER, class OUTPUT_BUFFER>
|
||||
int UpdateValues( OsdCpuEvalStencilsContext * context,
|
||||
OsdVertexBufferDescriptor const & controlDataDesc, CONTROL_BUFFER *controlVertices,
|
||||
OsdVertexBufferDescriptor const & outputDataDesc, OUTPUT_BUFFER *outputData ) {
|
||||
|
||||
if (not context->GetStencilTables()->GetNumStencils())
|
||||
return 0;
|
||||
|
||||
context->BindControlData( controlDataDesc, controlVertices );
|
||||
context->BindOutputData( outputDataDesc, outputData );
|
||||
|
||||
int n = _UpdateValues( context );
|
||||
|
||||
context->Unbind();
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/// \brief Applies derivative stencil weights to the control vertex data
|
||||
///
|
||||
/// Computes the U and V derivative stencils to the control vertex data at
|
||||
/// the parametric locations contained in each stencil
|
||||
///
|
||||
/// @param context the OsdCpuEvalStencilsContext with the stencil weights
|
||||
///
|
||||
/// @param controlDataDesc vertex buffer descriptor for the control vertex data
|
||||
///
|
||||
/// @param controlVertices vertex buffer with the control vertices data
|
||||
///
|
||||
/// @param outputDuDesc vertex buffer descriptor for the U derivative output data
|
||||
///
|
||||
/// @param outputDuData output vertex buffer for the U derivative data
|
||||
///
|
||||
/// @param outputDvDesc vertex buffer descriptor for the V deriv output data
|
||||
///
|
||||
/// @param outputDvData output vertex buffer for the V derivative data
|
||||
///
|
||||
template<class CONTROL_BUFFER, class OUTPUT_BUFFER>
|
||||
int UpdateDerivs( OsdCpuEvalStencilsContext * context,
|
||||
OsdVertexBufferDescriptor const & controlDataDesc, CONTROL_BUFFER *controlVertices,
|
||||
OsdVertexBufferDescriptor const & outputDuDesc, OUTPUT_BUFFER *outputDuData,
|
||||
OsdVertexBufferDescriptor const & outputDvDesc, OUTPUT_BUFFER *outputDvData ) {
|
||||
|
||||
if (not context->GetStencilTables()->GetNumStencils())
|
||||
return 0;
|
||||
|
||||
context->BindControlData( controlDataDesc, controlVertices );
|
||||
|
||||
context->BindOutputDerivData( outputDuDesc, outputDuData, outputDvDesc, outputDvData );
|
||||
|
||||
int n = _UpdateDerivs( context );
|
||||
|
||||
context->Unbind();
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/// Waits until all running subdivision kernels finish.
|
||||
void Synchronize();
|
||||
|
||||
private:
|
||||
|
||||
int _UpdateValues( OsdCpuEvalStencilsContext * context );
|
||||
int _UpdateDerivs( OsdCpuEvalStencilsContext * context );
|
||||
|
||||
int _numThreads;
|
||||
};
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif // FAR_TBB_EVALSTENCILS_CONTROLLER_H
|
@ -56,12 +56,12 @@ struct OsdVertexDescriptor {
|
||||
numVertexElements = numVertexElem;
|
||||
numVaryingElements = numVaryingElem;
|
||||
}
|
||||
|
||||
|
||||
/// Resets the descriptor
|
||||
void Reset() {
|
||||
numVertexElements = numVaryingElements = 0;
|
||||
}
|
||||
|
||||
|
||||
/// Returns the total number of elements (vertex + varying)
|
||||
int GetNumElements() const {
|
||||
return numVertexElements + numVaryingElements;
|
||||
@ -75,7 +75,7 @@ struct OsdVertexDescriptor {
|
||||
/// Resets the contents of vertex & varying primvar data buffers for a given
|
||||
/// vertex.
|
||||
///
|
||||
/// @param vertex The float array containing the vertex-interpolated primvar
|
||||
/// @param vertex The float array containing the vertex-interpolated primvar
|
||||
/// data that needs to be reset.
|
||||
///
|
||||
/// @param varying The float array containing the varying-interpolated primvar
|
||||
@ -85,15 +85,15 @@ struct OsdVertexDescriptor {
|
||||
///
|
||||
void Clear(float *vertex, float *varying, int index) const {
|
||||
if (vertex) {
|
||||
memset(vertex+index*numVertexElements, 0, sizeof(float)*numVertexElements);
|
||||
memset(vertex+index*numVertexElements, 0, sizeof(float)*numVertexElements);
|
||||
}
|
||||
|
||||
if (varying) {
|
||||
memset(varying+index*numVaryingElements, 0, sizeof(float)*numVaryingElements);
|
||||
|
||||
memset(varying+index*numVaryingElements, 0, sizeof(float)*numVaryingElements);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Applies "dst += src*weight" to "vertex" primvar data in a vertex buffer.
|
||||
///
|
||||
/// @param vertex The VertexData buffer
|
||||
@ -104,14 +104,14 @@ struct OsdVertexDescriptor {
|
||||
///
|
||||
/// @param weight Weight applied to the primvar data.
|
||||
///
|
||||
inline
|
||||
inline
|
||||
void AddWithWeight(float *vertex, int dstIndex, int srcIndex, float weight) const {
|
||||
int d = dstIndex * numVertexElements;
|
||||
int s = srcIndex * numVertexElements;
|
||||
int s = srcIndex * numVertexElements;
|
||||
#if defined ( __INTEL_COMPILER ) or defined ( __ICC )
|
||||
#pragma ivdep
|
||||
#pragma ivdep
|
||||
#pragma vector aligned
|
||||
#endif
|
||||
#endif
|
||||
for (int i = 0; i < numVertexElements; ++i)
|
||||
vertex[d++] += vertex[s++] * weight;
|
||||
}
|
||||
@ -131,9 +131,9 @@ struct OsdVertexDescriptor {
|
||||
int d = dstIndex * numVaryingElements;
|
||||
int s = srcIndex * numVaryingElements;
|
||||
#if defined ( __INTEL_COMPILER ) or defined ( __ICC )
|
||||
#pragma ivdep
|
||||
#pragma ivdep
|
||||
#pragma vector aligned
|
||||
#endif
|
||||
#endif
|
||||
for (int i = 0; i < numVaryingElements; ++i)
|
||||
varying[d++] += varying[s++] * weight;
|
||||
}
|
||||
@ -191,16 +191,15 @@ struct OsdVertexBufferDescriptor {
|
||||
|
||||
/// True if the descriptor values are internally consistent
|
||||
bool IsValid() const {
|
||||
return (length>0) and (offset<length) and (stride>=length);
|
||||
return ((length>0) and (offset<stride) and (length<=stride-offset));
|
||||
}
|
||||
|
||||
|
||||
/// True if the 'other' descriptor can be used as a destination for
|
||||
/// data evaluations.
|
||||
bool CanEval( OsdVertexBufferDescriptor const & other ) const {
|
||||
return IsValid() and
|
||||
other.IsValid() and
|
||||
(length==other.length) and
|
||||
(other.length <= (stride-offset));
|
||||
return (IsValid() and
|
||||
other.IsValid() and
|
||||
(length==other.length));
|
||||
}
|
||||
|
||||
/// Resets the descriptor to default
|
||||
|
@ -26,6 +26,6 @@
|
||||
#ifndef OPENSUBDIV_VERSION_H
|
||||
#define OPENSUBDIV_VERSION_H
|
||||
|
||||
#define OPENSUBDIV_VERSION v2_1_0
|
||||
#define OPENSUBDIV_VERSION v2_2_0
|
||||
|
||||
#endif /* OPENSUBDIV_VERSION_H */
|
||||
|
@ -51,7 +51,7 @@ if ( OPENCL_FOUND )
|
||||
endif()
|
||||
|
||||
|
||||
add_executable(osd_regression
|
||||
_add_possibly_cuda_executable(osd_regression
|
||||
${SOURCE_FILES}
|
||||
)
|
||||
|
||||
|