diff options
54 files changed, 4919 insertions, 2915 deletions
diff --git a/intern/opensubdiv/CMakeLists.txt b/intern/opensubdiv/CMakeLists.txt index 876b5c0181f..887eb399224 100644 --- a/intern/opensubdiv/CMakeLists.txt +++ b/intern/opensubdiv/CMakeLists.txt @@ -34,20 +34,40 @@ set(INC_SYS ) set(SRC - opensubdiv_capi.cc - opensubdiv_converter.cc - opensubdiv_device_context_cuda.cc - opensubdiv_device_context_opencl.cc - opensubdiv_evaluator_capi.cc - opensubdiv_gpu_capi.cc - opensubdiv_utils_capi.cc + internal/opensubdiv.cc + internal/opensubdiv_converter_factory.cc + internal/opensubdiv_converter_internal.cc + internal/opensubdiv_converter_orient.cc + internal/opensubdiv_device_context_cuda.cc + internal/opensubdiv_device_context_opencl.cc + internal/opensubdiv_evaluator.cc + internal/opensubdiv_evaluator_internal.cc + internal/opensubdiv_gl_mesh.cc + internal/opensubdiv_gl_mesh_draw.cc + internal/opensubdiv_gl_mesh_fvar.cc + internal/opensubdiv_gl_mesh_internal.cc + internal/opensubdiv_topology_refiner.cc + internal/opensubdiv_topology_refiner_internal.cc + internal/opensubdiv_util.cc + + internal/opensubdiv_converter_internal.h + internal/opensubdiv_converter_orient.h + internal/opensubdiv_converter_orient_impl.h + internal/opensubdiv_device_context_cuda.h + internal/opensubdiv_device_context_opencl.h + internal/opensubdiv_evaluator_internal.h + internal/opensubdiv_gl_mesh_fvar.h + internal/opensubdiv_gl_mesh_internal.h + internal/opensubdiv_internal.h + internal/opensubdiv_topology_refiner_internal.h + internal/opensubdiv_util.h opensubdiv_capi.h + opensubdiv_capi_type.h opensubdiv_converter_capi.h - opensubdiv_device_context_cuda.h - opensubdiv_device_context_opencl.h - opensubdiv_intern.h - opensubdiv_topology_refiner.h + opensubdiv_evaluator_capi.h + opensubdiv_gl_mesh_capi.h + opensubdiv_topology_refiner_capi.h ) macro(OPENSUBDIV_DEFINE_COMPONENT component) @@ -64,9 +84,9 @@ OPENSUBDIV_DEFINE_COMPONENT(OPENSUBDIV_HAS_OPENMP) OPENSUBDIV_DEFINE_COMPONENT(OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK) OPENSUBDIV_DEFINE_COMPONENT(OPENSUBDIV_HAS_GLSL_COMPUTE) -data_to_c_simple(gpu_shader_opensubdiv_vertex.glsl SRC) -data_to_c_simple(gpu_shader_opensubdiv_geometry.glsl SRC) -data_to_c_simple(gpu_shader_opensubdiv_fragment.glsl SRC) +data_to_c_simple(shader/gpu_shader_opensubdiv_vertex.glsl SRC) +data_to_c_simple(shader/gpu_shader_opensubdiv_geometry.glsl SRC) +data_to_c_simple(shader/gpu_shader_opensubdiv_fragment.glsl SRC) add_definitions(-DGLEW_STATIC) diff --git a/intern/opensubdiv/internal/opensubdiv.cc b/intern/opensubdiv/internal/opensubdiv.cc new file mode 100644 index 00000000000..c2945ed25ab --- /dev/null +++ b/intern/opensubdiv/internal/opensubdiv.cc @@ -0,0 +1,99 @@ +// Copyright 2013 Blender Foundation. All rights reserved. +// +// 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. +// +// Author: Sergey Sharybin +// Contributor(s): Brecht van Lommel + +#include "opensubdiv_capi.h" + +#ifdef _MSC_VER +# include <iso646.h> +#endif + +#include <GL/glew.h> + +#include "opensubdiv_device_context_opencl.h" +#include "opensubdiv_device_context_cuda.h" +#include "opensubdiv_gl_mesh_capi.h" + +void openSubdiv_init(void) { + // Ensure all OpenGL strings are cached. + openSubdiv_getAvailableEvaluators(); +} + +void openSubdiv_cleanup(void) { + openSubdiv_deinitGLMeshDrawingResources(); +} + +int openSubdiv_getAvailableEvaluators(void) { + int flags = OPENSUBDIV_EVALUATOR_CPU; + +#ifdef OPENSUBDIV_HAS_OPENMP + flags |= OPENSUBDIV_EVALUATOR_OPENMP; +#endif + +#ifdef OPENSUBDIV_HAS_OPENCL + if (CLDeviceContext::HAS_CL_VERSION_1_1()) { + flags |= OPENSUBDIV_EVALUATOR_OPENCL; + } +#endif + +#ifdef OPENSUBDIV_HAS_CUDA + if (CudaDeviceContext::HAS_CUDA_VERSION_4_0()) { + flags |= OPENSUBDIV_EVALUATOR_CUDA; + } +#endif + +#ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK + if (GLEW_VERSION_4_1) { + flags |= OPENSUBDIV_EVALUATOR_GLSL_TRANSFORM_FEEDBACK; + } +#endif + +#ifdef OPENSUBDIV_HAS_GLSL_COMPUTE + if (GLEW_VERSION_4_3 || GLEW_ARB_compute_shader) { + flags |= OPENSUBDIV_EVALUATOR_GLSL_COMPUTE; + } +#endif + + return flags; +} + +int openSubdiv_getVersionHex(void) { +#if defined(OPENSUBDIV_VERSION_NUMBER) + return OPENSUBDIV_VERSION_NUMBER; +#elif defined(OPENSUBDIV_VERSION_MAJOR) + return OPENSUBDIV_VERSION_MAJOR * 10000 + + OPENSUBDIV_VERSION_MINOR * 100 + + OPENSUBDIV_VERSION_PATCH; +#elif defined(OPENSUBDIV_VERSION) + const char* version = STRINGIFY(OPENSUBDIV_VERSION); + if (version[0] == 'v') { + version += 1; + } + int major = 0, minor = 0, patch = 0; + vector<string> tokens; + opensubdiv_capi::stringSplit(&tokens, version, "_", true); + if (tokens.size() == 3) { + major = atoi(tokens[0].c_str()); + minor = atoi(tokens[1].c_str()); + patch = atoi(tokens[2].c_str()); + } + return major * 10000 + minor * 100 + patch; +#else + return 0; +#endif +} diff --git a/intern/opensubdiv/internal/opensubdiv_converter_factory.cc b/intern/opensubdiv/internal/opensubdiv_converter_factory.cc new file mode 100644 index 00000000000..bd6edbb9648 --- /dev/null +++ b/intern/opensubdiv/internal/opensubdiv_converter_factory.cc @@ -0,0 +1,438 @@ +// Copyright 2015 Blender Foundation. All rights reserved. +// +// 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. +// +// Author: Sergey Sharybin + +#ifdef _MSC_VER +# include <iso646.h> +#endif + +#include "internal/opensubdiv_converter_factory.h" + +#include <cassert> +#include <cstdio> +#include <stack> +#include <vector> + +#include <opensubdiv/far/topologyRefinerFactory.h> + +#include "internal/opensubdiv_converter_internal.h" +#include "internal/opensubdiv_converter_orient.h" +#include "internal/opensubdiv_internal.h" +#include "opensubdiv_converter_capi.h" + +struct TopologyRefinerData { + const OpenSubdiv_Converter* converter; +}; + +namespace OpenSubdiv { +namespace OPENSUBDIV_VERSION { +namespace Far { + +template <> +inline bool +TopologyRefinerFactory<TopologyRefinerData>::resizeComponentTopology( + TopologyRefiner& refiner, + const TopologyRefinerData& cb_data) { + const OpenSubdiv_Converter* converter = cb_data.converter; + /// Faces and face-vertices. + const int num_faces = converter->getNumFaces(converter); + setNumBaseFaces(refiner, num_faces); + for (int face_index = 0; face_index < num_faces; ++face_index) { + const int num_face_vertices = + converter->getNumFaceVertices(converter, face_index); + setNumBaseFaceVertices(refiner, face_index, num_face_vertices); + } + // Edges and edge-faces. + const int num_edges = converter->getNumEdges(converter); + setNumBaseEdges(refiner, num_edges); + for (int edge_index = 0; edge_index < num_edges; ++edge_index) { + const int num_edge_faces = + converter->getNumEdgeFaces(converter, edge_index); + setNumBaseEdgeFaces(refiner, edge_index, num_edge_faces); + } + // Vertices and vertex-faces and vertex-edges. + const int num_vertices = converter->getNumVertices(converter); + setNumBaseVertices(refiner, num_vertices); + for (int vertex_index = 0; vertex_index < num_vertices; ++vertex_index) { + const int num_vert_edges = + converter->getNumVertexEdges(converter, vertex_index); + const int num_vert_faces = + converter->getNumVertexFaces(converter, vertex_index); + setNumBaseVertexEdges(refiner, vertex_index, num_vert_edges); + setNumBaseVertexFaces(refiner, vertex_index, num_vert_faces); + } + return true; +} + +template <> +inline bool +TopologyRefinerFactory<TopologyRefinerData>::assignComponentTopology( + TopologyRefiner& refiner, + const TopologyRefinerData& cb_data) { + using Far::IndexArray; + const OpenSubdiv_Converter* converter = cb_data.converter; + // Face relations. + const int num_faces = converter->getNumFaces(converter); + for (int face_index = 0; face_index < num_faces; ++face_index) { + IndexArray dst_face_verts = getBaseFaceVertices(refiner, face_index); + converter->getFaceVertices(converter, face_index, &dst_face_verts[0]); + IndexArray dst_face_edges = getBaseFaceEdges(refiner, face_index); + converter->getFaceEdges(converter, face_index, &dst_face_edges[0]); + } + // Edge relations. + const int num_edges = converter->getNumEdges(converter); + for (int edge_index = 0; edge_index < num_edges; ++edge_index) { + // Edge-vertices. + IndexArray dst_edge_vertices = getBaseEdgeVertices(refiner, edge_index); + converter->getEdgeVertices(converter, edge_index, &dst_edge_vertices[0]); + // Edge-faces. + IndexArray dst_edge_faces = getBaseEdgeFaces(refiner, edge_index); + converter->getEdgeFaces(converter, edge_index, &dst_edge_faces[0]); + } +// TODO(sergey): Find a way to move this to an utility function. +#ifdef OPENSUBDIV_ORIENT_TOPOLOGY + // Make face normals consistent. + std::vector<bool> face_used(num_faces, false); + std::stack<int> traverse_stack; + int face_start = 0, num_traversed_faces = 0; + // Traverse all islands. + while (num_traversed_faces != num_faces) { + // Find first face of any untraversed islands. + while (face_used[face_start]) { + ++face_start; + } + // Add first face to the stack. + traverse_stack.push(face_start); + face_used[face_start] = true; + // Go over whole connected component. + while (!traverse_stack.empty()) { + int face = traverse_stack.top(); + traverse_stack.pop(); + IndexArray face_edges = getBaseFaceEdges(refiner, face); + ConstIndexArray face_vertices = getBaseFaceVertices(refiner, face); + for (int i = 0; i < face_edges.size(); ++i) { + const int edge = face_edges[i]; + ConstIndexArray edge_faces = getBaseEdgeFaces(refiner, edge); + if (edge_faces.size() != 2) { + /* Can't make consistent normals for non-manifolds. */ + continue; + } + ConstIndexArray edge_vertices = getBaseEdgeVertices(refiner, edge); + // Get winding of the reference face. + const int vert0_of_face = face_vertices.FindIndex(edge_vertices[0]); + const int vert1_of_face = face_vertices.FindIndex(edge_vertices[1]); + const int delta_face = + opensubdiv_capi::getLoopWinding(vert0_of_face, vert1_of_face); + for (int edge_face = 0; edge_face < edge_faces.size(); ++edge_face) { + const int other_face_index = edge_faces[edge_face]; + // Never re-traverse faces, only move forward. + if (face_used[other_face_index]) { + continue; + } + IndexArray other_face_vertics = + getBaseFaceVertices(refiner, other_face_index); + const int vert0_of_other_face = + other_face_vertics.FindIndex(edge_vertices[0]); + const int vert1_of_other_face = + other_face_vertics.FindIndex(edge_vertices[1]); + const int delta_other_face = opensubdiv_capi::getLoopWinding( + vert0_of_other_face, vert1_of_other_face); + if (delta_face * delta_other_face > 0) { + IndexArray other_face_vertices = + getBaseFaceVertices(refiner, other_face_index); + IndexArray other_face_edges = + getBaseFaceEdges(refiner, other_face_index); + opensubdiv_capi::reverseFaceLoops(&other_face_vertices, + &other_face_edges); + } + traverse_stack.push(other_face_index); + face_used[other_face_index] = true; + } + } + ++num_traversed_faces; + } + } +#endif // OPENSUBDIV_ORIENT_TOPOLOGY + // Vertex relations. + const int num_vertices = converter->getNumVertices(converter); + std::vector<int> vertex_faces, vertex_edges; + for (int vertex_index = 0; vertex_index < num_vertices; ++vertex_index) { + // Vertex-faces. + IndexArray dst_vertex_faces = getBaseVertexFaces(refiner, vertex_index); + const int num_vertex_faces = + converter->getNumVertexFaces(converter, vertex_index); + vertex_faces.resize(num_vertex_faces); + converter->getVertexFaces(converter, vertex_index, &vertex_faces[0]); + // Vertex-edges. + IndexArray dst_vertex_edges = getBaseVertexEdges(refiner, vertex_index); + const int num_vertex_edges = + converter->getNumVertexEdges(converter, vertex_index); + vertex_edges.resize(num_vertex_edges); + converter->getVertexEdges(converter, vertex_index, &vertex_edges[0]); +// TODO(sergey): Find a way to move this to an utility function. +#ifdef OPENSUBDIV_ORIENT_TOPOLOGY + // Order vertex edges and faces to be in a CCW order. + std::fill(face_used.begin(), face_used.end(), false); + // Number of edges and faces added to the ordered array. + int edge_count_ordered = 0, face_count_ordered = 0; + // Add loose edges straight into the edges array. + bool has_fan_connections = false; + for (int i = 0; i < num_vertex_edges; ++i) { + IndexArray edge_faces = getBaseEdgeFaces(refiner, vertex_edges[i]); + if (edge_faces.size() == 0) { + dst_vertex_edges[edge_count_ordered++] = vertex_edges[i]; + } else if (edge_faces.size() > 2) { + has_fan_connections = true; + } + } + if (has_fan_connections) { + // OpenSubdiv currently doesn't give us clues how to handle fan face + // connections. and since handling such connections complicates the loop + // below we simply don't do special orientation for them. + memcpy(&dst_vertex_edges[0], &vertex_edges[0], + sizeof(int) * num_vertex_edges); + memcpy(&dst_vertex_faces[0], &vertex_faces[0], + sizeof(int) * num_vertex_faces); + continue; + } + // Perform at max numbder of vert-edges iteration and try to avoid + // deadlock here for malformed mesh. + for (int global_iter = 0; global_iter < num_vertex_edges; ++global_iter) { + // Number of edges and faces which are still to be ordered. + const int num_vertex_edges_remained = + num_vertex_edges - edge_count_ordered; + const int num_vertex_faces_remained = + num_vertex_faces - face_count_ordered; + if (num_vertex_edges_remained == 0 && num_vertex_faces_remained == 0) { + // All done, nothing to do anymore. + break; + } + // Face, edge and face-vertex index to start traversal from. + int face_start = -1, edge_start = -1, face_vertex_start = -1; + if (num_vertex_edges_remained == num_vertex_faces_remained) { + // Vertex is either complete manifold or is connected to several + // manifold islands (hourglass-like configuration), can pick up + // random edge unused and start from it. + // + // TODO(sergey): Start from previous edge from which traversal began at + // previous iteration. + for (int i = 0; i < num_vertex_edges; ++i) { + face_start = vertex_faces[i]; + if (!face_used[face_start]) { + ConstIndexArray face_vertices = + getBaseFaceVertices(refiner, face_start); + ConstIndexArray face_edges = getBaseFaceEdges(refiner, face_start); + face_vertex_start = face_vertices.FindIndex(vertex_index); + edge_start = face_edges[face_vertex_start]; + break; + } + } + } else { + // Special handle of non-manifold vertex. + for (int i = 0; i < num_vertex_edges; ++i) { + edge_start = vertex_edges[i]; + IndexArray edge_faces = getBaseEdgeFaces(refiner, edge_start); + if (edge_faces.size() == 1) { + face_start = edge_faces[0]; + if (!face_used[face_start]) { + ConstIndexArray face_vertices = + getBaseFaceVertices(refiner, face_start); + ConstIndexArray face_edges = + getBaseFaceEdges(refiner, face_start); + face_vertex_start = face_vertices.FindIndex(vertex_index); + if (edge_start == face_edges[face_vertex_start]) { + break; + } + } + } + // Reset indices for sanity check below. + face_start = edge_start = face_vertex_start = -1; + } + } + // Sanity check. + assert(face_start != -1); + assert(edge_start != -1); + assert(face_vertex_start != -1); + // Traverse faces starting from the current one. */ + int edge_first = edge_start; + dst_vertex_faces[face_count_ordered++] = face_start; + dst_vertex_edges[edge_count_ordered++] = edge_start; + face_used[face_start] = true; + while (edge_count_ordered < num_vertex_edges) { + IndexArray face_vertices = getBaseFaceVertices(refiner, face_start); + IndexArray face_edges = getBaseFaceEdges(refiner, face_start); + int face_edge_start = face_vertex_start; + int face_edge_next = (face_edge_start > 0) ? (face_edge_start - 1) + : (face_vertices.size() - 1); + Index edge_next = face_edges[face_edge_next]; + if (edge_next == edge_first) { + // Multiple manifolds found, stop for now and handle rest + // in the next iteration. + break; + } + dst_vertex_edges[edge_count_ordered++] = edge_next; + if (face_count_ordered < num_vertex_faces) { + IndexArray edge_faces = getBaseEdgeFaces(refiner, edge_next); + assert(edge_faces.size() != 0); + if (edge_faces.size() == 1) { + assert(edge_faces[0] == face_start); + break; + } else if (edge_faces.size() != 2) { + break; + } + assert(edge_faces.size() == 2); + face_start = edge_faces[(edge_faces[0] == face_start) ? 1 : 0]; + face_vertex_start = + getBaseFaceEdges(refiner, face_start).FindIndex(edge_next); + dst_vertex_faces[face_count_ordered++] = face_start; + face_used[face_start] = true; + } + edge_start = edge_next; + } + } + // Verify ordering doesn't ruin connectivity information. + assert(face_count_ordered == num_vertex_faces); + assert(edge_count_ordered == num_vertex_edges); + opensubdiv_capi::checkOrientedVertexConnectivity( + num_vertex_edges, num_vertex_faces, &vertex_edges[0], &vertex_faces[0], + &dst_vertex_edges[0], &dst_vertex_faces[0]); + // For the release builds we're failing mesh construction so instead of + // nasty bugs the unsupported mesh will simply disappear from the viewport. + if (face_count_ordered != num_vertex_faces || + edge_count_ordered != num_vertex_edges) { + return false; + } +#else // OPENSUBDIV_ORIENT_TOPOLOGY + memcpy(&dst_vertex_edges[0], &vertex_edges[0], + sizeof(int) * num_vertex_edges); + memcpy(&dst_vertex_faces[0], &vertex_faces[0], + sizeof(int) * num_vertex_faces); +#endif // OPENSUBDIV_ORIENT_TOPOLOGY + } + populateBaseLocalIndices(refiner); + return true; +} + +template <> +inline bool TopologyRefinerFactory<TopologyRefinerData>::assignComponentTags( + TopologyRefiner& refiner, + const TopologyRefinerData& cb_data) { + using OpenSubdiv::Sdc::Crease; + const OpenSubdiv_Converter* converter = cb_data.converter; + const int num_edges = converter->getNumEdges(converter); + for (int edge_index = 0; edge_index < num_edges; ++edge_index) { + const float sharpness = + opensubdiv_capi::getCompatibleEdgeSharpness(converter, edge_index); + setBaseEdgeSharpness(refiner, edge_index, sharpness); + } + // OpenSubdiv expects non-manifold vertices to be sharp but at the time it + // handles correct cases when vertex is a corner of plane. Currently mark + // vertices which are adjacent to a loose edge as sharp, but this decision + // needs some more investigation. + const int num_vertices = converter->getNumVertices(converter); + for (int vertex_index = 0; vertex_index < num_vertices; ++vertex_index) { + ConstIndexArray vertex_edges = getBaseVertexEdges(refiner, vertex_index); + for (int i = 0; i < vertex_edges.size(); ++i) { + const int edge_index = vertex_edges[i]; + ConstIndexArray edge_faces = getBaseEdgeFaces(refiner, edge_index); + if (edge_faces.size() == 0) { + setBaseVertexSharpness(refiner, vertex_index, + Crease::SHARPNESS_INFINITE); + break; + } + } + if (vertex_edges.size() == 2) { + const int edge0 = vertex_edges[0], edge1 = vertex_edges[1]; + const float sharpness0 = converter->getEdgeSharpness(converter, edge0); + const float sharpness1 = converter->getEdgeSharpness(converter, edge1); + const float sharpness = std::min(sharpness0, sharpness1); + setBaseVertexSharpness(refiner, vertex_index, sharpness); + } + } + return true; +} + +template <> +inline bool +TopologyRefinerFactory<TopologyRefinerData>::assignFaceVaryingTopology( + TopologyRefiner& refiner, + const TopologyRefinerData& cb_data) { + const OpenSubdiv_Converter* converter = cb_data.converter; + const int num_layers = converter->getNumUVLayers(converter); + if (num_layers <= 0) { + // No UV maps, we can skip any face-varying data. + return true; + } + const int num_faces = getNumBaseFaces(refiner); + for (int layer_index = 0; layer_index < num_layers; ++layer_index) { + converter->precalcUVLayer(converter, layer_index); + const int num_uvs = converter->getNumUVCoordinates(converter); + // Fill in per-corner index of the UV. + const int channel = createBaseFVarChannel(refiner, num_uvs); + for (int face_index = 0; face_index < num_faces; ++face_index) { + Far::IndexArray dst_face_uvs = + getBaseFaceFVarValues(refiner, face_index, channel); + for (int corner = 0; corner < dst_face_uvs.size(); ++corner) { + const int uv_index = + converter->getFaceCornerUVIndex(converter, face_index, corner); + dst_face_uvs[corner] = uv_index; + } + } + converter->finishUVLayer(converter); + } + return true; +} + +template <> +inline void TopologyRefinerFactory<TopologyRefinerData>::reportInvalidTopology( + TopologyError /*errCode*/, const char* msg, + const TopologyRefinerData& /*mesh*/) { + printf("OpenSubdiv Error: %s\n", msg); +} + +} /* namespace Far */ +} /* namespace OPENSUBDIV_VERSION */ +} /* namespace OpenSubdiv */ + +namespace opensubdiv_capi { + +OpenSubdiv::Far::TopologyRefiner* createOSDTopologyRefinerFromConverter( + OpenSubdiv_Converter* converter) { + using OpenSubdiv::Sdc::Options; + using OpenSubdiv::Far::TopologyRefinerFactory; + const OpenSubdiv::Sdc::SchemeType scheme_type = + getSchemeTypeFromCAPI(converter->getSchemeType(converter)); + const Options::FVarLinearInterpolation linear_interpolation = + getFVarLinearInterpolationFromCAPI( + converter->getFVarLinearInterpolation(converter)); + Options options; + options.SetVtxBoundaryInterpolation(Options::VTX_BOUNDARY_EDGE_ONLY); + options.SetCreasingMethod(Options::CREASE_UNIFORM); + options.SetFVarLinearInterpolation(linear_interpolation); + + TopologyRefinerFactory<TopologyRefinerData>::Options topology_options( + scheme_type, options); +#ifdef OPENSUBDIV_VALIDATE_TOPOLOGY + topology_options.validateFullTopology = true; +#endif + TopologyRefinerData cb_data; + cb_data.converter = converter; + return TopologyRefinerFactory<TopologyRefinerData>::Create( + cb_data, topology_options); +} + +} // namespace opensubdiv_capi diff --git a/intern/opensubdiv/internal/opensubdiv_converter_factory.h b/intern/opensubdiv/internal/opensubdiv_converter_factory.h new file mode 100644 index 00000000000..451418813e1 --- /dev/null +++ b/intern/opensubdiv/internal/opensubdiv_converter_factory.h @@ -0,0 +1,37 @@ +// Copyright 2015 Blender Foundation. All rights reserved. +// +// 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. +// +// Author: Sergey Sharybin + +#ifndef OPENSUBDIV_CONVERTER_FACTORY_H_ +#define OPENSUBDIV_CONVERTER_FACTORY_H_ + +#ifdef _MSC_VER +# include <iso646.h> +#endif + +#include <opensubdiv/far/topologyRefiner.h> + +struct OpenSubdiv_Converter; + +namespace opensubdiv_capi { + +OpenSubdiv::Far::TopologyRefiner* createOSDTopologyRefinerFromConverter( + struct OpenSubdiv_Converter* converter); + +} // namespace opensubdiv_capi + +#endif // OPENSUBDIV_CONVERTER_FACTORY_H_ diff --git a/intern/opensubdiv/internal/opensubdiv_converter_internal.cc b/intern/opensubdiv/internal/opensubdiv_converter_internal.cc new file mode 100644 index 00000000000..56b5657121d --- /dev/null +++ b/intern/opensubdiv/internal/opensubdiv_converter_internal.cc @@ -0,0 +1,70 @@ +// Copyright 2018 Blender Foundation. All rights reserved. +// +// 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. +// +// Author: Sergey Sharybin + +#ifdef _MSC_VER +# include <iso646.h> +#endif + +#include "internal/opensubdiv_converter_internal.h" + +#include <opensubdiv/sdc/crease.h> +#include <cassert> + +namespace opensubdiv_capi { + +OpenSubdiv::Sdc::SchemeType getSchemeTypeFromCAPI(OpenSubdiv_SchemeType type) { + switch (type) { + case OSD_SCHEME_BILINEAR: + return OpenSubdiv::Sdc::SCHEME_BILINEAR; + case OSD_SCHEME_CATMARK: + return OpenSubdiv::Sdc::SCHEME_CATMARK; + case OSD_SCHEME_LOOP: + return OpenSubdiv::Sdc::SCHEME_LOOP; + } + assert(!"Unknown scheme type passed via C-API"); + return OpenSubdiv::Sdc::SCHEME_CATMARK; +} + +OpenSubdiv::Sdc::Options::FVarLinearInterpolation +getFVarLinearInterpolationFromCAPI( + OpenSubdiv_FVarLinearInterpolation linear_interpolation) { + typedef OpenSubdiv::Sdc::Options Options; + switch (linear_interpolation) { + case OSD_FVAR_LINEAR_INTERPOLATION_NONE: + return Options::FVAR_LINEAR_NONE; + case OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY: + return Options::FVAR_LINEAR_CORNERS_ONLY; + case OSD_FVAR_LINEAR_INTERPOLATION_BOUNDARIES: + return Options::FVAR_LINEAR_BOUNDARIES; + case OSD_FVAR_LINEAR_INTERPOLATION_ALL: + return Options::FVAR_LINEAR_ALL; + } + assert(!"Unknown fvar linear interpolation passed via C-API"); + return Options::FVAR_LINEAR_NONE; +} + +float getCompatibleEdgeSharpness(const OpenSubdiv_Converter* converter, + int edge_index) { + if (converter->getNumEdgeFaces(converter, edge_index) == 2) { + return converter->getEdgeSharpness(converter, edge_index); + } else { + return OpenSubdiv::Sdc::Crease::SHARPNESS_INFINITE; + } +} + +} // namespace opensubdiv_capi diff --git a/intern/opensubdiv/internal/opensubdiv_converter_internal.h b/intern/opensubdiv/internal/opensubdiv_converter_internal.h new file mode 100644 index 00000000000..68518d67884 --- /dev/null +++ b/intern/opensubdiv/internal/opensubdiv_converter_internal.h @@ -0,0 +1,50 @@ +// Copyright 2018 Blender Foundation. All rights reserved. +// +// 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. +// +// Author: Sergey Sharybin + +#ifndef OPENSUBDIV_CONVERTER_INTERNAL_H_ +#define OPENSUBDIV_CONVERTER_INTERNAL_H_ + +#ifdef _MSC_VER +# include <iso646.h> +#endif + +#include <opensubdiv/sdc/options.h> +#include <opensubdiv/sdc/types.h> + +#include "opensubdiv_converter_capi.h" + +struct OpenSubdiv_Converter; + +namespace opensubdiv_capi { + +// Convert scheme type from C-API enum to an OpenSubdiv native enum. +OpenSubdiv::Sdc::SchemeType getSchemeTypeFromCAPI(OpenSubdiv_SchemeType type); + +// Convert face-varying interpolation type from C-API to an OpenSubdiv +// native enum. +OpenSubdiv::Sdc::Options::FVarLinearInterpolation +getFVarLinearInterpolationFromCAPI( + OpenSubdiv_FVarLinearInterpolation linear_interpolation); + +// Get edge sharpness in a way which makes OpenSubdiv happy. +float getCompatibleEdgeSharpness(const OpenSubdiv_Converter* converter, + int edge_index); + +} // namespace opensubdiv_capi + +#endif // OPENSUBDIV_CONVERTER_INTERNAL_H_ diff --git a/intern/opensubdiv/internal/opensubdiv_converter_orient.cc b/intern/opensubdiv/internal/opensubdiv_converter_orient.cc new file mode 100644 index 00000000000..449e9028180 --- /dev/null +++ b/intern/opensubdiv/internal/opensubdiv_converter_orient.cc @@ -0,0 +1,66 @@ +// Copyright 2018 Blender Foundation. All rights reserved. +// +// 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. +// +// Author: Sergey Sharybin + +#include "internal/opensubdiv_converter_orient.h" + +#include "internal/opensubdiv_internal.h" + +namespace opensubdiv_capi { + +void checkOrientedVertexConnectivity(const int num_vertex_edges, + const int num_vertex_faces, + const int* vertex_edges, + const int* vertex_faces, + const int* dst_vertex_edges, + const int* dst_vertex_faces) { +#ifndef NDEBUG + for (int i = 0; i < num_vertex_faces; ++i) { + bool found = false; + for (int j = 0; j < num_vertex_faces; ++j) { + if (vertex_faces[i] == dst_vertex_faces[j]) { + found = true; + break; + } + } + if (!found) { + assert(!"vert-faces connectivity ruined"); + } + } + for (int i = 0; i < num_vertex_edges; ++i) { + bool found = false; + for (int j = 0; j < num_vertex_edges; ++j) { + if (vertex_edges[i] == dst_vertex_edges[j]) { + found = true; + break; + } + } + if (!found) { + assert(!"vert-edges connectivity ruined"); + } + } +#else + (void) num_vertex_edges; + (void) num_vertex_faces; + (void) vertex_edges; + (void) vertex_faces; + (void) dst_vertex_edges; + (void) dst_vertex_faces; +#endif +} + +} // namespace opensubdiv_capi diff --git a/intern/opensubdiv/internal/opensubdiv_converter_orient.h b/intern/opensubdiv/internal/opensubdiv_converter_orient.h new file mode 100644 index 00000000000..b783007a0cb --- /dev/null +++ b/intern/opensubdiv/internal/opensubdiv_converter_orient.h @@ -0,0 +1,50 @@ +// Copyright 2018 Blender Foundation. All rights reserved. +// +// 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. +// +// Author: Sergey Sharybin + +#ifndef OPENSUBDIV_CONVERTER_ORIENT_H_ +#define OPENSUBDIV_CONVERTER_ORIENT_H_ + +#include <opensubdiv/far/types.h> + +// Set of utility functions which are needed to bring topology to an orientation +// (or, winding, if you wish) which OpenSubdiv expects. + +namespace opensubdiv_capi { + +inline void reverseFaceVertices(int* face_vertices, const int num_vertices); + +// TODO(sergey): Document which value corresponds to which winding. +inline int getLoopWinding(int vert0_of_face, int vert1_of_face); + +inline void reverseFaceLoops( + OpenSubdiv::Far::IndexArray* face_vertices, + OpenSubdiv::Far::IndexArray* face_edges); + +// Used for debugging, checks whether orientation happened correct. +void checkOrientedVertexConnectivity(const int num_vertex_edges, + const int num_vertex_faces, + const int* vertex_edges, + const int* vertex_faces, + const int* dst_vertex_edges, + const int* dst_vertex_faces); + +} // namespace opensubdiv_capi + +#endif // OPENSUBDIV_CONVERTER_ORIENT_H_ + +#include "internal/opensubdiv_converter_orient_impl.h" diff --git a/intern/opensubdiv/internal/opensubdiv_converter_orient_impl.h b/intern/opensubdiv/internal/opensubdiv_converter_orient_impl.h new file mode 100644 index 00000000000..3125bc600e5 --- /dev/null +++ b/intern/opensubdiv/internal/opensubdiv_converter_orient_impl.h @@ -0,0 +1,66 @@ +// Copyright 2018 Blender Foundation. All rights reserved. +// +// 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. +// +// Author: Sergey Sharybin + +#ifndef OPENSUBDIV_CONVERTER_ORIENT_IMPL_H_ +#define OPENSUBDIV_CONVERTER_ORIENT_IMPL_H_ + +#include "internal/opensubdiv_converter_orient.h" + +#include <algorithm> +#include <cmath> +#include <utility> + +namespace opensubdiv_capi { + +inline void reverseFaceVertices(int* face_vertices, const int num_vertices) { + int last_vert = face_vertices[num_vertices - 1]; + for (int i = num_vertices - 1; i > 0; --i) { + face_vertices[i] = face_vertices[i - 1]; + } + face_vertices[0] = last_vert; +} + +inline int getLoopWinding(int vert0_of_face, int vert1_of_face) { + int delta_face = vert1_of_face - vert0_of_face; + if (abs(delta_face) != 1) { + if (delta_face > 0) { + delta_face = -1; + } else { + delta_face = 1; + } + } + return delta_face; +} + +inline void reverseFaceLoops( + OpenSubdiv::Far::IndexArray* face_vertices, + OpenSubdiv::Far::IndexArray* face_edges) { + const int num_face_vertices = face_vertices->size(); + for (int i = 0; i < num_face_vertices / 2; ++i) { + const int j = num_face_vertices - i - 1; + if (i != j) { + std::swap((*face_vertices)[i], (*face_vertices)[j]); + std::swap((*face_edges)[i], (*face_edges)[j]); + } + } + reverseFaceVertices(&(*face_vertices)[0], num_face_vertices); +} + +} // namespace opensubdiv_capi + +#endif // OPENSUBDIV_CONVERTER_ORIENT_IMPL_H_ diff --git a/intern/opensubdiv/internal/opensubdiv_device_context_cuda.cc b/intern/opensubdiv/internal/opensubdiv_device_context_cuda.cc new file mode 100644 index 00000000000..875f503b9ab --- /dev/null +++ b/intern/opensubdiv/internal/opensubdiv_device_context_cuda.cc @@ -0,0 +1,226 @@ +// Adopted from OpenSubdiv with the following license: +// +// Copyright 2015 Pixar +// +// Licensed under the Apache License, Version 2.0 (the "Apache License") +// with the following modification; you may not use this file except in +// compliance with the Apache License and the following modification to it: +// Section 6. Trademarks. is deleted and replaced with: +// +// 6. Trademarks. This License does not grant permission to use the trade +// names, trademarks, service marks, or product names of the Licensor +// and its affiliates, except as required to comply with Section 4(c) of +// the License and to reproduce the content of the NOTICE file. +// +// You may obtain a copy of the Apache License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the Apache License with the above modification is +// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the Apache License for the specific +// language governing permissions and limitations under the Apache License. + +#ifdef OPENSUBDIV_HAS_CUDA + +#ifdef _MSC_VER +# include <iso646.h> +#endif + +#include "opensubdiv_device_context_cuda.h" + +#if defined(_WIN32) +# include <windows.h> +#elif defined(__APPLE__) +# include <OpenGL/OpenGL.h> +#else +# include <GL/glx.h> +# include <X11/Xlib.h> +#endif + +#include <cuda.h> +#include <cuda_gl_interop.h> +#include <cuda_runtime_api.h> +#include <algorithm> +#include <cstdio> + +#define message(fmt, ...) +// #define message(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__) +#define error(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__) + +namespace { + +int getCudaDeviceForCurrentGLContext() { + // Find and use the CUDA device for the current GL context + unsigned int interop_device_count = 0; + int interopDevices[1]; + cudaError_t status = cudaGLGetDevices(&interop_device_count, + interopDevices, + 1, + cudaGLDeviceListCurrentFrame); + if (status == cudaErrorNoDevice || interop_device_count != 1) { + message("CUDA no interop devices found.\n"); + return 0; + } + int device = interopDevices[0]; +#if defined(_WIN32) + return device; +#elif defined(__APPLE__) + return device; +#else // X11 + Display* display = glXGetCurrentDisplay(); + int screen = DefaultScreen(display); + if (device != screen) { + error("The CUDA interop device (%d) does not match " + "the screen used by the current GL context (%d), " + "which may cause slow performance on systems " + "with multiple GPU devices.", + device, screen); + } + message("CUDA init using device for current GL context: %d\n", device); + return device; +#endif +} + +// Beginning of GPU Architecture definitions. +int convertSMVer2Cores_local(int major, int minor) { + // Defines for GPU Architecture types (using the SM version to determine + // the # of cores per SM + typedef struct { + int SM; // 0xMm (hexidecimal notation), + // M = SM Major version, + // and m = SM minor version + int Cores; + } sSMtoCores; + + sSMtoCores nGpuArchCoresPerSM[] = { + {0x10, 8}, // Tesla Generation (SM 1.0) G80 class. + {0x11, 8}, // Tesla Generation (SM 1.1) G8x class. + {0x12, 8}, // Tesla Generation (SM 1.2) G9x class. + {0x13, 8}, // Tesla Generation (SM 1.3) GT200 class. + {0x20, 32}, // Fermi Generation (SM 2.0) GF100 class. + {0x21, 48}, // Fermi Generation (SM 2.1) GF10x class. + {0x30, 192}, // Fermi Generation (SM 3.0) GK10x class. + {-1, -1}}; + int index = 0; + while (nGpuArchCoresPerSM[index].SM != -1) { + if (nGpuArchCoresPerSM[index].SM == ((major << 4) + minor)) { + return nGpuArchCoresPerSM[index].Cores; + } + index++; + } + printf("MapSMtoCores undefined SMversion %d.%d!\n", major, minor); + return -1; +} + +// This function returns the best GPU (with maximum GFLOPS). +int cutGetMaxGflopsDeviceId() { + int current_device = 0, sm_per_multiproc = 0; + int max_compute_perf = 0, max_perf_device = -1; + int device_count = 0, best_SM_arch = 0; + int compat_major, compat_minor; + cuDeviceGetCount(&device_count); + // Find the best major SM Architecture GPU device. + while (current_device < device_count) { + cuDeviceComputeCapability(&compat_major, &compat_minor, current_device); + if (compat_major > 0 && compat_major < 9999) { + best_SM_arch = std::max(best_SM_arch, compat_major); + } + current_device++; + } + // Find the best CUDA capable GPU device. + current_device = 0; + while (current_device < device_count) { + cuDeviceComputeCapability(&compat_major, &compat_minor, current_device); + if (compat_major == 9999 && compat_minor == 9999) { + sm_per_multiproc = 1; + } else { + sm_per_multiproc = convertSMVer2Cores_local(compat_major, compat_minor); + } + int multi_processor_count; + cuDeviceGetAttribute(&multi_processor_count, + CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT, + current_device); + int clock_rate; + cuDeviceGetAttribute(&clock_rate, CU_DEVICE_ATTRIBUTE_CLOCK_RATE, + current_device); + int compute_perf = multi_processor_count * sm_per_multiproc * clock_rate; + if (compute_perf > max_compute_perf) { + /* If we find GPU with SM major > 2, search only these */ + if (best_SM_arch > 2) { + /* If our device==dest_SM_arch, choose this, or else pass. */ + if (compat_major == best_SM_arch) { + max_compute_perf = compute_perf; + max_perf_device = current_device; + } + } else { + max_compute_perf = compute_perf; + max_perf_device = current_device; + } + } + ++current_device; + } + return max_perf_device; +} + +} // namespace + +bool CudaDeviceContext::HAS_CUDA_VERSION_4_0() { +#ifdef OPENSUBDIV_HAS_CUDA + static bool cuda_initialized = false; + static bool cuda_load_success = true; + if (!cuda_initialized) { + cuda_initialized = true; + +#ifdef OPENSUBDIV_HAS_CUEW + cuda_load_success = cuewInit(CUEW_INIT_CUDA) == CUEW_SUCCESS; + if (!cuda_load_success) { + fprintf(stderr, "Loading CUDA failed.\n"); + } +#endif + // Need to initialize CUDA here so getting device + // with the maximum FPLOS works fine. + if (cuInit(0) == CUDA_SUCCESS) { + // This is to deal with cases like NVidia Optimus, + // when there might be CUDA library installed but + // NVidia card is not being active. + if (cutGetMaxGflopsDeviceId() < 0) { + cuda_load_success = false; + } + } else { + cuda_load_success = false; + } + } + return cuda_load_success; +#else + return false; +#endif +} + +CudaDeviceContext::CudaDeviceContext() + : initialized_(false) { +} + +CudaDeviceContext::~CudaDeviceContext() { + cudaDeviceReset(); +} + +bool CudaDeviceContext::Initialize() { + // See if any cuda device is available. + int device_count = 0; + cudaGetDeviceCount(&device_count); + message("CUDA device count: %d\n", device_count); + if (device_count <= 0) { + return false; + } + cudaGLSetGLDevice(getCudaDeviceForCurrentGLContext()); + initialized_ = true; + return true; +} + +bool CudaDeviceContext::IsInitialized() const { + return initialized_; +} + +#endif // OPENSUBDIV_HAS_CUDA diff --git a/intern/opensubdiv/internal/opensubdiv_device_context_cuda.h b/intern/opensubdiv/internal/opensubdiv_device_context_cuda.h new file mode 100644 index 00000000000..ef212df10f0 --- /dev/null +++ b/intern/opensubdiv/internal/opensubdiv_device_context_cuda.h @@ -0,0 +1,54 @@ +// Adopted from OpenSubdiv with the following license: +// +// Copyright 2013 Pixar +// +// Licensed under the Apache License, Version 2.0 (the "Apache License") +// with the following modification; you may not use this file except in +// compliance with the Apache License and the following modification to it: +// Section 6. Trademarks. is deleted and replaced with: +// +// 6. Trademarks. This License does not grant permission to use the trade +// names, trademarks, service marks, or product names of the Licensor +// and its affiliates, except as required to comply with Section 4(c) of +// the License and to reproduce the content of the NOTICE file. +// +// You may obtain a copy of the Apache License at +// +// http: //www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the Apache License with the above modification is +// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the Apache License for the specific +// language governing permissions and limitations under the Apache License. + +#ifndef OPENSUBDIV_DEVICE_CONTEXT_CUDA_H_ +#define OPENSUBDIV_DEVICE_CONTEXT_CUDA_H_ + +#ifdef OPENSUBDIV_HAS_CUDA + +struct ID3D11Device; + +class CudaDeviceContext { + public: + CudaDeviceContext(); + ~CudaDeviceContext(); + + static bool HAS_CUDA_VERSION_4_0(); + + // Initialze cuda device from the current GL context. + bool Initialize(); + + // Initialze cuda device from the ID3D11Device. + bool Initialize(ID3D11Device* device); + + // Returns true if the cuda device has already been initialized. + bool IsInitialized() const; + + private: + bool initialized_; +}; + +#endif // OPENSUBDIV_HAS_CUDA + +#endif // _OPENSUBDIV_DEVICE_CONTEXT_CUDA_H_ diff --git a/intern/opensubdiv/internal/opensubdiv_device_context_opencl.cc b/intern/opensubdiv/internal/opensubdiv_device_context_opencl.cc new file mode 100644 index 00000000000..00f58af894a --- /dev/null +++ b/intern/opensubdiv/internal/opensubdiv_device_context_opencl.cc @@ -0,0 +1,269 @@ +// Adopted from OpenSubdiv with the following license: +// +// Copyright 2015 Pixar +// +// Licensed under the Apache License, Version 2.0 (the "Apache License") +// with the following modification; you may not use this file except in +// compliance with the Apache License and the following modification to it: +// Section 6. Trademarks. is deleted and replaced with: +// +// 6. Trademarks. This License does not grant permission to use the trade +// names, trademarks, service marks, or product names of the Licensor +// and its affiliates, except as required to comply with Section 4(c) of +// the License and to reproduce the content of the NOTICE file. +// +// You may obtain a copy of the Apache License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the Apache License with the above modification is +// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the Apache License for the specific +// language governing permissions and limitations under the Apache License. + +#include "opensubdiv_device_context_opencl.h" + +#ifdef OPENSUBDIV_HAS_OPENCL + +#if defined(_WIN32) +# include <windows.h> +#elif defined(__APPLE__) +# include <OpenGL/OpenGL.h> +#else +# include <GL/glx.h> +#endif + +#include <cstdio> +#include <cstring> +#include <string> +#include <vector> + +#define message(...) // fprintf(stderr, __VA_ARGS__) +#define error(...) fprintf(stderr, __VA_ARGS__) + +namespace { + +// Returns the first found platform. +cl_platform_id findPlatform() { + cl_uint num_platforms; + cl_int ci_error_number = clGetPlatformIDs(0, NULL, &num_platforms); + if (ci_error_number != CL_SUCCESS) { + error("Error %d in clGetPlatformIDs call.\n", ci_error_number); + return NULL; + } + if (num_platforms == 0) { + error("No OpenCL platform found.\n"); + return NULL; + } + std::vector<cl_platform_id> cl_platform_ids(num_platforms); + ci_error_number = clGetPlatformIDs(num_platforms, &cl_platform_ids[0], NULL); + char ch_buffer[1024]; + for (cl_uint i = 0; i < num_platforms; ++i) { + ci_error_number = clGetPlatformInfo(cl_platform_ids[i], + CL_PLATFORM_NAME, + sizeof(ch_buffer), + ch_buffer, + NULL); + if (ci_error_number == CL_SUCCESS) { + cl_platform_id platform_id = cl_platform_ids[i]; + return platform_id; + } + } + return NULL; +} + +// Return the device in cl_devices which supports the extension. +int findExtensionSupportedDevice(cl_device_id* cl_devices, + int num_devices, + const char* extension_name) { + // Find a device that supports sharing with GL/D3D11 + // (SLI / X-fire configurations) + cl_int cl_error_number; + for (int i = 0; i < num_devices; ++i) { + // Get extensions string size. + size_t extensions_size; + cl_error_number = clGetDeviceInfo(cl_devices[i], + CL_DEVICE_EXTENSIONS, + 0, + NULL, + &extensions_size); + if (cl_error_number != CL_SUCCESS) { + error("Error %d in clGetDeviceInfo\n", cl_error_number); + return -1; + } + if (extensions_size > 0) { + // Get extensions string. + std::string extensions('\0', extensions_size); + cl_error_number = clGetDeviceInfo(cl_devices[i], + CL_DEVICE_EXTENSIONS, + extensions_size, + &extensions[0], + &extensions_size); + if (cl_error_number != CL_SUCCESS) { + error("Error %d in clGetDeviceInfo\n", cl_error_number); + continue; + } + // Parse string. This is bit deficient since the extentions + // is space separated. + // + // The actual string would be "cl_khr_d3d11_sharing" + // or "cl_nv_d3d11_sharing" + if (extensions.find(extension_name) != std::string::npos) { + return i; + } + } + } + return -1; +} + +} // namespace + +CLDeviceContext::CLDeviceContext() + : cl_context_(NULL), + cl_command_queue_(NULL) { +} + +CLDeviceContext::~CLDeviceContext() { + if (cl_command_queue_) { + clReleaseCommandQueue(cl_command_queue_); + } + if (cl_context_) { + clReleaseContext(cl_context_); + } +} + +bool CLDeviceContext::HAS_CL_VERSION_1_1() { +#ifdef OPENSUBDIV_HAS_CLEW + static bool clew_initialized = false; + static bool clew_load_success; + if (!clew_initialized) { + clew_initialized = true; + clew_load_success = clewInit() == CLEW_SUCCESS; + if (!clew_load_success) { + error("Loading OpenCL failed.\n"); + } + } + return clew_load_success; +#endif + return true; +} + +bool CLDeviceContext::Initialize() { +#ifdef OPENSUBDIV_HAS_CLEW + if (!clGetPlatformIDs) { + error("Error clGetPlatformIDs function not bound.\n"); + return false; + } +#endif + cl_int cl_error_number; + cl_platform_id cp_platform = findPlatform(); + +#if defined(_WIN32) + cl_context_properties props[] = { + CL_GL_CONTEXT_KHR, + (cl_context_properties)wglGetCurrentContext(), + CL_WGL_HDC_KHR, + (cl_context_properties)wglGetCurrentDC(), + CL_CONTEXT_PLATFORM, + (cl_context_properties)cp_platform, + 0}; +#elif defined(__APPLE__) + CGLContextObj kCGLContext = CGLGetCurrentContext(); + CGLShareGroupObj kCGLShareGroup = CGLGetShareGroup(kCGLContext); + cl_context_properties props[] = {CL_CONTEXT_PROPERTY_USE_CGL_SHAREGROUP_APPLE, + (cl_context_properties)kCGLShareGroup, + 0}; +#else + cl_context_properties props[] = { + CL_GL_CONTEXT_KHR, + (cl_context_properties)glXGetCurrentContext(), + CL_GLX_DISPLAY_KHR, + (cl_context_properties)glXGetCurrentDisplay(), + CL_CONTEXT_PLATFORM, + (cl_context_properties)cp_platform, + 0}; +#endif + +#if defined(__APPLE__) + _clContext = clCreateContext(props, 0, NULL, clLogMessagesToStdoutAPPLE, NULL, + &cl_error_number); + if (cl_error_number != CL_SUCCESS) { + error("Error %d in clCreateContext\n", cl_error_number); + return false; + } + size_t devices_size = 0; + clGetGLContextInfoAPPLE(_clContext, kCGLContext, + CL_CGL_DEVICES_FOR_SUPPORTED_VIRTUAL_SCREENS_APPLE, + 0, + NULL, + &devices_size); + const int num_devices = devices_size / sizeof(cl_device_id); + if (num_devices == 0) { + error("No sharable devices.\n"); + return false; + } + std::vector<cl_device_id> cl_devices(num_devices); + clGetGLContextInfoAPPLE(_clContext, kCGLContext, + CL_CGL_DEVICES_FOR_SUPPORTED_VIRTUAL_SCREENS_APPLE, + num_devices * sizeof(cl_device_id), + &cl_devices[0], + NULL); + int cl_device_used = 0; +#else // not __APPLE__ + // Get the number of GPU devices available to the platform. + cl_uint num_devices = 0; + clGetDeviceIDs(cp_platform, CL_DEVICE_TYPE_GPU, 0, NULL, &num_devices); + if (num_devices == 0) { + error("No CL GPU device found.\n"); + return false; + } + // Create the device list. + std::vector<cl_device_id> cl_devices(num_devices); + clGetDeviceIDs(cp_platform, + CL_DEVICE_TYPE_GPU, + num_devices, + &cl_devices[0], + NULL); + const char* extension = "cl_khr_gl_sharing"; + int cl_device_used = findExtensionSupportedDevice(&cl_devices[0], + num_devices, + extension); + if (cl_device_used < 0) { + error("No device found that supports CL/GL context sharing\n"); + return false; + } + cl_context_ = clCreateContext(props, + 1, + &cl_devices[cl_device_used], + NULL, NULL, + &cl_error_number); +#endif // not __APPLE__ + if (cl_error_number != CL_SUCCESS) { + error("Error %d in clCreateContext\n", cl_error_number); + return false; + } + cl_command_queue_ = clCreateCommandQueue(cl_context_, + cl_devices[cl_device_used], + 0, + &cl_error_number); + if (cl_error_number != CL_SUCCESS) { + error("Error %d in clCreateCommandQueue\n", cl_error_number); + return false; + } + return true; +} + +bool CLDeviceContext::IsInitialized() const { + return (cl_context_ != NULL); +} + +cl_context CLDeviceContext::GetContext() const { + return cl_context_; +} + +cl_command_queue CLDeviceContext::GetCommandQueue() const { + return cl_command_queue_; +} + +#endif // OPENSUBDIV_HAS_OPENCL diff --git a/intern/opensubdiv/internal/opensubdiv_device_context_opencl.h b/intern/opensubdiv/internal/opensubdiv_device_context_opencl.h new file mode 100644 index 00000000000..bc751cb6954 --- /dev/null +++ b/intern/opensubdiv/internal/opensubdiv_device_context_opencl.h @@ -0,0 +1,52 @@ +// Adopted from OpenSubdiv with the following license: +// +// Copyright 2015 Pixar +// +// Licensed under the Apache License, Version 2.0 (the "Apache License") +// with the following modification; you may not use this file except in +// compliance with the Apache License and the following modification to it: +// Section 6. Trademarks. is deleted and replaced with: +// +// 6. Trademarks. This License does not grant permission to use the trade +// names, trademarks, service marks, or product names of the Licensor +// and its affiliates, except as required to comply with Section 4(c) of +// the License and to reproduce the content of the NOTICE file. +// +// You may obtain a copy of the Apache License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the Apache License with the above modification is +// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the Apache License for the specific +// language governing permissions and limitations under the Apache License. + +#ifndef OPENSUBDIV_DEVICE_CONTEXT_OPENCL_H_ +#define OPENSUBDIV_DEVICE_CONTEXT_OPENCL_H_ + +#ifdef OPENSUBDIV_HAS_OPENCL +#include <opensubdiv/osd/opencl.h> + +class CLDeviceContext { + public: + static bool HAS_CL_VERSION_1_1(); + + CLDeviceContext(); + ~CLDeviceContext(); + + bool Initialize(); + + bool IsInitialized() const; + + cl_context GetContext() const; + cl_command_queue GetCommandQueue() const; + + protected: + cl_context cl_context_; + cl_command_queue cl_command_queue_; +}; + +#endif // OPENSUBDIV_HAS_OPENCL + +#endif // _OPENSUBDIV_DEVICE_CONTEXT_OPENCL_H_ diff --git a/intern/opensubdiv/internal/opensubdiv_evaluator.cc b/intern/opensubdiv/internal/opensubdiv_evaluator.cc new file mode 100644 index 00000000000..29d42a903ba --- /dev/null +++ b/intern/opensubdiv/internal/opensubdiv_evaluator.cc @@ -0,0 +1,154 @@ +// Copyright 2015 Blender Foundation. All rights reserved. +// +// 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. +// +// Author: Sergey Sharybin + +#include "opensubdiv_evaluator_capi.h" + +#include <new> +#include "MEM_guardedalloc.h" + +#include "internal/opensubdiv_evaluator_internal.h" + +namespace { + +void setCoarsePositions(OpenSubdiv_Evaluator* evaluator, + const float* positions, + const int start_vertex_index, const int num_vertices) { + evaluator->internal->eval_output->setCoarsePositions(positions, + start_vertex_index, + num_vertices); +} + +void setVaryingData(OpenSubdiv_Evaluator* evaluator, + const float* varying_data, + const int start_vertex_index, const int num_vertices) { + evaluator->internal->eval_output->setVaryingData(varying_data, + start_vertex_index, + num_vertices); +} + +void setFaceVaryingData(OpenSubdiv_Evaluator* evaluator, + const float* face_varying_data, + const int start_vertex_index, const int num_vertices) { + evaluator->internal->eval_output->setFaceVaryingData(face_varying_data, + start_vertex_index, + num_vertices); +} + +void setCoarsePositionsFromBuffer(OpenSubdiv_Evaluator* evaluator, + const void* buffer, + const int start_offset, + const int stride, + const int start_vertex_index, + const int num_vertices) { + evaluator->internal->eval_output->setCoarsePositionsFromBuffer( + buffer, + start_offset, + stride, + start_vertex_index, + num_vertices); +} + +void setVaryingDataFromBuffer(OpenSubdiv_Evaluator* evaluator, + const void* buffer, + const int start_offset, + const int stride, + const int start_vertex_index, + const int num_vertices) { + evaluator->internal->eval_output->setVaryingDataFromBuffer( + buffer, + start_offset, + stride, + start_vertex_index, + num_vertices); +} + +void setFaceVaryingDataFromBuffer(OpenSubdiv_Evaluator* evaluator, + const void* buffer, + const int start_offset, + const int stride, + const int start_vertex_index, + const int num_vertices) { + evaluator->internal->eval_output->setFaceVaryingDataFromBuffer( + buffer, + start_offset, + stride, + start_vertex_index, + num_vertices); +} + +void refine(OpenSubdiv_Evaluator* evaluator) { + evaluator->internal->eval_output->refine(); +} + +void evaluateLimit(OpenSubdiv_Evaluator* evaluator, + const int ptex_face_index, + const float face_u, const float face_v, + float P[3], float dPdu[3], float dPdv[3]) { + evaluator->internal->eval_output->evaluateLimit(ptex_face_index, + face_u, face_v, + P, dPdu, dPdv); +} + +void evaluateVarying(OpenSubdiv_Evaluator* evaluator, + const int ptex_face_index, + float face_u, float face_v, + float varying[3]) { + evaluator->internal->eval_output->evaluateVarying(ptex_face_index, + face_u, face_v, + varying); +} + +void evaluateFaceVarying(OpenSubdiv_Evaluator* evaluator, + const int ptex_face_index, + float face_u, float face_v, + float face_varying[2]) { + evaluator->internal->eval_output->evaluateFaceVarying(ptex_face_index, + face_u, face_v, + face_varying); +} + +void assignFunctionPointers(OpenSubdiv_Evaluator* evaluator) { + evaluator->setCoarsePositions = setCoarsePositions; + evaluator->setVaryingData = setVaryingData; + evaluator->setFaceVaryingData = setFaceVaryingData; + + evaluator->setCoarsePositionsFromBuffer = setCoarsePositionsFromBuffer; + evaluator->setVaryingDataFromBuffer = setVaryingDataFromBuffer; + evaluator->setFaceVaryingDataFromBuffer = setFaceVaryingDataFromBuffer; + + evaluator->refine = refine; + + evaluator->evaluateLimit = evaluateLimit; + evaluator->evaluateVarying = evaluateVarying; + evaluator->evaluateFaceVarying = evaluateFaceVarying; +} + +} // namespace + +OpenSubdiv_Evaluator* openSubdiv_createEvaluatorFromTopologyRefiner( + OpenSubdiv_TopologyRefiner* topology_refiner) { + OpenSubdiv_Evaluator* evaluator = OBJECT_GUARDED_NEW(OpenSubdiv_Evaluator); + assignFunctionPointers(evaluator); + evaluator->internal = openSubdiv_createEvaluatorInternal(topology_refiner); + return evaluator; +} + +void openSubdiv_deleteEvaluator(OpenSubdiv_Evaluator* evaluator) { + openSubdiv_deleteEvaluatorInternal(evaluator->internal); + OBJECT_GUARDED_DELETE(evaluator, OpenSubdiv_Evaluator); +} diff --git a/intern/opensubdiv/internal/opensubdiv_evaluator_internal.cc b/intern/opensubdiv/internal/opensubdiv_evaluator_internal.cc new file mode 100644 index 00000000000..595df3eaa75 --- /dev/null +++ b/intern/opensubdiv/internal/opensubdiv_evaluator_internal.cc @@ -0,0 +1,734 @@ +// Copyright 2018 Blender Foundation. All rights reserved. +// +// 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. +// +// Author: Sergey Sharybin + +#include "internal/opensubdiv_evaluator_internal.h" + +#include <cassert> +#include <cstdio> +#include <vector> + +#ifdef _MSC_VER +# include <iso646.h> +#endif + +#include <opensubdiv/far/patchMap.h> +#include <opensubdiv/far/patchTable.h> +#include <opensubdiv/far/patchTableFactory.h> +#include <opensubdiv/osd/cpuEvaluator.h> +#include <opensubdiv/osd/cpuPatchTable.h> +#include <opensubdiv/osd/cpuVertexBuffer.h> +#include <opensubdiv/osd/mesh.h> +#include <opensubdiv/osd/types.h> + +#include "MEM_guardedalloc.h" + +#include "internal/opensubdiv_topology_refiner_internal.h" +#include "opensubdiv_topology_refiner_capi.h" + +using OpenSubdiv::Osd::BufferDescriptor; +using OpenSubdiv::Osd::CpuEvaluator; +using OpenSubdiv::Osd::CpuPatchTable; +using OpenSubdiv::Osd::CpuVertexBuffer; +using OpenSubdiv::Osd::PatchCoord; +using OpenSubdiv::Far::PatchMap; +using OpenSubdiv::Far::PatchTable; +using OpenSubdiv::Far::PatchTableFactory; +using OpenSubdiv::Far::StencilTable; +using OpenSubdiv::Far::StencilTableFactory; +using OpenSubdiv::Far::TopologyRefiner; + +namespace opensubdiv_capi { + +namespace { + +// Helper class to wrap numerous of patch coordinates into a buffer. +// Used to pass coordinates to the CPU evaluator. Other evaluators are not +// supported. +class PatchCoordBuffer : public std::vector<PatchCoord> { + public: + static PatchCoordBuffer* Create(int size) { + PatchCoordBuffer* buffer = new PatchCoordBuffer(); + buffer->resize(size); + return buffer; + } + + PatchCoord* BindCpuBuffer() { + return reinterpret_cast<PatchCoord*>(&(*this)[0]); + } + + int GetNumVertices() { + return size(); + } + + void UpdateData(const PatchCoord* patch_coords, int num_patch_coords) { + memcpy(&(*this)[0], + reinterpret_cast<const void*>(patch_coords), + sizeof(PatchCoord) * num_patch_coords); + } +}; + +// Helper class to wrap single of patch coord into a buffer. Used to pass +// coordinates to the CPU evaluator. Other evaluators are not supported. +class SinglePatchCoordBuffer { + public: + static SinglePatchCoordBuffer* Create() { + return new SinglePatchCoordBuffer(); + } + + SinglePatchCoordBuffer() { + } + + explicit SinglePatchCoordBuffer(const PatchCoord &patch_coord) + : patch_coord_(patch_coord) { + } + + PatchCoord* BindCpuBuffer() { + return &patch_coord_; + } + + int GetNumVertices() { + return 1; + } + + void UpdateData(const PatchCoord &patch_coord) { + patch_coord_ = patch_coord; + } + + protected: + PatchCoord patch_coord_; +}; + +// Helper class which is aimed to be used in cases when buffer 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 evaluator. +template <int element_size, int num_vertices> +class StackAllocatedBuffer { + public: + static PatchCoordBuffer* Create(int /*size*/) { + // TODO(sergey): Validate that requested dize is smaller than static + // stack memory size. + return new StackAllocatedBuffer<element_size, num_vertices>(); + } + + float* BindCpuBuffer() { + return &data_[0]; + } + + int GetNumVertices() { + return num_vertices; + } + + // TODO(sergey): Support UpdateData(). + protected: + float data_[element_size * num_vertices]; +}; + +// Volatile evaluator which can be used from threads. +// +// TODO(sergey): Make it possible to evaluate coordinates in chunks. +// TODO(sergey): Make it possible to evaluate multiple face varying layers. +// (or maybe, it's cheap to create new evaluator for existing +// topology to evaluate all needed face varying layers?) +template <typename SRC_VERTEX_BUFFER, + typename EVAL_VERTEX_BUFFER, + typename STENCIL_TABLE, + typename PATCH_TABLE, + typename EVALUATOR, + typename DEVICE_CONTEXT = void> +class VolatileEvalOutput { + public: + typedef OpenSubdiv::Osd::EvaluatorCacheT<EVALUATOR> EvaluatorCache; + + VolatileEvalOutput(const StencilTable* vertex_stencils, + const StencilTable* varying_stencils, + const StencilTable* face_varying_stencils, + const int face_varying_channel, + const int face_varying_width, + const PatchTable* patch_table, + EvaluatorCache* evaluator_cache = NULL, + DEVICE_CONTEXT* device_context = NULL) + : src_desc_(0, 3, 3), + src_varying_desc_(0, 3, 3), + src_face_varying_desc_(0, face_varying_width, face_varying_width), + face_varying_channel_(face_varying_channel), + face_varying_width_(face_varying_width), + evaluator_cache_(evaluator_cache), + device_context_(device_context) { + // Total number of vertices = coarse points + refined points + local points. + int num_total_vertices = vertex_stencils->GetNumControlVertices() + + vertex_stencils->GetNumStencils(); + num_coarse_vertices_ = vertex_stencils->GetNumControlVertices(); + using OpenSubdiv::Osd::convertToCompatibleStencilTable; + src_data_ = + SRC_VERTEX_BUFFER::Create(3, num_total_vertices, device_context_); + src_varying_data_ = + SRC_VERTEX_BUFFER::Create(3, num_total_vertices, device_context_); + patch_table_ = PATCH_TABLE::Create(patch_table, device_context_); + patch_coords_ = NULL; + vertex_stencils_ = convertToCompatibleStencilTable<STENCIL_TABLE>( + vertex_stencils, device_context_); + varying_stencils_ = convertToCompatibleStencilTable<STENCIL_TABLE>( + varying_stencils, device_context_); + if (face_varying_stencils != NULL) { + num_coarse_face_varying_vertices_ = + face_varying_stencils->GetNumControlVertices(); + const int num_total_face_varying_vertices = + face_varying_stencils->GetNumControlVertices() + + face_varying_stencils->GetNumStencils(); + src_face_varying_data_ = + EVAL_VERTEX_BUFFER::Create(2, + num_total_face_varying_vertices, + device_context_); + face_varying_stencils_ = convertToCompatibleStencilTable<STENCIL_TABLE>( + face_varying_stencils, device_context_); + } else { + num_coarse_face_varying_vertices_ = 0; + src_face_varying_data_ = NULL; + face_varying_stencils_ = NULL; + } + } + + ~VolatileEvalOutput() { + delete src_data_; + delete src_varying_data_; + delete src_face_varying_data_; + delete patch_table_; + delete vertex_stencils_; + delete varying_stencils_; + delete face_varying_stencils_; + } + + // TODO(sergey): Implement binding API. + + void updateData(const float* src, int start_vertex, int num_vertices) { + src_data_->UpdateData(src, start_vertex, num_vertices, device_context_); + } + + void updateVaryingData(const float* src, int start_vertex, int num_vertices) { + src_varying_data_->UpdateData(src, + start_vertex, + num_vertices, + device_context_); + } + + void updateFaceVaryingData(const float* src, + int start_vertex, + int num_vertices) { + src_face_varying_data_->UpdateData(src, + start_vertex, + num_vertices, + device_context_); + } + + bool hasVaryingData() const { + // return varying_stencils_ != NULL; + // TODO(sergey): Check this based on actual topology. + return false; + } + + bool hasFaceVaryingData() const { + return face_varying_stencils_ != NULL; + } + + void refine() { + // Evaluate vertex positions. + BufferDescriptor dst_desc = src_desc_; + dst_desc.offset += num_coarse_vertices_ * src_desc_.stride; + const EVALUATOR* eval_instance = + OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(evaluator_cache_, + src_desc_, + dst_desc, + device_context_); + EVALUATOR::EvalStencils(src_data_, src_desc_, + src_data_, dst_desc, + vertex_stencils_, + eval_instance, + device_context_); + // Evaluate varying data. + if (hasVaryingData()) { + BufferDescriptor dst_varying_desc = src_varying_desc_; + dst_varying_desc.offset += + num_coarse_vertices_ * src_varying_desc_.stride; + eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>( + evaluator_cache_, + src_varying_desc_, + dst_varying_desc, + device_context_); + EVALUATOR::EvalStencils(src_varying_data_, src_varying_desc_, + src_varying_data_, dst_varying_desc, + varying_stencils_, + eval_instance, device_context_); + } + // Evaluate face-varying data. + if (hasFaceVaryingData()) { + BufferDescriptor dst_face_varying_desc = src_face_varying_desc_; + dst_face_varying_desc.offset += num_coarse_face_varying_vertices_ * + src_face_varying_desc_.stride; + eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>( + evaluator_cache_, + src_face_varying_desc_, + dst_face_varying_desc, + device_context_); + EVALUATOR::EvalStencils(src_face_varying_data_, src_face_varying_desc_, + src_face_varying_data_, dst_face_varying_desc, + face_varying_stencils_, + eval_instance, + device_context_); + } + } + + void evalPatchCoord(const PatchCoord& patch_coord, float P[3]) { + StackAllocatedBuffer<6, 1> vertex_data; + // TODO(sergey): Varying data is interleaved in vertex array, so need to + // adjust stride if there is a varying data. + // BufferDescriptor vertex_desc(0, 3, 6); + BufferDescriptor vertex_desc(0, 3, 3); + SinglePatchCoordBuffer patch_coord_buffer(patch_coord); + const EVALUATOR* eval_instance = + OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(evaluator_cache_, + src_desc_, + vertex_desc, + device_context_); + EVALUATOR::EvalPatches(src_data_, + src_desc_, + &vertex_data, + vertex_desc, + patch_coord_buffer.GetNumVertices(), + &patch_coord_buffer, + patch_table_, + eval_instance, + device_context_); + const float* refined_vertices = vertex_data.BindCpuBuffer(); + memcpy(P, refined_vertices, sizeof(float) * 3); + } + + void evalPatchesWithDerivatives(const PatchCoord& patch_coord, + float P[3], + float dPdu[3], float dPdv[3]) { + StackAllocatedBuffer<6, 1> vertex_data, derivatives; + // TODO(sergey): Varying data is interleaved in vertex array, so need to + // adjust stride if there is a varying data. + // BufferDescriptor vertex_desc(0, 3, 6); + BufferDescriptor vertex_desc(0, 3, 3); + BufferDescriptor du_desc(0, 3, 6), dv_desc(3, 3, 6); + SinglePatchCoordBuffer patch_coord_buffer(patch_coord); + const EVALUATOR* eval_instance = + OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(evaluator_cache_, + src_desc_, + vertex_desc, + du_desc, dv_desc, + device_context_); + EVALUATOR::EvalPatches(src_data_, src_desc_, + &vertex_data, vertex_desc, + &derivatives, du_desc, + &derivatives, dv_desc, + patch_coord_buffer.GetNumVertices(), + &patch_coord_buffer, + patch_table_, + eval_instance, + device_context_); + const float* refined_vertices = vertex_data.BindCpuBuffer(); + memcpy(P, refined_vertices, sizeof(float) * 3); + if (dPdu != NULL || dPdv != NULL) { + const float* refined_derivatives = derivatives.BindCpuBuffer(); + if (dPdu != NULL) { + memcpy(dPdu, refined_derivatives, sizeof(float) * 3); + } + if (dPdv != NULL) { + memcpy(dPdv, refined_derivatives + 3, sizeof(float) * 3); + } + } + } + + void evalPatchVarying(const PatchCoord& patch_coord, float varying[3]) { + StackAllocatedBuffer<6, 1> varying_data; + BufferDescriptor varying_desc(3, 3, 6); + SinglePatchCoordBuffer patch_coord_buffer(patch_coord); + const EVALUATOR* eval_instance = + OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(evaluator_cache_, + src_varying_desc_, + varying_desc, + device_context_); + EVALUATOR::EvalPatchesVarying(src_varying_data_, src_varying_desc_, + &varying_data, varying_desc, + patch_coord_buffer.GetNumVertices(), + &patch_coord_buffer, + patch_table_, + eval_instance, + device_context_); + const float* refined_varying = varying_data.BindCpuBuffer(); + memcpy(varying, refined_varying, sizeof(float) * 3); + } + + void evalPatchFaceVarying(const PatchCoord& patch_coord, + float face_varying[2]) { + StackAllocatedBuffer<2, 1> face_varying_data; + BufferDescriptor face_varying_desc(0, 2, 2); + SinglePatchCoordBuffer patch_coord_buffer(patch_coord); + const EVALUATOR* eval_instance = + OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(evaluator_cache_, + src_face_varying_desc_, + face_varying_desc, + device_context_); + EVALUATOR::EvalPatchesFaceVarying( + src_face_varying_data_, src_face_varying_desc_, + &face_varying_data, face_varying_desc, + patch_coord_buffer.GetNumVertices(), + &patch_coord_buffer, + patch_table_, + face_varying_channel_, + eval_instance, + device_context_); + const float* refined_face_varying = face_varying_data.BindCpuBuffer(); + memcpy(face_varying, refined_face_varying, sizeof(float) * 2); + } + + private: + SRC_VERTEX_BUFFER* src_data_; + SRC_VERTEX_BUFFER* src_varying_data_; + EVAL_VERTEX_BUFFER* src_face_varying_data_; + PatchCoordBuffer* patch_coords_; + PATCH_TABLE* patch_table_; + BufferDescriptor src_desc_; + BufferDescriptor src_varying_desc_; + BufferDescriptor src_face_varying_desc_; + + int num_coarse_vertices_; + int face_varying_channel_; + int face_varying_width_; + int num_coarse_face_varying_vertices_; + + const STENCIL_TABLE* vertex_stencils_; + const STENCIL_TABLE* varying_stencils_; + const STENCIL_TABLE* face_varying_stencils_; + + EvaluatorCache* evaluator_cache_; + DEVICE_CONTEXT* device_context_; +}; + +} // namespace + +// Note: Define as a class instead of typedcef to make it possible +// to have anonymous class in opensubdiv_evaluator_internal.h +class CpuEvalOutput : public VolatileEvalOutput<CpuVertexBuffer, + CpuVertexBuffer, + StencilTable, + CpuPatchTable, + CpuEvaluator> { + public: + CpuEvalOutput(const StencilTable* vertex_stencils, + const StencilTable* varying_stencils, + const StencilTable* face_varying_stencils, + const int face_varying_channel, + const int face_varying_width, + const PatchTable* patch_table, + EvaluatorCache* evaluator_cache = NULL) + : VolatileEvalOutput<CpuVertexBuffer, + CpuVertexBuffer, + StencilTable, + CpuPatchTable, + CpuEvaluator> (vertex_stencils, + varying_stencils, + face_varying_stencils, + face_varying_channel, + face_varying_width, + patch_table, + evaluator_cache) { + } +}; + +//////////////////////////////////////////////////////////////////////////////// +// Evaluator wrapper for anonymous API. + +CpuEvalOutputAPI::CpuEvalOutputAPI(CpuEvalOutput* implementation, + OpenSubdiv::Far::PatchMap* patch_map) + : implementation_(implementation), + patch_map_(patch_map) { +} + +CpuEvalOutputAPI::~CpuEvalOutputAPI() { + delete implementation_; +} + +void CpuEvalOutputAPI::setCoarsePositions(const float* positions, + const int start_vertex_index, + const int num_vertices) { + // TODO(sergey): Add sanity check on indices. + implementation_->updateData(positions, start_vertex_index, num_vertices); +} + +void CpuEvalOutputAPI::setVaryingData(const float* varying_data, + const int start_vertex_index, + const int num_vertices) { + // TODO(sergey): Add sanity check on indices. + implementation_->updateVaryingData(varying_data, + start_vertex_index, + num_vertices); +} + +void CpuEvalOutputAPI::setFaceVaryingData(const float* face_varying_data, + const int start_vertex_index, + const int num_vertices) { + // TODO(sergey): Add sanity check on indices. + implementation_->updateFaceVaryingData(face_varying_data, + start_vertex_index, + num_vertices); +} + +void CpuEvalOutputAPI::setCoarsePositionsFromBuffer( + const void* buffer, + const int start_offset, + const int stride, + const int start_vertex_index, + const int num_vertices) { + // TODO(sergey): Add sanity check on indices. + const unsigned char* current_buffer = (unsigned char *)buffer; + current_buffer += start_offset; + for (int i = 0; i < num_vertices; ++i) { + const int current_vertex_index = start_vertex_index + i; + implementation_->updateData(reinterpret_cast<const float*>(current_buffer), + current_vertex_index, 1); + current_buffer += stride; + } +} + +void CpuEvalOutputAPI::setVaryingDataFromBuffer( + const void* buffer, + const int start_offset, + const int stride, + const int start_vertex_index, + const int num_vertices) { + // TODO(sergey): Add sanity check on indices. + const unsigned char* current_buffer = (unsigned char *)buffer; + current_buffer += start_offset; + for (int i = 0; i < num_vertices; ++i) { + const int current_vertex_index = start_vertex_index + i; + implementation_->updateVaryingData( + reinterpret_cast<const float*>(current_buffer), + current_vertex_index, 1); + current_buffer += stride; + } +} + +void CpuEvalOutputAPI::setFaceVaryingDataFromBuffer( + const void* buffer, + const int start_offset, + const int stride, + const int start_vertex_index, + const int num_vertices) { + // TODO(sergey): Add sanity check on indices. + const unsigned char* current_buffer = (unsigned char *)buffer; + current_buffer += start_offset; + for (int i = 0; i < num_vertices; ++i) { + const int current_vertex_index = start_vertex_index + i; + implementation_->updateFaceVaryingData( + reinterpret_cast<const float*>(current_buffer), + current_vertex_index, 1); + current_buffer += stride; + } +} + +void CpuEvalOutputAPI::refine() { + implementation_->refine(); +} + +void CpuEvalOutputAPI::evaluateLimit(const int ptex_face_index, + float face_u, float face_v, + float P[3], float dPdu[3], float dPdv[3]) { + assert(face_u >= 0.0f); + assert(face_u <= 1.0f); + assert(face_v >= 0.0f); + assert(face_v <= 1.0f); + const PatchTable::PatchHandle* handle = + patch_map_->FindPatch(ptex_face_index, face_u, face_v); + PatchCoord patch_coord(*handle, face_u, face_v); + if (dPdu != NULL || dPdv != NULL) { + implementation_->evalPatchesWithDerivatives(patch_coord, P, dPdu, dPdv); + } else { + implementation_->evalPatchCoord(patch_coord, P); + }} + +void CpuEvalOutputAPI::evaluateVarying(const int ptex_face_index, + float face_u, float face_v, + float varying[3]) { + assert(face_u >= 0.0f); + assert(face_u <= 1.0f); + assert(face_v >= 0.0f); + assert(face_v <= 1.0f); + const PatchTable::PatchHandle* handle = + patch_map_->FindPatch(ptex_face_index, face_u, face_v); + PatchCoord patch_coord(*handle, face_u, face_v); + implementation_->evalPatchVarying(patch_coord, varying); +} + +void CpuEvalOutputAPI::evaluateFaceVarying(const int ptex_face_index, + float face_u, float face_v, + float face_varying[2]) { + assert(face_u >= 0.0f); + assert(face_u <= 1.0f); + assert(face_v >= 0.0f); + assert(face_v <= 1.0f); + const PatchTable::PatchHandle* handle = + patch_map_->FindPatch(ptex_face_index, face_u, face_v); + PatchCoord patch_coord(*handle, face_u, face_v); + implementation_->evalPatchFaceVarying(patch_coord, face_varying); +} + +} // namespace opensubdiv_capi + +OpenSubdiv_EvaluatorInternal::OpenSubdiv_EvaluatorInternal() + : eval_output(NULL), + patch_map(NULL), + patch_table(NULL) { +} + +OpenSubdiv_EvaluatorInternal::~OpenSubdiv_EvaluatorInternal() { + delete eval_output; + delete patch_map; + delete patch_table; +} + +OpenSubdiv_EvaluatorInternal* openSubdiv_createEvaluatorInternal( + OpenSubdiv_TopologyRefiner* topology_refiner) { + TopologyRefiner* refiner = topology_refiner->internal->osd_topology_refiner; + if (refiner == NULL) { + // Happens on bad topology. + return NULL; + } + // TODO(sergey): Base this on actual topology. + // const bool bas_varying_data = false; + const bool has_face_varying_data = + (refiner->GetNumFVarChannels() != 0); + const int level = topology_refiner->getSubdivisionLevel(topology_refiner); + // TODO(sergey): Query from topology refiner. + const bool is_adaptive = topology_refiner->getIsAdaptive(topology_refiner); + // Refine the topology with given settings. + // TODO(sergey): What if topology is already refined? + if (is_adaptive) { + TopologyRefiner::AdaptiveOptions options(level); + options.considerFVarChannels = has_face_varying_data; + options.useInfSharpPatch = false; + refiner->RefineAdaptive(options); + } else { + TopologyRefiner::UniformOptions options(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). + // + // Vertex stencils. + StencilTableFactory::Options vertex_stencil_options; + vertex_stencil_options.generateOffsets = true; + vertex_stencil_options.generateIntermediateLevels = is_adaptive; + const StencilTable* vertex_stencils = + StencilTableFactory::Create(*refiner, vertex_stencil_options); + // Varying stencils. + // + // TODO(sergey): Seems currently varying stencils are always required in + // OpenSubdiv itself. + const StencilTable* varying_stencils = NULL; + StencilTableFactory::Options varying_stencil_options; + varying_stencil_options.generateOffsets = true; + varying_stencil_options.generateIntermediateLevels = is_adaptive; + varying_stencil_options.interpolationMode = + StencilTableFactory::INTERPOLATE_VARYING; + varying_stencils = + StencilTableFactory::Create(*refiner, varying_stencil_options); + // Face warying stencil. + const StencilTable* face_varying_stencils = NULL; + if (has_face_varying_data) { + StencilTableFactory::Options face_varying_stencil_options; + face_varying_stencil_options.generateOffsets = true; + face_varying_stencil_options.generateIntermediateLevels = is_adaptive; + face_varying_stencil_options.interpolationMode = + StencilTableFactory::INTERPOLATE_FACE_VARYING; + // TODO(sergey): Make it configurable which face varying channel is being + // interpolated. + face_varying_stencil_options.fvarChannel = 0; + face_varying_stencils = + StencilTableFactory::Create(*refiner, face_varying_stencil_options); + } + // Generate bi-cubic patch table for the limit surface. + // TODO(sergey): Ideally we would want to expose end-cap settings via + // C-API to make it more generic. Currently it matches old Blender's + // subsurf code. + PatchTableFactory::Options patch_options(level); + patch_options.SetEndCapType(PatchTableFactory::Options::ENDCAP_BSPLINE_BASIS); + patch_options.useInfSharpPatch = false; + patch_options.generateFVarTables = has_face_varying_data; + patch_options.generateFVarLegacyLinearPatches = false; + const PatchTable* patch_table = PatchTableFactory::Create( + *refiner, patch_options); + // Append local points stencils. + 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); + delete vertex_stencils; + vertex_stencils = table; + } + 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); + delete varying_stencils; + varying_stencils = table; + } + const StencilTable* local_point_face_varying_stencil_table = + patch_table->GetLocalPointFaceVaryingStencilTable(); + if (local_point_face_varying_stencil_table != NULL) { + const StencilTable* table = + StencilTableFactory::AppendLocalPointStencilTableFaceVarying( + *refiner, + face_varying_stencils, + local_point_face_varying_stencil_table); + delete face_varying_stencils; + face_varying_stencils = table; + } + // Create OpenSubdiv's CPU side evaluator. + // TODO(sergey): Make it possible to use different evaluators. + opensubdiv_capi::CpuEvalOutput* eval_output = + new opensubdiv_capi::CpuEvalOutput(vertex_stencils, + varying_stencils, + face_varying_stencils, + 0, 2, + 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_EvaluatorInternal* evaluator_descr; + evaluator_descr = OBJECT_GUARDED_NEW(OpenSubdiv_EvaluatorInternal); + evaluator_descr->eval_output = + new opensubdiv_capi::CpuEvalOutputAPI(eval_output, patch_map); + evaluator_descr->patch_map = patch_map; + evaluator_descr->patch_table = patch_table; + // TOOD(sergey): Look into whether we've got duplicated stencils arrays. + delete vertex_stencils; + delete varying_stencils; + delete face_varying_stencils; + return evaluator_descr; +} + +void openSubdiv_deleteEvaluatorInternal( + OpenSubdiv_EvaluatorInternal* evaluator) { + OBJECT_GUARDED_DELETE(evaluator, OpenSubdiv_EvaluatorInternal); +} diff --git a/intern/opensubdiv/internal/opensubdiv_evaluator_internal.h b/intern/opensubdiv/internal/opensubdiv_evaluator_internal.h new file mode 100644 index 00000000000..cc69db6abc6 --- /dev/null +++ b/intern/opensubdiv/internal/opensubdiv_evaluator_internal.h @@ -0,0 +1,134 @@ +// Copyright 2018 Blender Foundation. All rights reserved. +// +// 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. +// +// Author: Sergey Sharybin + +#ifndef OPENSUBDIV_EVALUATOR_INTERNAL_H_ +#define OPENSUBDIV_EVALUATOR_INTERNAL_H_ + +#ifdef _MSC_VER +# include <iso646.h> +#endif + +#include <opensubdiv/far/patchMap.h> +#include <opensubdiv/far/patchTable.h> + +struct OpenSubdiv_TopologyRefiner; + +namespace opensubdiv_capi { + +// Anonymous forward declaration of actual evaluator implementation. +class CpuEvalOutput; + +// Wrapper around implementaiton, which defines API which we are capable to +// provide over the implementation. +// +// TODO(sergey): It is almost the same as C-API object, so ideally need to +// merge them somehow, but how to do this and keep files with all the templates +// and such separate? +class CpuEvalOutputAPI { + public: + // NOTE: API object becomes an owner of evaluator. Patch we are referencing. + CpuEvalOutputAPI(CpuEvalOutput* implementation, + OpenSubdiv::Far::PatchMap* patch_map); + ~CpuEvalOutputAPI(); + + // Set coarse positions from a continuous array of coordinates. + void setCoarsePositions(const float* positions, + const int start_vertex_index, + const int num_vertices); + // Set varying data from a continuous array of data. + void setVaryingData(const float* varying_data, + const int start_vertex_index, const int num_vertices); + // Set face varying data from a continuous array of data. + // + // TODO(sergey): Find a better name for vertex here. It is not the vertex of + // geometry, but a vertex of UV map. + void setFaceVaryingData(const float* varying_data, + const int start_vertex_index, const int num_vertices); + + // Set coarse vertex position from a continuous memory buffer where + // first coordinate starts at offset of `start_offset` and there is `stride` + // bytes between adjacent vertex coordinates. + void setCoarsePositionsFromBuffer(const void* buffer, + const int start_offset, + const int stride, + const int start_vertex_index, + const int num_vertices); + // Set varying data from a continuous memory buffer where + // first coordinate starts at offset of `start_offset` and there is `stride` + // bytes between adjacent vertex coordinates. + void setVaryingDataFromBuffer(const void* buffer, + const int start_offset, + const int stride, + const int start_vertex_index, + const int num_vertices); + // Set face varying data from a continuous memory buffer where + // first coordinate starts at offset of `start_offset` and there is `stride` + // bytes between adjacent vertex coordinates. + // + // TODO(sergey): Find a better name for vertex here. It is not the vertex of + // geometry, but a vertex of UV map. + void setFaceVaryingDataFromBuffer(const void* buffer, + const int start_offset, + const int stride, + const int start_vertex_index, + const int num_vertices); + + // Refine after coarse positions update. + void refine(); + + // Evaluate given ptex face at given bilinear coordinate. + // If derivatives are NULL, they will not be evaluated. + void evaluateLimit(const int ptex_face_index, + float face_u, float face_v, + float P[3], float dPdu[3], float dPdv[3]); + + // Evaluate varying data at a given bilinear coordinate of given ptex face. + void evaluateVarying(const int ptes_face_index, + float face_u, float face_v, + float varying[3]); + + // Evaluate facee-varying data at a given bilinear coordinate of given + // ptex face. + void evaluateFaceVarying(const int ptes_face_index, + float face_u, float face_v, + float face_varying[2]); + + protected: + CpuEvalOutput* implementation_; + OpenSubdiv::Far::PatchMap* patch_map_; +}; + +} // namespace opensubdiv_capi + +struct OpenSubdiv_EvaluatorInternal { + public: + OpenSubdiv_EvaluatorInternal(); + ~OpenSubdiv_EvaluatorInternal(); + + opensubdiv_capi::CpuEvalOutputAPI* eval_output; + const OpenSubdiv::Far::PatchMap* patch_map; + const OpenSubdiv::Far::PatchTable* patch_table; +}; + +OpenSubdiv_EvaluatorInternal* openSubdiv_createEvaluatorInternal( + struct OpenSubdiv_TopologyRefiner* topology_refiner); + +void openSubdiv_deleteEvaluatorInternal( + OpenSubdiv_EvaluatorInternal* evaluator); + +#endif // OPENSUBDIV_EVALUATOR_INTERNAL_H_ diff --git a/intern/opensubdiv/internal/opensubdiv_gl_mesh.cc b/intern/opensubdiv/internal/opensubdiv_gl_mesh.cc new file mode 100644 index 00000000000..34d27591d0b --- /dev/null +++ b/intern/opensubdiv/internal/opensubdiv_gl_mesh.cc @@ -0,0 +1,287 @@ +// Copyright 2013 Blender Foundation. All rights reserved. +// +// 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. +// +// Author: Sergey Sharybin +// Contributor(s): Brecht van Lommel + +#include "opensubdiv_gl_mesh_capi.h" + +#ifdef _MSC_VER +# include <iso646.h> +#endif + +#include <opensubdiv/far/stencilTable.h> +#include <opensubdiv/osd/glMesh.h> +#include <opensubdiv/osd/glPatchTable.h> + +using OpenSubdiv::Far::StencilTable; +using OpenSubdiv::Osd::GLMeshInterface; +using OpenSubdiv::Osd::GLPatchTable; +using OpenSubdiv::Osd::Mesh; +using OpenSubdiv::Osd::MeshBitset; + +// CPU backend. +#include <opensubdiv/osd/cpuEvaluator.h> +#include <opensubdiv/osd/cpuGLVertexBuffer.h> +using OpenSubdiv::Osd::CpuGLVertexBuffer; +using OpenSubdiv::Osd::CpuEvaluator; +typedef Mesh<CpuGLVertexBuffer, + StencilTable, + CpuEvaluator, + GLPatchTable> OsdCpuMesh; +// OpenMP backend. +#ifdef OPENSUBDIV_HAS_OPENMP +# include <opensubdiv/osd/ompEvaluator.h> +using OpenSubdiv::Osd::OmpEvaluator; +typedef Mesh<CpuGLVertexBuffer, + StencilTable, + OmpEvaluator, + GLPatchTable> OsdOmpMesh; +#endif +// OpenCL backend. +#ifdef OPENSUBDIV_HAS_OPENCL +# include <opensubdiv/osd/clEvaluator.h> +# include <opensubdiv/osd/clGLVertexBuffer.h> +# include "opensubdiv_device_context_opencl.h" +using OpenSubdiv::Osd::CLEvaluator; +using OpenSubdiv::Osd::CLGLVertexBuffer; +using OpenSubdiv::Osd::CLStencilTable; +/* TODO(sergey): Use CLDeviceContext similar to OSD examples? */ +typedef Mesh<CLGLVertexBuffer, + CLStencilTable, + CLEvaluator, + GLPatchTable, + CLDeviceContext> OsdCLMesh; +static CLDeviceContext g_cl_device_context; +#endif +// CUDA backend. +#ifdef OPENSUBDIV_HAS_CUDA +# include <opensubdiv/osd/cudaEvaluator.h> +# include <opensubdiv/osd/cudaGLVertexBuffer.h> +# include "opensubdiv_device_context_cuda.h" +using OpenSubdiv::Osd::CudaEvaluator; +using OpenSubdiv::Osd::CudaGLVertexBuffer; +using OpenSubdiv::Osd::CudaStencilTable; +typedef Mesh<CudaGLVertexBuffer, + CudaStencilTable, + CudaEvaluator, + GLPatchTable> OsdCudaMesh; +static CudaDeviceContext g_cuda_device_context; +#endif +// Transform feedback backend. +#ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK +# include <opensubdiv/osd/glVertexBuffer.h> +# include <opensubdiv/osd/glXFBEvaluator.h> +using OpenSubdiv::Osd::GLXFBEvaluator; +using OpenSubdiv::Osd::GLStencilTableTBO; +using OpenSubdiv::Osd::GLVertexBuffer; +typedef Mesh<GLVertexBuffer, + GLStencilTableTBO, + GLXFBEvaluator, + GLPatchTable> OsdGLSLTransformFeedbackMesh; +#endif +// GLSL compute backend. +#ifdef OPENSUBDIV_HAS_GLSL_COMPUTE +# include <opensubdiv/osd/glComputeEvaluator.h> +# include <opensubdiv/osd/glVertexBuffer.h> +using OpenSubdiv::Osd::GLComputeEvaluator; +using OpenSubdiv::Osd::GLStencilTableSSBO; +using OpenSubdiv::Osd::GLVertexBuffer; +typedef Mesh<GLVertexBuffer, + GLStencilTableSSBO, + GLComputeEvaluator, + GLPatchTable> OsdGLSLComputeMesh; +#endif + +#include <string> +#include <vector> + +#include "MEM_guardedalloc.h" + +#include "opensubdiv_topology_refiner_capi.h" +#include "internal/opensubdiv_gl_mesh_draw.h" +#include "internal/opensubdiv_gl_mesh_fvar.h" +#include "internal/opensubdiv_gl_mesh_internal.h" +#include "internal/opensubdiv_topology_refiner_internal.h" + +namespace { + +GLMeshInterface* createGLMeshInterface( + OpenSubdiv::Far::TopologyRefiner* topology_refiner, + const MeshBitset& bits, + const int num_vertex_elements, + const int num_varying_elements, + const int level, + eOpenSubdivEvaluator evaluator_type) { + GLMeshInterface* mesh = NULL; + switch (evaluator_type) { +#define CHECK_EVALUATOR_TYPE(type, class) \ + case OPENSUBDIV_EVALUATOR_##type: \ + mesh = new class(topology_refiner, \ + num_vertex_elements, \ + num_varying_elements, \ + level, \ + bits); \ + break; + +#define CHECK_EVALUATOR_TYPE_STUB(type) \ + case OPENSUBDIV_EVALUATOR_##type: \ + mesh = NULL; \ + break; + + CHECK_EVALUATOR_TYPE(CPU, OsdCpuMesh) +#ifdef OPENSUBDIV_HAS_OPENMP + CHECK_EVALUATOR_TYPE(OPENMP, OsdOmpMesh) +#else + CHECK_EVALUATOR_TYPE_STUB(OPENMP) +#endif +#ifdef OPENSUBDIV_HAS_OPENCL + CHECK_EVALUATOR_TYPE(OPENCL, OsdCLMesh) +#else + CHECK_EVALUATOR_TYPE_STUB(OPENCL) +#endif +#ifdef OPENSUBDIV_HAS_CUDA + CHECK_EVALUATOR_TYPE(CUDA, OsdCudaMesh) +#else + CHECK_EVALUATOR_TYPE_STUB(CUDA) +#endif +#ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK + CHECK_EVALUATOR_TYPE(GLSL_TRANSFORM_FEEDBACK, OsdGLSLTransformFeedbackMesh) +#else + CHECK_EVALUATOR_TYPE_STUB(GLSL_TRANSFORM_FEEDBACK) +#endif +#ifdef OPENSUBDIV_HAS_GLSL_COMPUTE + CHECK_EVALUATOR_TYPE(GLSL_COMPUTE, OsdGLSLComputeMesh) +#else + CHECK_EVALUATOR_TYPE_STUB(GLSL_COMPUTE) +#endif + +#undef CHECK_EVALUATOR_TYPE +#undef CHECK_EVALUATOR_TYPE_STUB + } + return mesh; +} + +//////////////////////////////////////////////////////////////////////////////// +// GLMesh structure "methods". + +opensubdiv_capi::GLMeshFVarData* createFVarData( + OpenSubdiv::Far::TopologyRefiner* topology_refiner, + GLMeshInterface* mesh, + const float *fvar_src_buffer) { + using opensubdiv_capi::GLMeshFVarData; + GLMeshFVarData* fvar_data = new GLMeshFVarData(); + fvar_data->create(topology_refiner, + mesh->GetFarPatchTable(), + 2, + fvar_src_buffer); + return fvar_data; +} + +unsigned int getPatchIndexBuffer(OpenSubdiv_GLMesh* gl_mesh) { + return gl_mesh->internal->mesh_interface + ->GetPatchTable() + ->GetPatchIndexBuffer(); +} + +void bindVertexBuffer(OpenSubdiv_GLMesh* gl_mesh) { + gl_mesh->internal->mesh_interface->BindVertexBuffer(); +} + +void setCoarsePositions(OpenSubdiv_GLMesh* gl_mesh, + const float* positions, + const int start_vertex, + const int num_vertices) { + gl_mesh->internal->mesh_interface->UpdateVertexBuffer(positions, + start_vertex, + num_vertices); +} + +void refine(OpenSubdiv_GLMesh* gl_mesh) { + gl_mesh->internal->mesh_interface->Refine(); +} + +void synchronize(struct OpenSubdiv_GLMesh* gl_mesh) { + gl_mesh->internal->mesh_interface->Synchronize(); +} + +void assignFunctionPointers(OpenSubdiv_GLMesh* gl_mesh) { + gl_mesh->getPatchIndexBuffer = getPatchIndexBuffer; + gl_mesh->bindVertexBuffer = bindVertexBuffer; + gl_mesh->setCoarsePositions = setCoarsePositions; + gl_mesh->refine = refine; + gl_mesh->synchronize = synchronize; + + gl_mesh->prepareDraw = opensubdiv_capi::GLMeshDisplayPrepare; + gl_mesh->drawPatches = opensubdiv_capi::GLMeshDisplayDrawPatches; +} + +} // namespace + +struct OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner( + OpenSubdiv_TopologyRefiner* topology_refiner, + eOpenSubdivEvaluator evaluator_type) { + using OpenSubdiv::Far::TopologyRefiner; + TopologyRefiner* osd_topology_refiner = + topology_refiner->internal->osd_topology_refiner; + // TODO(sergey): Query this from refiner. + const bool is_adaptive = false; + MeshBitset bits; + bits.set(OpenSubdiv::Osd::MeshAdaptive, is_adaptive); + bits.set(OpenSubdiv::Osd::MeshUseSingleCreasePatch, 0); + bits.set(OpenSubdiv::Osd::MeshInterleaveVarying, 1); + bits.set(OpenSubdiv::Osd::MeshFVarData, 1); + bits.set(OpenSubdiv::Osd::MeshEndCapBSplineBasis, 1); + const int num_vertex_elements = 3; + const int num_varying_elements = 3; + GLMeshInterface* mesh = createGLMeshInterface( + osd_topology_refiner, + bits, + num_vertex_elements, + num_varying_elements, + osd_topology_refiner->GetMaxLevel(), + evaluator_type); + if (mesh == NULL) { + return NULL; + } + OpenSubdiv_GLMesh* gl_mesh = OBJECT_GUARDED_NEW(OpenSubdiv_GLMesh); + assignFunctionPointers(gl_mesh); + gl_mesh->internal = new OpenSubdiv_GLMeshInternal(); + gl_mesh->internal->evaluator_type = evaluator_type; + gl_mesh->internal->mesh_interface = mesh; + // Face-varying support. + // TODO(sergey): This part needs to be re-done. + if (osd_topology_refiner->GetNumFVarChannels() > 0) { + // TODO(sergey): This is a temporary stub to get things compiled. Need + // to store base level UVs somewhere else. + std::vector<float> uvs; + std::vector<float> fvar_data_buffer; + opensubdiv_capi::interpolateFVarData(*osd_topology_refiner, + uvs, + &fvar_data_buffer); + gl_mesh->internal->fvar_data = createFVarData(osd_topology_refiner, + mesh, + &fvar_data_buffer[0]); + } else { + gl_mesh->internal->fvar_data = NULL; + } + return gl_mesh; +} + +void openSubdiv_deleteOsdGLMesh(OpenSubdiv_GLMesh *gl_mesh) { + delete gl_mesh->internal; + OBJECT_GUARDED_DELETE(gl_mesh, OpenSubdiv_GLMesh); +} diff --git a/intern/opensubdiv/internal/opensubdiv_gl_mesh_draw.cc b/intern/opensubdiv/internal/opensubdiv_gl_mesh_draw.cc new file mode 100644 index 00000000000..0d2f8dc9842 --- /dev/null +++ b/intern/opensubdiv/internal/opensubdiv_gl_mesh_draw.cc @@ -0,0 +1,587 @@ +// Copyright 2013 Blender Foundation. All rights reserved. +// +// 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. +// +// Author: Sergey Sharybin + +#include "internal/opensubdiv_gl_mesh_draw.h" + +#ifdef _MSC_VER +# include <iso646.h> +#endif + +#include <GL/glew.h> +#include <cmath> +#include <cstdio> + +#include <opensubdiv/osd/glMesh.h> + +#ifdef OPENSUBDIV_HAS_CUDA +# include <opensubdiv/osd/cudaGLVertexBuffer.h> +#endif // OPENSUBDIV_HAS_CUDA + +#include <opensubdiv/osd/cpuEvaluator.h> +#include <opensubdiv/osd/cpuGLVertexBuffer.h> + +#include "internal/opensubdiv_gl_mesh_fvar.h" +#include "internal/opensubdiv_gl_mesh_internal.h" +#include "opensubdiv_capi.h" +#include "opensubdiv_gl_mesh_capi.h" + +using OpenSubdiv::Osd::GLMeshInterface; + +extern "C" char datatoc_gpu_shader_opensubdiv_vertex_glsl[]; +extern "C" char datatoc_gpu_shader_opensubdiv_geometry_glsl[]; +extern "C" char datatoc_gpu_shader_opensubdiv_fragment_glsl[]; + +// TODO(sergey): Those are a bit of bad level calls :S +extern "C" { +void copy_m3_m3(float m1[3][3], float m2[3][3]); +void copy_m3_m4(float m1[3][3], float m2[4][4]); +void adjoint_m3_m3(float m1[3][3], float m[3][3]); +float determinant_m3_array(float m[3][3]); +bool invert_m3_m3(float m1[3][3], float m2[3][3]); +bool invert_m3(float m[3][3]); +void transpose_m3(float mat[3][3]); +} + +#define MAX_LIGHTS 8 +#define SUPPORT_COLOR_MATERIAL + +typedef struct Light { + float position[4]; + float ambient[4]; + float diffuse[4]; + float specular[4]; + float spot_direction[4]; +#ifdef SUPPORT_COLOR_MATERIAL + float constant_attenuation; + float linear_attenuation; + float quadratic_attenuation; + float spot_cutoff; + float spot_exponent; + float spot_cos_cutoff; + float pad, pad2; +#endif +} Light; + +typedef struct Lighting { + Light lights[MAX_LIGHTS]; + int num_enabled; +} Lighting; + +typedef struct Transform { + float projection_matrix[16]; + float model_view_matrix[16]; + float normal_matrix[9]; +} Transform; + +static bool g_use_osd_glsl = false; +static int g_active_uv_index = 0; + +static GLuint g_flat_fill_solid_program = 0; +static GLuint g_flat_fill_texture2d_program = 0; +static GLuint g_smooth_fill_solid_program = 0; +static GLuint g_smooth_fill_texture2d_program = 0; + +static GLuint g_flat_fill_solid_shadeless_program = 0; +static GLuint g_flat_fill_texture2d_shadeless_program = 0; +static GLuint g_smooth_fill_solid_shadeless_program = 0; +static GLuint g_smooth_fill_texture2d_shadeless_program = 0; + +static GLuint g_wireframe_program = 0; + +static GLuint g_lighting_ub = 0; +static Lighting g_lighting_data; +static Transform g_transform; + +namespace { + +GLuint compileShader(GLenum shaderType, + const char* version, + const char* define, + const char* source) { + const char* sources[] = { + version, define, +#ifdef SUPPORT_COLOR_MATERIAL + "#define SUPPORT_COLOR_MATERIAL\n", +#else + "", +#endif + source, + }; + + GLuint shader = glCreateShader(shaderType); + glShaderSource(shader, 4, sources, NULL); + glCompileShader(shader); + + GLint status; + glGetShaderiv(shader, GL_COMPILE_STATUS, &status); + if (status == GL_FALSE) { + GLchar emsg[1024]; + glGetShaderInfoLog(shader, sizeof(emsg), 0, emsg); + fprintf(stderr, "Error compiling GLSL: %s\n", emsg); + fprintf(stderr, "Version: %s\n", version); + fprintf(stderr, "Defines: %s\n", define); + fprintf(stderr, "Source: %s\n", source); + return 0; + } + + return shader; +} + +GLuint linkProgram(const char* version, const char* define) { + GLuint vertexShader = + compileShader(GL_VERTEX_SHADER, version, define, + datatoc_gpu_shader_opensubdiv_vertex_glsl); + if (vertexShader == 0) { + return 0; + } + GLuint geometryShader = + compileShader(GL_GEOMETRY_SHADER, version, define, + datatoc_gpu_shader_opensubdiv_geometry_glsl); + if (geometryShader == 0) { + return 0; + } + GLuint fragmentShader = + compileShader(GL_FRAGMENT_SHADER, version, define, + datatoc_gpu_shader_opensubdiv_fragment_glsl); + if (fragmentShader == 0) { + return 0; + } + + GLuint program = glCreateProgram(); + + glAttachShader(program, vertexShader); + glAttachShader(program, geometryShader); + glAttachShader(program, fragmentShader); + + glBindAttribLocation(program, 0, "position"); + glBindAttribLocation(program, 1, "normal"); + + glLinkProgram(program); + + glDeleteShader(vertexShader); + glDeleteShader(geometryShader); + glDeleteShader(fragmentShader); + + GLint status; + glGetProgramiv(program, GL_LINK_STATUS, &status); + if (status == GL_FALSE) { + GLchar emsg[1024]; + glGetProgramInfoLog(program, sizeof(emsg), 0, emsg); + fprintf(stderr, "Error linking GLSL program : %s\n", emsg); + fprintf(stderr, "Defines: %s\n", define); + glDeleteProgram(program); + return 0; + } + + glUniformBlockBinding(program, glGetUniformBlockIndex(program, "Lighting"), + 0); + + if (GLEW_VERSION_4_1) { + glProgramUniform1i( + program, glGetUniformLocation(program, "texture_buffer"), 0); + glProgramUniform1i( + program, glGetUniformLocation(program, "FVarDataOffsetBuffer"), 30); + glProgramUniform1i( + program, glGetUniformLocation(program, "FVarDataBuffer"), 31); + } else { + glUseProgram(program); + glUniform1i(glGetUniformLocation(program, "texture_buffer"), 0); + glUniform1i(glGetUniformLocation(program, "FVarDataOffsetBuffer"), 30); + glUniform1i(glGetUniformLocation(program, "FVarDataBuffer"), 31); + glUseProgram(0); + } + + return program; +} + +void bindProgram(OpenSubdiv_GLMesh* gl_mesh, int program) { + glUseProgram(program); + // Matrices + glUniformMatrix4fv(glGetUniformLocation(program, "modelViewMatrix"), + 1, + false, + g_transform.model_view_matrix); + glUniformMatrix4fv(glGetUniformLocation(program, "projectionMatrix"), + 1, + false, + g_transform.projection_matrix); + glUniformMatrix3fv(glGetUniformLocation(program, "normalMatrix"), + 1, + false, + g_transform.normal_matrix); + // Lighting. + glBindBuffer(GL_UNIFORM_BUFFER, g_lighting_ub); + glBufferSubData( + GL_UNIFORM_BUFFER, 0, sizeof(g_lighting_data), &g_lighting_data); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + glBindBufferBase(GL_UNIFORM_BUFFER, 0, g_lighting_ub); + // Color. + { + // TODO(sergey): Stop using glGetMaterial. + float color[4]; + glGetMaterialfv(GL_FRONT, GL_DIFFUSE, color); + glUniform4fv(glGetUniformLocation(program, "diffuse"), 1, color); + glGetMaterialfv(GL_FRONT, GL_SPECULAR, color); + glUniform4fv(glGetUniformLocation(program, "specular"), 1, color); + glGetMaterialfv(GL_FRONT, GL_SHININESS, color); + glUniform1f(glGetUniformLocation(program, "shininess"), color[0]); + } + // Face-vertex data. + opensubdiv_capi::GLMeshFVarData* fvar_data = gl_mesh->internal->fvar_data; + if (fvar_data != NULL) { + if (fvar_data->texture_buffer) { + glActiveTexture(GL_TEXTURE31); + glBindTexture(GL_TEXTURE_BUFFER, fvar_data->texture_buffer); + glActiveTexture(GL_TEXTURE0); + } + if (fvar_data->offset_buffer) { + glActiveTexture(GL_TEXTURE30); + glBindTexture(GL_TEXTURE_BUFFER, fvar_data->offset_buffer); + glActiveTexture(GL_TEXTURE0); + } + glUniform1i(glGetUniformLocation(program, "osd_fvar_count"), + fvar_data->fvar_width); + if (fvar_data->channel_offsets.size() > 0 && g_active_uv_index >= 0) { + glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), + fvar_data->channel_offsets[g_active_uv_index]); + } else { + glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), 0); + } + } else { + glUniform1i(glGetUniformLocation(program, "osd_fvar_count"), 0); + glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), 0); + } +} + +} // namespace + +bool openSubdiv_initGLMeshDrawingResources(void) { + static bool need_init = true; + static bool init_success = false; + if (!need_init) { + return init_success; + } + // TODO(sergey): Update OSD drawing to OpenGL 3.3 core, + // then remove following line. + return false; + const char* version = ""; + if (GLEW_VERSION_3_2) { + version = "#version 150 compatibility\n"; + } else if (GLEW_VERSION_3_1) { + version = "#version 140\n" + "#extension GL_ARB_compatibility: enable\n"; + } else { + version = "#version 130\n"; + // Minimum supported for OpenSubdiv. + } + g_flat_fill_solid_program = linkProgram(version, + "#define USE_COLOR_MATERIAL\n" + "#define USE_LIGHTING\n" + "#define FLAT_SHADING\n"); + g_flat_fill_texture2d_program = linkProgram(version, + "#define USE_COLOR_MATERIAL\n" + "#define USE_LIGHTING\n" + "#define USE_TEXTURE_2D\n" + "#define FLAT_SHADING\n"); + g_smooth_fill_solid_program = linkProgram(version, + "#define USE_COLOR_MATERIAL\n" + "#define USE_LIGHTING\n" + "#define SMOOTH_SHADING\n"); + g_smooth_fill_texture2d_program = linkProgram(version, + "#define USE_COLOR_MATERIAL\n" + "#define USE_LIGHTING\n" + "#define USE_TEXTURE_2D\n" + "#define SMOOTH_SHADING\n"); + + g_flat_fill_solid_shadeless_program = + linkProgram(version, + "#define USE_COLOR_MATERIAL\n" + "#define FLAT_SHADING\n"); + g_flat_fill_texture2d_shadeless_program = + linkProgram(version, + "#define USE_COLOR_MATERIAL\n" + "#define USE_TEXTURE_2D\n" + "#define FLAT_SHADING\n"); + g_smooth_fill_solid_shadeless_program = + linkProgram(version, + "#define USE_COLOR_MATERIAL\n" + "#define SMOOTH_SHADING\n"); + g_smooth_fill_texture2d_shadeless_program = + linkProgram(version, + "#define USE_COLOR_MATERIAL\n" + "#define USE_TEXTURE_2D\n" + "#define SMOOTH_SHADING\n"); + g_wireframe_program = linkProgram(version, "#define WIREFRAME\n"); + + glGenBuffers(1, &g_lighting_ub); + glBindBuffer(GL_UNIFORM_BUFFER, g_lighting_ub); + glBufferData(GL_UNIFORM_BUFFER, + sizeof(g_lighting_data), + NULL, + GL_STATIC_DRAW); + need_init = false; + init_success = g_flat_fill_solid_program != 0 && + g_flat_fill_texture2d_program != 0 && + g_smooth_fill_solid_program != 0 && + g_smooth_fill_texture2d_program != 0 && g_wireframe_program; + return init_success; +} + +void openSubdiv_deinitGLMeshDrawingResources(void) { + if (g_lighting_ub != 0) { + glDeleteBuffers(1, &g_lighting_ub); + } +#define SAFE_DELETE_PROGRAM(program) \ + do { \ + if (program) { \ + glDeleteProgram(program); \ + } \ + } while (false) + + SAFE_DELETE_PROGRAM(g_flat_fill_solid_program); + SAFE_DELETE_PROGRAM(g_flat_fill_texture2d_program); + SAFE_DELETE_PROGRAM(g_smooth_fill_solid_program); + SAFE_DELETE_PROGRAM(g_smooth_fill_texture2d_program); + SAFE_DELETE_PROGRAM(g_flat_fill_solid_shadeless_program); + SAFE_DELETE_PROGRAM(g_flat_fill_texture2d_shadeless_program); + SAFE_DELETE_PROGRAM(g_smooth_fill_solid_shadeless_program); + SAFE_DELETE_PROGRAM(g_smooth_fill_texture2d_shadeless_program); + SAFE_DELETE_PROGRAM(g_wireframe_program); + +#undef SAFE_DELETE_PROGRAM +} + +namespace opensubdiv_capi { + +namespace { + +GLuint prepare_patchDraw(OpenSubdiv_GLMesh* gl_mesh, bool fill_quads) { + GLint program = 0; + if (!g_use_osd_glsl) { + glGetIntegerv(GL_CURRENT_PROGRAM, &program); + if (program) { + GLint model; + glGetIntegerv(GL_SHADE_MODEL, &model); + GLint location = glGetUniformLocation(program, "osd_flat_shading"); + if (location != -1) { + glUniform1i(location, model == GL_FLAT); + } + // Face-vertex data. + opensubdiv_capi::GLMeshFVarData* fvar_data = gl_mesh->internal->fvar_data; + if (fvar_data != NULL) { + if (fvar_data->texture_buffer) { + glActiveTexture(GL_TEXTURE31); + glBindTexture(GL_TEXTURE_BUFFER, fvar_data->texture_buffer); + glActiveTexture(GL_TEXTURE0); + } + if (fvar_data->offset_buffer) { + glActiveTexture(GL_TEXTURE30); + glBindTexture(GL_TEXTURE_BUFFER, fvar_data->offset_buffer); + glActiveTexture(GL_TEXTURE0); + } + GLint location = glGetUniformLocation(program, "osd_fvar_count"); + if (location != -1) { + glUniform1i(location, fvar_data->fvar_width); + } + location = glGetUniformLocation(program, "osd_active_uv_offset"); + if (location != -1) { + if (fvar_data->channel_offsets.size() > 0 && g_active_uv_index >= 0) { + glUniform1i(location, + fvar_data->channel_offsets[g_active_uv_index]); + } else { + glUniform1i(location, 0); + } + } + } else { + glUniform1i(glGetUniformLocation(program, "osd_fvar_count"), 0); + glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), 0); + } + } + return program; + } + if (fill_quads) { + int model; + GLboolean use_texture_2d; + glGetIntegerv(GL_SHADE_MODEL, &model); + glGetBooleanv(GL_TEXTURE_2D, &use_texture_2d); + if (model == GL_FLAT) { + if (use_texture_2d) { + program = g_flat_fill_texture2d_program; + } else { + program = g_flat_fill_solid_program; + } + } else { + if (use_texture_2d) { + program = g_smooth_fill_texture2d_program; + } else { + program = g_smooth_fill_solid_program; + } + } + + } else { + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + program = g_wireframe_program; + } + bindProgram(gl_mesh, program); + return program; +} + +void perform_drawElements(GLuint program, + int patch_index, + int num_elements, + int start_element) { + if (program) { + glUniform1i(glGetUniformLocation(program, "PrimitiveIdBase"), patch_index); + } + glDrawElements(GL_LINES_ADJACENCY, + num_elements, + GL_UNSIGNED_INT, + reinterpret_cast<void*>(start_element * sizeof(unsigned int))); +} + +void finishPatchDraw(bool fill_quads) { + // TODO(sergey): Some of the stuff could be done once after the whole + // mesh is displayed. + /// Restore state. + if (!fill_quads) { + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } + glBindVertexArray(0); + if (g_use_osd_glsl) { + // TODO(sergey): Store previously used program and roll back to it? + glUseProgram(0); + } +} + +void drawPartitionPatchesRange(GLMeshInterface* mesh, + GLuint program, + int start_patch, + int num_patches) { + int traversed_patches = 0, num_remained_patches = num_patches; + const OpenSubdiv::Osd::PatchArrayVector &patches = + mesh->GetPatchTable()->GetPatchArrays(); + for (int i = 0; i < patches.size(); ++i) { + const OpenSubdiv::Osd::PatchArray &patch = patches[i]; + OpenSubdiv::Far::PatchDescriptor desc = patch.GetDescriptor(); + OpenSubdiv::Far::PatchDescriptor::Type patchType = desc.GetType(); + if (patchType == OpenSubdiv::Far::PatchDescriptor::QUADS) { + const int num_block_patches = patch.GetNumPatches(); + if (start_patch >= traversed_patches && + start_patch < traversed_patches + num_block_patches) { + const int num_control_verts = desc.GetNumControlVertices(); + const int start_draw_patch = start_patch - traversed_patches; + const int num_draw_patches = std::min( + num_remained_patches, num_block_patches - start_draw_patch); + perform_drawElements( + program, i + start_draw_patch, num_draw_patches * num_control_verts, + patch.GetIndexBase() + start_draw_patch * num_control_verts); + num_remained_patches -= num_draw_patches; + } + if (num_remained_patches == 0) { + break; + } + traversed_patches += num_block_patches; + } + } +} + +static void drawAllPatches(GLMeshInterface* mesh, GLuint program) { + const OpenSubdiv::Osd::PatchArrayVector &patches = + mesh->GetPatchTable()->GetPatchArrays(); + for (int i = 0; i < patches.size(); ++i) { + const OpenSubdiv::Osd::PatchArray &patch = patches[i]; + OpenSubdiv::Far::PatchDescriptor desc = patch.GetDescriptor(); + OpenSubdiv::Far::PatchDescriptor::Type patchType = desc.GetType(); + + if (patchType == OpenSubdiv::Far::PatchDescriptor::QUADS) { + perform_drawElements(program, i, + patch.GetNumPatches() * desc.GetNumControlVertices(), + patch.GetIndexBase()); + } + } +} + +} // namespace + +void GLMeshDisplayPrepare(struct OpenSubdiv_GLMesh* /*gl_mesh*/, + const bool use_osd_glsl, + const int active_uv_index) { + g_active_uv_index = active_uv_index; + g_use_osd_glsl = (use_osd_glsl != 0); + // Update transformation matrices. + glGetFloatv(GL_PROJECTION_MATRIX, g_transform.projection_matrix); + glGetFloatv(GL_MODELVIEW_MATRIX, g_transform.model_view_matrix); + copy_m3_m4((float(*)[3])g_transform.normal_matrix, + (float(*)[4])g_transform.model_view_matrix); + invert_m3((float(*)[3])g_transform.normal_matrix); + transpose_m3((float(*)[3])g_transform.normal_matrix); + // Update OpenGL lights positions, colors etc. + g_lighting_data.num_enabled = 0; + for (int i = 0; i < MAX_LIGHTS; ++i) { + GLboolean enabled; + glGetBooleanv(GL_LIGHT0 + i, &enabled); + if (enabled) { + g_lighting_data.num_enabled++; + } + // TODO(sergey): Stop using glGetLight. + glGetLightfv(GL_LIGHT0 + i, GL_POSITION, + g_lighting_data.lights[i].position); + glGetLightfv(GL_LIGHT0 + i, GL_AMBIENT, g_lighting_data.lights[i].ambient); + glGetLightfv(GL_LIGHT0 + i, GL_DIFFUSE, g_lighting_data.lights[i].diffuse); + glGetLightfv(GL_LIGHT0 + i, GL_SPECULAR, + g_lighting_data.lights[i].specular); + glGetLightfv(GL_LIGHT0 + i, GL_SPOT_DIRECTION, + g_lighting_data.lights[i].spot_direction); +#ifdef SUPPORT_COLOR_MATERIAL + glGetLightfv(GL_LIGHT0 + i, GL_CONSTANT_ATTENUATION, + &g_lighting_data.lights[i].constant_attenuation); + glGetLightfv(GL_LIGHT0 + i, GL_LINEAR_ATTENUATION, + &g_lighting_data.lights[i].linear_attenuation); + glGetLightfv(GL_LIGHT0 + i, GL_QUADRATIC_ATTENUATION, + &g_lighting_data.lights[i].quadratic_attenuation); + glGetLightfv(GL_LIGHT0 + i, GL_SPOT_CUTOFF, + &g_lighting_data.lights[i].spot_cutoff); + glGetLightfv(GL_LIGHT0 + i, GL_SPOT_EXPONENT, + &g_lighting_data.lights[i].spot_exponent); + g_lighting_data.lights[i].spot_cos_cutoff = + cos(g_lighting_data.lights[i].spot_cutoff); +#endif + } +} + +void GLMeshDisplayDrawPatches(OpenSubdiv_GLMesh* gl_mesh, + const bool fill_quads, + const int start_patch, + const int num_patches) { + GLMeshInterface* mesh = gl_mesh->internal->mesh_interface; + // Make sure all global invariants are initialized. + if (!openSubdiv_initGLMeshDrawingResources()) { + return; + } + /// Setup GLSL/OpenGL to draw patches in current context. + GLuint program = prepare_patchDraw(gl_mesh, fill_quads != 0); + if (start_patch != -1) { + drawPartitionPatchesRange(mesh, program, start_patch, num_patches); + } else { + drawAllPatches(mesh, program); + } + // Finish patch drawing by restoring all changes to the OpenGL context. + finishPatchDraw(fill_quads != 0); +} + +} // namespace opensubdiv_capi diff --git a/intern/opensubdiv/internal/opensubdiv_gl_mesh_draw.h b/intern/opensubdiv/internal/opensubdiv_gl_mesh_draw.h new file mode 100644 index 00000000000..5421b5cf707 --- /dev/null +++ b/intern/opensubdiv/internal/opensubdiv_gl_mesh_draw.h @@ -0,0 +1,39 @@ +// Copyright 2013 Blender Foundation. All rights reserved. +// +// 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. +// +// Author: Sergey Sharybin + +#ifndef OPENSUBDIV_GL_MESH_DRAW_H_ +#define OPENSUBDIV_GL_MESH_DRAW_H_ + +#include <stdint.h> // for bool + +struct OpenSubdiv_GLMesh; + +namespace opensubdiv_capi { + +void GLMeshDisplayPrepare(struct OpenSubdiv_GLMesh* gl_mesh, + const bool use_osd_glsl, + const int active_uv_index); + +void GLMeshDisplayDrawPatches(OpenSubdiv_GLMesh* gl_mesh, + const bool fill_quads, + const int start_patch, + const int num_patches); + +} // namespace opensubdiv_capi + +#endif // OPENSUBDIV_GL_MESH_DRAW_H_ diff --git a/intern/opensubdiv/internal/opensubdiv_gl_mesh_fvar.cc b/intern/opensubdiv/internal/opensubdiv_gl_mesh_fvar.cc new file mode 100644 index 00000000000..5c9033c8dd1 --- /dev/null +++ b/intern/opensubdiv/internal/opensubdiv_gl_mesh_fvar.cc @@ -0,0 +1,175 @@ +// Copyright 2013 Blender Foundation. All rights reserved. +// +// 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. +// +// Author: Sergey Sharybin + +#include "internal/opensubdiv_gl_mesh_fvar.h" + +#include <GL/glew.h> +#include <opensubdiv/far/primvarRefiner.h> + +namespace opensubdiv_capi { + +//////////////////////////////////////////////////////////////////////////////// +// GLMeshFVarData + +GLMeshFVarData::GLMeshFVarData() + : texture_buffer(0), + offset_buffer(0) { +} + +GLMeshFVarData::~GLMeshFVarData() { + release(); +} + +void GLMeshFVarData::release() { + if (texture_buffer) { + glDeleteTextures(1, &texture_buffer); + } + if (offset_buffer) { + glDeleteTextures(1, &offset_buffer); + } + texture_buffer = 0; + offset_buffer = 0; + fvar_width = 0; + channel_offsets.clear(); +} + +void GLMeshFVarData::create( + const OpenSubdiv::Far::TopologyRefiner* topology_refiner, + const OpenSubdiv::Far::PatchTable* patch_table, + int fvar_width, + const float* fvar_src_data) { + release(); + this->fvar_width = fvar_width; + /// Expand fvar data to per-patch array. + const int max_level = topology_refiner->GetMaxLevel(); + const int num_channels = patch_table->GetNumFVarChannels(); + std::vector<float> data; + int fvar_data_offset = 0; + channel_offsets.resize(num_channels); + for (int channel = 0; channel < num_channels; ++channel) { + OpenSubdiv::Far::ConstIndexArray indices = + patch_table->GetFVarValues(channel); + channel_offsets[channel] = data.size(); + data.reserve(data.size() + indices.size() * fvar_width); + for (int fvert = 0; fvert < indices.size(); ++fvert) { + int index = indices[fvert] * fvar_width; + for (int i = 0; i < fvar_width; ++i) { + data.push_back(fvar_src_data[fvar_data_offset + index++]); + } + } + if (topology_refiner->IsUniform()) { + const int num_values_max = + topology_refiner->GetLevel(max_level).GetNumFVarValues(channel); + fvar_data_offset += num_values_max * fvar_width; + } else { + const int num_values_total = + topology_refiner->GetNumFVarValuesTotal(channel); + fvar_data_offset += num_values_total * fvar_width; + } + } + GLuint buffer; + glGenBuffers(1, &buffer); + glBindBuffer(GL_ARRAY_BUFFER, buffer); + glBufferData(GL_ARRAY_BUFFER, + data.size() * sizeof(float), &data[0], + GL_STATIC_DRAW); + glGenTextures(1, &texture_buffer); + glBindTexture(GL_TEXTURE_BUFFER, texture_buffer); + glTexBuffer(GL_TEXTURE_BUFFER, GL_R32F, buffer); + glDeleteBuffers(1, &buffer); + glGenBuffers(1, &buffer); + glBindBuffer(GL_ARRAY_BUFFER, buffer); + glBufferData(GL_ARRAY_BUFFER, + channel_offsets.size() * sizeof(int), + &channel_offsets[0], + GL_STATIC_DRAW); + glGenTextures(1, &offset_buffer); + glBindTexture(GL_TEXTURE_BUFFER, offset_buffer); + glTexBuffer(GL_TEXTURE_BUFFER, GL_R32I, buffer); + glBindTexture(GL_TEXTURE_BUFFER, 0); + glBindBuffer(GL_ARRAY_BUFFER, 0); +} + +//////////////////////////////////////////////////////////////////////////////// +// Helper functions. + +struct FVarVertex { + float u, v; + + void Clear() { + u = v = 0.0f; + } + + void AddWithWeight(FVarVertex const& src, float weight) { + u += weight * src.u; + v += weight * src.v; + } +}; + +void interpolateFVarData(const OpenSubdiv::Far::TopologyRefiner& refiner, + const std::vector<float>& uvs, + std::vector<float>* fvar_data) { + const int fvar_width = 2; + const int max_level = refiner.GetMaxLevel(); + size_t fvar_data_offset = 0, values_offset = 0; + for (int channel = 0; channel < refiner.GetNumFVarChannels(); ++channel) { + const int num_values = refiner.GetLevel(0).GetNumFVarValues(channel) * 2; + const int num_values_max = + refiner.GetLevel(max_level).GetNumFVarValues(channel); + const int num_values_total = refiner.GetNumFVarValuesTotal(channel); + if (num_values_total <= 0) { + continue; + } + OpenSubdiv::Far::PrimvarRefiner primvar_refiner(refiner); + if (refiner.IsUniform()) { + // For uniform we only keep the highest level of refinement. + fvar_data->resize(fvar_data->size() + num_values_max * fvar_width); + std::vector<FVarVertex> buffer(num_values_total - num_values_max); + FVarVertex* src = &buffer[0]; + memcpy(src, &uvs[values_offset], num_values * sizeof(float)); + // Defer the last level to treat separately with its alternate + // destination. + for (int level = 1; level < max_level; ++level) { + FVarVertex* dst = + src + refiner.GetLevel(level - 1).GetNumFVarValues(channel); + primvar_refiner.InterpolateFaceVarying(level, src, dst, channel); + src = dst; + } + FVarVertex* dst = + reinterpret_cast<FVarVertex*>(&(*fvar_data)[fvar_data_offset]); + primvar_refiner.InterpolateFaceVarying(max_level, src, dst, channel); + fvar_data_offset += num_values_max * fvar_width; + } else { + // For adaptive we keep all levels. + fvar_data->resize(fvar_data->size() + num_values_total * fvar_width); + FVarVertex* src = + reinterpret_cast<FVarVertex*>(&(*fvar_data)[fvar_data_offset]); + memcpy(src, &uvs[values_offset], num_values * sizeof(float)); + for (int level = 1; level <= max_level; ++level) { + FVarVertex* dst = + src + refiner.GetLevel(level - 1).GetNumFVarValues(channel); + primvar_refiner.InterpolateFaceVarying(level, src, dst, channel); + src = dst; + } + fvar_data_offset += num_values_total * fvar_width; + } + values_offset += num_values; + } +} + +} // namespace opensubdiv_capi diff --git a/intern/opensubdiv/internal/opensubdiv_gl_mesh_fvar.h b/intern/opensubdiv/internal/opensubdiv_gl_mesh_fvar.h new file mode 100644 index 00000000000..039a94eaf86 --- /dev/null +++ b/intern/opensubdiv/internal/opensubdiv_gl_mesh_fvar.h @@ -0,0 +1,57 @@ +// Copyright 2013 Blender Foundation. All rights reserved. +// +// 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. +// +// Author: Sergey Sharybin + +#ifndef OPENSUBDIV_GL_MESH_FVAR_H_ +#define OPENSUBDIV_GL_MESH_FVAR_H_ + +// NOTE: This is a [sane(er)] port of previous ground work for getting UVs to +// work. Still needs a lot of work to make it easy, correct and have proper +// data ownership. + +#include <opensubdiv/far/topologyRefiner.h> +#include <opensubdiv/far/patchTable.h> + +#include <vector> + +namespace opensubdiv_capi { + +// The buffer which holds GPU resources for face-varying elements. +class GLMeshFVarData { + public: + GLMeshFVarData(); + ~GLMeshFVarData(); + + void release(); + void create(const OpenSubdiv::Far::TopologyRefiner* refiner, + const OpenSubdiv::Far::PatchTable* patch_table, + int fvar_width, + const float* fvar_src_data); + + unsigned int texture_buffer; + unsigned int offset_buffer; + std::vector<int> channel_offsets; + int fvar_width; +}; + +void interpolateFVarData(const OpenSubdiv::Far::TopologyRefiner& refiner, + const std::vector<float>& uvs, + std::vector<float>* fvar_data); + +} // namespace opensubdiv_capi + +#endif // OPENSUBDIV_GL_MESH_FVAR_H_ diff --git a/intern/opensubdiv/internal/opensubdiv_gl_mesh_internal.cc b/intern/opensubdiv/internal/opensubdiv_gl_mesh_internal.cc new file mode 100644 index 00000000000..3abba9cf8f8 --- /dev/null +++ b/intern/opensubdiv/internal/opensubdiv_gl_mesh_internal.cc @@ -0,0 +1,32 @@ +// Copyright 2018 Blender Foundation. All rights reserved. +// +// 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. +// +// Author: Sergey Sharybin + +#include "internal/opensubdiv_gl_mesh_internal.h" + +#include "internal/opensubdiv_gl_mesh_fvar.h" + +OpenSubdiv_GLMeshInternal::OpenSubdiv_GLMeshInternal() + : evaluator_type(OPENSUBDIV_EVALUATOR_CPU), + mesh_interface(NULL), + fvar_data(NULL) { +} + +OpenSubdiv_GLMeshInternal::~OpenSubdiv_GLMeshInternal() { + delete mesh_interface; + delete fvar_data; +} diff --git a/intern/opensubdiv/internal/opensubdiv_gl_mesh_internal.h b/intern/opensubdiv/internal/opensubdiv_gl_mesh_internal.h new file mode 100644 index 00000000000..7796b450e69 --- /dev/null +++ b/intern/opensubdiv/internal/opensubdiv_gl_mesh_internal.h @@ -0,0 +1,43 @@ +// Copyright 2018 Blender Foundation. All rights reserved. +// +// 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. +// +// Author: Sergey Sharybin + +#ifndef OPENSUBDIV_GL_MESH_INTERNAL_H_ +#define OPENSUBDIV_GL_MESH_INTERNAL_H_ + +#ifdef _MSC_VER +# include <iso646.h> +#endif + +#include <opensubdiv/osd/glMesh.h> + +#include "opensubdiv_capi_type.h" + +namespace opensubdiv_capi { +class GLMeshFVarData; +} // namespace opensubdiv_capi + +typedef struct OpenSubdiv_GLMeshInternal { + OpenSubdiv_GLMeshInternal(); + ~OpenSubdiv_GLMeshInternal(); + + eOpenSubdivEvaluator evaluator_type; + OpenSubdiv::Osd::GLMeshInterface* mesh_interface; + opensubdiv_capi::GLMeshFVarData* fvar_data; +} OpenSubdiv_GLMeshInternal; + +#endif // OPENSUBDIV_GL_MESH_INTERNAL_H_ diff --git a/intern/opensubdiv/opensubdiv_gpu_capi.cc b/intern/opensubdiv/internal/opensubdiv_gpu.cc index d28b48ddd18..d28b48ddd18 100644 --- a/intern/opensubdiv/opensubdiv_gpu_capi.cc +++ b/intern/opensubdiv/internal/opensubdiv_gpu.cc diff --git a/intern/opensubdiv/internal/opensubdiv_internal.h b/intern/opensubdiv/internal/opensubdiv_internal.h new file mode 100644 index 00000000000..b9d196bbe9e --- /dev/null +++ b/intern/opensubdiv/internal/opensubdiv_internal.h @@ -0,0 +1,38 @@ +// Copyright 2015 Blender Foundation. All rights reserved. +// +// 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. +// +// Author: Sergey Sharybin + +#ifndef OPENSUBDIV_INTERNAL_H_ +#define OPENSUBDIV_INTERNAL_H_ + +// Perform full topology validation when exporting it to OpenSubdiv. +#ifdef NDEBUG +// Never do for release builds. +# undef OPENSUBDIV_VALIDATE_TOPOLOGY +#else +// TODO(sergey): Always disabled for now, the check doesn't handle multiple +// non-manifolds from the OpenSubdiv side currently. +// # undef OPENSUBDIV_VALIDATE_TOPOLOGY +# define OPENSUBDIV_VALIDATE_TOPOLOGY +#endif + +// Currently OpenSubdiv expects topology to be oriented, but sometimes it's +// handy to disable orientation code to check whether it causes some weird +// issues by using pre-oriented model. +#define OPENSUBDIV_ORIENT_TOPOLOGY + +#endif // OPENSUBDIV_INTERNAL_H_ diff --git a/intern/opensubdiv/internal/opensubdiv_topology_refiner.cc b/intern/opensubdiv/internal/opensubdiv_topology_refiner.cc new file mode 100644 index 00000000000..aa6ba953ef9 --- /dev/null +++ b/intern/opensubdiv/internal/opensubdiv_topology_refiner.cc @@ -0,0 +1,315 @@ +// Copyright 2018 Blender Foundation. All rights reserved. +// +// 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. +// +// Author: Sergey Sharybin + +#include "opensubdiv_topology_refiner_capi.h" + +#include <vector> + +#include "MEM_guardedalloc.h" +#include "internal/opensubdiv_converter_factory.h" +#include "internal/opensubdiv_converter_internal.h" +#include "internal/opensubdiv_internal.h" +#include "internal/opensubdiv_topology_refiner_internal.h" + +namespace { + +const OpenSubdiv::Far::TopologyRefiner* getOSDTopologyRefiner( + const OpenSubdiv_TopologyRefiner* topology_refiner) { + return topology_refiner->internal->osd_topology_refiner; +} + +const OpenSubdiv::Far::TopologyLevel* getOSDTopologyBaseLevel( + const OpenSubdiv_TopologyRefiner* topology_refiner) { + return &getOSDTopologyRefiner(topology_refiner)->GetLevel(0); +} + +int getSubdivisionLevel(const OpenSubdiv_TopologyRefiner* topology_refiner) { + return topology_refiner->internal->settings.level; +} + +bool getIsAdaptive(const OpenSubdiv_TopologyRefiner* topology_refiner) { + return topology_refiner->internal->settings.is_adaptive; +} + +int getNumVertices(const OpenSubdiv_TopologyRefiner* topology_refiner) { + return getOSDTopologyBaseLevel(topology_refiner)->GetNumVertices(); +} + +int getNumEdges(const OpenSubdiv_TopologyRefiner* topology_refiner) { + return getOSDTopologyBaseLevel(topology_refiner)->GetNumEdges(); +} + +int getNumFaces(const OpenSubdiv_TopologyRefiner* topology_refiner) { + return getOSDTopologyBaseLevel(topology_refiner)->GetNumFaces(); +} + +int getNumFaceVertices(const OpenSubdiv_TopologyRefiner* topology_refiner, + const int face_index) { + const OpenSubdiv::Far::TopologyLevel* base_level = + getOSDTopologyBaseLevel(topology_refiner); + return base_level->GetFaceVertices(face_index).size(); +} + +int getNumFacePtexFaces(const OpenSubdiv_TopologyRefiner* topology_refiner, + const int face_index) { + const int num_face_vertices = + topology_refiner->getNumFaceVertices(topology_refiner, face_index); + if (num_face_vertices == 4) { + return 1; + } else { + return num_face_vertices; + } +} + +int getNumPtexFaces(const OpenSubdiv_TopologyRefiner* topology_refiner) { + const int num_faces = topology_refiner->getNumFaces(topology_refiner); + int num_ptex_faces = 0; + for (int face_index = 0; face_index < num_faces; ++face_index) { + num_ptex_faces += + topology_refiner->getNumFacePtexFaces(topology_refiner, face_index); + } + return num_ptex_faces; +} + +void fillFacePtexIndexOffset(const OpenSubdiv_TopologyRefiner* topology_refiner, + int* face_ptex_index_offset) { + const int num_faces = topology_refiner->getNumFaces(topology_refiner); + int num_ptex_faces = 0; + for (int face_index = 0; face_index < num_faces; ++face_index) { + face_ptex_index_offset[face_index] = num_ptex_faces; + num_ptex_faces += + topology_refiner->getNumFacePtexFaces(topology_refiner, face_index); + } +} + +void assignFunctionPointers(OpenSubdiv_TopologyRefiner* topology_refiner) { + topology_refiner->getSubdivisionLevel = getSubdivisionLevel; + topology_refiner->getIsAdaptive = getIsAdaptive; + + topology_refiner->getNumVertices = getNumVertices; + topology_refiner->getNumEdges = getNumEdges; + topology_refiner->getNumFaces = getNumFaces; + topology_refiner->getNumFaceVertices = getNumFaceVertices; + + topology_refiner->getNumFacePtexFaces = getNumFacePtexFaces; + topology_refiner->getNumPtexFaces = getNumPtexFaces; + topology_refiner->fillFacePtexIndexOffset = fillFacePtexIndexOffset; +} + +OpenSubdiv_TopologyRefiner* allocateTopologyRefiner() { + OpenSubdiv_TopologyRefiner* topology_refiner = + OBJECT_GUARDED_NEW(OpenSubdiv_TopologyRefiner); + topology_refiner->internal = + OBJECT_GUARDED_NEW(OpenSubdiv_TopologyRefinerInternal); + assignFunctionPointers(topology_refiner); + return topology_refiner; +} + +} // namespace + +OpenSubdiv_TopologyRefiner* openSubdiv_createTopologyRefinerFromConverter( + OpenSubdiv_Converter* converter, + const OpenSubdiv_TopologyRefinerSettings* settings) { + OpenSubdiv_TopologyRefiner* topology_refiner = allocateTopologyRefiner(); + topology_refiner->internal->osd_topology_refiner = + opensubdiv_capi::createOSDTopologyRefinerFromConverter(converter); + // Store setting which we want to keep track of and which can not be stored + // in OpenSubdiv's descriptor yet. + topology_refiner->internal->settings = *settings; + return topology_refiner; +} + +void openSubdiv_deleteTopologyRefiner( + OpenSubdiv_TopologyRefiner* topology_refiner) { + OBJECT_GUARDED_DELETE(topology_refiner->internal, + OpenSubdiv_TopologyRefinerInternal); + OBJECT_GUARDED_DELETE(topology_refiner, OpenSubdiv_TopologyRefiner); +} + +//////////////////////////////////////////////////////////////////////////////// +// Comparison with converter. + +namespace { + +/////////////////////////////////////////////////////////// +// Quick preliminary checks. + +bool checkSchemeTypeMatches( + const OpenSubdiv::Far::TopologyRefiner* topology_refiner, + const OpenSubdiv_Converter* converter) { + const OpenSubdiv::Sdc::SchemeType converter_scheme_type = + opensubdiv_capi::getSchemeTypeFromCAPI( + converter->getSchemeType(converter)); + return (converter_scheme_type == topology_refiner->GetSchemeType()); +} + +bool checkOptionsMatches( + const OpenSubdiv::Far::TopologyRefiner* topology_refiner, + const OpenSubdiv_Converter* converter) { + typedef OpenSubdiv::Sdc::Options Options; + const Options options = topology_refiner->GetSchemeOptions(); + const Options::FVarLinearInterpolation fvar_interpolation = + options.GetFVarLinearInterpolation(); + const Options::FVarLinearInterpolation converter_fvar_interpolation = + opensubdiv_capi::getFVarLinearInterpolationFromCAPI( + converter->getFVarLinearInterpolation(converter)); + if (fvar_interpolation != converter_fvar_interpolation) { + return false; + } + return true; +} + +bool checkGeometryCoountersMatches( + const OpenSubdiv::Far::TopologyRefiner* topology_refiner, + const OpenSubdiv_Converter* converter) { + using OpenSubdiv::Far::TopologyLevel; + const TopologyLevel& base_level = topology_refiner->GetLevel(0); + return ( + (converter->getNumVertices(converter) == base_level.GetNumVertices()) && + (converter->getNumEdges(converter) == base_level.GetNumEdges()) && + (converter->getNumFaces(converter) == base_level.GetNumFaces())); +} + +bool checkPreliminaryMatches( + const OpenSubdiv::Far::TopologyRefiner* topology_refiner, + const OpenSubdiv_Converter* converter) { + return checkSchemeTypeMatches(topology_refiner, converter) && + checkOptionsMatches(topology_refiner, converter) && + checkGeometryCoountersMatches(topology_refiner, converter); +} + +/////////////////////////////////////////////////////////// +// Geometry comparison. + +bool checkGeometryEdgesMatch( + const OpenSubdiv::Far::TopologyRefiner* topology_refiner, + const OpenSubdiv_Converter* converter) { + using OpenSubdiv::Far::ConstIndexArray; + using OpenSubdiv::Far::TopologyLevel; + const TopologyLevel& base_level = topology_refiner->GetLevel(0); + const int num_edges = base_level.GetNumEdges(); + for (int edge_index = 0; edge_index < num_edges; ++edge_index) { + const ConstIndexArray& edge_vertices = + base_level.GetEdgeVertices(edge_index); + int conv_edge_vertices[2]; + converter->getEdgeVertices(converter, edge_index, conv_edge_vertices); + if (conv_edge_vertices[0] != edge_vertices[0] || + conv_edge_vertices[1] != edge_vertices[1]) { + return false; + } + } + return true; +} + +bool checkGeometryFacesMatch( + const OpenSubdiv::Far::TopologyRefiner* topology_refiner, + const OpenSubdiv_Converter* converter) { + using OpenSubdiv::Far::ConstIndexArray; + using OpenSubdiv::Far::TopologyLevel; + const TopologyLevel& base_level = topology_refiner->GetLevel(0); + const int num_faces = base_level.GetNumFaces(); + // TODO(sergey): Consider using data structure which keeps handful of + // elements on stack before doing heep allocation. + std::vector<int> conv_face_vertices; + for (int face_index = 0; face_index < num_faces; ++face_index) { + const ConstIndexArray& face_vertices = + base_level.GetFaceVertices(face_index); + const int num_face_vertices = face_vertices.size(); + if (num_face_vertices != + converter->getNumFaceVertices(converter, face_index)) { + return false; + } + conv_face_vertices.resize(num_face_vertices); + converter->getFaceVertices(converter, face_index, &conv_face_vertices[0]); + // Check face-vertex indices in the direct order (assuming topology + // orientation is disabled or did not flip order of the face-vertices). + // + // TODO(sergey): Can we simply memcmp() with OpenSubdiv's array? + bool direct_match = true; + for (int face_vertex_index = 0; face_vertex_index < num_face_vertices; + ++face_vertex_index) { + if (conv_face_vertices[face_vertex_index] != + face_vertices[face_vertex_index]) { + direct_match = false; + break; + } + } + if (!direct_match) { +// If face didn't match in direct direction we also test if it matches in +// reversed direction. This is because conversion might reverse loops to +// make normals consistent. +#ifdef OPENSUBDIV_ORIENT_TOPOLOGY + for (int face_vertex_index = 0; face_vertex_index < num_face_vertices; + ++face_vertex_index) { + if (conv_face_vertices[face_vertex_index] != + face_vertices[num_face_vertices - face_vertex_index - 1]) { + return false; + } + } +#endif + return false; + } + } + return true; +} + +bool checkGeometryMatches( + const OpenSubdiv::Far::TopologyRefiner* topology_refiner, + const OpenSubdiv_Converter* converter) { + return checkGeometryEdgesMatch(topology_refiner, converter) && + checkGeometryFacesMatch(topology_refiner, converter); +} + +/////////////////////////////////////////////////////////// +// Compare attributes which affects on topology + +bool checkEdgeSharpnessMatch( + const OpenSubdiv::Far::TopologyRefiner* topology_refiner, + const OpenSubdiv_Converter* converter) { + using OpenSubdiv::Far::ConstIndexArray; + using OpenSubdiv::Far::TopologyLevel; + const TopologyLevel& base_level = topology_refiner->GetLevel(0); + const int num_edges = base_level.GetNumEdges(); + for (int edge_index = 0; edge_index < num_edges; ++edge_index) { + const float sharpness = base_level.GetEdgeSharpness(edge_index); + const float conv_sharpness = + opensubdiv_capi::getCompatibleEdgeSharpness(converter, edge_index); + if (sharpness != conv_sharpness) { + return false; + } + } + return false; +} + +bool checkTopologyAttributesMatch( + const OpenSubdiv::Far::TopologyRefiner* topology_refiner, + const OpenSubdiv_Converter* converter) { + return checkEdgeSharpnessMatch(topology_refiner, converter); +} + +} // namespace + +bool openSubdiv_topologyRefinerCompareWithConverter( + const OpenSubdiv_TopologyRefiner* topology_refiner, + const OpenSubdiv_Converter* converter) { + const OpenSubdiv::Far::TopologyRefiner* refiner = + getOSDTopologyRefiner(topology_refiner); + return (checkPreliminaryMatches(refiner, converter) && + checkGeometryMatches(refiner, converter) && + checkTopologyAttributesMatch(refiner, converter)); +} diff --git a/intern/opensubdiv/opensubdiv_topology_refiner.h b/intern/opensubdiv/internal/opensubdiv_topology_refiner.h index b00f6a54201..b00f6a54201 100644 --- a/intern/opensubdiv/opensubdiv_topology_refiner.h +++ b/intern/opensubdiv/internal/opensubdiv_topology_refiner.h diff --git a/intern/opensubdiv/internal/opensubdiv_topology_refiner_internal.cc b/intern/opensubdiv/internal/opensubdiv_topology_refiner_internal.cc new file mode 100644 index 00000000000..4636679761f --- /dev/null +++ b/intern/opensubdiv/internal/opensubdiv_topology_refiner_internal.cc @@ -0,0 +1,26 @@ +// Copyright 2016 Blender Foundation. All rights reserved. +// +// 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. +// +// Author: Sergey Sharybin + +#include "internal/opensubdiv_topology_refiner_internal.h" + +OpenSubdiv_TopologyRefinerInternal::OpenSubdiv_TopologyRefinerInternal() + : osd_topology_refiner(NULL) {} + +OpenSubdiv_TopologyRefinerInternal::~OpenSubdiv_TopologyRefinerInternal() { + delete osd_topology_refiner; +} diff --git a/intern/opensubdiv/internal/opensubdiv_topology_refiner_internal.h b/intern/opensubdiv/internal/opensubdiv_topology_refiner_internal.h new file mode 100644 index 00000000000..f7ca6a7ad5e --- /dev/null +++ b/intern/opensubdiv/internal/opensubdiv_topology_refiner_internal.h @@ -0,0 +1,47 @@ +// Copyright 2016 Blender Foundation. All rights reserved. +// +// 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. +// +// Author: Sergey Sharybin + +#ifndef OPENSUBDIV_TOPOLOGY_REFINER_INTERNAL_H_ +#define OPENSUBDIV_TOPOLOGY_REFINER_INTERNAL_H_ + +#ifdef _MSC_VER +# include <iso646.h> +#endif + +#include <opensubdiv/far/topologyRefiner.h> + +#include "opensubdiv_topology_refiner_capi.h" + +struct OpenSubdiv_TopologyRefinerInternal { + public: + OpenSubdiv_TopologyRefinerInternal(); + ~OpenSubdiv_TopologyRefinerInternal(); + + OpenSubdiv::Far::TopologyRefiner* osd_topology_refiner; + + // Subdivision settingsa this refiner is created for. + // + // We store it here since OpenSubdiv's refiner will only know about level and + // "adaptivity" after performing actual "refine" step. + // + // Ideally, we would also support refining topology without re-importing it + // from external world, but that is for later. + OpenSubdiv_TopologyRefinerSettings settings; +}; + +#endif // OPENSUBDIV_TOPOLOGY_REFINER_H_ diff --git a/intern/opensubdiv/internal/opensubdiv_util.cc b/intern/opensubdiv/internal/opensubdiv_util.cc new file mode 100644 index 00000000000..87bfce2116c --- /dev/null +++ b/intern/opensubdiv/internal/opensubdiv_util.cc @@ -0,0 +1,61 @@ +// Copyright 2013 Blender Foundation. All rights reserved. +// +// 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. +// +// Author: Sergey Sharybin +// Contributor(s): Brecht van Lommel + +#include "internal/opensubdiv_util.h" + +#include <GL/glew.h> +#include <cstring> + +#ifdef _MSC_VER +# include <iso646.h> +#endif + +namespace opensubdiv_capi { + +void stringSplit(std::vector<std::string>* tokens, + const std::string& str, + const std::string& separators, + bool skip_empty) { + size_t token_start = 0, token_length = 0; + for (size_t i = 0; i < str.length(); ++i) { + const char ch = str[i]; + if (separators.find(ch) == std::string::npos) { + // Append non-separator char to a token. + ++token_length; + } else { + // Append current token to the list (if any). + if (token_length > 0 || !skip_empty) { + std::string token = str.substr(token_start, token_length); + tokens->push_back(token); + } + // Re-set token pointers, + token_start = i + 1; + token_length = 0; + } + } + // Append token which might be at the end of the string. + if ((token_length != 0) || + (!skip_empty && token_start > 0 && + separators.find(str[token_start-1]) != std::string::npos)) { + std::string token = str.substr(token_start, token_length); + tokens->push_back(token); + } +} + +} // namespace opensubdiv_capi diff --git a/intern/opensubdiv/internal/opensubdiv_util.h b/intern/opensubdiv/internal/opensubdiv_util.h new file mode 100644 index 00000000000..6ed19b37e33 --- /dev/null +++ b/intern/opensubdiv/internal/opensubdiv_util.h @@ -0,0 +1,39 @@ +// Copyright 2013 Blender Foundation. All rights reserved. +// +// 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. +// +// Author: Sergey Sharybin +// Contributor(s): Brecht van Lommel + +#ifndef OPENSUBDIV_UTIL_H_ +#define OPENSUBDIV_UTIL_H_ + +#include <vector> +#include <string> + +namespace opensubdiv_capi { + +#define STRINGIFY_ARG(x) "" #x +#define STRINGIFY_APPEND(a, b) "" a #b +#define STRINGIFY(x) STRINGIFY_APPEND("", x) + +void stringSplit(std::vector<std::string>* tokens, + const std::string& str, + const std::string& separators, + bool skip_empty); + +} // namespace opensubdiv_capi + +#endif // OPENSUBDIV_UTIL_H_ diff --git a/intern/opensubdiv/opensubdiv_capi.cc b/intern/opensubdiv/opensubdiv_capi.cc deleted file mode 100644 index 638039f4f3e..00000000000 --- a/intern/opensubdiv/opensubdiv_capi.cc +++ /dev/null @@ -1,441 +0,0 @@ -/* - * ***** 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) 2013 Blender Foundation. - * All rights reserved. - * - * Contributor(s): Sergey Sharybin. - * Brecht van Lommel - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include "opensubdiv_capi.h" - -#ifdef _MSC_VER -# include "iso646.h" -#endif - -#include <stdlib.h> -#include <GL/glew.h> - -#include <opensubdiv/version.h> -#include <opensubdiv/osd/glMesh.h> - -/* CPU Backend */ -#include <opensubdiv/osd/cpuGLVertexBuffer.h> -#include <opensubdiv/osd/cpuEvaluator.h> - -#ifdef OPENSUBDIV_HAS_OPENMP -# include <opensubdiv/osd/ompEvaluator.h> -#endif /* OPENSUBDIV_HAS_OPENMP */ - -#ifdef OPENSUBDIV_HAS_OPENCL -# include <opensubdiv/osd/clGLVertexBuffer.h> -# include <opensubdiv/osd/clEvaluator.h> -# include "opensubdiv_device_context_opencl.h" -#endif /* OPENSUBDIV_HAS_OPENCL */ - -#ifdef OPENSUBDIV_HAS_CUDA -# include <opensubdiv/osd/cudaGLVertexBuffer.h> -# include <opensubdiv/osd/cudaEvaluator.h> -# include "opensubdiv_device_context_cuda.h" -#endif /* OPENSUBDIV_HAS_CUDA */ - -#ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK -# include <opensubdiv/osd/glXFBEvaluator.h> -# include <opensubdiv/osd/glVertexBuffer.h> -#endif /* OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK */ - -#ifdef OPENSUBDIV_HAS_GLSL_COMPUTE -# include <opensubdiv/osd/glComputeEvaluator.h> -# include <opensubdiv/osd/glVertexBuffer.h> -#endif /* OPENSUBDIV_HAS_GLSL_COMPUTE */ - -#include <opensubdiv/osd/glPatchTable.h> -#include <opensubdiv/far/stencilTable.h> -#include <opensubdiv/far/primvarRefiner.h> - -#include "opensubdiv_gl_mesh.h" -#include "opensubdiv_intern.h" -#include "opensubdiv_topology_refiner.h" - -#include "MEM_guardedalloc.h" - -#include <string> -#include <vector> - -using std::string; -using std::vector; - -#define STRINGIFY_ARG(x) "" #x -#define STRINGIFY_APPEND(a, b) "" a #b -#define STRINGIFY(x) STRINGIFY_APPEND("", x) - -/* **************** Types declaration **************** */ - -using OpenSubdiv::Osd::GLMeshInterface; -using OpenSubdiv::Osd::Mesh; -using OpenSubdiv::Osd::MeshBitset; -using OpenSubdiv::Far::StencilTable; -using OpenSubdiv::Osd::GLPatchTable; - -using OpenSubdiv::Osd::Mesh; - -/* CPU backend */ -using OpenSubdiv::Osd::CpuGLVertexBuffer; -using OpenSubdiv::Osd::CpuEvaluator; -typedef Mesh<CpuGLVertexBuffer, - StencilTable, - CpuEvaluator, - GLPatchTable> OsdCpuMesh; - -#ifdef OPENSUBDIV_HAS_OPENMP -using OpenSubdiv::Osd::OmpEvaluator; -typedef Mesh<CpuGLVertexBuffer, - StencilTable, - OmpEvaluator, - GLPatchTable> OsdOmpMesh; -#endif /* OPENSUBDIV_HAS_OPENMP */ - -#ifdef OPENSUBDIV_HAS_OPENCL -using OpenSubdiv::Osd::CLEvaluator; -using OpenSubdiv::Osd::CLGLVertexBuffer; -using OpenSubdiv::Osd::CLStencilTable; -/* TODO(sergey): Use CLDeviceCOntext similar to OSD examples? */ -typedef Mesh<CLGLVertexBuffer, - CLStencilTable, - CLEvaluator, - GLPatchTable, - CLDeviceContext> OsdCLMesh; -static CLDeviceContext g_clDeviceContext; -#endif /* OPENSUBDIV_HAS_OPENCL */ - -#ifdef OPENSUBDIV_HAS_CUDA -using OpenSubdiv::Osd::CudaEvaluator; -using OpenSubdiv::Osd::CudaGLVertexBuffer; -using OpenSubdiv::Osd::CudaStencilTable; -typedef Mesh<CudaGLVertexBuffer, - CudaStencilTable, - CudaEvaluator, - GLPatchTable> OsdCudaMesh; -static CudaDeviceContext g_cudaDeviceContext; -#endif /* OPENSUBDIV_HAS_CUDA */ - -#ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK -using OpenSubdiv::Osd::GLXFBEvaluator; -using OpenSubdiv::Osd::GLStencilTableTBO; -using OpenSubdiv::Osd::GLVertexBuffer; -typedef Mesh<GLVertexBuffer, - GLStencilTableTBO, - GLXFBEvaluator, - GLPatchTable> OsdGLSLTransformFeedbackMesh; -#endif /* OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK */ - -#ifdef OPENSUBDIV_HAS_GLSL_COMPUTE -using OpenSubdiv::Osd::GLComputeEvaluator; -using OpenSubdiv::Osd::GLStencilTableSSBO; -using OpenSubdiv::Osd::GLVertexBuffer; -typedef Mesh<GLVertexBuffer, - GLStencilTableSSBO, - GLComputeEvaluator, - GLPatchTable> OsdGLSLComputeMesh; -#endif - -namespace { - -#if !defined(OPENSUBDIV_VERSION_NUMBER) && !defined(OPENSUBDIV_VERSION_MINOR) -void stringSplit(vector<string>* tokens, - const string& str, - const string& separators, - bool skip_empty) { - size_t token_start = 0, token_length = 0; - for (size_t i = 0; i < str.length(); ++i) { - const char ch = str[i]; - if (separators.find(ch) == string::npos) { - /* Append non-separator char to a token. */ - ++token_length; - } else { - /* Append current token to the list (if any). */ - if (token_length > 0 || !skip_empty) { - string token = str.substr(token_start, token_length); - tokens->push_back(token); - } - /* Re-set token pointers, */ - token_start = i + 1; - token_length = 0; - } - } - /* Append token which might be at the end of the string. */ - if ((token_length != 0) || - (!skip_empty && token_start > 0 && - separators.find(str[token_start-1]) != string::npos)) { - string token = str.substr(token_start, token_length); - tokens->push_back(token); - } -} -#endif - -struct FVarVertex { - float u, v; - void Clear() { - u = v = 0.0f; - } - void AddWithWeight(FVarVertex const & src, float weight) { - u += weight * src.u; - v += weight * src.v; - } -}; - -static void interpolate_fvar_data(OpenSubdiv::Far::TopologyRefiner& refiner, - const std::vector<float> uvs, - std::vector<float> &fvar_data) { - /* TODO(sergey): Make it somehow more generic way. */ - const int fvar_width = 2; - const int max_level = refiner.GetMaxLevel(); - size_t fvar_data_offset = 0, values_offset = 0; - for (int channel = 0; channel < refiner.GetNumFVarChannels(); ++channel) { - const int num_values = refiner.GetLevel(0).GetNumFVarValues(channel) * 2, - num_values_max = refiner.GetLevel(max_level).GetNumFVarValues(channel), - num_values_total = refiner.GetNumFVarValuesTotal(channel); - if (num_values_total <= 0) { - continue; - } - OpenSubdiv::Far::PrimvarRefiner primvar_refiner(refiner); - if (refiner.IsUniform()) { - /* For uniform we only keep the highest level of refinement. */ - fvar_data.resize(fvar_data.size() + num_values_max * fvar_width); - std::vector<FVarVertex> buffer(num_values_total - num_values_max); - FVarVertex *src = &buffer[0]; - memcpy(src, &uvs[values_offset], num_values * sizeof(float)); - /* Defer the last level to treat separately with its alternate - * destination. - */ - for (int level = 1; level < max_level; ++level) { - FVarVertex *dst = src + refiner.GetLevel(level-1).GetNumFVarValues(channel); - primvar_refiner.InterpolateFaceVarying(level, src, dst, channel); - src = dst; - } - FVarVertex *dst = reinterpret_cast<FVarVertex *>(&fvar_data[fvar_data_offset]); - primvar_refiner.InterpolateFaceVarying(max_level, src, dst, channel); - fvar_data_offset += num_values_max * fvar_width; - } else { - /* For adaptive we keep all levels. */ - fvar_data.resize(fvar_data.size() + num_values_total * fvar_width); - FVarVertex *src = reinterpret_cast<FVarVertex *>(&fvar_data[fvar_data_offset]); - memcpy(src, &uvs[values_offset], num_values * sizeof(float)); - for (int level = 1; level <= max_level; ++level) { - FVarVertex *dst = src + refiner.GetLevel(level-1).GetNumFVarValues(channel); - primvar_refiner.InterpolateFaceVarying(level, src, dst, channel); - src = dst; - } - fvar_data_offset += num_values_total * fvar_width; - } - values_offset += num_values; - } -} - -} // namespace - -struct OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner( - OpenSubdiv_TopologyRefinerDescr *topology_refiner, - int evaluator_type, - int level) -{ - using OpenSubdiv::Far::TopologyRefiner; - - MeshBitset bits; - /* TODO(sergey): Adaptive subdivisions are not currently - * possible because of the lack of tessellation shader. - */ - bits.set(OpenSubdiv::Osd::MeshAdaptive, 0); - bits.set(OpenSubdiv::Osd::MeshUseSingleCreasePatch, 0); - bits.set(OpenSubdiv::Osd::MeshInterleaveVarying, 1); - bits.set(OpenSubdiv::Osd::MeshFVarData, 1); - bits.set(OpenSubdiv::Osd::MeshEndCapBSplineBasis, 1); - - const int num_vertex_elements = 3; - const int num_varying_elements = 3; - - GLMeshInterface *mesh = NULL; - TopologyRefiner *refiner = topology_refiner->osd_refiner; - - switch(evaluator_type) { -#define CHECK_EVALUATOR_TYPE(type, class) \ - case OPENSUBDIV_EVALUATOR_ ## type: \ - mesh = new class(refiner, \ - num_vertex_elements, \ - num_varying_elements, \ - level, \ - bits); \ - break; - - CHECK_EVALUATOR_TYPE(CPU, OsdCpuMesh) - -#ifdef OPENSUBDIV_HAS_OPENMP - CHECK_EVALUATOR_TYPE(OPENMP, OsdOmpMesh) -#endif - -#ifdef OPENSUBDIV_HAS_OPENCL - CHECK_EVALUATOR_TYPE(OPENCL, OsdCLMesh) -#endif - -#ifdef OPENSUBDIV_HAS_CUDA - CHECK_EVALUATOR_TYPE(CUDA, OsdCudaMesh) -#endif - -#ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK - CHECK_EVALUATOR_TYPE(GLSL_TRANSFORM_FEEDBACK, - OsdGLSLTransformFeedbackMesh) -#endif - -#ifdef OPENSUBDIV_HAS_GLSL_COMPUTE - CHECK_EVALUATOR_TYPE(GLSL_COMPUTE, OsdGLSLComputeMesh) -#endif - -#undef CHECK_EVALUATOR_TYPE - } - - if (mesh == NULL) { - return NULL; - } - - OpenSubdiv_GLMesh *gl_mesh = - (OpenSubdiv_GLMesh *) OBJECT_GUARDED_NEW(OpenSubdiv_GLMesh); - gl_mesh->evaluator_type = evaluator_type; - gl_mesh->descriptor = (OpenSubdiv_GLMeshDescr *) mesh; - gl_mesh->topology_refiner = topology_refiner; - - if (refiner->GetNumFVarChannels() > 0) { - std::vector<float> fvar_data; - interpolate_fvar_data(*refiner, topology_refiner->uvs, fvar_data); - openSubdiv_osdGLAllocFVar(topology_refiner, gl_mesh, &fvar_data[0]); - } - else { - gl_mesh->fvar_data = NULL; - } - - return gl_mesh; -} - -void openSubdiv_deleteOsdGLMesh(struct OpenSubdiv_GLMesh *gl_mesh) -{ - openSubdiv_osdGLDestroyFVar(gl_mesh); - switch (gl_mesh->evaluator_type) { -#define CHECK_EVALUATOR_TYPE(type, class) \ - case OPENSUBDIV_EVALUATOR_ ## type: \ - delete (class *) gl_mesh->descriptor; \ - break; - - CHECK_EVALUATOR_TYPE(CPU, OsdCpuMesh) - -#ifdef OPENSUBDIV_HAS_OPENMP - CHECK_EVALUATOR_TYPE(OPENMP, OsdOmpMesh) -#endif - -#ifdef OPENSUBDIV_HAS_OPENCL - CHECK_EVALUATOR_TYPE(OPENCL, OsdCLMesh) -#endif - -#ifdef OPENSUBDIV_HAS_CUDA - CHECK_EVALUATOR_TYPE(CUDA, OsdCudaMesh) -#endif - -#ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK - CHECK_EVALUATOR_TYPE(GLSL_TRANSFORM_FEEDBACK, - OsdGLSLTransformFeedbackMesh) -#endif - -#ifdef OPENSUBDIV_HAS_GLSL_COMPUTE - CHECK_EVALUATOR_TYPE(GLSL_COMPUTE, OsdGLSLComputeMesh) -#endif - -#undef CHECK_EVALUATOR_TYPE - } - - /* NOTE: OSD refiner was owned by gl_mesh, no need to free it here. */ - OBJECT_GUARDED_DELETE(gl_mesh->topology_refiner, OpenSubdiv_TopologyRefinerDescr); - OBJECT_GUARDED_DELETE(gl_mesh, OpenSubdiv_GLMesh); -} - -unsigned int openSubdiv_getOsdGLMeshPatchIndexBuffer(struct OpenSubdiv_GLMesh *gl_mesh) -{ - return ((GLMeshInterface *)gl_mesh->descriptor)->GetPatchTable()->GetPatchIndexBuffer(); -} - -unsigned int openSubdiv_getOsdGLMeshVertexBuffer(struct OpenSubdiv_GLMesh *gl_mesh) -{ - return ((GLMeshInterface *)gl_mesh->descriptor)->BindVertexBuffer(); -} - -void openSubdiv_osdGLMeshUpdateVertexBuffer(struct OpenSubdiv_GLMesh *gl_mesh, - const float *vertex_data, - int start_vertex, - int num_verts) -{ - ((GLMeshInterface *)gl_mesh->descriptor)->UpdateVertexBuffer(vertex_data, - start_vertex, - num_verts); -} - -void openSubdiv_osdGLMeshRefine(struct OpenSubdiv_GLMesh *gl_mesh) -{ - ((GLMeshInterface *)gl_mesh->descriptor)->Refine(); -} - -void openSubdiv_osdGLMeshSynchronize(struct OpenSubdiv_GLMesh *gl_mesh) -{ - ((GLMeshInterface *)gl_mesh->descriptor)->Synchronize(); -} - -void openSubdiv_osdGLMeshBindVertexBuffer(OpenSubdiv_GLMesh *gl_mesh) -{ - ((GLMeshInterface *)gl_mesh->descriptor)->BindVertexBuffer(); -} - -const struct OpenSubdiv_TopologyRefinerDescr *openSubdiv_getGLMeshTopologyRefiner( - OpenSubdiv_GLMesh *gl_mesh) -{ - return gl_mesh->topology_refiner; -} - -int openSubdiv_getVersionHex(void) -{ -#if defined(OPENSUBDIV_VERSION_NUMBER) - return OPENSUBDIV_VERSION_NUMBER; -#elif defined(OPENSUBDIV_VERSION_MAJOR) - return OPENSUBDIV_VERSION_MAJOR * 10000 + - OPENSUBDIV_VERSION_MINOR * 100 + - OPENSUBDIV_VERSION_PATCH; -#elif defined(OPENSUBDIV_VERSION) - const char* version = STRINGIFY(OPENSUBDIV_VERSION); - if (version[0] == 'v') { - version += 1; - } - int major = 0, minor = 0, patch = 0; - vector<string> tokens; - stringSplit(&tokens, version, "_", true); - if (tokens.size() == 3) { - major = atoi(tokens[0].c_str()); - minor = atoi(tokens[1].c_str()); - patch = atoi(tokens[2].c_str()); - } - return major * 10000 + minor * 100 + patch; -#else - return 0; -#endif -} diff --git a/intern/opensubdiv/opensubdiv_capi.h b/intern/opensubdiv/opensubdiv_capi.h index c29d08a77e1..a26ea36b863 100644 --- a/intern/opensubdiv/opensubdiv_capi.h +++ b/intern/opensubdiv/opensubdiv_capi.h @@ -1,163 +1,43 @@ -/* - * ***** 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) 2013 Blender Foundation. - * All rights reserved. - * - * Contributor(s): Sergey Sharybin - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifndef __OPENSUBDIV_CAPI_H__ -#define __OPENSUBDIV_CAPI_H__ +// Copyright 2013 Blender Foundation. All rights reserved. +// +// 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. +// +// Author: Sergey Sharybin + +#ifndef OPENSUBDIV_CAPI_H_ +#define OPENSUBDIV_CAPI_H_ + +#include "opensubdiv_capi_type.h" #ifdef __cplusplus extern "C" { #endif -// Types declaration. -struct OpenSubdiv_GLMesh; -struct OpenSubdiv_GLMeshDescr; -struct OpenSubdiv_GLMeshFVarData; -struct OpenSubdiv_TopologyRefinerDescr; - -typedef struct OpenSubdiv_GLMesh OpenSubdiv_GLMesh; - -// Keep this a bitmask os it's possible to pass available -// evaluators to Blender. -enum { - OPENSUBDIV_EVALUATOR_CPU = (1 << 0), - OPENSUBDIV_EVALUATOR_OPENMP = (1 << 1), - OPENSUBDIV_EVALUATOR_OPENCL = (1 << 2), - OPENSUBDIV_EVALUATOR_CUDA = (1 << 3), - OPENSUBDIV_EVALUATOR_GLSL_TRANSFORM_FEEDBACK = (1 << 4), - OPENSUBDIV_EVALUATOR_GLSL_COMPUTE = (1 << 5), -}; - -enum { - OPENSUBDIV_SCHEME_CATMARK, - OPENSUBDIV_SCHEME_BILINEAR, - OPENSUBDIV_SCHEME_LOOP, -}; - -/* TODO(sergey): Re-name and avoid bad level data access. */ -OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner( - struct OpenSubdiv_TopologyRefinerDescr *topology_refiner, - int evaluator_type, - int level); - -void openSubdiv_deleteOsdGLMesh(OpenSubdiv_GLMesh *gl_mesh); -unsigned int openSubdiv_getOsdGLMeshPatchIndexBuffer( - OpenSubdiv_GLMesh *gl_mesh); -unsigned int openSubdiv_getOsdGLMeshVertexBuffer(OpenSubdiv_GLMesh *gl_mesh); -void openSubdiv_osdGLMeshUpdateVertexBuffer(OpenSubdiv_GLMesh *gl_mesh, - const float *vertex_data, - int start_vertex, - int num_verts); -void openSubdiv_osdGLMeshRefine(OpenSubdiv_GLMesh *gl_mesh); -void openSubdiv_osdGLMeshSynchronize(OpenSubdiv_GLMesh *gl_mesh); -void openSubdiv_osdGLMeshBindVertexBuffer(OpenSubdiv_GLMesh *gl_mesh); - -const struct OpenSubdiv_TopologyRefinerDescr *openSubdiv_getGLMeshTopologyRefiner( - OpenSubdiv_GLMesh *gl_mesh); - -/* ============================= Evaluator API ============================== */ - -struct OpenSubdiv_EvaluatorDescr; -typedef struct OpenSubdiv_EvaluatorDescr OpenSubdiv_EvaluatorDescr; - -/* TODO(sergey): Avoid bad-level data access, */ -OpenSubdiv_EvaluatorDescr *openSubdiv_createEvaluatorDescr( - struct OpenSubdiv_TopologyRefinerDescr *topology_refiner, - int subsurf_level); - -void openSubdiv_deleteEvaluatorDescr( - OpenSubdiv_EvaluatorDescr *evaluator_descr); - -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_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, - float face_u, float face_v, - float P[3], - float dPdu[3], - float dPdv[3]); - -void openSubdiv_evaluateVarying(OpenSubdiv_EvaluatorDescr *evaluator_descr, - int osd_face_index, - float face_u, float face_v, - float varying[3]); - -/* ============================== 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); - -/* Draw specified patches. */ -void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh, - int fill_quads, - int start_patch, - int num_patches); - -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 ============================ */ - -int openSubdiv_getAvailableEvaluators(void); +// Global initialization/deinitialization. +// +// Supposed to be called from main thread. void openSubdiv_init(void); void openSubdiv_cleanup(void); +// Bitmask of eOpenSubdivEvaluator. +int openSubdiv_getAvailableEvaluators(void); + int openSubdiv_getVersionHex(void); #ifdef __cplusplus } #endif -#endif // __OPENSUBDIV_CAPI_H__ +#endif // OPENSUBDIV_CAPI_H_ diff --git a/intern/opensubdiv/opensubdiv_capi_type.h b/intern/opensubdiv/opensubdiv_capi_type.h new file mode 100644 index 00000000000..04fe2afff53 --- /dev/null +++ b/intern/opensubdiv/opensubdiv_capi_type.h @@ -0,0 +1,41 @@ +// Copyright 2013 Blender Foundation. All rights reserved. +// +// 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. +// +// Author: Sergey Sharybin + +#ifndef OPENSUBDIV_CAPI_TYPES_H_ +#define OPENSUBDIV_CAPI_TYPES_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +// Keep this a bitmask os it's possible to pass available +// evaluators to Blender. +typedef enum eOpenSubdivEvaluator { + OPENSUBDIV_EVALUATOR_CPU = (1 << 0), + OPENSUBDIV_EVALUATOR_OPENMP = (1 << 1), + OPENSUBDIV_EVALUATOR_OPENCL = (1 << 2), + OPENSUBDIV_EVALUATOR_CUDA = (1 << 3), + OPENSUBDIV_EVALUATOR_GLSL_TRANSFORM_FEEDBACK = (1 << 4), + OPENSUBDIV_EVALUATOR_GLSL_COMPUTE = (1 << 5), +} eOpenSubdivEvaluator; + +#ifdef __cplusplus +} +#endif + +#endif // OPENSUBDIV_CAPI_TYPES_H_ diff --git a/intern/opensubdiv/opensubdiv_converter.cc b/intern/opensubdiv/opensubdiv_converter.cc deleted file mode 100644 index fec15b118ae..00000000000 --- a/intern/opensubdiv/opensubdiv_converter.cc +++ /dev/null @@ -1,764 +0,0 @@ -/* - * ***** 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) 2015 Blender Foundation. - * All rights reserved. - * - * Contributor(s): Sergey Sharybin. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include <cstdio> -#include <vector> - -#ifdef _MSC_VER -# include "iso646.h" -#endif - -#include <opensubdiv/far/topologyRefinerFactory.h> - -#include "MEM_guardedalloc.h" - -#include "opensubdiv_converter_capi.h" -#include "opensubdiv_intern.h" -#include "opensubdiv_topology_refiner.h" - - -#include <stack> - -#ifdef OPENSUBDIV_ORIENT_TOPOLOGY -namespace { - -inline void reverse_face_verts(int *face_verts, int num_verts) -{ - int last_vert = face_verts[num_verts - 1]; - for (int i = num_verts - 1; i > 0; --i) { - face_verts[i] = face_verts[i - 1]; - } - face_verts[0] = last_vert; -} - -struct TopologyRefinerData { - const OpenSubdiv_Converter& conv; - std::vector<float> *uvs; -}; - -} /* namespace */ -#endif /* OPENSUBDIV_ORIENT_TOPOLOGY */ - -namespace OpenSubdiv { -namespace OPENSUBDIV_VERSION { -namespace Far { - -namespace { - -template <typename T> -inline int findInArray(T array, int value) -{ - return (int)(std::find(array.begin(), array.end(), value) - array.begin()); -} - -#ifdef OPENSUBDIV_ORIENT_TOPOLOGY -inline int get_loop_winding(int vert0_of_face, int vert1_of_face) -{ - int delta_face = vert1_of_face - vert0_of_face; - if (abs(delta_face) != 1) { - if (delta_face > 0) { - delta_face = -1; - } - else { - delta_face = 1; - } - } - return delta_face; -} - -inline void reverse_face_loops(IndexArray face_verts, IndexArray face_edges) -{ - for (int i = 0; i < face_verts.size() / 2; ++i) { - int j = face_verts.size() - i - 1; - if (i != j) { - std::swap(face_verts[i], face_verts[j]); - std::swap(face_edges[i], face_edges[j]); - } - } - reverse_face_verts(&face_verts[0], face_verts.size()); -} - -inline void check_oriented_vert_connectivity(const int num_vert_edges, - const int num_vert_faces, - const int *vert_edges, - const int *vert_faces, - const int *dst_vert_edges, - const int *dst_vert_faces) -{ -# ifndef NDEBUG - for (int i = 0; i < num_vert_faces; ++i) { - bool found = false; - for (int j = 0; j < num_vert_faces; ++j) { - if (vert_faces[i] == dst_vert_faces[j]) { - found = true; - break; - } - } - if (!found) { - assert(!"vert-faces connectivity ruined"); - } - } - for (int i = 0; i < num_vert_edges; ++i) { - bool found = false; - for (int j = 0; j < num_vert_edges; ++j) { - if (vert_edges[i] == dst_vert_edges[j]) { - found = true; - break; - } - } - if (!found) { - assert(!"vert-edges connectivity ruined"); - } - } -# else - (void)num_vert_edges; - (void)num_vert_faces; - (void)vert_edges; - (void)vert_faces; - (void)dst_vert_edges; - (void)dst_vert_faces; -# endif -} -#endif - -} /* namespace */ - -template <> -inline bool TopologyRefinerFactory<TopologyRefinerData>::resizeComponentTopology( - TopologyRefiner& refiner, - const TopologyRefinerData& cb_data) -{ - const OpenSubdiv_Converter& conv = cb_data.conv; - /* Faces and face-verts */ - const int num_faces = conv.get_num_faces(&conv); - setNumBaseFaces(refiner, num_faces); - for (int face = 0; face < num_faces; ++face) { - const int num_verts = conv.get_num_face_verts(&conv, face); - setNumBaseFaceVertices(refiner, face, num_verts); - } - /* Edges and edge-faces. */ - const int num_edges = conv.get_num_edges(&conv); - setNumBaseEdges(refiner, num_edges); - for (int edge = 0; edge < num_edges; ++edge) { - const int num_edge_faces = conv.get_num_edge_faces(&conv, edge); - setNumBaseEdgeFaces(refiner, edge, num_edge_faces); - } - /* Vertices and vert-faces and vert-edges/ */ - const int num_verts = conv.get_num_verts(&conv); - setNumBaseVertices(refiner, num_verts); - for (int vert = 0; vert < num_verts; ++vert) { - const int num_vert_edges = conv.get_num_vert_edges(&conv, vert), - num_vert_faces = conv.get_num_vert_faces(&conv, vert); - setNumBaseVertexEdges(refiner, vert, num_vert_edges); - setNumBaseVertexFaces(refiner, vert, num_vert_faces); - } - return true; -} - -template <> -inline bool TopologyRefinerFactory<TopologyRefinerData>::assignComponentTopology( - TopologyRefiner& refiner, - const TopologyRefinerData &cb_data) -{ - const OpenSubdiv_Converter& conv = cb_data.conv; - using Far::IndexArray; - /* Face relations. */ - const int num_faces = conv.get_num_faces(&conv); - for (int face = 0; face < num_faces; ++face) { - IndexArray dst_face_verts = getBaseFaceVertices(refiner, face); - conv.get_face_verts(&conv, face, &dst_face_verts[0]); - IndexArray dst_face_edges = getBaseFaceEdges(refiner, face); - conv.get_face_edges(&conv, face, &dst_face_edges[0]); - } - /* Edge relations. */ - const int num_edges = conv.get_num_edges(&conv); - for (int edge = 0; edge < num_edges; ++edge) { - /* Edge-vertices */ - IndexArray dst_edge_verts = getBaseEdgeVertices(refiner, edge); - conv.get_edge_verts(&conv, edge, &dst_edge_verts[0]); - /* Edge-faces */ - IndexArray dst_edge_faces = getBaseEdgeFaces(refiner, edge); - conv.get_edge_faces(&conv, edge, &dst_edge_faces[0]); - } -#ifdef OPENSUBDIV_ORIENT_TOPOLOGY - /* Make face normals consistent. */ - bool *face_used = new bool[num_faces]; - memset(face_used, 0, sizeof(bool) * num_faces); - std::stack<int> traverse_stack; - int face_start = 0, num_traversed_faces = 0; - /* Traverse all islands. */ - while (num_traversed_faces != num_faces) { - /* Find first face of any untraversed islands. */ - while (face_used[face_start]) { - ++face_start; - } - /* Add first face to the stack. */ - traverse_stack.push(face_start); - face_used[face_start] = true; - /* Go over whole connected component. */ - while (!traverse_stack.empty()) { - int face = traverse_stack.top(); - traverse_stack.pop(); - IndexArray face_edges = getBaseFaceEdges(refiner, face); - ConstIndexArray face_verts = getBaseFaceVertices(refiner, face); - for (int edge_index = 0; edge_index < face_edges.size(); ++edge_index) { - const int edge = face_edges[edge_index]; - ConstIndexArray edge_faces = getBaseEdgeFaces(refiner, edge); - if (edge_faces.size() != 2) { - /* Can't make consistent normals for non-manifolds. */ - continue; - } - ConstIndexArray edge_verts = getBaseEdgeVertices(refiner, edge); - /* Get winding of the reference face. */ - int vert0_of_face = findInArray(face_verts, edge_verts[0]), - vert1_of_face = findInArray(face_verts, edge_verts[1]); - int delta_face = get_loop_winding(vert0_of_face, vert1_of_face); - for (int edge_face = 0; edge_face < edge_faces.size(); ++edge_face) { - int other_face = edge_faces[edge_face]; - /* Never re-traverse faces, only move forward. */ - if (face_used[other_face]) { - continue; - } - IndexArray other_face_verts = getBaseFaceVertices(refiner, - other_face); - int vert0_of_other_face = findInArray(other_face_verts, - edge_verts[0]), - vert1_of_other_face = findInArray(other_face_verts, - edge_verts[1]); - int delta_other_face = get_loop_winding(vert0_of_other_face, - vert1_of_other_face); - if (delta_face * delta_other_face > 0) { - IndexArray other_face_verts = getBaseFaceVertices(refiner, - other_face), - other_face_edges = getBaseFaceEdges(refiner, - other_face); - reverse_face_loops(other_face_verts, - other_face_edges); - } - traverse_stack.push(other_face); - face_used[other_face] = true; - } - } - ++num_traversed_faces; - } - } -#endif /* OPENSUBDIV_ORIENT_TOPOLOGY */ - /* Vertex relations */ - const int num_verts = conv.get_num_verts(&conv); - for (int vert = 0; vert < num_verts; ++vert) { - - /* Vert-Faces */ - IndexArray dst_vert_faces = getBaseVertexFaces(refiner, vert); - int num_vert_faces = conv.get_num_vert_faces(&conv, vert); - int *vert_faces = new int[num_vert_faces]; - conv.get_vert_faces(&conv, vert, vert_faces); - /* Vert-Edges */ - IndexArray dst_vert_edges = getBaseVertexEdges(refiner, vert); - int num_vert_edges = conv.get_num_vert_edges(&conv, vert); - int *vert_edges = new int[num_vert_edges]; - conv.get_vert_edges(&conv, vert, vert_edges); -#ifdef OPENSUBDIV_ORIENT_TOPOLOGY - /* ** Order vertex edges and faces in a CCW order. ** */ - memset(face_used, 0, sizeof(bool) * num_faces); - /* Number of edges and faces added to the ordered array. */ - int edge_count_ordered = 0, face_count_ordered = 0; - /* Add loose edges straight into the edges array. */ - bool has_fan_connections = false; - for (int i = 0; i < num_vert_edges; ++i) { - IndexArray edge_faces = getBaseEdgeFaces(refiner, vert_edges[i]); - if (edge_faces.size() == 0) { - dst_vert_edges[edge_count_ordered++] = vert_edges[i]; - } - else if (edge_faces.size() > 2) { - has_fan_connections = true; - } - } - if (has_fan_connections) { - /* OpenSubdiv currently doesn't give us clues how to handle - * fan face connections. and since handling such connections - * complicates the loop below we simply don't do special - * orientation for them. - */ - memcpy(&dst_vert_edges[0], vert_edges, sizeof(int) * num_vert_edges); - memcpy(&dst_vert_faces[0], vert_faces, sizeof(int) * num_vert_faces); - delete [] vert_edges; - delete [] vert_faces; - continue; - } - /* Perform at max numbder of vert-edges iteration and try to avoid - * deadlock here for malformed mesh. - */ - for (int global_iter = 0; global_iter < num_vert_edges; ++global_iter) { - /* Numbr of edges and faces which are still to be ordered. */ - int num_vert_edges_remained = num_vert_edges - edge_count_ordered, - num_vert_faces_remained = num_vert_faces - face_count_ordered; - if (num_vert_edges_remained == 0 && num_vert_faces_remained == 0) { - /* All done, nothing to do anymore. */ - break; - } - /* Face, edge and face-vertex inndex to start traversal from. */ - int face_start = -1, edge_start = -1, face_vert_start = -1; - if (num_vert_edges_remained == num_vert_faces_remained) { - /* Vertex is eitehr complete manifold or is connected to seevral - * manifold islands (hourglass-like configuration), can pick up - * random edge unused and start from it. - */ - /* TODO(sergey): Start from previous edge from which traversal - * began at previous iteration. - */ - for (int i = 0; i < num_vert_edges; ++i) { - face_start = vert_faces[i]; - if (!face_used[face_start]) { - ConstIndexArray - face_verts = getBaseFaceVertices(refiner, face_start), - face_edges = getBaseFaceEdges(refiner, face_start); - face_vert_start = findInArray(face_verts, vert); - edge_start = face_edges[face_vert_start]; - break; - } - } - } - else { - /* Special handle of non-manifold vertex. */ - for (int i = 0; i < num_vert_edges; ++i) { - edge_start = vert_edges[i]; - IndexArray edge_faces = getBaseEdgeFaces(refiner, edge_start); - if (edge_faces.size() == 1) { - face_start = edge_faces[0]; - if (!face_used[face_start]) { - ConstIndexArray - face_verts = getBaseFaceVertices(refiner, face_start), - face_edges = getBaseFaceEdges(refiner, face_start); - face_vert_start = findInArray(face_verts, vert); - if (edge_start == face_edges[face_vert_start]) { - break; - } - } - } - /* Reset indices for sanity check below. */ - face_start = edge_start = face_vert_start = -1; - } - } - /* Sanity check. */ - assert(face_start != -1 && - edge_start != -1 && - face_vert_start != -1); - /* Traverse faces starting from the current one. */ - int edge_first = edge_start; - dst_vert_faces[face_count_ordered++] = face_start; - dst_vert_edges[edge_count_ordered++] = edge_start; - face_used[face_start] = true; - while (edge_count_ordered < num_vert_edges) { - IndexArray face_verts = getBaseFaceVertices(refiner, face_start); - IndexArray face_edges = getBaseFaceEdges(refiner, face_start); - int face_edge_start = face_vert_start; - int face_edge_next = (face_edge_start > 0) ? (face_edge_start - 1) : (face_verts.size() - 1); - Index edge_next = face_edges[face_edge_next]; - if (edge_next == edge_first) { - /* Multiple manifolds found, stop for now and handle rest - * in the next iteration. - */ - break; - } - dst_vert_edges[edge_count_ordered++] = edge_next; - if (face_count_ordered < num_vert_faces) { - IndexArray edge_faces = getBaseEdgeFaces(refiner, edge_next); - assert(edge_faces.size() != 0); - if (edge_faces.size() == 1) { - assert(edge_faces[0] == face_start); - break; - } - else if (edge_faces.size() != 2) { - break; - } - assert(edge_faces.size() == 2); - face_start = edge_faces[(edge_faces[0] == face_start) ? 1 : 0]; - face_vert_start = findInArray(getBaseFaceEdges(refiner, face_start), edge_next); - dst_vert_faces[face_count_ordered++] = face_start; - face_used[face_start] = true; - } - edge_start = edge_next; - } - } - /* Verify ordering doesn't ruin connectivity information. */ - assert(face_count_ordered == num_vert_faces); - assert(edge_count_ordered == num_vert_edges); - check_oriented_vert_connectivity(num_vert_edges, - num_vert_faces, - vert_edges, - vert_faces, - &dst_vert_edges[0], - &dst_vert_faces[0]); - /* For the release builds we're failing mesh construction so instead - * of nasty bugs the unsupported mesh will simply disappear from the - * viewport. - */ - if (face_count_ordered != num_vert_faces || - edge_count_ordered != num_vert_edges) - { - delete [] vert_edges; - delete [] vert_faces; - return false; - } -#else /* OPENSUBDIV_ORIENT_TOPOLOGY */ - memcpy(&dst_vert_edges[0], vert_edges, sizeof(int) * num_vert_edges); - memcpy(&dst_vert_faces[0], vert_faces, sizeof(int) * num_vert_faces); -#endif /* OPENSUBDIV_ORIENT_TOPOLOGY */ - delete [] vert_edges; - delete [] vert_faces; - } -#ifdef OPENSUBDIV_ORIENT_TOPOLOGY - delete [] face_used; -#endif - populateBaseLocalIndices(refiner); - return true; -}; - -template <> -inline bool TopologyRefinerFactory<TopologyRefinerData>::assignComponentTags( - TopologyRefiner& refiner, - const TopologyRefinerData& cb_data) -{ - const OpenSubdiv_Converter& conv = cb_data.conv; - typedef OpenSubdiv::Sdc::Crease Crease; - - int num_edges = conv.get_num_edges(&conv); - for (int edge = 0; edge < num_edges; ++edge) { - float sharpness; - ConstIndexArray edge_faces = getBaseEdgeFaces(refiner, edge); - if (edge_faces.size() == 2) { - sharpness = conv.get_edge_sharpness(&conv, edge); - } - else { - /* Non-manifold edges must be sharp. */ - sharpness = Crease::SHARPNESS_INFINITE; - } - setBaseEdgeSharpness(refiner, edge, sharpness); - } - - /* OpenSubdiv expects non-manifold vertices to be sharp but at the - * time it handles correct cases when vertex is a corner of plane. - * Currently mark verts which are adjacent to a loose edge as sharp, - * but this decision needs some more investigation. - */ - int num_vert = conv.get_num_verts(&conv); - for (int vert = 0; vert < num_vert; ++vert) { - ConstIndexArray vert_edges = getBaseVertexEdges(refiner, vert); - for (int edge_index = 0; edge_index < vert_edges.size(); ++edge_index) { - int edge = vert_edges[edge_index]; - ConstIndexArray edge_faces = getBaseEdgeFaces(refiner, edge); - if (edge_faces.size() == 0) { - setBaseVertexSharpness(refiner, vert, Crease::SHARPNESS_INFINITE); - break; - } - } - if (vert_edges.size() == 2) { - int edge0 = vert_edges[0], - edge1 = vert_edges[1]; - float sharpness0 = conv.get_edge_sharpness(&conv, edge0), - sharpness1 = conv.get_edge_sharpness(&conv, edge1); - float sharpness = std::min(sharpness0, sharpness1); - setBaseVertexSharpness(refiner, vert, sharpness); - } - } - - return true; -} - -template <> -inline void TopologyRefinerFactory<TopologyRefinerData>::reportInvalidTopology( - TopologyError /*errCode*/, - const char *msg, - const TopologyRefinerData& /*mesh*/) -{ - printf("OpenSubdiv Error: %s\n", msg); -} - -template <> -inline bool TopologyRefinerFactory<TopologyRefinerData>::assignFaceVaryingTopology( - TopologyRefiner& refiner, - const TopologyRefinerData& cb_data) -{ - const OpenSubdiv_Converter& conv = cb_data.conv; - const int num_layers = conv.get_num_uv_layers(&conv); - if (num_layers <= 0) { - /* No UV maps, we can skip any face-varying data. */ - return true; - } - const int num_faces = getNumBaseFaces(refiner); - size_t uvs_offset = 0; - for (int layer = 0; layer < num_layers; ++layer) { - conv.precalc_uv_layer(&conv, layer); - const int num_uvs = conv.get_num_uvs(&conv); - /* Fill in UV coordinates. */ - cb_data.uvs->resize(cb_data.uvs->size() + num_uvs * 2); - conv.get_uvs(&conv, &cb_data.uvs->at(uvs_offset)); - uvs_offset += num_uvs * 2; - /* Fill in per-corner index of the UV. */ - const int channel = createBaseFVarChannel(refiner, num_uvs); - for (int face = 0; face < num_faces; ++face) { - Far::IndexArray dst_face_uvs = getBaseFaceFVarValues(refiner, - face, - channel); - for (int corner = 0; corner < dst_face_uvs.size(); ++corner) { - const int uv_index = conv.get_face_corner_uv_index(&conv, - face, - corner); - dst_face_uvs[corner] = uv_index; - } - } - conv.finish_uv_layer(&conv); - } - return true; -} - -} /* namespace Far */ -} /* namespace OPENSUBDIV_VERSION */ -} /* namespace OpenSubdiv */ - -namespace { - -OpenSubdiv::Sdc::SchemeType get_capi_scheme_type(OpenSubdiv_SchemeType type) -{ - switch (type) { - case OSD_SCHEME_BILINEAR: - return OpenSubdiv::Sdc::SCHEME_BILINEAR; - case OSD_SCHEME_CATMARK: - return OpenSubdiv::Sdc::SCHEME_CATMARK; - case OSD_SCHEME_LOOP: - return OpenSubdiv::Sdc::SCHEME_LOOP; - } - assert(!"Unknown scheme type passed via C-API"); - return OpenSubdiv::Sdc::SCHEME_CATMARK; -} - -OpenSubdiv::Sdc::Options::FVarLinearInterpolation -get_capi_fvar_linear_interpolation( - OpenSubdiv_FVarLinearInterpolation linear_interpolation) -{ - typedef OpenSubdiv::Sdc::Options Options; - switch (linear_interpolation) { - case OSD_FVAR_LINEAR_INTERPOLATION_NONE: - return Options::FVAR_LINEAR_NONE; - case OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY: - return Options::FVAR_LINEAR_CORNERS_ONLY; - case OSD_FVAR_LINEAR_INTERPOLATION_BOUNDARIES: - return Options::FVAR_LINEAR_BOUNDARIES; - case OSD_FVAR_LINEAR_INTERPOLATION_ALL: - return Options::FVAR_LINEAR_ALL; - } - assert(!"Unknown fvar linear interpolation passed via C-API"); - return Options::FVAR_LINEAR_NONE; -} - -} /* namespace */ - -struct OpenSubdiv_TopologyRefinerDescr *openSubdiv_createTopologyRefinerDescr( - OpenSubdiv_Converter *converter) -{ - typedef OpenSubdiv::Sdc::Options Options; - - using OpenSubdiv::Far::TopologyRefinerFactory; - const OpenSubdiv::Sdc::SchemeType scheme_type = - get_capi_scheme_type(converter->get_scheme_type(converter)); - const Options::FVarLinearInterpolation linear_interpolation = - get_capi_fvar_linear_interpolation( - converter->get_fvar_linear_interpolation(converter)); - Options options; - options.SetVtxBoundaryInterpolation(Options::VTX_BOUNDARY_EDGE_ONLY); - options.SetCreasingMethod(Options::CREASE_UNIFORM); - options.SetFVarLinearInterpolation(linear_interpolation); - - TopologyRefinerFactory<TopologyRefinerData>::Options - topology_options(scheme_type, options); -#ifdef OPENSUBDIV_VALIDATE_TOPOLOGY - topology_options.validateFullTopology = true; -#endif - OpenSubdiv_TopologyRefinerDescr *result = OBJECT_GUARDED_NEW(OpenSubdiv_TopologyRefinerDescr); - TopologyRefinerData cb_data = {*converter, &result->uvs}; - /* We don't use guarded allocation here so we can re-use the refiner - * for GL mesh creation directly. - */ - result->osd_refiner = - TopologyRefinerFactory<TopologyRefinerData>::Create( - cb_data, - topology_options); - - return result; -} - -void openSubdiv_deleteTopologyRefinerDescr( - OpenSubdiv_TopologyRefinerDescr *topology_refiner) -{ - delete topology_refiner->osd_refiner; - OBJECT_GUARDED_DELETE(topology_refiner, OpenSubdiv_TopologyRefinerDescr); -} - -int openSubdiv_topologyRefinerGetSubdivLevel( - const OpenSubdiv_TopologyRefinerDescr *topology_refiner) -{ - using OpenSubdiv::Far::TopologyRefiner; - const TopologyRefiner *refiner = topology_refiner->osd_refiner; - return refiner->GetMaxLevel(); -} - -int openSubdiv_topologyRefinerGetNumVerts( - const OpenSubdiv_TopologyRefinerDescr *topology_refiner) -{ - using OpenSubdiv::Far::TopologyLevel; - using OpenSubdiv::Far::TopologyRefiner; - const TopologyRefiner *refiner = topology_refiner->osd_refiner; - const TopologyLevel &base_level = refiner->GetLevel(0); - return base_level.GetNumVertices(); -} - -int openSubdiv_topologyRefinerGetNumEdges( - const OpenSubdiv_TopologyRefinerDescr *topology_refiner) -{ - using OpenSubdiv::Far::TopologyLevel; - using OpenSubdiv::Far::TopologyRefiner; - const TopologyRefiner *refiner = topology_refiner->osd_refiner; - const TopologyLevel &base_level = refiner->GetLevel(0); - return base_level.GetNumEdges(); -} - -int openSubdiv_topologyRefinerGetNumFaces( - const OpenSubdiv_TopologyRefinerDescr *topology_refiner) -{ - using OpenSubdiv::Far::TopologyLevel; - using OpenSubdiv::Far::TopologyRefiner; - const TopologyRefiner *refiner = topology_refiner->osd_refiner; - const TopologyLevel &base_level = refiner->GetLevel(0); - return base_level.GetNumFaces(); -} - -int openSubdiv_topologyRefinerGetNumFaceVerts( - const OpenSubdiv_TopologyRefinerDescr *topology_refiner, - int face) -{ - using OpenSubdiv::Far::TopologyLevel; - using OpenSubdiv::Far::TopologyRefiner; - const TopologyRefiner *refiner = topology_refiner->osd_refiner; - const TopologyLevel &base_level = refiner->GetLevel(0); - return base_level.GetFaceVertices(face).size(); -} - -int openSubdiv_topologyRefnerCompareConverter( - const OpenSubdiv_TopologyRefinerDescr *topology_refiner, - OpenSubdiv_Converter *converter) -{ - typedef OpenSubdiv::Sdc::Options Options; - using OpenSubdiv::Far::ConstIndexArray; - using OpenSubdiv::Far::TopologyRefiner; - using OpenSubdiv::Far::TopologyLevel; - const TopologyRefiner *refiner = topology_refiner->osd_refiner; - const TopologyLevel &base_level = refiner->GetLevel(0); - const int num_verts = base_level.GetNumVertices(); - const int num_edges = base_level.GetNumEdges(); - const int num_faces = base_level.GetNumFaces(); - /* Quick preliminary check. */ - OpenSubdiv::Sdc::SchemeType scheme_type = - get_capi_scheme_type(converter->get_scheme_type(converter)); - if (scheme_type != refiner->GetSchemeType()) { - return false; - } - const Options options = refiner->GetSchemeOptions(); - const Options::FVarLinearInterpolation interp = - options.GetFVarLinearInterpolation(); - const Options::FVarLinearInterpolation new_interp = - get_capi_fvar_linear_interpolation( - converter->get_fvar_linear_interpolation(converter)); - if (new_interp != interp) { - return false; - } - if (converter->get_num_verts(converter) != num_verts || - converter->get_num_edges(converter) != num_edges || - converter->get_num_faces(converter) != num_faces) - { - return false; - } - /* Compare all edges. */ - for (int edge = 0; edge < num_edges; ++edge) { - ConstIndexArray edge_verts = base_level.GetEdgeVertices(edge); - int conv_edge_verts[2]; - converter->get_edge_verts(converter, edge, conv_edge_verts); - if (conv_edge_verts[0] != edge_verts[0] || - conv_edge_verts[1] != edge_verts[1]) - { - return false; - } - } - /* Compare all faces. */ - std::vector<int> conv_face_verts; - for (int face = 0; face < num_faces; ++face) { - ConstIndexArray face_verts = base_level.GetFaceVertices(face); - if (face_verts.size() != converter->get_num_face_verts(converter, - face)) - { - return false; - } - conv_face_verts.resize(face_verts.size()); - converter->get_face_verts(converter, face, &conv_face_verts[0]); - bool direct_match = true; - for (int i = 0; i < face_verts.size(); ++i) { - if (conv_face_verts[i] != face_verts[i]) { - direct_match = false; - break; - } - } - if (!direct_match) { - /* If face didn't match in direct direction we also test if it - * matches in reversed direction. This is because conversion might - * reverse loops to make normals consistent. - */ -#ifdef OPENSUBDIV_ORIENT_TOPOLOGY - reverse_face_verts(&conv_face_verts[0], conv_face_verts.size()); - for (int i = 0; i < face_verts.size(); ++i) { - if (conv_face_verts[i] != face_verts[i]) { - return false; - } - } -#else - return false; -#endif - } - } - /* Compare sharpness. */ - for (int edge = 0; edge < num_edges; ++edge) { - ConstIndexArray edge_faces = base_level.GetEdgeFaces(edge); - float sharpness = base_level.GetEdgeSharpness(edge); - float conv_sharpness; - if (edge_faces.size() == 2) { - conv_sharpness = converter->get_edge_sharpness(converter, edge); - } - else { - conv_sharpness = OpenSubdiv::Sdc::Crease::SHARPNESS_INFINITE; - } - if (sharpness != conv_sharpness) { - return false; - } - } - return true; -} diff --git a/intern/opensubdiv/opensubdiv_converter_capi.h b/intern/opensubdiv/opensubdiv_converter_capi.h index ea4f20c5961..1d76da4d76b 100644 --- a/intern/opensubdiv/opensubdiv_converter_capi.h +++ b/intern/opensubdiv/opensubdiv_converter_capi.h @@ -1,149 +1,150 @@ -/* - * ***** 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) 2015 Blender Foundation. - * All rights reserved. - * - * Contributor(s): Sergey Sharybin. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifndef __OPENSUBDIV_CONVERTER_CAPI_H__ -#define __OPENSUBDIV_CONVERTER_CAPI_H__ +// Copyright 2015 Blender Foundation. All rights reserved. +// +// 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. +// +// Author: Sergey Sharybin + +#ifndef OPENSUBDIV_CONVERTER_CAPI_H_ +#define OPENSUBDIV_CONVERTER_CAPI_H_ #ifdef __cplusplus extern "C" { #endif -struct OpenSubdiv_TopologyRefinerDescr; -typedef struct OpenSubdiv_TopologyRefinerDescr OpenSubdiv_TopologyRefinerDescr; - -typedef struct OpenSubdiv_Converter OpenSubdiv_Converter; - typedef enum OpenSubdiv_SchemeType { - OSD_SCHEME_BILINEAR, - OSD_SCHEME_CATMARK, - OSD_SCHEME_LOOP, + OSD_SCHEME_BILINEAR, + OSD_SCHEME_CATMARK, + OSD_SCHEME_LOOP, } OpenSubdiv_SchemeType; typedef enum OpenSubdiv_FVarLinearInterpolation { - OSD_FVAR_LINEAR_INTERPOLATION_NONE, - OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY, - OSD_FVAR_LINEAR_INTERPOLATION_BOUNDARIES, - OSD_FVAR_LINEAR_INTERPOLATION_ALL, + OSD_FVAR_LINEAR_INTERPOLATION_NONE, + OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY, + OSD_FVAR_LINEAR_INTERPOLATION_BOUNDARIES, + OSD_FVAR_LINEAR_INTERPOLATION_ALL, } OpenSubdiv_FVarLinearInterpolation; typedef struct OpenSubdiv_Converter { - /* TODO(sergey): Needs to be implemented. */ - /* OpenSubdiv::Sdc::Options get_options() const; */ - - OpenSubdiv_SchemeType (*get_scheme_type)( - const OpenSubdiv_Converter *converter); - - OpenSubdiv_FVarLinearInterpolation (*get_fvar_linear_interpolation)( - const OpenSubdiv_Converter *converter); - - int (*get_num_faces)(const OpenSubdiv_Converter *converter); - int (*get_num_edges)(const OpenSubdiv_Converter *converter); - int (*get_num_verts)(const OpenSubdiv_Converter *converter); - - /* Face relationships. */ - int (*get_num_face_verts)(const OpenSubdiv_Converter *converter, - int face); - void (*get_face_verts)(const OpenSubdiv_Converter *converter, - int face, - int *face_verts); - void (*get_face_edges)(const OpenSubdiv_Converter *converter, - int face, - int *face_edges); - - /* Edge relationships. */ - void (*get_edge_verts)(const OpenSubdiv_Converter *converter, - int edge, - int *edge_verts); - int (*get_num_edge_faces)(const OpenSubdiv_Converter *converter, - int edge); - void (*get_edge_faces)(const OpenSubdiv_Converter *converter, - int edge, - int *edge_faces); - float (*get_edge_sharpness)(const OpenSubdiv_Converter *converter, - int edge); - - /* Vertex relationships. */ - int (*get_num_vert_edges)(const OpenSubdiv_Converter *converter, int vert); - void (*get_vert_edges)(const OpenSubdiv_Converter *converter, - int vert, - int *vert_edges); - int (*get_num_vert_faces)(const OpenSubdiv_Converter *converter, int vert); - void (*get_vert_faces)(const OpenSubdiv_Converter *converter, - int vert, - int *vert_faces); - - /* Face-varying data. */ - int (*get_num_uv_layers)(const OpenSubdiv_Converter *converter); - - void (*precalc_uv_layer)(const OpenSubdiv_Converter *converter, int layer); - void (*finish_uv_layer)(const OpenSubdiv_Converter *converter); - - int (*get_num_uvs)(const OpenSubdiv_Converter *converter); - void (*get_uvs)(const OpenSubdiv_Converter *converter, float *uvs); - - int (*get_face_corner_uv_index)(const OpenSubdiv_Converter *converter, - int face, - int corner); - - /* User data associated with this converter. */ - void (*free_user_data)(const OpenSubdiv_Converter *converter); - void *user_data; + OpenSubdiv_SchemeType (*getSchemeType)( + const struct OpenSubdiv_Converter* converter); + + OpenSubdiv_FVarLinearInterpolation (*getFVarLinearInterpolation)( + const struct OpenSubdiv_Converter* converter); + + ////////////////////////////////////////////////////////////////////////////// + // Global geometry counters. + // Number of faces/edges/vertices in the base mesh. + int (*getNumFaces)(const struct OpenSubdiv_Converter* converter); + int (*getNumEdges)(const struct OpenSubdiv_Converter* converter); + int (*getNumVertices)(const struct OpenSubdiv_Converter* converter); + + ////////////////////////////////////////////////////////////////////////////// + // Face relationships. + + // Number of vertices the face consists of. + int (*getNumFaceVertices)(const struct OpenSubdiv_Converter* converter, + const int face_index); + // Array of vertex indices the face consists of. + void (*getFaceVertices)(const struct OpenSubdiv_Converter* converter, + const int face_index, + int* face_vertices); + // Array of edge indices the face consists of. + // Aligned with the vertex indices array, edge i connects face vertex i + // with face index i+1. + void (*getFaceEdges)(const struct OpenSubdiv_Converter *converter, + const int face_index, + int *face_edges); + + ////////////////////////////////////////////////////////////////////////////// + // Edge relationships. + + // Vertices the edge consists of. + void (*getEdgeVertices)(const struct OpenSubdiv_Converter* converter, + const int edge_index, + int edge_vertices[2]); + // Number of faces which are sharing the given edge. + int (*getNumEdgeFaces)(const struct OpenSubdiv_Converter* converter, + const int edge_index); + // Array of face indices which are sharing the given edge. + void (*getEdgeFaces)(const struct OpenSubdiv_Converter* converter, + const int edge, + int* edge_faces); + // Edge sharpness (aka crease). + float (*getEdgeSharpness)(const struct OpenSubdiv_Converter* converter, + const int edge_index); + + ////////////////////////////////////////////////////////////////////////////// + // Vertex relationships. + + // Number of edges which are adjacent to the given vertex. + int (*getNumVertexEdges)(const struct OpenSubdiv_Converter* converter, + const int vertex_index); + // Array fo edge indices which are adjacent to the given vertex. + void (*getVertexEdges)(const struct OpenSubdiv_Converter* converter, + const int vertex_index, + int* vertex_edges); + // Number of faces which are adjacent to the given vertex. + int (*getNumVertexFaces)(const struct OpenSubdiv_Converter* converter, + const int vertex_index); + // Array fo face indices which are adjacent to the given vertex. + void (*getVertexFaces)(const struct OpenSubdiv_Converter* converter, + const int vertex_index, + int* vertex_faces); + + ////////////////////////////////////////////////////////////////////////////// + // Face-varying data. + + ///////////////////////////////////// + // UV coordinates. + + // Number of UV layers. + int (*getNumUVLayers)(const struct OpenSubdiv_Converter* converter); + + // We need some corner connectivity information, which might not be trivial + // to be gathered (might require multiple matching calculations per corver + // query). + // precalc() is called before any corner connectivity or UV coordinate is + // queried from the given layer, allowing converter to calculate and cache + // complex complex-to-calculate information. + // finish() is called after converter is done porting UV layer to OpenSubdiv, + // allowing to free cached data. + void (*precalcUVLayer)(const struct OpenSubdiv_Converter* converter, + const int layer_index); + void (*finishUVLayer)(const struct OpenSubdiv_Converter* converter); + + // Get number of UV coordinates in the current layer (layer which was + // specified in precalcUVLayer(). + int (*getNumUVCoordinates)(const struct OpenSubdiv_Converter* converter); + // Get cooridnates themselves. + void (*getUVCoordinates)(const struct OpenSubdiv_Converter* converter, + float* uvs_coordinates); + // For the given face index and its corner (known as loop in Blender) + // get corrsponding UV coordinate index. + int (*getFaceCornerUVIndex)(const struct OpenSubdiv_Converter* converter, + const int face_index, + const int corner_index); + + ////////////////////////////////////////////////////////////////////////////// + // User data associated with this converter. + + void (*freeUserData)(const struct OpenSubdiv_Converter* converter); + void* user_data; } OpenSubdiv_Converter; -OpenSubdiv_TopologyRefinerDescr *openSubdiv_createTopologyRefinerDescr( - OpenSubdiv_Converter *converter); - -void openSubdiv_deleteTopologyRefinerDescr( - OpenSubdiv_TopologyRefinerDescr *topology_refiner); - -/* TODO(sergey): Those calls are not strictly related to conversion. - * needs some dedicated file perhaps. - */ - -int openSubdiv_topologyRefinerGetSubdivLevel( - const OpenSubdiv_TopologyRefinerDescr *topology_refiner); - -int openSubdiv_topologyRefinerGetNumVerts( - const OpenSubdiv_TopologyRefinerDescr *topology_refiner); - -int openSubdiv_topologyRefinerGetNumEdges( - const OpenSubdiv_TopologyRefinerDescr *topology_refiner); - -int openSubdiv_topologyRefinerGetNumFaces( - const OpenSubdiv_TopologyRefinerDescr *topology_refiner); - -int openSubdiv_topologyRefinerGetNumFaceVerts( - const OpenSubdiv_TopologyRefinerDescr *topology_refiner, - int face); - -int openSubdiv_topologyRefnerCompareConverter( - const OpenSubdiv_TopologyRefinerDescr *topology_refiner, - OpenSubdiv_Converter *converter); - #ifdef __cplusplus } #endif -#endif /* __OPENSUBDIV_CONVERTER_CAPI_H__ */ +#endif /* OPENSUBDIV_CONVERTER_CAPI_H_ */ diff --git a/intern/opensubdiv/opensubdiv_device_context_cuda.cc b/intern/opensubdiv/opensubdiv_device_context_cuda.cc deleted file mode 100644 index 46b66a6b35e..00000000000 --- a/intern/opensubdiv/opensubdiv_device_context_cuda.cc +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Adopted from OpenSubdiv with the following license: - * - * Copyright 2015 Pixar - * - * Licensed under the Apache License, Version 2.0 (the "Apache License") - * with the following modification; you may not use this file except in - * compliance with the Apache License and the following modification to it: - * Section 6. Trademarks. is deleted and replaced with: - * - * 6. Trademarks. This License does not grant permission to use the trade - * names, trademarks, service marks, or product names of the Licensor - * and its affiliates, except as required to comply with Section 4(c) of - * the License and to reproduce the content of the NOTICE file. - * - * You may obtain a copy of the Apache License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Apache License with the above modification is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the Apache License for the specific - * language governing permissions and limitations under the Apache License. - */ - -#ifdef OPENSUBDIV_HAS_CUDA - -#ifdef _MSC_VER -# include "iso646.h" -#endif - -#include "opensubdiv_device_context_cuda.h" - -#if defined(_WIN32) -# include <windows.h> -#elif defined(__APPLE__) -# include <OpenGL/OpenGL.h> -#else -# include <X11/Xlib.h> -# include <GL/glx.h> -#endif - -#include <cstdio> -#include <algorithm> -#include <cuda.h> -#include <cuda_runtime_api.h> -#include <cuda_gl_interop.h> - -#define message(fmt, ...) -//#define message(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__) -#define error(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__) - -static int _GetCudaDeviceForCurrentGLContext() -{ - // Find and use the CUDA device for the current GL context - unsigned int interopDeviceCount = 0; - int interopDevices[1]; - cudaError_t status = cudaGLGetDevices(&interopDeviceCount, interopDevices, - 1, cudaGLDeviceListCurrentFrame); - if (status == cudaErrorNoDevice or interopDeviceCount != 1) { - message("CUDA no interop devices found.\n"); - return 0; - } - int device = interopDevices[0]; - -#if defined(_WIN32) - return device; - -#elif defined(__APPLE__) - return device; - -#else // X11 - Display * display = glXGetCurrentDisplay(); - int screen = DefaultScreen(display); - if (device != screen) { - error("The CUDA interop device (%d) does not match " - "the screen used by the current GL context (%d), " - "which may cause slow performance on systems " - "with multiple GPU devices.", device, screen); - } - message("CUDA init using device for current GL context: %d\n", device); - return device; -#endif -} - -/* From "NVIDIA GPU Computing SDK 4.2/C/common/inc/cutil_inline_runtime.h": */ - -/* Beginning of GPU Architecture definitions */ -inline int _ConvertSMVer2Cores_local(int major, int minor) -{ - /* Defines for GPU Architecture types (using the SM version to determine - * the # of cores per SM - */ - typedef struct { - int SM; /* 0xMm (hexidecimal notation), - * M = SM Major version, - * and m = SM minor version - */ - int Cores; - } sSMtoCores; - - sSMtoCores nGpuArchCoresPerSM[] = - { { 0x10, 8 }, /* Tesla Generation (SM 1.0) G80 class */ - { 0x11, 8 }, /* Tesla Generation (SM 1.1) G8x class */ - { 0x12, 8 }, /* Tesla Generation (SM 1.2) G9x class */ - { 0x13, 8 }, /* Tesla Generation (SM 1.3) GT200 class */ - { 0x20, 32 }, /* Fermi Generation (SM 2.0) GF100 class */ - { 0x21, 48 }, /* Fermi Generation (SM 2.1) GF10x class */ - { 0x30, 192}, /* Fermi Generation (SM 3.0) GK10x class */ - { -1, -1 } - }; - - int index = 0; - while (nGpuArchCoresPerSM[index].SM != -1) { - if (nGpuArchCoresPerSM[index].SM == ((major << 4) + minor)) { - return nGpuArchCoresPerSM[index].Cores; - } - index++; - } - printf("MapSMtoCores undefined SMversion %d.%d!\n", major, minor); - return -1; -} -/* End of GPU Architecture definitions. */ - -/* This function returns the best GPU (with maximum GFLOPS) */ -inline int cutGetMaxGflopsDeviceId() -{ - int current_device = 0, sm_per_multiproc = 0; - int max_compute_perf = 0, max_perf_device = -1; - int device_count = 0, best_SM_arch = 0; - int compat_major, compat_minor; - - cuDeviceGetCount(&device_count); - /* Find the best major SM Architecture GPU device. */ - while (current_device < device_count) { - cuDeviceComputeCapability(&compat_major, &compat_minor, current_device); - if (compat_major > 0 && compat_major < 9999) { - best_SM_arch = std::max(best_SM_arch, compat_major); - } - current_device++; - } - - /* Find the best CUDA capable GPU device. */ - current_device = 0; - while (current_device < device_count) { - cuDeviceComputeCapability(&compat_major, &compat_minor, current_device); - if (compat_major == 9999 && compat_minor == 9999) { - sm_per_multiproc = 1; - } else { - sm_per_multiproc = _ConvertSMVer2Cores_local(compat_major, - compat_minor); - } - int multi_processor_count; - cuDeviceGetAttribute(&multi_processor_count, - CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT, - current_device); - int clock_rate; - cuDeviceGetAttribute(&clock_rate, - CU_DEVICE_ATTRIBUTE_CLOCK_RATE, - current_device); - int compute_perf = multi_processor_count * sm_per_multiproc * clock_rate; - if (compute_perf > max_compute_perf) { - /* If we find GPU with SM major > 2, search only these */ - if (best_SM_arch > 2) { - /* If our device==dest_SM_arch, choose this, or else pass. */ - if (compat_major == best_SM_arch) { - max_compute_perf = compute_perf; - max_perf_device = current_device; - } - } else { - max_compute_perf = compute_perf; - max_perf_device = current_device; - } - } - ++current_device; - } - return max_perf_device; -} - -bool CudaDeviceContext::HAS_CUDA_VERSION_4_0() -{ -#ifdef OPENSUBDIV_HAS_CUDA - static bool cudaInitialized = false; - static bool cudaLoadSuccess = true; - if (!cudaInitialized) { - cudaInitialized = true; - -# ifdef OPENSUBDIV_HAS_CUEW - cudaLoadSuccess = cuewInit(CUEW_INIT_CUDA) == CUEW_SUCCESS; - if (!cudaLoadSuccess) { - fprintf(stderr, "Loading CUDA failed.\n"); - } -# endif - // Need to initialize CUDA here so getting device - // with the maximum FPLOS works fine. - if (cuInit(0) == CUDA_SUCCESS) { - // This is to deal with cases like NVidia Optimus, - // when there might be CUDA library installed but - // NVidia card is not being active. - if (cutGetMaxGflopsDeviceId() < 0) { - cudaLoadSuccess = false; - } - } - else { - cudaLoadSuccess = false; - } - } - return cudaLoadSuccess; -#else - return false; -#endif -} - -CudaDeviceContext::CudaDeviceContext() - : _initialized(false) { -} - -CudaDeviceContext::~CudaDeviceContext() { - cudaDeviceReset(); -} - -bool CudaDeviceContext::Initialize() -{ - /* See if any cuda device is available. */ - int deviceCount = 0; - cudaGetDeviceCount(&deviceCount); - message("CUDA device count: %d\n", deviceCount); - if (deviceCount <= 0) { - return false; - } - cudaGLSetGLDevice(_GetCudaDeviceForCurrentGLContext()); - _initialized = true; - return true; -} - -#endif /* OPENSUBDIV_HAS_CUDA */ diff --git a/intern/opensubdiv/opensubdiv_device_context_cuda.h b/intern/opensubdiv/opensubdiv_device_context_cuda.h deleted file mode 100644 index eb30b76f507..00000000000 --- a/intern/opensubdiv/opensubdiv_device_context_cuda.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Adopted from OpenSubdiv with the following license: - * - * Copyright 2013 Pixar - * - * Licensed under the Apache License, Version 2.0 (the "Apache License") - * with the following modification; you may not use this file except in - * compliance with the Apache License and the following modification to it: - * Section 6. Trademarks. is deleted and replaced with: - * - * 6. Trademarks. This License does not grant permission to use the trade - * names, trademarks, service marks, or product names of the Licensor - * and its affiliates, except as required to comply with Section 4(c) of - * the License and to reproduce the content of the NOTICE file. - * - * You may obtain a copy of the Apache License at - * - * http: //www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Apache License with the above modification is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the Apache License for the specific - * language governing permissions and limitations under the Apache License. - * - */ - -#ifndef __OPENSUBDIV_DEV_CE_CONTEXT_CUDA_H__ -#define __OPENSUBDIV_DEV_CE_CONTEXT_CUDA_H__ - -struct ID3D11Device; - -class CudaDeviceContext { -public: - CudaDeviceContext(); - ~CudaDeviceContext(); - - static bool HAS_CUDA_VERSION_4_0(); - - /* Initialze cuda device from the current GL context. */ - bool Initialize(); - - /* Initialze cuda device from the ID3D11Device/ */ - bool Initialize(ID3D11Device *device); - - /* Returns true if the cuda device has already been initialized. */ - bool IsInitialized() const { - return _initialized; - } -private: - bool _initialized; -}; - -#endif /* __OPENSUBDIV_DEV_CE_CONTEXT_OPENCL_H__ */ diff --git a/intern/opensubdiv/opensubdiv_device_context_opencl.cc b/intern/opensubdiv/opensubdiv_device_context_opencl.cc deleted file mode 100644 index 4cacdc9e845..00000000000 --- a/intern/opensubdiv/opensubdiv_device_context_opencl.cc +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Adopted from OpenSubdiv with the following license: - * - * Copyright 2015 Pixar - * - * Licensed under the Apache License, Version 2.0 (the "Apache License") - * with the following modification; you may not use this file except in - * compliance with the Apache License and the following modification to it: - * Section 6. Trademarks. is deleted and replaced with: - * - * 6. Trademarks. This License does not grant permission to use the trade - * names, trademarks, service marks, or product names of the Licensor - * and its affiliates, except as required to comply with Section 4(c) of - * the License and to reproduce the content of the NOTICE file. - * - * You may obtain a copy of the Apache License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Apache License with the above modification is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the Apache License for the specific - * language governing permissions and limitations under the Apache License. - * - */ - -#ifdef OPENSUBDIV_HAS_OPENCL - -#ifdef _MSC_VER -# include "iso646.h" -#endif - -#include "opensubdiv_device_context_opencl.h" - -#if defined(_WIN32) -# include <windows.h> -#elif defined(__APPLE__) -# include <OpenGL/OpenGL.h> -#else -# include <GL/glx.h> -#endif - -#include <cstdio> -#include <cstring> -#include <string> - -#define message(...) // fprintf(stderr, __VA_ARGS__) -#define error(...) fprintf(stderr, __VA_ARGS__) - -/* Returns the first found platform. */ -static cl_platform_id findPlatform() { - cl_uint numPlatforms; - cl_int ciErrNum = clGetPlatformIDs(0, NULL, &numPlatforms); - if (ciErrNum != CL_SUCCESS) { - error("Error %d in clGetPlatformIDs call.\n", ciErrNum); - return NULL; - } - if (numPlatforms == 0) { - error("No OpenCL platform found.\n"); - return NULL; - } - cl_platform_id *clPlatformIDs = new cl_platform_id[numPlatforms]; - ciErrNum = clGetPlatformIDs(numPlatforms, clPlatformIDs, NULL); - char chBuffer[1024]; - for (cl_uint i = 0; i < numPlatforms; ++i) { - ciErrNum = clGetPlatformInfo(clPlatformIDs[i], CL_PLATFORM_NAME, - 1024, chBuffer,NULL); - if (ciErrNum == CL_SUCCESS) { - cl_platform_id platformId = clPlatformIDs[i]; - delete[] clPlatformIDs; - return platformId; - } - } - delete[] clPlatformIDs; - return NULL; -} - -/* Return. the device in clDevices which supports the extension. */ -static int findExtensionSupportedDevice(cl_device_id *clDevices, - int numDevices, - const char *extensionName) { - /* Find a device that supports sharing with GL/D3D11 - * (SLI / X-fire configurations) - */ - cl_int ciErrNum; - for (int i = 0; i < numDevices; ++i) { - /* Get extensions string size. */ - size_t extensionSize; - ciErrNum = clGetDeviceInfo(clDevices[i], - CL_DEVICE_EXTENSIONS, 0, NULL, - &extensionSize); - if (ciErrNum != CL_SUCCESS) { - error("Error %d in clGetDeviceInfo\n", ciErrNum); - return -1; - } - if (extensionSize > 0) { - /* Get extensions string. */ - char *extensions = new char[extensionSize]; - ciErrNum = clGetDeviceInfo(clDevices[i], CL_DEVICE_EXTENSIONS, - extensionSize, extensions, - &extensionSize); - if (ciErrNum != CL_SUCCESS) { - error("Error %d in clGetDeviceInfo\n", ciErrNum); - delete[] extensions; - continue; - } - std::string extString(extensions); - delete[] extensions; - /* Parse string. This is bit deficient since the extentions - * is space separated. - * - * The actual string would be "cl_khr_d3d11_sharing" - * or "cl_nv_d3d11_sharing" - */ - if (extString.find(extensionName) != std::string::npos) { - return i; - } - } - } - return -1; -} - -CLDeviceContext::CLDeviceContext() - : _clContext(NULL), - _clCommandQueue(NULL) { -} - -CLDeviceContext::~CLDeviceContext() { - if (_clCommandQueue) - clReleaseCommandQueue(_clCommandQueue); - if (_clContext) - clReleaseContext(_clContext); -} - -bool CLDeviceContext::HAS_CL_VERSION_1_1() -{ -#ifdef OPENSUBDIV_HAS_CLEW - static bool clewInitialized = false; - static bool clewLoadSuccess; - if (not clewInitialized) { - clewInitialized = true; - clewLoadSuccess = clewInit() == CLEW_SUCCESS; - if (!clewLoadSuccess) { - error("Loading OpenCL failed.\n"); - } - } - return clewLoadSuccess; -#endif - return true; -} - -bool CLDeviceContext::Initialize() -{ -#ifdef OPENSUBDIV_HAS_CLEW - if (!clGetPlatformIDs) { - error("Error clGetPlatformIDs function not bound.\n"); - return false; - } -#endif - cl_int ciErrNum; - cl_platform_id cpPlatform = findPlatform(); - -#if defined(_WIN32) - cl_context_properties props[] = { - CL_GL_CONTEXT_KHR, (cl_context_properties)wglGetCurrentContext(), - CL_WGL_HDC_KHR, (cl_context_properties)wglGetCurrentDC(), - CL_CONTEXT_PLATFORM, (cl_context_properties)cpPlatform, - 0 - }; -#elif defined(__APPLE__) - CGLContextObj kCGLContext = CGLGetCurrentContext(); - CGLShareGroupObj kCGLShareGroup = CGLGetShareGroup(kCGLContext); - cl_context_properties props[] = { - CL_CONTEXT_PROPERTY_USE_CGL_SHAREGROUP_APPLE, (cl_context_properties)kCGLShareGroup, - 0 - }; -#else - cl_context_properties props[] = { - CL_GL_CONTEXT_KHR, (cl_context_properties)glXGetCurrentContext(), - CL_GLX_DISPLAY_KHR, (cl_context_properties)glXGetCurrentDisplay(), - CL_CONTEXT_PLATFORM, (cl_context_properties)cpPlatform, - 0 - }; -#endif - -#if defined(__APPLE__) - _clContext = clCreateContext(props, 0, NULL, clLogMessagesToStdoutAPPLE, - NULL, &ciErrNum); - if (ciErrNum != CL_SUCCESS) { - error("Error %d in clCreateContext\n", ciErrNum); - return false; - } - - size_t devicesSize = 0; - clGetGLContextInfoAPPLE(_clContext, kCGLContext, - CL_CGL_DEVICES_FOR_SUPPORTED_VIRTUAL_SCREENS_APPLE, - 0, NULL, &devicesSize); - int numDevices = int(devicesSize / sizeof(cl_device_id)); - if (numDevices == 0) { - error("No sharable devices.\n"); - return false; - } - cl_device_id *clDevices = new cl_device_id[numDevices]; - clGetGLContextInfoAPPLE(_clContext, kCGLContext, - CL_CGL_DEVICES_FOR_SUPPORTED_VIRTUAL_SCREENS_APPLE, - numDevices * sizeof(cl_device_id), clDevices, NULL); - int clDeviceUsed = 0; - -#else // not __APPLE__ - /* Get the number of GPU devices available to the platform. */ - cl_uint numDevices = 0; - clGetDeviceIDs(cpPlatform, CL_DEVICE_TYPE_GPU, 0, NULL, &numDevices); - if (numDevices == 0) { - error("No CL GPU device found.\n"); - return false; - } - - /* Create the device list. */ - cl_device_id *clDevices = new cl_device_id[numDevices]; - clGetDeviceIDs(cpPlatform, CL_DEVICE_TYPE_GPU, numDevices, clDevices, NULL); - - const char *extension = "cl_khr_gl_sharing"; - int clDeviceUsed = findExtensionSupportedDevice(clDevices, numDevices, - extension); - - if (clDeviceUsed < 0) { - error("No device found that supports CL/GL context sharing\n"); - delete[] clDevices; - return false; - } - - _clContext = clCreateContext(props, 1, &clDevices[clDeviceUsed], - NULL, NULL, &ciErrNum); -#endif // not __APPLE__ - if (ciErrNum != CL_SUCCESS) { - error("Error %d in clCreateContext\n", ciErrNum); - delete[] clDevices; - return false; - } - _clCommandQueue = clCreateCommandQueue(_clContext, clDevices[clDeviceUsed], - 0, &ciErrNum); - delete[] clDevices; - if (ciErrNum != CL_SUCCESS) { - error("Error %d in clCreateCommandQueue\n", ciErrNum); - return false; - } - return true; -} - -#endif /* OPENSUBDIV_HAS_OPENCL */ diff --git a/intern/opensubdiv/opensubdiv_device_context_opencl.h b/intern/opensubdiv/opensubdiv_device_context_opencl.h deleted file mode 100644 index a640dce1f07..00000000000 --- a/intern/opensubdiv/opensubdiv_device_context_opencl.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Adopted from OpenSubdiv with the following license: - * - * Copyright 2015 Pixar - * - * Licensed under the Apache License, Version 2.0 (the "Apache License") - * with the following modification; you may not use this file except in - * compliance with the Apache License and the following modification to it: - * Section 6. Trademarks. is deleted and replaced with: - * - * 6. Trademarks. This License does not grant permission to use the trade - * names, trademarks, service marks, or product names of the Licensor - * and its affiliates, except as required to comply with Section 4(c) of - * the License and to reproduce the content of the NOTICE file. - * - * You may obtain a copy of the Apache License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Apache License with the above modification is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the Apache License for the specific - * language governing permissions and limitations under the Apache License. - * - */ - -#ifndef __OPENSUBDIV_DEV_CE_CONTEXT_OPENCL_H__ -#define __OPENSUBDIV_DEV_CE_CONTEXT_OPENCL_H__ - -#include <opensubdiv/osd/opencl.h> - -class CLDeviceContext { -public: - CLDeviceContext(); - ~CLDeviceContext(); - - static bool HAS_CL_VERSION_1_1 (); - - bool Initialize(); - - bool IsInitialized() const { - return (_clContext != NULL); - } - - cl_context GetContext() const { - return _clContext; - } - cl_command_queue GetCommandQueue() const { - return _clCommandQueue; - } - -protected: - cl_context _clContext; - cl_command_queue _clCommandQueue; -}; - -#endif /* __OPENSUBDIV_DEV_CE_CONTEXT_OPENCL_H__ */ diff --git a/intern/opensubdiv/opensubdiv_evaluator_capi.cc b/intern/opensubdiv/opensubdiv_evaluator_capi.cc deleted file mode 100644 index fb5313b8501..00000000000 --- a/intern/opensubdiv/opensubdiv_evaluator_capi.cc +++ /dev/null @@ -1,516 +0,0 @@ -/* - * ***** 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) 2015 Blender Foundation. - * All rights reserved. - * - * Contributor(s): Sergey Sharybin. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include "opensubdiv_capi.h" - -#include <cstdio> -#include <vector> - -#ifdef _MSC_VER -# include "iso646.h" -#endif - -#include <opensubdiv/far/patchMap.h> -#include <opensubdiv/far/patchTable.h> -#include <opensubdiv/far/patchTableFactory.h> -#include <opensubdiv/osd/cpuEvaluator.h> -#include <opensubdiv/osd/cpuPatchTable.h> -#include <opensubdiv/osd/cpuVertexBuffer.h> -#include <opensubdiv/osd/mesh.h> -#include <opensubdiv/osd/types.h> - -#include "opensubdiv_intern.h" -#include "opensubdiv_topology_refiner.h" - -#include "MEM_guardedalloc.h" - -using OpenSubdiv::Osd::BufferDescriptor; -using OpenSubdiv::Osd::PatchCoord; -using OpenSubdiv::Far::PatchMap; -using OpenSubdiv::Far::PatchTable; -using OpenSubdiv::Far::PatchTableFactory; -using OpenSubdiv::Far::StencilTable; -using OpenSubdiv::Far::StencilTableFactory; -using OpenSubdiv::Far::TopologyRefiner; - -namespace { - -/* Helper class to wrap numerous of patch coords into a buffer. - * Used to pass coordinates to the CPU evaluator. Other evaluators - * are not supported. - */ -class PatchCoordBuffer : public std::vector<PatchCoord> { -public: - static PatchCoordBuffer *Create(int size) - { - PatchCoordBuffer *buffer = new PatchCoordBuffer(); - buffer->resize(size); - return buffer; - } - PatchCoord *BindCpuBuffer() { - return (PatchCoord*)&(*this)[0]; - } - int GetNumVertices() { - return size(); - } - void UpdateData(const PatchCoord *patch_coords, - int num_patch_coords) - { - memcpy(&(*this)[0], - (void*)patch_coords, - num_patch_coords * sizeof(PatchCoord)); - } -}; - -/* Helper class to wrap single of patch coord into a buffer. - * Used to pass coordinates to the CPU evaluator. Other evaluators - * are not supported. - */ -class SinglePatchCoordBuffer { -public: - SinglePatchCoordBuffer() { - } - SinglePatchCoordBuffer(const PatchCoord& patch_coord) - : patch_coord_(patch_coord){ - } - static SinglePatchCoordBuffer *Create() - { - SinglePatchCoordBuffer *buffer = new SinglePatchCoordBuffer(); - return buffer; - } - PatchCoord *BindCpuBuffer() { - return (PatchCoord*)&patch_coord_; - } - int GetNumVertices() { - return 1; - } - void UpdateData(const PatchCoord& patch_coord) - { - patch_coord_ = patch_coord; - } -protected: - PatchCoord patch_coord_; -}; - -/* Helper class which is aimed to be used in cases when buffer - * 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 evaluator. - */ -template <int element_size, int num_verts> -class StackAllocatedBuffer { -public: - static PatchCoordBuffer *Create(int /*size*/) - { - StackAllocatedBuffer<element_size, num_verts> *buffer = - new StackAllocatedBuffer<element_size, num_verts>(); - return buffer; - } - float *BindCpuBuffer() { - return &data_[0]; - } - int GetNumVertices() { - return num_verts; - } - /* TODO(sergey): Support UpdateData(). */ -protected: - float data_[element_size * num_verts]; -}; - -/* Volatile evaluator which can be used from threads. - * - * TODO(sergey): Make it possible to evaluate coordinates in chunks. - */ -template<typename SRC_VERTEX_BUFFER, - typename EVAL_VERTEX_BUFFER, - typename STENCIL_TABLE, - typename PATCH_TABLE, - typename EVALUATOR, - typename DEVICE_CONTEXT = void> -class VolatileEvalOutput { -public: - typedef OpenSubdiv::Osd::EvaluatorCacheT<EVALUATOR> EvaluatorCache; - - VolatileEvalOutput(const StencilTable *vertex_stencils, - const StencilTable *varying_stencils, - int num_coarse_verts, - int num_total_verts, - const PatchTable *patch_table, - EvaluatorCache *evaluator_cache = NULL, - DEVICE_CONTEXT *device_context = NULL) - : src_desc_( /*offset*/ 0, /*length*/ 3, /*stride*/ 3), - src_varying_desc_(/*offset*/ 0, /*length*/ 3, /*stride*/ 3), - num_coarse_verts_(num_coarse_verts), - evaluator_cache_ (evaluator_cache), - device_context_(device_context) - { - using OpenSubdiv::Osd::convertToCompatibleStencilTable; - src_data_ = SRC_VERTEX_BUFFER::Create(3, num_total_verts, device_context_); - src_varying_data_ = SRC_VERTEX_BUFFER::Create(3, num_total_verts, device_context_); - patch_table_ = PATCH_TABLE::Create(patch_table, device_context_); - patch_coords_ = NULL; - vertex_stencils_ = convertToCompatibleStencilTable<STENCIL_TABLE>(vertex_stencils, - device_context_); - varying_stencils_ = convertToCompatibleStencilTable<STENCIL_TABLE>(varying_stencils, - device_context_); - } - - ~VolatileEvalOutput() - { - delete src_data_; - delete src_varying_data_; - delete patch_table_; - delete vertex_stencils_; - delete varying_stencils_; - } - - void UpdateData(const float *src, int start_vertex, int num_vertices) - { - src_data_->UpdateData(src, start_vertex, num_vertices, device_context_); - } - - void UpdateVaryingData(const float *src, int start_vertex, int num_vertices) - { - src_varying_data_->UpdateData(src, - start_vertex, - num_vertices, - device_context_); - } - - void Refine() - { - BufferDescriptor dst_desc = src_desc_; - dst_desc.offset += num_coarse_verts_ * src_desc_.stride; - - const EVALUATOR *eval_instance = - OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(evaluator_cache_, - src_desc_, - dst_desc, - device_context_); - - EVALUATOR::EvalStencils(src_data_, src_desc_, - src_data_, dst_desc, - vertex_stencils_, - eval_instance, - device_context_); - - dst_desc = src_varying_desc_; - dst_desc.offset += num_coarse_verts_ * src_varying_desc_.stride; - eval_instance = - OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(evaluator_cache_, - src_varying_desc_, - dst_desc, - device_context_); - - EVALUATOR::EvalStencils(src_varying_data_, src_varying_desc_, - src_varying_data_, dst_desc, - varying_stencils_, - eval_instance, - device_context_); - } - - void EvalPatchCoord(PatchCoord& patch_coord, float P[3]) - { - StackAllocatedBuffer<6, 1> vertex_data; - BufferDescriptor vertex_desc(0, 3, 6); - SinglePatchCoordBuffer patch_coord_buffer(patch_coord); - const EVALUATOR *eval_instance = - OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(evaluator_cache_, - src_desc_, - vertex_desc, - device_context_); - EVALUATOR::EvalPatches(src_data_, src_desc_, - &vertex_data, vertex_desc, - patch_coord_buffer.GetNumVertices(), - &patch_coord_buffer, - patch_table_, eval_instance, device_context_); - float *refined_verts = vertex_data.BindCpuBuffer(); - memcpy(P, refined_verts, sizeof(float) * 3); - } - - void EvalPatchesWithDerivatives(PatchCoord& patch_coord, - float P[3], - float dPdu[3], - float dPdv[3]) - { - StackAllocatedBuffer<6, 1> vertex_data, derivatives; - BufferDescriptor vertex_desc(0, 3, 6), - du_desc(0, 3, 6), - dv_desc(3, 3, 6); - SinglePatchCoordBuffer patch_coord_buffer(patch_coord); - const EVALUATOR *eval_instance = - OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(evaluator_cache_, - src_desc_, - vertex_desc, - du_desc, - dv_desc, - device_context_); - EVALUATOR::EvalPatches(src_data_, src_desc_, - &vertex_data, vertex_desc, - &derivatives, du_desc, - &derivatives, dv_desc, - patch_coord_buffer.GetNumVertices(), - &patch_coord_buffer, - patch_table_, eval_instance, device_context_); - float *refined_verts = vertex_data.BindCpuBuffer(); - memcpy(P, refined_verts, sizeof(float) * 3); - if (dPdu != NULL || dPdv != NULL) { - float *refined_drivatives = derivatives.BindCpuBuffer(); - if (dPdu) { - memcpy(dPdu, refined_drivatives, sizeof(float) * 3); - } - if (dPdv) { - memcpy(dPdv, refined_drivatives + 3, sizeof(float) * 3); - } - } - } - - void EvalPatchVarying(PatchCoord& patch_coord, - float varying[3]) { - StackAllocatedBuffer<3, 1> varying_data; - BufferDescriptor varying_desc(0, 3, 3); - SinglePatchCoordBuffer patch_coord_buffer(patch_coord); - EVALUATOR const *eval_instance = - OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(evaluator_cache_, - src_varying_desc_, - varying_desc, - device_context_); - - EVALUATOR::EvalPatches(src_varying_data_, src_varying_desc_, - &varying_data, varying_desc, - patch_coord_buffer.GetNumVertices(), - &patch_coord_buffer, - patch_table_, eval_instance, device_context_); - float *refined_varying = varying_data.BindCpuBuffer(); - memcpy(varying, refined_varying, sizeof(float) * 3); - } -private: - SRC_VERTEX_BUFFER *src_data_; - SRC_VERTEX_BUFFER *src_varying_data_; - PatchCoordBuffer *patch_coords_; - PATCH_TABLE *patch_table_; - BufferDescriptor src_desc_; - BufferDescriptor src_varying_desc_; - int num_coarse_verts_; - - const STENCIL_TABLE *vertex_stencils_; - const STENCIL_TABLE *varying_stencils_; - - EvaluatorCache *evaluator_cache_; - DEVICE_CONTEXT *device_context_; -}; - -} /* namespace */ - -typedef VolatileEvalOutput<OpenSubdiv::Osd::CpuVertexBuffer, - OpenSubdiv::Osd::CpuVertexBuffer, - OpenSubdiv::Far::StencilTable, - OpenSubdiv::Osd::CpuPatchTable, - OpenSubdiv::Osd::CpuEvaluator> CpuEvalOutput; - -typedef struct OpenSubdiv_EvaluatorDescr { - CpuEvalOutput *eval_output; - const PatchMap *patch_map; - const PatchTable *patch_table; -} OpenSubdiv_EvaluatorDescr; - -OpenSubdiv_EvaluatorDescr *openSubdiv_createEvaluatorDescr( - OpenSubdiv_TopologyRefinerDescr *topology_refiner, - int subsurf_level) -{ - /* TODO(sergey): Look into re-using refiner with GLMesh. */ - TopologyRefiner *refiner = topology_refiner->osd_refiner; - if(refiner == NULL) { - /* Happens on bad topology. */ - return NULL; - } - /* 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 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); - /* Append local points stencils. */ - 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); - delete vertex_stencils; - vertex_stencils = table; - } - 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); - delete varying_stencils; - varying_stencils = table; - } - - /* 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 we've got duplicated stencils arrays. */ - delete varying_stencils; - delete vertex_stencils; - return evaluator_descr; -} - -void openSubdiv_deleteEvaluatorDescr(OpenSubdiv_EvaluatorDescr *evaluator_descr) -{ - delete evaluator_descr->eval_output; - delete evaluator_descr->patch_map; - delete evaluator_descr->patch_table; - OBJECT_GUARDED_DELETE(evaluator_descr, OpenSubdiv_EvaluatorDescr); -} - -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_vertex_index, - num_vertices); -} - -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_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(); -} - -void openSubdiv_evaluateLimit(OpenSubdiv_EvaluatorDescr *evaluator_descr, - int osd_face_index, - float face_u, float face_v, - float P[3], - float dPdu[3], - float dPdv[3]) -{ - assert((face_u >= 0.0f) && (face_u <= 1.0f) && (face_v >= 0.0f) && (face_v <= 1.0f)); - const PatchTable::PatchHandle *handle = - evaluator_descr->patch_map->FindPatch(osd_face_index, face_u, face_v); - PatchCoord patch_coord(*handle, face_u, face_v); - if (dPdu != NULL || dPdv != NULL) { - evaluator_descr->eval_output->EvalPatchesWithDerivatives(patch_coord, - P, - dPdu, - dPdv); - } - else { - evaluator_descr->eval_output->EvalPatchCoord(patch_coord, P); - } -} - -void openSubdiv_evaluateVarying(OpenSubdiv_EvaluatorDescr *evaluator_descr, - int osd_face_index, - float face_u, float face_v, - float varying[3]) -{ - assert((face_u >= 0.0f) && (face_u <= 1.0f) && (face_v >= 0.0f) && (face_v <= 1.0f)); - const PatchTable::PatchHandle *handle = - evaluator_descr->patch_map->FindPatch(osd_face_index, face_u, face_v); - PatchCoord patch_coord(*handle, face_u, face_v); - evaluator_descr->eval_output->EvalPatchVarying(patch_coord, varying); -} diff --git a/intern/opensubdiv/opensubdiv_evaluator_capi.h b/intern/opensubdiv/opensubdiv_evaluator_capi.h new file mode 100644 index 00000000000..07a55cfd349 --- /dev/null +++ b/intern/opensubdiv/opensubdiv_evaluator_capi.h @@ -0,0 +1,117 @@ +// Copyright 2013 Blender Foundation. All rights reserved. +// +// 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. +// +// Author: Sergey Sharybin + +#ifndef OPENSUBDIV_EVALUATOR_CAPI_H_ +#define OPENSUBDIV_EVALUATOR_CAPI_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +struct OpenSubdiv_EvaluatorInternal; +struct OpenSubdiv_TopologyRefiner; + +typedef struct OpenSubdiv_Evaluator { + // Set coarse positions from a continuous array of coordinates. + void (*setCoarsePositions)(struct OpenSubdiv_Evaluator* evaluator, + const float* positions, + const int start_vertex_index, + const int num_vertices); + // Set varying data from a continuous array of data. + void (*setVaryingData)(struct OpenSubdiv_Evaluator* evaluator, + const float* varying_data, + const int start_vertex_index, const int num_vertices); + // Set face varying data from a continuous array of data. + // + // TODO(sergey): Find a better name for vertex here. It is not the vertex of + // geometry, but a vertex of UV map. + void (*setFaceVaryingData)(struct OpenSubdiv_Evaluator* evaluator, + const float* face_varying_data, + const int start_vertex_index, + const int num_vertices); + + // Set coarse vertex position from a continuous memory buffer where + // first coordinate starts at offset of `start_offset` and there is `stride` + // bytes between adjacent vertex coordinates. + void (*setCoarsePositionsFromBuffer)(struct OpenSubdiv_Evaluator* evaluator, + const void* buffer, + const int start_offset, + const int stride, + const int start_vertex_index, + const int num_vertices); + // Set varying data from a continuous memory buffer where + // first coordinate starts at offset of `start_offset` and there is `stride` + // bytes between adjacent vertex coordinates. + void (*setVaryingDataFromBuffer)(struct OpenSubdiv_Evaluator* evaluator, + const void* buffer, + const int start_offset, + const int stride, + const int start_vertex_index, + const int num_vertices); + // Set face varying data from a continuous memory buffer where + // first coordinate starts at offset of `start_offset` and there is `stride` + // bytes between adjacent vertex coordinates. + // + // TODO(sergey): Find a better name for vertex here. It is not the vertex of + // geometry, but a vertex of UV map. + void (*setFaceVaryingDataFromBuffer)(struct OpenSubdiv_Evaluator* evaluator, + const void* buffer, + const int start_offset, + const int stride, + const int start_vertex_index, + const int num_vertices); + + // Refine after coarse positions update. + void (*refine)(struct OpenSubdiv_Evaluator* evaluator); + + // Evaluate given ptex face at given bilinear coordinate. + // If derivatives are NULL, they will not be evaluated. + void (*evaluateLimit)(struct OpenSubdiv_Evaluator* evaluator, + const int ptex_face_index, + float face_u, float face_v, + float P[3], float dPdu[3], float dPdv[3]); + + // Evaluate varying data at a given bilinear coordinate of given ptex face. + void (*evaluateVarying)(struct OpenSubdiv_Evaluator* evaluator, + const int ptex_face_index, + float face_u, float face_v, + float varying[3]); + + // Evaluate face-varying data at a given bilinear coordinate of given + // ptex face. + void (*evaluateFaceVarying)(struct OpenSubdiv_Evaluator* evaluator, + const int ptex_face_index, + float face_u, float face_v, + float face_varying[2]); + + // Internal storage for the use in this module only. + // + // This is where actual OpenSubdiv's evaluator is living. + struct OpenSubdiv_EvaluatorInternal* internal; +} OpenSubdiv_Evaluator; + +OpenSubdiv_Evaluator* openSubdiv_createEvaluatorFromTopologyRefiner( + struct OpenSubdiv_TopologyRefiner* topology_refiner); + +void openSubdiv_deleteEvaluator(OpenSubdiv_Evaluator* evaluator); + +#ifdef __cplusplus +} +#endif + +#endif // OPENSUBDIV_EVALUATOR_CAPI_H_ diff --git a/intern/opensubdiv/opensubdiv_gl_mesh.h b/intern/opensubdiv/opensubdiv_gl_mesh.h deleted file mode 100644 index 1e99fc5bce4..00000000000 --- a/intern/opensubdiv/opensubdiv_gl_mesh.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * ***** 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__ */ diff --git a/intern/opensubdiv/opensubdiv_gl_mesh_capi.h b/intern/opensubdiv/opensubdiv_gl_mesh_capi.h new file mode 100644 index 00000000000..971f6b9dcd3 --- /dev/null +++ b/intern/opensubdiv/opensubdiv_gl_mesh_capi.h @@ -0,0 +1,92 @@ +// Copyright 2013 Blender Foundation. All rights reserved. +// +// 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. +// +// Author: Sergey Sharybin + +#ifndef OPENSUBDIV_CAPI_GL_MESH_CAPI_H_ +#define OPENSUBDIV_CAPI_GL_MESH_CAPI_H_ + +#include <stdint.h> // for bool + +#include "opensubdiv_capi_type.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct OpenSubdiv_GLMeshInternal; + +// Mesh which is displayable in OpenGL context. +typedef struct OpenSubdiv_GLMesh { + ////////////////////////////////////////////////////////////////////////////// + // Subdivision/topology part. + + // Returns the GL index buffer containing the patch control vertices. + unsigned int (*getPatchIndexBuffer)(struct OpenSubdiv_GLMesh* gl_mesh); + + // Bind GL buffer which contains vertices (VBO). + // TODO(sergey): Is this a coarse vertices? + void (*bindVertexBuffer)(struct OpenSubdiv_GLMesh* gl_mesh); + + // Set coarse positions from a continuous array of coordinates. + void (*setCoarsePositions)(struct OpenSubdiv_GLMesh* gl_mesh, + const float* positions, + const int start_vertex, + const int num_vertices); + // TODO(sergey): setCoarsePositionsFromBuffer(). + + // Refine after coarse positions update. + void (*refine)(struct OpenSubdiv_GLMesh* gl_mesh); + + // Synchronize after coarse positions update and refine. + void (*synchronize)(struct OpenSubdiv_GLMesh* gl_mesh); + + ////////////////////////////////////////////////////////////////////////////// + // Drawing part. + + // Prepare mesh for display. + void (*prepareDraw)(struct OpenSubdiv_GLMesh* gl_mesh, + const bool use_osd_glsl, + const int active_uv_index); + + // Draw given range of patches. + // + // If fill_quads is false, then patches are drawn in wireframe. + void (*drawPatches)(struct OpenSubdiv_GLMesh *gl_mesh, + const bool fill_quads, + const int start_patch, const int num_patches); + + // Internal storage for the use in this module only. + // + // Tease: This contains an actual OpenSubdiv's Mesh object. + struct OpenSubdiv_GLMeshInternal* internal; +} OpenSubdiv_GLMesh; + +OpenSubdiv_GLMesh* openSubdiv_createOsdGLMeshFromTopologyRefiner( + struct OpenSubdiv_TopologyRefiner* topology_refiner, + eOpenSubdivEvaluator evaluator_type); + +void openSubdiv_deleteOsdGLMesh(OpenSubdiv_GLMesh *gl_mesh); + +// Global resources needed for GL mesh drawing. +bool openSubdiv_initGLMeshDrawingResources(void); +void openSubdiv_deinitGLMeshDrawingResources(void); + +#ifdef __cplusplus +} +#endif + +#endif // OPENSUBDIV_CAPI_GL_MESH_CAPI_H_ diff --git a/intern/opensubdiv/opensubdiv_intern.h b/intern/opensubdiv/opensubdiv_intern.h deleted file mode 100644 index ccb32f9d0ac..00000000000 --- a/intern/opensubdiv/opensubdiv_intern.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * ***** 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) 2015 Blender Foundation. - * All rights reserved. - * - * Contributor(s): Sergey Sharybin. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifndef __OPENSUBDIV_INTERN_H__ -#define __OPENSUBDIV_INTERN_H__ - -/* Perform full topology validation when exporting it to OpenSubdiv. */ -#ifdef NDEBUG -# undef OPENSUBDIV_VALIDATE_TOPOLOGY -#else -/* TODO(sergey): Always disabled for now, the check doesn't handle - * multiple non-manifolds from the OpenSubdiv side currently. - */ -# undef OPENSUBDIV_VALIDATE_TOPOLOGY -#endif - -/* Currently OpenSubdiv expects topology to be oriented, - * but sometimes it's handy to disable orientation code - * to check whether it causes some weird issues by using - * pre-oriented model. - */ -#define OPENSUBDIV_ORIENT_TOPOLOGY - -#endif /* __OPENSUBDIV_INTERN_H__ */ diff --git a/intern/opensubdiv/opensubdiv_topology_refiner_capi.h b/intern/opensubdiv/opensubdiv_topology_refiner_capi.h new file mode 100644 index 00000000000..103ccd2c1f9 --- /dev/null +++ b/intern/opensubdiv/opensubdiv_topology_refiner_capi.h @@ -0,0 +1,110 @@ +// Copyright 2018 Blender Foundation. All rights reserved. +// +// 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. +// +// Author: Sergey Sharybin + +#ifndef OPENSUBDIV_TOPOLOGY_REFINER_CAPI_H_ +#define OPENSUBDIV_TOPOLOGY_REFINER_CAPI_H_ + +#include <stdint.h> // for bool + +#ifdef __cplusplus +extern "C" { +#endif + +struct OpenSubdiv_Converter; +struct OpenSubdiv_TopologyRefinerInternal; + +// Those settings don't really belong to OpenSubdiv's topology refiner, but +// we are keeping track of them on our side of topology refiner. This is to +// make it possible to ensure we are not trying to abuse same OpenSubdiv's +// topology refiner with different subdivision levels or with different +// adaptive settings. +typedef struct OpenSubdiv_TopologyRefinerSettings { + bool is_adaptive; + int level; +} OpenSubdiv_TopologyRefinerSettings; + +typedef struct OpenSubdiv_TopologyRefiner { + // Query subdivision level the refiner is created for. + int (*getSubdivisionLevel)( + const struct OpenSubdiv_TopologyRefiner* topology_refiner); + bool (*getIsAdaptive)( + const struct OpenSubdiv_TopologyRefiner* topology_refiner); + + // Query basic topology information from base level. + int (*getNumVertices)( + const struct OpenSubdiv_TopologyRefiner* topology_refiner); + int (*getNumEdges)( + const struct OpenSubdiv_TopologyRefiner* topology_refiner); + int (*getNumFaces)( + const struct OpenSubdiv_TopologyRefiner* topology_refiner); + int (*getNumFaceVertices)( + const struct OpenSubdiv_TopologyRefiner* topology_refiner, + const int face_index); + + // Ptex face corresponds to OpenSubdiv's internal "patch" and to Blender's + // subdivision grid. The rule commes as: + // - Triangle face consist of 3 ptex faces, ordered in the order of + // face-vertices. + // - Quad face consists of a single ptex face. + // - N-gons (similar to triangle) consists of N ptex faces, ordered same + // way as for triangle. + int (*getNumFacePtexFaces)( + const struct OpenSubdiv_TopologyRefiner* topology_refiner, + const int face_index); + int (*getNumPtexFaces)( + const struct OpenSubdiv_TopologyRefiner* topology_refiner); + + // Initialize a per-base-face offset measured in ptex face indices. + // + // Basically, face_ptex_offset[base_face_index] is a total number of ptex + // faces created for bases faces [0 .. base_face_index - 1]. + // + // The array must contain at least total number of ptex faces elements. + void (*fillFacePtexIndexOffset)( + const struct OpenSubdiv_TopologyRefiner* topology_refiner, + int* face_ptex_index_offset); + + // Internal storage for the use in this module only. + // + // Tease: Contains actual OpenSubdiv's refiner and (optionally) some other + // data and state needed for an internbal use. + struct OpenSubdiv_TopologyRefinerInternal* internal; +} OpenSubdiv_TopologyRefiner; + +OpenSubdiv_TopologyRefiner* openSubdiv_createTopologyRefinerFromConverter( + struct OpenSubdiv_Converter* converter, + const OpenSubdiv_TopologyRefinerSettings* settings); + +void openSubdiv_deleteTopologyRefiner( + OpenSubdiv_TopologyRefiner* topology_refiner); + +// Compare given topology refiner with converter. Returns truth if topology +// refiner matches given converter, false otherwise. +// +// This allows users to construct converter (which is supposed to be cheap) +// and compare with existing refiner before going into more computationally +// complicated parts of subdivision process. +bool openSubdiv_topologyRefinerCompareWithConverter( + const OpenSubdiv_TopologyRefiner* topology_refiner, + const OpenSubdiv_Converter* converter); + +#ifdef __cplusplus +} +#endif + +#endif // OPENSUBDIV_TOPOLOGY_REFINER_CAPI_H_ diff --git a/intern/opensubdiv/opensubdiv_utils_capi.cc b/intern/opensubdiv/opensubdiv_utils_capi.cc deleted file mode 100644 index 72e3751e6b3..00000000000 --- a/intern/opensubdiv/opensubdiv_utils_capi.cc +++ /dev/null @@ -1,88 +0,0 @@ -/* - * ***** 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) 2013 Blender Foundation. - * All rights reserved. - * - * Contributor(s): Sergey Sharybin. - * Brecht van Lommel - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include "opensubdiv_capi.h" - -#include <cstring> -#include <GL/glew.h> - -#ifdef _MSC_VER -# include "iso646.h" -#endif - -#ifdef OPENSUBDIV_HAS_OPENCL -# include "opensubdiv_device_context_opencl.h" -#endif /* OPENSUBDIV_HAS_OPENCL */ - -#ifdef OPENSUBDIV_HAS_CUDA -# include "opensubdiv_device_context_cuda.h" -#endif /* OPENSUBDIV_HAS_CUDA */ - -int openSubdiv_getAvailableEvaluators(void) -{ - int flags = OPENSUBDIV_EVALUATOR_CPU; - -#ifdef OPENSUBDIV_HAS_OPENMP - flags |= OPENSUBDIV_EVALUATOR_OPENMP; -#endif /* OPENSUBDIV_HAS_OPENMP */ - -#ifdef OPENSUBDIV_HAS_OPENCL - if (CLDeviceContext::HAS_CL_VERSION_1_1()) { - flags |= OPENSUBDIV_EVALUATOR_OPENCL; - } -#endif /* OPENSUBDIV_HAS_OPENCL */ - -#ifdef OPENSUBDIV_HAS_CUDA - if (CudaDeviceContext::HAS_CUDA_VERSION_4_0()) { - flags |= OPENSUBDIV_EVALUATOR_CUDA; - } -#endif /* OPENSUBDIV_HAS_OPENCL */ - -#ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK - if (GLEW_VERSION_4_1) { - flags |= OPENSUBDIV_EVALUATOR_GLSL_TRANSFORM_FEEDBACK; - } -#endif /* OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK */ - -#ifdef OPENSUBDIV_HAS_GLSL_COMPUTE - if (GLEW_VERSION_4_3 || GLEW_ARB_compute_shader) { - flags |= OPENSUBDIV_EVALUATOR_GLSL_COMPUTE; - } -#endif /* OPENSUBDIV_HAS_GLSL_COMPUTE */ - - return flags; -} - -void openSubdiv_init(void) -{ - /* Ensure all OpenGL strings are cached. */ - (void)openSubdiv_getAvailableEvaluators(); -} - -void openSubdiv_cleanup(void) -{ - openSubdiv_osdGLDisplayDeinit(); -} diff --git a/intern/opensubdiv/gpu_shader_opensubdiv_fragment.glsl b/intern/opensubdiv/shader/gpu_shader_opensubdiv_fragment.glsl index 1e36d549360..1e36d549360 100644 --- a/intern/opensubdiv/gpu_shader_opensubdiv_fragment.glsl +++ b/intern/opensubdiv/shader/gpu_shader_opensubdiv_fragment.glsl diff --git a/intern/opensubdiv/gpu_shader_opensubdiv_geometry.glsl b/intern/opensubdiv/shader/gpu_shader_opensubdiv_geometry.glsl index b16a5cca733..b16a5cca733 100644 --- a/intern/opensubdiv/gpu_shader_opensubdiv_geometry.glsl +++ b/intern/opensubdiv/shader/gpu_shader_opensubdiv_geometry.glsl diff --git a/intern/opensubdiv/gpu_shader_opensubdiv_vertex.glsl b/intern/opensubdiv/shader/gpu_shader_opensubdiv_vertex.glsl index 6fcf5ad20cd..6fcf5ad20cd 100644 --- a/intern/opensubdiv/gpu_shader_opensubdiv_vertex.glsl +++ b/intern/opensubdiv/shader/gpu_shader_opensubdiv_vertex.glsl diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c index 81b1afa3621..dd5a87a445d 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf.c +++ b/source/blender/blenkernel/intern/CCGSubSurf.c @@ -40,6 +40,8 @@ #ifdef WITH_OPENSUBDIV # include "opensubdiv_capi.h" # include "opensubdiv_converter_capi.h" +# include "opensubdiv_evaluator_capi.h" +# include "opensubdiv_topology_refiner_capi.h" #endif #include "GPU_glew.h" @@ -329,7 +331,7 @@ void ccgSubSurf_free(CCGSubSurf *ss) CCGAllocatorHDL allocator = ss->allocator; #ifdef WITH_OPENSUBDIV if (ss->osd_evaluator != NULL) { - openSubdiv_deleteEvaluatorDescr(ss->osd_evaluator); + openSubdiv_deleteEvaluator(ss->osd_evaluator); } if (ss->osd_mesh != NULL) { ccgSubSurf__delete_osdGLMesh(ss->osd_mesh); @@ -341,7 +343,7 @@ void ccgSubSurf_free(CCGSubSurf *ss) MEM_freeN(ss->osd_coarse_coords); } if (ss->osd_topology_refiner != NULL) { - openSubdiv_deleteTopologyRefinerDescr(ss->osd_topology_refiner); + openSubdiv_deleteTopologyRefiner(ss->osd_topology_refiner); } #endif diff --git a/source/blender/blenkernel/intern/CCGSubSurf_intern.h b/source/blender/blenkernel/intern/CCGSubSurf_intern.h index 9df1c9021ef..29e327d8973 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf_intern.h +++ b/source/blender/blenkernel/intern/CCGSubSurf_intern.h @@ -236,7 +236,7 @@ struct CCGSubSurf { * Refiner is created from the modifier stack and used later from the main * thread to construct GL mesh to avoid threaded access to GL. */ - struct OpenSubdiv_TopologyRefinerDescr *osd_topology_refiner; /* Only used at synchronization stage. */ + struct OpenSubdiv_TopologyRefiner *osd_topology_refiner; /* Only used at synchronization stage. */ /* Denotes whether osd_mesh is invalid now due to topology changes and needs * to be reconstructed. * @@ -249,7 +249,7 @@ struct CCGSubSurf { /* ** CPU backend. ** */ /* Limit evaluator, used to evaluate CCG. */ - struct OpenSubdiv_EvaluatorDescr *osd_evaluator; + struct OpenSubdiv_Evaluator *osd_evaluator; /* Next PTex face index, used while CCG synchronization * to fill in PTex index of CCGFace. */ diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c index 46204898709..98a17ad8009 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c +++ b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c @@ -42,6 +42,9 @@ #include "opensubdiv_capi.h" #include "opensubdiv_converter_capi.h" +#include "opensubdiv_evaluator_capi.h" +#include "opensubdiv_gl_mesh_capi.h" +#include "opensubdiv_topology_refiner_capi.h" #include "GPU_glew.h" #include "GPU_extensions.h" @@ -131,7 +134,6 @@ static bool compare_ccg_derivedmesh_topology(CCGSubSurf *ss, DerivedMesh *dm) static bool compare_osd_derivedmesh_topology(CCGSubSurf *ss, DerivedMesh *dm) { - const OpenSubdiv_TopologyRefinerDescr *topology_refiner; OpenSubdiv_Converter converter; bool result; if (ss->osd_mesh == NULL && ss->osd_topology_refiner == NULL) { @@ -140,15 +142,10 @@ static bool compare_osd_derivedmesh_topology(CCGSubSurf *ss, DerivedMesh *dm) /* TODO(sergey): De-duplicate with topology counter at the bottom of * the file. */ - if (ss->osd_topology_refiner != NULL) { - topology_refiner = ss->osd_topology_refiner; - } - else { - topology_refiner = openSubdiv_getGLMeshTopologyRefiner(ss->osd_mesh); - } ccgSubSurf_converter_setup_from_derivedmesh(ss, dm, &converter); - result = openSubdiv_topologyRefnerCompareConverter(topology_refiner, - &converter); + result = openSubdiv_topologyRefinerCompareWithConverter( + ss->osd_topology_refiner, + &converter); ccgSubSurf_converter_free(&converter); return result; } @@ -159,22 +156,13 @@ static bool opensubdiv_is_topology_changed(CCGSubSurf *ss, DerivedMesh *dm) return true; } if (ss->osd_topology_refiner != NULL) { - int levels = openSubdiv_topologyRefinerGetSubdivLevel( + const int levels = ss->osd_topology_refiner->getSubdivisionLevel( ss->osd_topology_refiner); BLI_assert(ss->osd_mesh_invalid == true); if (levels != ss->subdivLevels) { return true; } } - if (ss->osd_mesh != NULL && ss->osd_mesh_invalid == false) { - const OpenSubdiv_TopologyRefinerDescr *topology_refiner = - openSubdiv_getGLMeshTopologyRefiner(ss->osd_mesh); - int levels = openSubdiv_topologyRefinerGetSubdivLevel(topology_refiner); - BLI_assert(ss->osd_topology_refiner == NULL); - if (levels != ss->subdivLevels) { - return true; - } - } if (ss->skip_grids == false) { return compare_ccg_derivedmesh_topology(ss, dm) == false; } @@ -194,13 +182,13 @@ void ccgSubSurf_checkTopologyChanged(CCGSubSurf *ss, DerivedMesh *dm) /* Reset GPU part. */ ss->osd_mesh_invalid = true; if (ss->osd_topology_refiner != NULL) { - openSubdiv_deleteTopologyRefinerDescr(ss->osd_topology_refiner); + openSubdiv_deleteTopologyRefiner(ss->osd_topology_refiner); ss->osd_topology_refiner = NULL; } /* Reset CPU side. */ if (ss->osd_evaluator != NULL) { - openSubdiv_deleteEvaluatorDescr(ss->osd_evaluator); + openSubdiv_deleteEvaluator(ss->osd_evaluator); ss->osd_evaluator = NULL; } } @@ -209,10 +197,10 @@ void ccgSubSurf_checkTopologyChanged(CCGSubSurf *ss, DerivedMesh *dm) static void ccgSubSurf__updateGLMeshCoords(CCGSubSurf *ss) { BLI_assert(ss->meshIFC.numLayers == 3); - openSubdiv_osdGLMeshUpdateVertexBuffer(ss->osd_mesh, - (float *) ss->osd_coarse_coords, - 0, - ss->osd_num_coarse_coords); + ss->osd_mesh->setCoarsePositions(ss->osd_mesh, + (float *) ss->osd_coarse_coords, + 0, + ss->osd_num_coarse_coords); } bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, @@ -259,9 +247,7 @@ bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, ss->osd_mesh = openSubdiv_createOsdGLMeshFromTopologyRefiner( ss->osd_topology_refiner, - compute_type, - ss->subdivLevels); - ss->osd_topology_refiner = NULL; + compute_type); if (UNLIKELY(ss->osd_mesh == NULL)) { /* Most likely compute device is not available. */ @@ -269,13 +255,12 @@ bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, } ccgSubSurf__updateGLMeshCoords(ss); - openSubdiv_osdGLMeshRefine(ss->osd_mesh); - openSubdiv_osdGLMeshSynchronize(ss->osd_mesh); + ss->osd_mesh->refine(ss->osd_mesh); + ss->osd_mesh->synchronize(ss->osd_mesh); ss->osd_coarse_coords_invalid = false; glBindVertexArray(ss->osd_vao); - glBindBuffer(GL_ARRAY_BUFFER, - openSubdiv_getOsdGLMeshVertexBuffer(ss->osd_mesh)); + ss->osd_mesh->bindVertexBuffer(ss->osd_mesh); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); @@ -289,12 +274,12 @@ bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, } else if (ss->osd_coarse_coords_invalid) { ccgSubSurf__updateGLMeshCoords(ss); - openSubdiv_osdGLMeshRefine(ss->osd_mesh); - openSubdiv_osdGLMeshSynchronize(ss->osd_mesh); + ss->osd_mesh->refine(ss->osd_mesh); + ss->osd_mesh->synchronize(ss->osd_mesh); ss->osd_coarse_coords_invalid = false; } - openSubdiv_osdGLMeshDisplayPrepare(use_osd_glsl, active_uv_index); + ss->osd_mesh->prepareDraw(ss->osd_mesh, use_osd_glsl, active_uv_index); return true; } @@ -305,12 +290,12 @@ void ccgSubSurf_drawGLMesh(CCGSubSurf *ss, bool fill_quads, if (LIKELY(ss->osd_mesh != NULL)) { glBindVertexArray(ss->osd_vao); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, - openSubdiv_getOsdGLMeshPatchIndexBuffer(ss->osd_mesh)); + ss->osd_mesh->getPatchIndexBuffer(ss->osd_mesh)); - openSubdiv_osdGLMeshBindVertexBuffer(ss->osd_mesh); + ss->osd_mesh->bindVertexBuffer(ss->osd_mesh); glBindVertexArray(ss->osd_vao); - openSubdiv_osdGLMeshDisplay(ss->osd_mesh, fill_quads, - start_partition, num_partitions); + ss->osd_mesh->drawPatches(ss->osd_mesh, fill_quads, + start_partition, num_partitions); glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); @@ -319,33 +304,21 @@ void ccgSubSurf_drawGLMesh(CCGSubSurf *ss, bool fill_quads, int ccgSubSurf_getNumGLMeshBaseFaces(CCGSubSurf *ss) { - const OpenSubdiv_TopologyRefinerDescr *topology_refiner; if (ss->osd_topology_refiner != NULL) { - topology_refiner = ss->osd_topology_refiner; - } - else if (ss->osd_mesh != NULL) { - topology_refiner = openSubdiv_getGLMeshTopologyRefiner(ss->osd_mesh); - } - else { - return 0; + return ss->osd_topology_refiner->getNumFaces( + ss->osd_topology_refiner); } - return openSubdiv_topologyRefinerGetNumFaces(topology_refiner); + return 0; } /* Get number of vertices in base faces in a particular GL mesh. */ int ccgSubSurf_getNumGLMeshBaseFaceVerts(CCGSubSurf *ss, int face) { - const OpenSubdiv_TopologyRefinerDescr *topology_refiner; if (ss->osd_topology_refiner != NULL) { - topology_refiner = ss->osd_topology_refiner; - } - else if (ss->osd_mesh != NULL) { - topology_refiner = openSubdiv_getGLMeshTopologyRefiner(ss->osd_mesh); - } - else { - return 0; + return ss->osd_topology_refiner->getNumFaceVertices( + ss->osd_topology_refiner, face); } - return openSubdiv_topologyRefinerGetNumFaceVerts(topology_refiner, face); + return 0; } void ccgSubSurf_setSkipGrids(CCGSubSurf *ss, bool skip_grids) @@ -453,17 +426,21 @@ void ccgSubSurf_evaluatorFVarUV(CCGSubSurf *ss, static bool opensubdiv_createEvaluator(CCGSubSurf *ss) { OpenSubdiv_Converter converter; - OpenSubdiv_TopologyRefinerDescr *topology_refiner; + OpenSubdiv_TopologyRefiner *topology_refiner; if (ss->fMap->numEntries == 0) { /* OpenSubdiv doesn't support meshes without faces. */ return false; } ccgSubSurf_converter_setup_from_ccg(ss, &converter); - topology_refiner = openSubdiv_createTopologyRefinerDescr(&converter); + OpenSubdiv_TopologyRefinerSettings settings; + settings.level = ss->subdivLevels; + settings.is_adaptive = false; + topology_refiner = + openSubdiv_createTopologyRefinerFromConverter( + &converter, &settings); ccgSubSurf_converter_free(&converter); ss->osd_evaluator = - openSubdiv_createEvaluatorDescr(topology_refiner, - ss->subdivLevels); + openSubdiv_createEvaluatorFromTopologyRefiner(topology_refiner); if (ss->osd_evaluator == NULL) { BLI_assert(!"OpenSubdiv initialization failed, should not happen."); return false; @@ -519,11 +496,11 @@ static void opensubdiv_updateEvaluatorCoarsePositions(CCGSubSurf *ss) } } - openSubdiv_setEvaluatorCoarsePositions(ss->osd_evaluator, - (float *)positions, - 0, - num_basis_verts); - openSubdiv_refineEvaluator(ss->osd_evaluator); + ss->osd_evaluator->setCoarsePositions(ss->osd_evaluator, + (float *)positions, + 0, + num_basis_verts); + ss->osd_evaluator->refine(ss->osd_evaluator); MEM_freeN(positions); } @@ -558,11 +535,12 @@ static void opensubdiv_evaluateQuadFaceGrids(CCGSubSurf *ss, ccgSubSurf__mapGridToFace(S, grid_u, grid_v, &face_u, &face_v); /* TODO(sergey): Need proper port. */ - openSubdiv_evaluateLimit(ss->osd_evaluator, osd_face_index, - face_u, face_v, - P, - do_normals ? dPdu : NULL, - do_normals ? dPdv : NULL); + ss->osd_evaluator->evaluateLimit( + ss->osd_evaluator, osd_face_index, + face_u, face_v, + P, + do_normals ? dPdu : NULL, + do_normals ? dPdv : NULL); OSD_LOG("face=%d, corner=%d, grid_u=%f, grid_v=%f, face_u=%f, face_v=%f, P=(%f, %f, %f)\n", osd_face_index, S, grid_u, grid_v, face_u, face_v, P[0], P[1], P[2]); @@ -636,7 +614,11 @@ static void opensubdiv_evaluateQuadFaceGrids(CCGSubSurf *ss, * let's just re-evaluate for simplicity. */ /* TODO(sergey): Need proper port. */ - openSubdiv_evaluateLimit(ss->osd_evaluator, osd_face_index, u, v, P, dPdu, dPdv); + ss->osd_evaluator->evaluateLimit( + ss->osd_evaluator, + osd_face_index, + u, v, + P, dPdu, dPdv); VertDataCopy(co, P, ss); if (do_normals) { cross_v3_v3v3(no, dPdu, dPdv); @@ -700,7 +682,11 @@ static void opensubdiv_evaluateNGonFaceGrids(CCGSubSurf *ss, float P[3], dPdu[3], dPdv[3]; /* TODO(sergey): Need proper port. */ - openSubdiv_evaluateLimit(ss->osd_evaluator, osd_face_index + S, u, v, P, dPdu, dPdv); + ss->osd_evaluator->evaluateLimit( + ss->osd_evaluator, + osd_face_index + S, + u, v, + P, dPdu, dPdv); OSD_LOG("face=%d, corner=%d, u=%f, v=%f, P=(%f, %f, %f)\n", osd_face_index + S, S, u, v, P[0], P[1], P[2]); @@ -838,7 +824,12 @@ void ccgSubSurf_prepareTopologyRefiner(CCGSubSurf *ss, DerivedMesh *dm) OpenSubdiv_Converter converter; ccgSubSurf_converter_setup_from_derivedmesh(ss, dm, &converter); /* TODO(sergey): Remove possibly previously allocated refiner. */ - ss->osd_topology_refiner = openSubdiv_createTopologyRefinerDescr(&converter); + OpenSubdiv_TopologyRefinerSettings settings; + settings.level = ss->subdivLevels; + settings.is_adaptive = false; + ss->osd_topology_refiner = + openSubdiv_createTopologyRefinerFromConverter( + &converter, &settings); ccgSubSurf_converter_free(&converter); } } diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c index 8c1ba0c3782..219d77a6c52 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c +++ b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c @@ -432,35 +432,35 @@ void ccgSubSurf_converter_setup_from_derivedmesh( { ConvDMStorage *user_data; - converter->get_scheme_type = conv_dm_get_type; + converter->getSchemeType = conv_dm_get_type; - converter->get_fvar_linear_interpolation = + converter->getFVarLinearInterpolation = conv_dm_get_fvar_linear_interpolation; - converter->get_num_faces = conv_dm_get_num_faces; - converter->get_num_edges = conv_dm_get_num_edges; - converter->get_num_verts = conv_dm_get_num_verts; + converter->getNumFaces = conv_dm_get_num_faces; + converter->getNumEdges = conv_dm_get_num_edges; + converter->getNumVertices = conv_dm_get_num_verts; - converter->get_num_face_verts = conv_dm_get_num_face_verts; - converter->get_face_verts = conv_dm_get_face_verts; - converter->get_face_edges = conv_dm_get_face_edges; + converter->getNumFaceVertices = conv_dm_get_num_face_verts; + converter->getFaceVertices = conv_dm_get_face_verts; + converter->getFaceEdges = conv_dm_get_face_edges; - converter->get_edge_verts = conv_dm_get_edge_verts; - converter->get_num_edge_faces = conv_dm_get_num_edge_faces; - converter->get_edge_faces = conv_dm_get_edge_faces; - converter->get_edge_sharpness = conv_dm_get_edge_sharpness; + converter->getEdgeVertices = conv_dm_get_edge_verts; + converter->getNumEdgeFaces = conv_dm_get_num_edge_faces; + converter->getEdgeFaces = conv_dm_get_edge_faces; + converter->getEdgeSharpness = conv_dm_get_edge_sharpness; - converter->get_num_vert_edges = conv_dm_get_num_vert_edges; - converter->get_vert_edges = conv_dm_get_vert_edges; - converter->get_num_vert_faces = conv_dm_get_num_vert_faces; - converter->get_vert_faces = conv_dm_get_vert_faces; + converter->getNumVertexEdges = conv_dm_get_num_vert_edges; + converter->getVertexEdges = conv_dm_get_vert_edges; + converter->getNumVertexFaces = conv_dm_get_num_vert_faces; + converter->getVertexFaces = conv_dm_get_vert_faces; - converter->get_num_uv_layers = conv_dm_get_num_uv_layers; - converter->precalc_uv_layer = conv_dm_precalc_uv_layer; - converter->finish_uv_layer = conv_dm_finish_uv_layer; - converter->get_num_uvs = conv_dm_get_num_uvs; - converter->get_uvs = conv_dm_get_uvs; - converter->get_face_corner_uv_index = conv_dm_get_face_corner_uv_index; + converter->getNumUVLayers = conv_dm_get_num_uv_layers; + converter->precalcUVLayer = conv_dm_precalc_uv_layer; + converter->finishUVLayer = conv_dm_finish_uv_layer; + converter->getNumUVCoordinates = conv_dm_get_num_uvs; + converter->getUVCoordinates = conv_dm_get_uvs; + converter->getFaceCornerUVIndex = conv_dm_get_face_corner_uv_index; user_data = MEM_mallocN(sizeof(ConvDMStorage), __func__); user_data->ss = ss; @@ -476,7 +476,7 @@ void ccgSubSurf_converter_setup_from_derivedmesh( user_data->uvs = NULL; user_data->face_uvs = NULL; - converter->free_user_data = conv_dm_free_user_data; + converter->freeUserData = conv_dm_free_user_data; converter->user_data = user_data; #ifdef USE_MESH_ELEMENT_MAPPING @@ -717,45 +717,45 @@ static int conv_ccg_get_face_corner_uv_index(const OpenSubdiv_Converter *UNUSED( void ccgSubSurf_converter_setup_from_ccg(CCGSubSurf *ss, OpenSubdiv_Converter *converter) { - converter->get_scheme_type = conv_ccg_get_bilinear_type; + converter->getSchemeType = conv_ccg_get_bilinear_type; - converter->get_fvar_linear_interpolation = + converter->getFVarLinearInterpolation = conv_ccg_get_fvar_linear_interpolation; - converter->get_num_faces = conv_ccg_get_num_faces; - converter->get_num_edges = conv_ccg_get_num_edges; - converter->get_num_verts = conv_ccg_get_num_verts; + converter->getNumFaces = conv_ccg_get_num_faces; + converter->getNumEdges = conv_ccg_get_num_edges; + converter->getNumVertices = conv_ccg_get_num_verts; - converter->get_num_face_verts = conv_ccg_get_num_face_verts; - converter->get_face_verts = conv_ccg_get_face_verts; - converter->get_face_edges = conv_ccg_get_face_edges; + converter->getNumFaceVertices = conv_ccg_get_num_face_verts; + converter->getFaceVertices = conv_ccg_get_face_verts; + converter->getFaceEdges = conv_ccg_get_face_edges; - converter->get_edge_verts = conv_ccg_get_edge_verts; - converter->get_num_edge_faces = conv_ccg_get_num_edge_faces; - converter->get_edge_faces = conv_ccg_get_edge_faces; - converter->get_edge_sharpness = conv_ccg_get_edge_sharpness; + converter->getEdgeVertices = conv_ccg_get_edge_verts; + converter->getNumEdgeFaces = conv_ccg_get_num_edge_faces; + converter->getEdgeFaces = conv_ccg_get_edge_faces; + converter->getEdgeSharpness = conv_ccg_get_edge_sharpness; - converter->get_num_vert_edges = conv_ccg_get_num_vert_edges; - converter->get_vert_edges = conv_ccg_get_vert_edges; - converter->get_num_vert_faces = conv_ccg_get_num_vert_faces; - converter->get_vert_faces = conv_ccg_get_vert_faces; + converter->getNumVertexEdges = conv_ccg_get_num_vert_edges; + converter->getVertexEdges = conv_ccg_get_vert_edges; + converter->getNumVertexFaces = conv_ccg_get_num_vert_faces; + converter->getVertexFaces = conv_ccg_get_vert_faces; - converter->get_num_uv_layers = conv_ccg_get_num_uv_layers; - converter->precalc_uv_layer = conv_ccg_precalc_uv_layer; - converter->finish_uv_layer = conv_ccg_finish_uv_layer; - converter->get_num_uvs = conv_ccg_get_num_uvs; - converter->get_uvs = conv_ccg_get_uvs; - converter->get_face_corner_uv_index = conv_ccg_get_face_corner_uv_index; + converter->getNumUVLayers = conv_ccg_get_num_uv_layers; + converter->precalcUVLayer = conv_ccg_precalc_uv_layer; + converter->finishUVLayer = conv_ccg_finish_uv_layer; + converter->getNumUVCoordinates = conv_ccg_get_num_uvs; + converter->getUVCoordinates = conv_ccg_get_uvs; + converter->getFaceCornerUVIndex = conv_ccg_get_face_corner_uv_index; - converter->free_user_data = NULL; + converter->freeUserData = NULL; converter->user_data = ss; } void ccgSubSurf_converter_free( struct OpenSubdiv_Converter *converter) { - if (converter->free_user_data) { - converter->free_user_data(converter); + if (converter->freeUserData) { + converter->freeUserData(converter); } } |