OpenSubdiv: Changes in C-API

- Made OpenSubdiv_GLMesh private
  Previously, it was still accessible via C-API from C++ code.

- Don't implicitly refine evaluator when updating coarse positions,
  now there is an explicit call to do this.

  Allows to first apply all changes to the coarse mesh and then
  refine once.

- Added coarse positions update from a continuous buffer with given
  starts offset and stride.

  Allows to update coarse positions directly from MVert array.

- Refiner is no longer freed when CPU evaluator is created.
  Allows to re-use refiner for multiple purposes.
This commit is contained in:
Sergey Sharybin 2018-07-11 10:36:13 +02:00
parent 3eab8156d3
commit c37ca43720
6 changed files with 160 additions and 93 deletions

@ -70,6 +70,7 @@
#include <opensubdiv/far/stencilTable.h>
#include <opensubdiv/far/primvarRefiner.h>
#include "opensubdiv_gl_mesh.h"
#include "opensubdiv_intern.h"
#include "opensubdiv_topology_refiner.h"

@ -32,22 +32,12 @@ extern "C" {
// Types declaration.
struct OpenSubdiv_GLMesh;
struct OpenSubdiv_GLMeshDescr;
struct OpenSubdiv_GLMeshFVarData;
struct OpenSubdiv_TopologyRefinerDescr;
typedef struct OpenSubdiv_GLMesh OpenSubdiv_GLMesh;
#ifdef __cplusplus
struct OpenSubdiv_GLMeshDescr;
typedef struct OpenSubdiv_GLMesh {
int evaluator_type;
OpenSubdiv_GLMeshDescr *descriptor;
OpenSubdiv_TopologyRefinerDescr *topology_refiner;
OpenSubdiv_GLMeshFVarData *fvar_data;
} OpenSubdiv_GLMesh;
#endif
// Keep this a bitmask os it's possible to pass available
// evaluators to Blender.
enum {
@ -86,11 +76,7 @@ void openSubdiv_osdGLMeshBindVertexBuffer(OpenSubdiv_GLMesh *gl_mesh);
const struct OpenSubdiv_TopologyRefinerDescr *openSubdiv_getGLMeshTopologyRefiner(
OpenSubdiv_GLMesh *gl_mesh);
/* ** Initialize/Deinitialize global OpenGL drawing buffers/GLSL programs ** */
bool openSubdiv_osdGLDisplayInit(void);
void openSubdiv_osdGLDisplayDeinit(void);
/* ** Evaluator API ** */
/* ============================= Evaluator API ============================== */
struct OpenSubdiv_EvaluatorDescr;
typedef struct OpenSubdiv_EvaluatorDescr OpenSubdiv_EvaluatorDescr;
@ -100,17 +86,29 @@ OpenSubdiv_EvaluatorDescr *openSubdiv_createEvaluatorDescr(
struct OpenSubdiv_TopologyRefinerDescr *topology_refiner,
int subsurf_level);
void openSubdiv_deleteEvaluatorDescr(OpenSubdiv_EvaluatorDescr *evaluator_descr);
void openSubdiv_deleteEvaluatorDescr(
OpenSubdiv_EvaluatorDescr *evaluator_descr);
void openSubdiv_setEvaluatorCoarsePositions(OpenSubdiv_EvaluatorDescr *evaluator_descr,
float *positions,
int start_vert,
int num_vert);
void openSubdiv_setEvaluatorCoarsePositions(
OpenSubdiv_EvaluatorDescr *evaluator_descr,
const float *positions,
int start_vertex_index,
int num_vertices);
void openSubdiv_setEvaluatorVaryingData(
OpenSubdiv_EvaluatorDescr *evaluator_descr,
const float *varying_data,
int start_vertex_index,
int num_vertices);
void openSubdiv_setEvaluatorVaryingData(OpenSubdiv_EvaluatorDescr *evaluator_descr,
float *varying_data,
int start_vert,
int num_vert);
void openSubdiv_setEvaluatorCoarsePositionsFromBuffer(
OpenSubdiv_EvaluatorDescr *evaluator_descr,
const void *buffer,
int start_offset,
int stride,
int start_vertex_index,
int num_vertices);
void openSubdiv_refineEvaluator(OpenSubdiv_EvaluatorDescr *evaluator_descr);
void openSubdiv_evaluateLimit(OpenSubdiv_EvaluatorDescr *evaluator_descr,
int osd_face_index,
@ -124,15 +122,18 @@ void openSubdiv_evaluateVarying(OpenSubdiv_EvaluatorDescr *evaluator_descr,
float face_u, float face_v,
float varying[3]);
/* ** Actual drawing ** */
/* ============================== Mesh drawing =============================== */
/* Initialize/Deinitialize global OpenGL drawing buffers/GLSL programs. */
bool openSubdiv_osdGLDisplayInit(void);
void openSubdiv_osdGLDisplayDeinit(void);
/* Initialize all the invariants which stays the same for every single path,
* for example lighting model stays untouched for the whole mesh.
*
* TODO(sergey): Some of the stuff could be initialized once for all meshes.
*/
void openSubdiv_osdGLMeshDisplayPrepare(int use_osd_glsl,
int active_uv_index);
void openSubdiv_osdGLMeshDisplayPrepare(int use_osd_glsl, int active_uv_index);
/* Draw specified patches. */
void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh,
@ -140,12 +141,15 @@ void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh,
int start_patch,
int num_patches);
void openSubdiv_osdGLAllocFVar(struct OpenSubdiv_TopologyRefinerDescr *topology_refiner,
OpenSubdiv_GLMesh *gl_mesh,
const float *fvar_data);
void openSubdiv_osdGLAllocFVar(
struct OpenSubdiv_TopologyRefinerDescr *topology_refiner,
OpenSubdiv_GLMesh *gl_mesh,
const float *fvar_data);
void openSubdiv_osdGLDestroyFVar(OpenSubdiv_GLMesh *gl_mesh);
/* ** Utility functions ** */
/* =========================== Utility functions ============================ */
int openSubdiv_getAvailableEvaluators(void);
void openSubdiv_init(void);
void openSubdiv_cleanup(void);

@ -118,7 +118,7 @@ protected:
* is small enough and better to be allocated in stack rather
* than in heap.
*
* TODO(sergey): Check if bare arrays could be used by CPU evalautor.
* TODO(sergey): Check if bare arrays could be used by CPU evaluator.
*/
template <int element_size, int num_verts>
class StackAllocatedBuffer {
@ -142,7 +142,7 @@ protected:
/* Volatile evaluator which can be used from threads.
*
* TODO(sergey): Make it possible to evaluate coordinates in chuncks.
* TODO(sergey): Make it possible to evaluate coordinates in chunks.
*/
template<typename SRC_VERTEX_BUFFER,
typename EVAL_VERTEX_BUFFER,
@ -347,85 +347,80 @@ OpenSubdiv_EvaluatorDescr *openSubdiv_createEvaluatorDescr(
/* Happens on bad topology. */
return NULL;
}
const StencilTable *vertex_stencils = NULL;
const StencilTable *varying_stencils = NULL;
int num_total_verts = 0;
/* Apply uniform refinement to the mesh so that we can use the
* limit evaluation API features.
*/
TopologyRefiner::UniformOptions options(subsurf_level);
refiner->RefineUniform(options);
/* Generate stencil table to update the bi-cubic patches control
* vertices after they have been re-posed (both for vertex & varying
* interpolation).
*/
StencilTableFactory::Options soptions;
soptions.generateOffsets = true;
soptions.generateIntermediateLevels = false;
vertex_stencils = StencilTableFactory::Create(*refiner, soptions);
soptions.interpolationMode = StencilTableFactory::INTERPOLATE_VARYING;
varying_stencils = StencilTableFactory::Create(*refiner, soptions);
StencilTableFactory::Options vertex_stencil_options;
vertex_stencil_options.generateOffsets = true;
vertex_stencil_options.generateIntermediateLevels = false;
const StencilTable *vertex_stencils =
StencilTableFactory::Create(*refiner, vertex_stencil_options);
StencilTableFactory::Options varying_stencil_options;
varying_stencil_options.generateOffsets = true;
varying_stencil_options.generateIntermediateLevels = false;
varying_stencil_options.interpolationMode =
StencilTableFactory::INTERPOLATE_VARYING;
const StencilTable *varying_stencils =
StencilTableFactory::Create(*refiner, varying_stencil_options);
/* Generate bi-cubic patch table for the limit surface. */
PatchTableFactory::Options poptions;
poptions.SetEndCapType(PatchTableFactory::Options::ENDCAP_BSPLINE_BASIS);
const PatchTable *patch_table = PatchTableFactory::Create(*refiner, poptions);
const PatchTable *patch_table =
PatchTableFactory::Create(*refiner, poptions);
/* Append local points stencils. */
/* TODO(sergey): Do we really need to worry about local points stencils? */
if (const StencilTable *local_point_stencil_table =
patch_table->GetLocalPointStencilTable())
{
const StencilTable *local_point_stencil_table =
patch_table->GetLocalPointStencilTable();
if (local_point_stencil_table != NULL) {
const StencilTable *table =
StencilTableFactory::AppendLocalPointStencilTable(*refiner,
vertex_stencils,
local_point_stencil_table);
StencilTableFactory::AppendLocalPointStencilTable(
*refiner,
vertex_stencils,
local_point_stencil_table);
delete vertex_stencils;
vertex_stencils = table;
}
if (const StencilTable *local_point_varying_stencil_table =
patch_table->GetLocalPointVaryingStencilTable())
{
const StencilTable *local_point_varying_stencil_table =
patch_table->GetLocalPointVaryingStencilTable();
if (local_point_varying_stencil_table != NULL) {
const StencilTable *table =
StencilTableFactory::AppendLocalPointStencilTable(*refiner,
varying_stencils,
local_point_varying_stencil_table);
StencilTableFactory::AppendLocalPointStencilTable(
*refiner,
varying_stencils,
local_point_varying_stencil_table);
delete varying_stencils;
varying_stencils = table;
}
/* Total number of vertices = coarse verts + refined verts + gregory basis verts. */
num_total_verts = vertex_stencils->GetNumControlVertices() +
vertex_stencils->GetNumStencils();
/* Total number of vertices = coarse verts + refined verts + gregory
* basis verts.
*/
const int num_total_verts = vertex_stencils->GetNumControlVertices() +
vertex_stencils->GetNumStencils();
const int num_coarse_verts = refiner->GetLevel(0).GetNumVertices();
/* Create OpenSubdiv's CPU side evaluator. */
CpuEvalOutput *eval_output = new CpuEvalOutput(vertex_stencils,
varying_stencils,
num_coarse_verts,
num_total_verts,
patch_table);
OpenSubdiv::Far::PatchMap *patch_map = new PatchMap(*patch_table);
/* Wrap everything we need into an object which we control from our
* side.
*/
OpenSubdiv_EvaluatorDescr *evaluator_descr;
evaluator_descr = OBJECT_GUARDED_NEW(OpenSubdiv_EvaluatorDescr);
evaluator_descr->eval_output = eval_output;
evaluator_descr->patch_map = patch_map;
evaluator_descr->patch_table = patch_table;
/* TOOD(sergey): Look into whether w've got duplicated stencils arrays. */
/* TOOD(sergey): Look into whether we've got duplicated stencils arrays. */
delete varying_stencils;
delete vertex_stencils;
delete refiner;
return evaluator_descr;
}
@ -437,27 +432,52 @@ void openSubdiv_deleteEvaluatorDescr(OpenSubdiv_EvaluatorDescr *evaluator_descr)
OBJECT_GUARDED_DELETE(evaluator_descr, OpenSubdiv_EvaluatorDescr);
}
void openSubdiv_setEvaluatorCoarsePositions(OpenSubdiv_EvaluatorDescr *evaluator_descr,
float *positions,
int start_vert,
int num_verts)
void openSubdiv_setEvaluatorCoarsePositions(
OpenSubdiv_EvaluatorDescr *evaluator_descr,
const float *positions,
int start_vertex_index,
int num_vertices)
{
/* TODO(sergey): Add sanity check on indices. */
evaluator_descr->eval_output->UpdateData(positions, start_vert, num_verts);
/* TODO(sergey): Consider moving this to a separate call,
* so we can updatwe coordinates in chunks.
*/
evaluator_descr->eval_output->Refine();
evaluator_descr->eval_output->UpdateData(positions,
start_vertex_index,
num_vertices);
}
void openSubdiv_setEvaluatorVaryingData(OpenSubdiv_EvaluatorDescr *evaluator_descr,
float *varying_data,
int start_vert,
int num_verts)
void openSubdiv_setEvaluatorVaryingData(
OpenSubdiv_EvaluatorDescr *evaluator_descr,
const float *varying_data,
int start_vertex_index,
int num_vertices)
{
/* TODO(sergey): Add sanity check on indices. */
evaluator_descr->eval_output->UpdateVaryingData(varying_data, start_vert, num_verts);
/* TODO(sergey): Get rid of this ASAP. */
evaluator_descr->eval_output->UpdateVaryingData(varying_data,
start_vertex_index,
num_vertices);
}
void openSubdiv_setEvaluatorCoarsePositionsFromBuffer(
OpenSubdiv_EvaluatorDescr *evaluator_descr,
const void *buffer,
int start_offset,
int stride,
int start_vertex_index,
int num_vertices)
{
const unsigned char *current_buffer = (unsigned char *)buffer;
current_buffer += start_offset;
/* TODO(sergey): Add sanity check on indices. */
for (int i = 0; i < num_vertices; ++i) {
const int current_vertex_index = start_vertex_index + i;
evaluator_descr->eval_output->UpdateData((float *)current_buffer,
current_vertex_index,
1);
current_buffer += stride;
}
}
void openSubdiv_refineEvaluator(OpenSubdiv_EvaluatorDescr *evaluator_descr)
{
evaluator_descr->eval_output->Refine();
}

@ -0,0 +1,40 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2018 Blender Foundation.
* All rights reserved.
*
* Contributor(s): Sergey Sharybin.
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __OPENSUBDIV_GL_MESH_H__
#define __OPENSUBDIV_GL_MESH_H__
struct OpenSubdiv_GLMeshDescr;
struct OpenSubdiv_TopologyRefinerDescr;
struct OpenSubdiv_GLMeshFVarData;
typedef struct OpenSubdiv_GLMesh {
int evaluator_type;
OpenSubdiv_GLMeshDescr *descriptor;
OpenSubdiv_TopologyRefinerDescr *topology_refiner;
OpenSubdiv_GLMeshFVarData *fvar_data;
} OpenSubdiv_GLMesh;
#endif /* __OPENSUBDIV_GL_MESH_H__ */

@ -45,6 +45,7 @@
#include "MEM_guardedalloc.h"
#include "opensubdiv_capi.h"
#include "opensubdiv_gl_mesh.h"
#include "opensubdiv_topology_refiner.h"
using OpenSubdiv::Osd::GLMeshInterface;

@ -198,7 +198,7 @@ void ccgSubSurf_checkTopologyChanged(CCGSubSurf *ss, DerivedMesh *dm)
ss->osd_topology_refiner = NULL;
}
/* Reste CPU side. */
/* Reset CPU side. */
if (ss->osd_evaluator != NULL) {
openSubdiv_deleteEvaluatorDescr(ss->osd_evaluator);
ss->osd_evaluator = NULL;
@ -523,6 +523,7 @@ static void opensubdiv_updateEvaluatorCoarsePositions(CCGSubSurf *ss)
(float *)positions,
0,
num_basis_verts);
openSubdiv_refineEvaluator(ss->osd_evaluator);
MEM_freeN(positions);
}