OpenSubdiv: Add new OpenSubdiv related files
authorSergey Sharybin <sergey.vfx@gmail.com>
Mon, 20 Jul 2015 13:18:35 +0000 (15:18 +0200)
committerSergey Sharybin <sergey.vfx@gmail.com>
Mon, 20 Jul 2015 20:29:25 +0000 (22:29 +0200)
This includes C-API bindings in intern/opensubdiv and CMAke module
which finds the OpenSubdiv library. This filea are not in use so
far, making it a separate commit to make actual integration commit
more clear.

17 files changed:
build_files/cmake/Modules/FindOpenSubdiv.cmake [new file with mode: 0644]
intern/opensubdiv/CMakeLists.txt [new file with mode: 0644]
intern/opensubdiv/SConscript [new file with mode: 0644]
intern/opensubdiv/gpu_shader_opensubd_display.glsl [new file with mode: 0644]
intern/opensubdiv/opensubdiv_capi.cc [new file with mode: 0644]
intern/opensubdiv/opensubdiv_capi.h [new file with mode: 0644]
intern/opensubdiv/opensubdiv_converter.cc [new file with mode: 0644]
intern/opensubdiv/opensubdiv_converter_capi.h [new file with mode: 0644]
intern/opensubdiv/opensubdiv_device_context_cuda.cc [new file with mode: 0644]
intern/opensubdiv/opensubdiv_device_context_cuda.h [new file with mode: 0644]
intern/opensubdiv/opensubdiv_device_context_opencl.cc [new file with mode: 0644]
intern/opensubdiv/opensubdiv_device_context_opencl.h [new file with mode: 0644]
intern/opensubdiv/opensubdiv_evaluator_capi.cc [new file with mode: 0644]
intern/opensubdiv/opensubdiv_gpu_capi.cc [new file with mode: 0644]
intern/opensubdiv/opensubdiv_intern.h [new file with mode: 0644]
intern/opensubdiv/opensubdiv_partitioned.h [new file with mode: 0644]
intern/opensubdiv/opensubdiv_utils_capi.cc [new file with mode: 0644]

diff --git a/build_files/cmake/Modules/FindOpenSubdiv.cmake b/build_files/cmake/Modules/FindOpenSubdiv.cmake
new file mode 100644 (file)
index 0000000..efbe8a9
--- /dev/null
@@ -0,0 +1,111 @@
+# - Find OpenSubdiv library
+# Find the native OpenSubdiv includes and library
+# This module defines
+#  OPENSUBDIV_INCLUDE_DIRS, where to find OpenSubdiv headers, Set when
+#                           OPENSUBDIV_INCLUDE_DIR is found.
+#  OPENSUBDIV_LIBRARIES, libraries to link against to use OpenSubdiv.
+#  OPENSUBDIV_ROOT_DIR, the base directory to search for OpenSubdiv.
+#                        This can also be an environment variable.
+#  OPENSUBDIV_FOUND, if false, do not try to use OpenSubdiv.
+#
+# also defined, but not for general use are
+#  OPENSUBDIV_LIBRARY, where to find the OpenSubdiv library.
+
+#=============================================================================
+# Copyright 2013 Blender Foundation.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+
+# If OPENSUBDIV_ROOT_DIR was defined in the environment, use it.
+IF(NOT OPENSUBDIV_ROOT_DIR AND NOT $ENV{OPENSUBDIV_ROOT_DIR} STREQUAL "")
+  SET(OPENSUBDIV_ROOT_DIR $ENV{OPENSUBDIV_ROOT_DIR})
+ENDIF()
+
+SET(_opensubdiv_FIND_COMPONENTS
+  osdGPU
+  osdCPU
+)
+
+SET(_opensubdiv_SEARCH_DIRS
+  ${OPENSUBDIV_ROOT_DIR}
+  /usr/local
+  /sw # Fink
+  /opt/local # DarwinPorts
+  /opt/csw # Blastwave
+  /opt/lib/opensubdiv
+)
+
+FIND_PATH(OPENSUBDIV_INCLUDE_DIR
+  NAMES
+    opensubdiv/osd/mesh.h
+  HINTS
+    ${_opensubdiv_SEARCH_DIRS}
+  PATH_SUFFIXES
+    include
+)
+
+SET(_opensubdiv_LIBRARIES)
+FOREACH(COMPONENT ${_opensubdiv_FIND_COMPONENTS})
+  STRING(TOUPPER ${COMPONENT} UPPERCOMPONENT)
+
+  FIND_LIBRARY(OPENSUBDIV_${UPPERCOMPONENT}_LIBRARY
+    NAMES
+      ${COMPONENT}
+    HINTS
+      ${_opensubdiv_SEARCH_DIRS}
+    PATH_SUFFIXES
+      lib64 lib
+    )
+  LIST(APPEND _opensubdiv_LIBRARIES "${OPENSUBDIV_${UPPERCOMPONENT}_LIBRARY}")
+ENDFOREACH()
+
+MACRO(OPENSUBDIV_CHECK_CONTROLLER
+      controller_include_file
+      variable_name)
+  IF(EXISTS "${OPENSUBDIV_INCLUDE_DIR}/opensubdiv/osd/${controller_include_file}")
+    SET(${variable_name} TRUE)
+  ELSE()
+    SET(${variable_name} FALSE)
+  ENDIF()
+ENDMACRO()
+
+
+# handle the QUIETLY and REQUIRED arguments and set OPENSUBDIV_FOUND to TRUE if
+# all listed variables are TRUE
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(OpenSubdiv DEFAULT_MSG
+    _opensubdiv_LIBRARIES OPENSUBDIV_INCLUDE_DIR)
+
+IF(OPENSUBDIV_FOUND)
+  SET(OPENSUBDIV_LIBRARIES ${_opensubdiv_LIBRARIES})
+  SET(OPENSUBDIV_INCLUDE_DIRS ${OPENSUBDIV_INCLUDE_DIR})
+
+  # Find available compute controllers.
+
+  FIND_PACKAGE(OpenMP)
+  IF(OPENMP_FOUND)
+    SET(OPENSUBDIV_HAS_OPENMP TRUE)
+  ELSE()
+    SET(OPENSUBDIV_HAS_OPENMP FALSE)
+  ENDIF()
+
+  OPENSUBDIV_CHECK_CONTROLLER("tbbEvaluator.h" OPENSUBDIV_HAS_TBB)
+  OPENSUBDIV_CHECK_CONTROLLER("clEvaluator.h" OPENSUBDIV_HAS_OPENCL)
+  OPENSUBDIV_CHECK_CONTROLLER("cudaEvaluator.h" OPENSUBDIV_HAS_CUDA)
+  OPENSUBDIV_CHECK_CONTROLLER("glXFBEvaluator.h" OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK)
+  OPENSUBDIV_CHECK_CONTROLLER("glComputeEvaluator.h" OPENSUBDIV_HAS_GLSL_COMPUTE)
+ENDIF(OPENSUBDIV_FOUND)
+
+MARK_AS_ADVANCED(
+  OPENSUBDIV_INCLUDE_DIR
+)
+FOREACH(COMPONENT ${_opensubdiv_FIND_COMPONENTS})
+  STRING(TOUPPER ${COMPONENT} UPPERCOMPONENT)
+  MARK_AS_ADVANCED(OPENSUBDIV_${UPPERCOMPONENT}_LIBRARY)
+ENDFOREACH()
diff --git a/intern/opensubdiv/CMakeLists.txt b/intern/opensubdiv/CMakeLists.txt
new file mode 100644 (file)
index 0000000..3f88ba5
--- /dev/null
@@ -0,0 +1,90 @@
+# ***** 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.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Sergey Sharybin.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+       .
+       ../guardedalloc
+)
+
+set(INC_SYS
+       ${OPENSUBDIV_INCLUDE_DIR}
+       ${GLEW_INCLUDE_PATH}
+)
+
+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
+
+       opensubdiv_capi.h
+       opensubdiv_converter_capi.h
+       opensubdiv_device_context_cuda.h
+       opensubdiv_device_context_opencl.h
+       opensubdiv_intern.h
+       opensubdiv_partitioned.h
+)
+
+macro(OPENSUBDIV_DEFINE_COMPONENT component)
+       if(${${component}})
+               add_definitions(-D${component})
+       endif()
+endmacro()
+
+OPENSUBDIV_DEFINE_COMPONENT(OPENSUBDIV_HAS_OPENMP)
+# TODO(sergey): OpenCL is not tested and totally unstable atm.
+# OPENSUBDIV_DEFINE_COMPONENT(OPENSUBDIV_HAS_OPENCL)
+# TODO(sergey): CUDA stays disabled for util it's ported to drievr API.
+# OPENSUBDIV_DEFINE_COMPONENT(OPENSUBDIV_HAS_CUDA)
+OPENSUBDIV_DEFINE_COMPONENT(OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK)
+OPENSUBDIV_DEFINE_COMPONENT(OPENSUBDIV_HAS_GLSL_COMPUTE)
+
+data_to_c_simple(gpu_shader_opensubd_display.glsl SRC)
+
+add_definitions(-DGLEW_STATIC)
+
+if(WIN32)
+       add_definitions(-DNOMINMAX)
+endif()
+
+# TODO(sergey): Put CUEW back when CUDA is officially supported by OSD.
+#if(OPENSUBDIV_HAS_CUDA)
+#      list(APPEND INC
+#              ../../extern/cuew/include
+#      )
+#      add_definitions(-DOPENSUBDIV_HAS_CUEW)
+#endif()
+
+if(OPENSUBDIV_HAS_OPENCL)
+       list(APPEND INC
+               ../../extern/clew/include
+       )
+       add_definitions(-DOPENSUBDIV_HAS_CLEW)
+endif()
+
+blender_add_lib(bf_intern_opensubdiv "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/intern/opensubdiv/SConscript b/intern/opensubdiv/SConscript
new file mode 100644 (file)
index 0000000..58926c6
--- /dev/null
@@ -0,0 +1,67 @@
+#!/usr/bin/env python
+#
+# ***** 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.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Sergey Sharybin.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+import os
+
+Import('env')
+
+sources = env.Glob('*.cc')
+
+defs = [ 'GLEW_STATIC' ]
+
+if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
+    defs += [ 'NOMINMAX' ]
+
+incs = '. ../guardedalloc #extern/clew/include/'
+incs += ' ' + env['BF_OPENSUBDIV_INC']
+incs += ' #/extern/glew/include'
+
+def checkOpenSubdivHeaderDefine(header, define):
+    include_path = Dir(env.subst(env['BF_OPENSUBDIV_INC'])).abspath
+    header_path = os.path.join(include_path, 'opensubdiv', 'osd', header)
+    if os.path.exists(header_path):
+        defs.append(define)
+        return True
+    return False
+
+checkOpenSubdivHeaderDefine("tbbComputeController.h", 'OPENSUBDIV_HAS_TBB')
+checkOpenSubdivHeaderDefine("gcdComputeController.h", 'OPENSUBDIV_HAS_GCD')
+if checkOpenSubdivHeaderDefine("clComputeController.h", 'OPENSUBDIV_HAS_OPENCL'):
+    defs += ['OPENSUBDIV_HAS_CLEW']
+    incs += ' #/extern/clew/include'
+if checkOpenSubdivHeaderDefine("cudaComputeController.h", 'OPENSUBDIV_HAS_CUDA'):
+    defs += ['OPENSUBDIV_HAS_CUEW']
+    incs += ' #/extern/cuew/include'
+checkOpenSubdivHeaderDefine("glslTransformFeedbackComputeController.h", 'OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK')
+checkOpenSubdivHeaderDefine("osd/glslComputeController.h", 'OPENSUBDIV_HAS_GLSL_COMPUTE')
+
+# generated data files
+sources.extend((
+    os.path.join(env['DATA_SOURCES'], "gpu_shader_opensubd_display.glsl.c"),
+))
+
+env.BlenderLib('bf_intern_opensubdiv', sources, Split(incs), defs, libtype=['extern','player'], priority=[10, 185])
diff --git a/intern/opensubdiv/gpu_shader_opensubd_display.glsl b/intern/opensubdiv/gpu_shader_opensubd_display.glsl
new file mode 100644 (file)
index 0000000..fb46971
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ * ***** 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) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/* ***** Vertex shader ***** */
+
+#extension GL_EXT_geometry_shader4 : enable
+#extension GL_ARB_gpu_shader5 : enable
+#extension GL_ARB_explicit_attrib_location : require
+
+struct VertexData {
+       vec4 position;
+       vec3 normal;
+       vec2 uv;
+};
+
+#ifdef VERTEX_SHADER
+
+in vec3 normal;
+in vec4 position;
+
+uniform mat4 modelViewMatrix;
+uniform mat3 normalMatrix;
+
+out block {
+       VertexData v;
+} outpt;
+
+void main()
+{
+       outpt.v.position = modelViewMatrix * position;
+       outpt.v.normal = normalize(normalMatrix * normal);
+}
+
+#endif  /* VERTEX_SHADER */
+
+/* ***** geometry shader ***** */
+#ifdef GEOMETRY_SHADER
+
+#ifndef GLSL_COMPAT_WORKAROUND
+layout(lines_adjacency) in;
+#ifndef WIREFRAME
+layout(triangle_strip, max_vertices = 4) out;
+#else
+layout(line_strip, max_vertices = 8) out;
+#endif
+#endif
+
+uniform mat4 modelViewMatrix;
+uniform mat4 projectionMatrix;
+uniform int PrimitiveIdBase;
+uniform int osd_fvar_count;
+uniform int osd_active_uv_offset;
+
+in block {
+       VertexData v;
+} inpt[4];
+
+#define INTERP_FACE_VARYING_2(result, fvarOffset, tessCoord)  \
+       { \
+               vec2 v[4]; \
+               int primOffset = (gl_PrimitiveID + PrimitiveIdBase) * 4; \
+               for (int i = 0; i < 4; ++i) { \
+                       int index = (primOffset + i) * osd_fvar_count + fvarOffset; \
+                       v[i] = vec2(texelFetch(FVarDataBuffer, index).s, \
+                                   texelFetch(FVarDataBuffer, index + 1).s); \
+               } \
+               result = mix(mix(v[0], v[1], tessCoord.s), \
+                            mix(v[3], v[2], tessCoord.s), \
+                            tessCoord.t); \
+       }
+
+uniform samplerBuffer FVarDataBuffer;
+
+out block {
+       VertexData v;
+} outpt;
+
+#ifdef FLAT_SHADING
+void emit(int index, vec3 normal)
+{
+       outpt.v.position = inpt[index].v.position;
+       outpt.v.normal = normal;
+
+       /* TODO(sergey): Only uniform subdivisions atm. */
+       vec2 quadst[4] = vec2[](vec2(0,0), vec2(1,0), vec2(1,1), vec2(0,1));
+       vec2 st = quadst[index];
+
+       INTERP_FACE_VARYING_2(outpt.v.uv, osd_active_uv_offset, st);
+
+       gl_Position = projectionMatrix * inpt[index].v.position;
+       EmitVertex();
+}
+
+#  ifdef WIREFRAME
+void emit_edge(int v0, int v1, vec3 normal)
+{
+       emit(v0, normal);
+       emit(v1, normal);
+}
+#  endif
+
+#else
+void emit(int index)
+{
+       outpt.v.position = inpt[index].v.position;
+       outpt.v.normal = inpt[index].v.normal;
+
+       /* TODO(sergey): Only uniform subdivisions atm. */
+       vec2 quadst[4] = vec2[](vec2(0,0), vec2(1,0), vec2(1,1), vec2(0,1));
+       vec2 st = quadst[index];
+
+       INTERP_FACE_VARYING_2(outpt.v.uv, osd_active_uv_offset, st);
+
+       gl_Position = projectionMatrix * inpt[index].v.position;
+       EmitVertex();
+}
+
+#  ifdef WIREFRAME
+void emit_edge(int v0, int v1)
+{
+       emit(v0);
+       emit(v1);
+}
+#  endif
+
+#endif
+
+void main()
+{
+       gl_PrimitiveID = gl_PrimitiveIDIn;
+
+#ifdef FLAT_SHADING
+       vec3 A = (inpt[0].v.position - inpt[1].v.position).xyz;
+       vec3 B = (inpt[3].v.position - inpt[1].v.position).xyz;
+       vec3 flat_normal = normalize(cross(B, A));
+#  ifndef WIREFRAME
+       emit(0, flat_normal);
+       emit(1, flat_normal);
+       emit(3, flat_normal);
+       emit(2, flat_normal);
+#  else
+       emit_edge(0, 1, flat_normal);
+       emit_edge(1, 2, flat_normal);
+       emit_edge(2, 3, flat_normal);
+       emit_edge(3, 0, flat_normal);
+#  endif
+#else
+#  ifndef WIREFRAME
+       emit(0);
+       emit(1);
+       emit(3);
+       emit(2);
+#  else
+       emit_edge(0, 1);
+       emit_edge(1, 2);
+       emit_edge(2, 3);
+       emit_edge(3, 0);
+#  endif
+#endif
+
+       EndPrimitive();
+}
+
+#endif  /* GEOMETRY_SHADER */
+
+/* ***** Fragment shader ***** */
+#ifdef FRAGMENT_SHADER
+
+#define MAX_LIGHTS 8
+#define NUM_SOLID_LIGHTS 3
+
+struct LightSource {
+       vec4 position;
+       vec4 ambient;
+       vec4 diffuse;
+       vec4 specular;
+       vec4 spotDirection;
+       float constantAttenuation;
+       float linearAttenuation;
+       float quadraticAttenuation;
+       float spotCutoff;
+       float spotExponent;
+       float spotCosCutoff;
+};
+
+uniform Lighting {
+       LightSource lightSource[MAX_LIGHTS];
+       int num_enabled_lights;
+};
+
+uniform vec4 diffuse;
+uniform vec4 specular;
+uniform float shininess;
+
+uniform sampler2D texture_buffer;
+uniform bool use_color_material;
+uniform bool use_texture_2d;
+
+in block {
+       VertexData v;
+} inpt;
+
+void main()
+{
+#ifdef WIREFRAME
+       gl_FragColor = diffuse;
+#else
+       vec3 N = inpt.v.normal;
+
+       if (!gl_FrontFacing)
+               N = -N;
+
+       /* Compute diffuse and specular lighting. */
+       vec3 L_diffuse = vec3(0.0);
+       vec3 L_specular = vec3(0.0);
+
+       if (use_color_material == false) {
+               /* Assume NUM_SOLID_LIGHTS directional lights. */
+               for (int i = 0; i < NUM_SOLID_LIGHTS; i++) {
+                       vec3 light_direction = lightSource[i].position.xyz;
+
+                       /* Diffuse light. */
+                       vec3 light_diffuse = lightSource[i].diffuse.rgb;
+                       float diffuse_bsdf = max(dot(N, light_direction), 0.0);
+                       L_diffuse += light_diffuse * diffuse_bsdf;
+
+                       vec4 Plight = lightSource[i].position;
+                       vec3 l = (Plight.w == 0.0)
+                               ? normalize(Plight.xyz) : normalize(Plight.xyz -
+                                                                   inpt.v.position.xyz);
+
+                       /* Specular light. */
+                       vec3 light_specular = lightSource[i].specular.rgb;
+                       vec3 H = normalize(l + vec3(0,0,1));
+
+                       float specular_bsdf = pow(max(dot(N, H), 0.0),
+                                                 shininess);
+                       L_specular += light_specular * specular_bsdf;
+               }
+       }
+       else {
+               vec3 varying_position = inpt.v.position.xyz;
+               vec3 V = (gl_ProjectionMatrix[3][3] == 0.0) ?
+                       normalize(varying_position): vec3(0.0, 0.0, -1.0);
+               for (int i = 0; i < num_enabled_lights; i++) {
+                       /* todo: this is a slow check for disabled lights */
+                       if (lightSource[i].specular.a == 0.0)
+                               continue;
+
+                       float intensity = 1.0;
+                       vec3 light_direction;
+
+                       if (lightSource[i].position.w == 0.0) {
+                               /* directional light */
+                               light_direction = lightSource[i].position.xyz;
+                       }
+                       else {
+                               /* point light */
+                               vec3 d = lightSource[i].position.xyz - varying_position;
+                               light_direction = normalize(d);
+
+                               /* spot light cone */
+                               if (lightSource[i].spotCutoff < 90.0) {
+                                       float cosine = max(dot(light_direction,
+                                                              -lightSource[i].spotDirection.xyz),
+                                                          0.0);
+                                       intensity = pow(cosine, lightSource[i].spotExponent);
+                                       intensity *= step(lightSource[i].spotCosCutoff, cosine);
+                               }
+
+                               /* falloff */
+                               float distance = length(d);
+
+                               intensity /= lightSource[i].constantAttenuation +
+                                       lightSource[i].linearAttenuation * distance +
+                                       lightSource[i].quadraticAttenuation * distance * distance;
+                       }
+
+                       /* diffuse light */
+                       vec3 light_diffuse = lightSource[i].diffuse.rgb;
+                       float diffuse_bsdf = max(dot(N, light_direction), 0.0);
+                       L_diffuse += light_diffuse*diffuse_bsdf*intensity;
+
+                       /* specular light */
+                       vec3 light_specular = lightSource[i].specular.rgb;
+                       vec3 H = normalize(light_direction - V);
+
+                       float specular_bsdf = pow(max(dot(N, H), 0.0),
+                                                 gl_FrontMaterial.shininess);
+                       L_specular += light_specular*specular_bsdf * intensity;
+               }
+       }
+
+       /* Compute diffuse color. */
+       float alpha;
+       if (use_texture_2d) {
+               L_diffuse *= texture2D(texture_buffer, inpt.v.uv).rgb;
+       }
+       else {
+               L_diffuse *= diffuse.rgb;
+       }
+       alpha = diffuse.a;
+
+       /* Sum lighting. */
+       vec3 L = /*gl_FrontLightModelProduct.sceneColor.rgb +*/ L_diffuse;
+       L += L_specular * specular.rgb;
+
+       /* Write out fragment color. */
+       gl_FragColor = vec4(L, alpha);
+#endif
+}
+
+#endif  // FRAGMENT_SHADER
diff --git a/intern/opensubdiv/opensubdiv_capi.cc b/intern/opensubdiv/opensubdiv_capi.cc
new file mode 100644 (file)
index 0000000..717af4f
--- /dev/null
@@ -0,0 +1,303 @@
+/*
+ * ***** 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 <GL/glew.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_intern.h"
+#include "opensubdiv_partitioned.h"
+
+#include "MEM_guardedalloc.h"
+
+/* **************** 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::PartitionedMesh;
+
+/* CPU backend */
+using OpenSubdiv::Osd::CpuGLVertexBuffer;
+using OpenSubdiv::Osd::CpuEvaluator;
+typedef PartitionedMesh<CpuGLVertexBuffer,
+                        StencilTable,
+                        CpuEvaluator,
+                        GLPatchTable> OsdCpuMesh;
+
+#ifdef OPENSUBDIV_HAS_OPENMP
+using OpenSubdiv::Osd::OmpEvaluator;
+typedef PartitionedMesh<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 PartitionedMesh<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 PartitionedMesh<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 PartitionedMesh<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 PartitionedMesh<GLVertexBuffer,
+                        GLStencilTableSSBO,
+                        GLComputeEvaluator,
+                        GLPatchTable> OsdGLSLComputeMesh;
+#endif
+
+struct OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner(
+        OpenSubdiv_TopologyRefinerDescr *topology_refiner,
+        int evaluator_type,
+        int level,
+        int /*subdivide_uvs*/)
+{
+       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, 0);
+       bits.set(OpenSubdiv::Osd::MeshFVarData, 1);
+       bits.set(OpenSubdiv::Osd::MeshEndCapBSplineBasis, 1);
+       // bits.set(Osd::MeshEndCapGregoryBasis, 1);
+       // bits.set(Osd::MeshEndCapLegacyGregory, 1);
+
+       const int num_vertex_elements = 6;
+       const int num_varying_elements = 0;
+
+       GLMeshInterface *mesh = NULL;
+       TopologyRefiner *refiner = (TopologyRefiner*)topology_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 = (OpenSubdiv_TopologyRefinerDescr*)refiner;
+
+       return gl_mesh;
+}
+
+void openSubdiv_deleteOsdGLMesh(struct OpenSubdiv_GLMesh *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
+       }
+
+       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_supportGPUDisplay(void)
+{
+       return GL_EXT_geometry_shader4 &&
+              GL_ARB_gpu_shader5 &&
+              glProgramParameteriEXT;
+}
diff --git a/intern/opensubdiv/opensubdiv_capi.h b/intern/opensubdiv/opensubdiv_capi.h
new file mode 100644 (file)
index 0000000..c86e739
--- /dev/null
@@ -0,0 +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) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __OPENSUBDIV_CAPI_H__
+#define __OPENSUBDIV_CAPI_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Types declaration.
+struct OpenSubdiv_GLMesh;
+struct OpenSubdiv_TopologyRefinerDescr;
+
+typedef struct OpenSubdiv_GLMesh OpenSubdiv_GLMesh;
+
+#ifdef __cplusplus
+struct OpenSubdiv_GLMeshDescr;
+typedef struct OpenSubdiv_GLMesh {
+       int evaluator_type;
+       OpenSubdiv_GLMeshDescr *descriptor;
+       OpenSubdiv_TopologyRefinerDescr *topology_refiner;
+} OpenSubdiv_GLMesh;
+#endif
+
+// 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,
+        int subdivide_uvs);
+
+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);
+
+/* ** Initialize/Deinitialize global OpenGL drawing buffers/GLSL programs ** */
+void openSubdiv_osdGLDisplayInit(void);
+void openSubdiv_osdGLDisplayDeinit(void);
+
+/* ** 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,
+                                            float *positions,
+                                            int start_vert,
+                                            int num_vert);
+
+void openSubdiv_setEvaluatorVaryingData(OpenSubdiv_EvaluatorDescr *evaluator_descr,
+                                        float *varying_data,
+                                        int start_vert,
+                                        int num_vert);
+
+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]);
+
+/* ** Actual drawing ** */
+
+/* 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 patches which corresponds to a given partition. */
+void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh,
+                                 int fill_quads,
+                                 int start_partition,
+                                 int num_partitions);
+
+/* ** Utility functions ** */
+int openSubdiv_supportGPUDisplay(void);
+int openSubdiv_getAvailableEvaluators(void);
+void openSubdiv_cleanup(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // __OPENSUBDIV_CAPI_H__
diff --git a/intern/opensubdiv/opensubdiv_converter.cc b/intern/opensubdiv/opensubdiv_converter.cc
new file mode 100644 (file)
index 0000000..f5f3547
--- /dev/null
@@ -0,0 +1,341 @@
+/*
+ * ***** 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 "opensubdiv_converter_capi.h"
+#include "opensubdiv_intern.h"
+
+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());
+}
+
+}  /* namespace */
+
+template <>
+inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::resizeComponentTopology(
+        TopologyRefiner& refiner,
+        const OpenSubdiv_Converter& 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<OpenSubdiv_Converter>::assignComponentTopology(
+         TopologyRefiner& refiner,
+        const OpenSubdiv_Converter& 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]);
+       }
+       /* 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_edges = conv.get_num_vert_edges(&conv, vert);
+               int *vert_edges = new int[num_vert_edges];
+               conv.get_vert_edges(&conv, vert, vert_edges);
+               /* Vert-Edges */
+               IndexArray dst_vert_edges = getBaseVertexEdges(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);
+               /* Order vertex edges and faces in a CCW order. */
+               Index face_start = INDEX_INVALID;
+               Index edge_start = INDEX_INVALID;
+               int face_vert_start = 0;
+               if (num_vert_edges == num_vert_faces) {
+                       face_start  = vert_faces[0];
+                       face_vert_start = findInArray(getBaseFaceVertices(refiner, face_start), vert);
+                       edge_start = getBaseFaceEdges(refiner, face_start)[face_vert_start];
+               } else {
+                       for (int i = 0; i < num_vert_edges; ++i) {
+                               IndexArray edge_faces = getBaseEdgeFaces(refiner, vert_edges[i]);
+                               if (edge_faces.size() == 1) {
+                                       edge_start = vert_edges[i];
+                                       face_start = edge_faces[0];
+                                       face_vert_start = findInArray(getBaseFaceVertices(refiner, face_start), vert);
+                                       if (edge_start == (getBaseFaceEdges(refiner, face_start)[face_vert_start])) {
+                                               break;
+                                       }
+                               }
+                       }
+               }
+               int edge_count_ordered = 1;
+               int face_count_ordered = 1;
+               dst_vert_faces[0] = face_start;
+               dst_vert_edges[0] = edge_start;
+               while (edge_count_ordered < num_vert_edges) {
+                       IndexArray fVerts = getBaseFaceVertices(refiner, face_start);
+                       IndexArray fEdges = getBaseFaceEdges(refiner, face_start);
+                       int feStart = face_vert_start;
+                       int feNext = feStart ? (feStart - 1) : (fVerts.size() - 1);
+                       Index eNext = fEdges[feNext];
+                       dst_vert_edges[edge_count_ordered++] = eNext;
+                       if (face_count_ordered < num_vert_faces) {
+                               IndexArray edge_faces = getBaseEdgeFaces(refiner, eNext);
+                               face_start = edge_faces[edge_faces[0] == face_start];
+                               face_vert_start = findInArray(getBaseFaceEdges(refiner, face_start), eNext);
+                               dst_vert_faces[face_count_ordered++] = face_start;
+                       }
+                       edge_start = eNext;
+               }
+
+               delete [] vert_edges;
+               delete [] vert_faces;
+       }
+       populateBaseLocalIndices(refiner);
+       return true;
+};
+
+template <>
+inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::assignComponentTags(
+        TopologyRefiner& refiner,
+        const OpenSubdiv_Converter& conv)
+{
+       int num_edges = conv.get_num_edges(&conv);
+       for (int edge = 0; edge < num_edges; ++edge) {
+               float sharpness = conv.get_edge_sharpness(&conv, edge);
+               setBaseEdgeSharpness(refiner, edge, sharpness);
+       }
+       return true;
+}
+
+template <>
+inline void TopologyRefinerFactory<OpenSubdiv_Converter>::reportInvalidTopology(
+        TopologyError /*errCode*/,
+        const char *msg,
+        const OpenSubdiv_Converter& /*mesh*/)
+{
+       printf("OpenSubdiv Error: %s\n", msg);
+}
+
+}  /* 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 sceme type passed via C-API");
+       return OpenSubdiv::Sdc::SCHEME_CATMARK;
+}
+
+}  /* namespace */
+
+struct OpenSubdiv_TopologyRefinerDescr *openSubdiv_createTopologyRefinerDescr(
+        OpenSubdiv_Converter *converter)
+{
+       using OpenSubdiv::Far::TopologyRefinerFactory;
+       OpenSubdiv::Sdc::SchemeType scheme_type =
+               get_capi_scheme_type(converter->get_type(converter));
+       OpenSubdiv::Sdc::Options options;
+       options.SetVtxBoundaryInterpolation(OpenSubdiv::Sdc::Options::VTX_BOUNDARY_EDGE_AND_CORNER);
+       options.SetFVarLinearInterpolation(OpenSubdiv::Sdc::Options::FVAR_LINEAR_ALL);
+
+       TopologyRefinerFactory<OpenSubdiv_Converter>::Options
+               topology_options(scheme_type, options);
+#ifdef OPENSUBDIV_VALIDATE_TOPOLOGY
+       topology_options.validateFullTopology = true;
+#endif
+       /* We don't use guarded allocation here so we can re-use the refiner
+        * for GL mesh creation directly.
+        */
+       return (struct OpenSubdiv_TopologyRefinerDescr*)
+               TopologyRefinerFactory<OpenSubdiv_Converter>::Create(
+                       *converter,
+                       topology_options);
+}
+
+void openSubdiv_deleteTopologyRefinerDescr(
+        OpenSubdiv_TopologyRefinerDescr *topology_refiner)
+{
+       delete (OpenSubdiv::Far::TopologyRefiner *)topology_refiner;
+}
+
+int openSubdiv_topologyRefinerGetSubdivLevel(
+        const OpenSubdiv_TopologyRefinerDescr *topology_refiner)
+{
+       using OpenSubdiv::Far::TopologyRefiner;
+       const TopologyRefiner *refiner = (const TopologyRefiner *)topology_refiner;
+       return refiner->GetMaxLevel();
+}
+
+int openSubdiv_topologyRefinerGetNumVerts(
+        const OpenSubdiv_TopologyRefinerDescr *topology_refiner)
+{
+       using OpenSubdiv::Far::TopologyLevel;
+       using OpenSubdiv::Far::TopologyRefiner;
+       const TopologyRefiner *refiner = (const TopologyRefiner *)topology_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 = (const TopologyRefiner *)topology_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 = (const TopologyRefiner *)topology_refiner;
+       const TopologyLevel &base_level = refiner->GetLevel(0);
+       return base_level.GetNumFaces();
+}
+
+int openSubdiv_topologyRefnerCompareConverter(
+        const OpenSubdiv_TopologyRefinerDescr *topology_refiner,
+        OpenSubdiv_Converter *converter)
+{
+       using OpenSubdiv::Far::ConstIndexArray;
+       using OpenSubdiv::Far::TopologyRefiner;
+       using OpenSubdiv::Far::TopologyLevel;
+       const TopologyRefiner *refiner = (const TopologyRefiner *)topology_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_type(converter));
+       if (scheme_type != refiner->GetSchemeType()) {
+               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]);
+               for (int i = 0; i < face_verts.size(); ++i) {
+                       if (conv_face_verts[i] != face_verts[i]) {
+                               return false;
+                       }
+               }
+       }
+       /* Compare sharpness. */
+       for (int edge = 0; edge < num_edges; ++edge) {
+               float sharpness = base_level.GetEdgeSharpness(edge);
+               float conv_sharpness = converter->get_edge_sharpness(converter, edge);
+               if (sharpness != conv_sharpness) {
+                       return false;
+               }
+       }
+       return true;
+}
diff --git a/intern/opensubdiv/opensubdiv_converter_capi.h b/intern/opensubdiv/opensubdiv_converter_capi.h
new file mode 100644 (file)
index 0000000..7c96d3d
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * ***** 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__
+
+#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,
+} OpenSubdiv_SchemeType;
+
+typedef struct OpenSubdiv_Converter {
+       /* TODO(sergey): Needs to be implemented. */
+       /* OpenSubdiv::Sdc::Options get_options() const; */
+
+       OpenSubdiv_SchemeType (*get_type)(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);
+
+       void (*free_user_data)(const 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 on conversion.
+ * needs some dedicated fiel 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_topologyRefnerCompareConverter(
+        const OpenSubdiv_TopologyRefinerDescr *topology_refiner,
+        OpenSubdiv_Converter *converter);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* __OPENSUBDIV_CONVERTER_CAPI_H__ */
diff --git a/intern/opensubdiv/opensubdiv_device_context_cuda.cc b/intern/opensubdiv/opensubdiv_device_context_cuda.cc
new file mode 100644 (file)
index 0000000..81c52f5
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * 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_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
new file mode 100644 (file)
index 0000000..eb30b76
--- /dev/null
@@ -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_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
new file mode 100644 (file)
index 0000000..4cacdc9
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * 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
new file mode 100644 (file)
index 0000000..a640dce
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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
new file mode 100644 (file)
index 0000000..b8527fd
--- /dev/null
@@ -0,0 +1,499 @@
+/*
+ * ***** 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 "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 sued by CPU evalautor.
+ */
+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 chuncks.
+ */
+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 = (TopologyRefiner *)topology_refiner;
+       if(refiner == NULL) {
+               /* Happens on bad topology. */
+               return NULL;
+       }
+
+       const StencilTable *vertex_stencils = NULL;
+       const StencilTable *varying_stencils = NULL;
+       int num_total_verts = 0;
+
+       /* Apply adaptive refinement to the mesh so that we can use the
+        * limit evaluation API features.
+        *
+        * TODO(sergey): Once OpenSubdiv supports uniform meshes in limit
+        * evlauation we need to switch to uniform here, which will match
+        * original Blender subsurf.
+        */
+       TopologyRefiner::AdaptiveOptions options(subsurf_level);
+       refiner->RefineAdaptive(options);
+
+       /* Generate stencil table to update the bi-cubic patches control
+        * vertices after they have been re-posed (both for vertex & varying
+        * interpolation).
+        */
+       StencilTableFactory::Options soptions;
+       soptions.generateOffsets = true;
+       soptions.generateIntermediateLevels = true;
+
+       vertex_stencils = StencilTableFactory::Create(*refiner, soptions);
+
+       soptions.interpolationMode = StencilTableFactory::INTERPOLATE_VARYING;
+       varying_stencils = StencilTableFactory::Create(*refiner, soptions);
+
+       /* 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. */
+       /* TODO(sergey): Do we really need to worry about local points stencils? */
+       if (const StencilTable *local_point_stencil_table =
+           patch_table->GetLocalPointStencilTable())
+       {
+               const StencilTable *table =
+                       StencilTableFactory::AppendLocalPointStencilTable(*refiner,
+                                                                         vertex_stencils,
+                                                                         local_point_stencil_table);
+               delete vertex_stencils;
+               vertex_stencils = table;
+       }
+       if (const StencilTable *local_point_varying_stencil_table =
+            patch_table->GetLocalPointVaryingStencilTable())
+       {
+               const StencilTable *table =
+                       StencilTableFactory::AppendLocalPointStencilTable(*refiner,
+                                                                         varying_stencils,
+                                                                         local_point_varying_stencil_table);
+               delete varying_stencils;
+               varying_stencils = table;
+       }
+
+       /* Total number of vertices = coarse verts + refined verts + gregory basis verts. */
+       num_total_verts = vertex_stencils->GetNumControlVertices() +
+               vertex_stencils->GetNumStencils();
+
+       const int num_coarse_verts = refiner->GetLevel(0).GetNumVertices();
+
+       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);
+
+       OpenSubdiv_EvaluatorDescr *evaluator_descr;
+       evaluator_descr = OBJECT_GUARDED_NEW(OpenSubdiv_EvaluatorDescr);
+       evaluator_descr->eval_output = eval_output;
+       evaluator_descr->patch_map = patch_map;
+       evaluator_descr->patch_table = patch_table;
+
+       /* TOOD(sergey): Look into whether w've got duplicated stencils arrays. */
+       delete varying_stencils;
+       delete vertex_stencils;
+
+       delete refiner;
+
+       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,
+                                            float *positions,
+                                            int start_vert,
+                                            int num_verts)
+{
+       /* TODO(sergey): Add sanity check on indices. */
+       evaluator_descr->eval_output->UpdateData(positions, start_vert, num_verts);
+       /* TODO(sergey): Consider moving this to a separate call,
+        * so we can updatwe coordinates in chunks.
+        */
+       evaluator_descr->eval_output->Refine();
+}
+
+void openSubdiv_setEvaluatorVaryingData(OpenSubdiv_EvaluatorDescr *evaluator_descr,
+                                        float *varying_data,
+                                        int start_vert,
+                                        int num_verts)
+{
+       /* TODO(sergey): Add sanity check on indices. */
+       evaluator_descr->eval_output->UpdateVaryingData(varying_data, start_vert, num_verts);
+       /* TODO(sergey): Get rid of this ASAP. */
+       evaluator_descr->eval_output->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_gpu_capi.cc b/intern/opensubdiv/opensubdiv_gpu_capi.cc
new file mode 100644 (file)
index 0000000..8b3f144
--- /dev/null
@@ -0,0 +1,659 @@
+/*
+ * ***** 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 *****
+ */
+
+/* Do some compatibility hacks in order to make
+ * the code working with GPU_material pipeline.
+ */
+#define GLSL_COMPAT_WORKAROUND
+
+#include "opensubdiv_capi.h"
+
+#ifdef _MSC_VER
+#  include "iso646.h"
+#endif
+
+#include <cstdio>
+#include <cmath>
+#include <GL/glew.h>
+
+#include <opensubdiv/osd/glMesh.h>
+
+#ifdef OPENSUBDIV_HAS_CUDA
+#  include <opensubdiv/osd/cudaGLVertexBuffer.h>
+#endif  /* OPENSUBDIV_HAS_CUDA */
+
+#include <opensubdiv/osd/cpuGLVertexBuffer.h>
+#include <opensubdiv/osd/cpuEvaluator.h>
+
+#include "opensubdiv_partitioned.h"
+
+//using OpenSubdiv::FarPatchTables;
+using OpenSubdiv::Osd::GLMeshInterface;
+//sing OpenSubdiv::PartitionedGLMeshInterface;
+
+extern "C" char datatoc_gpu_shader_opensubd_display_glsl[];
+
+#define MAX_LIGHTS 8
+typedef struct Light {
+       float position[4];
+       float ambient[4];
+       float diffuse[4];
+       float specular[4];
+       float spot_direction[4];
+       float constant_attenuation;
+       float linear_attenuation;
+       float quadratic_attenuation;
+       float spot_cutoff;
+       float spot_exponent;
+       float spot_cos_cutoff;
+       float pad[2];
+} Light;
+
+typedef struct Lighting {
+       Light lights[MAX_LIGHTS];
+       int num_enabled;
+       int pad[3];
+} 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 = -1;
+
+static GLuint g_flat_fill_program = 0;
+static GLuint g_smooth_fill_program = 0;
+static GLuint g_wireframe_program = 0;
+
+static GLuint g_lighting_ub = 0;
+static Lighting g_lighting_data;
+static Transform g_transform;
+
+/* TODO(sergey): This is actually duplicated code from BLI. */
+namespace {
+void copy_m3_m3(float m1[3][3], float m2[3][3])
+{
+       /* destination comes first: */
+       memcpy(&m1[0], &m2[0], 9 * sizeof(float));
+}
+
+void copy_m3_m4(float m1[3][3], float m2[4][4])
+{
+       m1[0][0] = m2[0][0];
+       m1[0][1] = m2[0][1];
+       m1[0][2] = m2[0][2];
+
+       m1[1][0] = m2[1][0];
+       m1[1][1] = m2[1][1];
+       m1[1][2] = m2[1][2];
+
+       m1[2][0] = m2[2][0];
+       m1[2][1] = m2[2][1];
+       m1[2][2] = m2[2][2];
+}
+
+void adjoint_m3_m3(float m1[3][3], float m[3][3])
+{
+       m1[0][0] = m[1][1] * m[2][2] - m[1][2] * m[2][1];
+       m1[0][1] = -m[0][1] * m[2][2] + m[0][2] * m[2][1];
+       m1[0][2] = m[0][1] * m[1][2] - m[0][2] * m[1][1];
+
+       m1[1][0] = -m[1][0] * m[2][2] + m[1][2] * m[2][0];
+       m1[1][1] = m[0][0] * m[2][2] - m[0][2] * m[2][0];
+       m1[1][2] = -m[0][0] * m[1][2] + m[0][2] * m[1][0];
+
+       m1[2][0] = m[1][0] * m[2][1] - m[1][1] * m[2][0];
+       m1[2][1] = -m[0][0] * m[2][1] + m[0][1] * m[2][0];
+       m1[2][2] = m[0][0] * m[1][1] - m[0][1] * m[1][0];
+}
+
+float determinant_m3_array(float m[3][3])
+{
+       return (m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1]) -
+               m[1][0] * (m[0][1] * m[2][2] - m[0][2] * m[2][1]) +
+               m[2][0] * (m[0][1] * m[1][2] - m[0][2] * m[1][1]));
+}
+
+bool invert_m3_m3(float m1[3][3], float m2[3][3])
+{
+       float det;
+       int a, b;
+       bool success;
+
+       /* calc adjoint */
+       adjoint_m3_m3(m1, m2);
+
+       /* then determinant old matrix! */
+       det = determinant_m3_array(m2);
+
+       success = (det != 0.0f);
+
+       if (det != 0.0f) {
+               det = 1.0f / det;
+               for (a = 0; a < 3; a++) {
+                       for (b = 0; b < 3; b++) {
+                               m1[a][b] *= det;
+                       }
+               }
+       }
+
+       return success;
+}
+
+bool invert_m3(float m[3][3])
+{
+       float tmp[3][3];
+       bool success;
+
+       success = invert_m3_m3(tmp, m);
+       copy_m3_m3(m, tmp);
+
+       return success;
+}
+
+void transpose_m3(float mat[3][3])
+{
+       float t;
+
+       t = mat[0][1];
+       mat[0][1] = mat[1][0];
+       mat[1][0] = t;
+       t = mat[0][2];
+       mat[0][2] = mat[2][0];
+       mat[2][0] = t;
+       t = mat[1][2];
+       mat[1][2] = mat[2][1];
+       mat[2][1] = t;
+}
+
+GLuint compileShader(GLenum shaderType,
+                     const char *section,
+                     const char *define)
+{
+       const char *sources[3];
+       char sdefine[64];
+       sprintf(sdefine, "#define %s\n#define GLSL_COMPAT_WORKAROUND\n", section);
+
+       sources[0] = define;
+       sources[1] = sdefine;
+       sources[2] = datatoc_gpu_shader_opensubd_display_glsl;
+
+       GLuint shader = glCreateShader(shaderType);
+       glShaderSource(shader, 3, 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 shader (%s): %s\n", section, emsg);
+               fprintf(stderr, "Section: %s\n", sdefine);
+               fprintf(stderr, "Defines: %s\n", define);
+               fprintf(stderr, "Source: %s\n", sources[2]);
+               exit(1);
+       }
+
+       return shader;
+}
+
+GLuint linkProgram(const char *define)
+{
+       GLuint vertexShader = compileShader(GL_VERTEX_SHADER,
+                                           "VERTEX_SHADER",
+                                           define);
+       GLuint geometryShader = compileShader(GL_GEOMETRY_SHADER,
+                                             "GEOMETRY_SHADER",
+                                             define);
+       GLuint fragmentShader = compileShader(GL_FRAGMENT_SHADER,
+                                             "FRAGMENT_SHADER",
+                                             define);
+
+       GLuint program = glCreateProgram();
+
+       glAttachShader(program, vertexShader);
+       glAttachShader(program, geometryShader);
+       glAttachShader(program, fragmentShader);
+
+       glBindAttribLocation(program, 0, "position");
+       glBindAttribLocation(program, 1, "normal");
+
+#ifdef GLSL_COMPAT_WORKAROUND
+       glProgramParameteriEXT(program,
+                              GL_GEOMETRY_INPUT_TYPE_EXT,
+                              GL_LINES_ADJACENCY_EXT);
+
+       if (strstr(define, "WIREFRAME") == NULL) {
+               glProgramParameteriEXT(program,
+                                      GL_GEOMETRY_OUTPUT_TYPE_EXT,
+                                      GL_TRIANGLE_STRIP);
+
+               glProgramParameteriEXT(program,
+                                      GL_GEOMETRY_VERTICES_OUT_EXT,
+                                      4);
+       }
+       else {
+               glProgramParameteriEXT(program,
+                                      GL_GEOMETRY_OUTPUT_TYPE_EXT,
+                                      GL_LINE_STRIP);
+
+               glProgramParameteriEXT(program,
+                                      GL_GEOMETRY_VERTICES_OUT_EXT,
+                                      8);
+       }
+#endif
+
+       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);
+               exit(1);
+       }
+
+       glUniformBlockBinding(program,
+                             glGetUniformBlockIndex(program, "Lighting"),
+                             0);
+
+       glProgramUniform1i(program,
+                          glGetUniformLocation(program, "texture_buffer"),
+                          0);  /* GL_TEXTURE0 */
+
+       glProgramUniform1i(program,
+                          glGetUniformLocation(program, "FVarDataBuffer"),
+                          31);  /* GL_TEXTURE31 */
+
+       return program;
+}
+
+void bindProgram(PartitionedGLMeshInterface * /*mesh*/,
+                 int program)
+{
+       glUseProgram(program);
+
+       /* Matricies */
+       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);
+
+       /* Ligthing */
+       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 */
+       GLboolean use_lighting, use_color_material, use_texture_2d;
+       glGetBooleanv(GL_LIGHTING, &use_lighting);
+       glGetBooleanv(GL_COLOR_MATERIAL, &use_color_material);
+       glGetBooleanv(GL_TEXTURE_2D, &use_texture_2d);
+
+       glUniform1i(glGetUniformLocation(program, "use_color_material"),
+                   use_color_material);
+       glUniform1i(glGetUniformLocation(program, "use_texture_2d"),
+                   use_texture_2d);
+
+       if (use_lighting) {
+               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]);
+       }
+       else {
+               float color[4];
+               glGetFloatv(GL_CURRENT_COLOR, color);
+               glUniform4fv(glGetUniformLocation(program, "diffuse"), 1, color);
+       }
+
+       /* TODO(sergey): Bring face varying back. */
+#if 0
+       /* Face-vertex data */
+       if (mesh->GetDrawContext()->GetFvarDataTextureBuffer()) {
+               glActiveTexture(GL_TEXTURE31);
+               glBindTexture(GL_TEXTURE_BUFFER,
+                             mesh->GetDrawContext()->GetFvarDataTextureBuffer());
+               glActiveTexture(GL_TEXTURE0);
+       }
+#endif
+
+       /* TODO(sergey): Bring face varying back. */
+       glUniform1i(glGetUniformLocation(program, "osd_fvar_count"),
+                   0/* * mesh->GetFVarCount()*/);
+
+       glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"),
+                   g_active_uv_index * 2);
+}
+
+}  /* namespace */
+
+void openSubdiv_osdGLDisplayInit(void)
+{
+       static bool need_init = true;
+       if (need_init) {
+               g_flat_fill_program = linkProgram("#define FLAT_SHADING\n");
+               g_smooth_fill_program = linkProgram("#define SMOOTH_SHADING\n");
+               g_wireframe_program = linkProgram("#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;
+       }
+}
+
+void openSubdiv_osdGLDisplayDeinit(void)
+{
+       if (g_lighting_ub != 0) {
+               glDeleteBuffers(1, &g_lighting_ub);
+       }
+       if (g_flat_fill_program) {
+               glDeleteProgram(g_flat_fill_program);
+       }
+       if (g_smooth_fill_program) {
+               glDeleteProgram(g_flat_fill_program);
+       }
+       if (g_wireframe_program) {
+               glDeleteProgram(g_wireframe_program);
+       }
+}
+
+void openSubdiv_osdGLMeshDisplayPrepare(int use_osd_glsl,
+                                        int active_uv_index)
+{
+       g_use_osd_glsl = use_osd_glsl != 0;
+       g_active_uv_index = active_uv_index;
+
+       /* Update transformation matricies. */
+       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++;
+               }
+
+               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);
+               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);
+       }
+}
+
+static GLuint preapre_patchDraw(PartitionedGLMeshInterface *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);
+                       }
+
+                       /* TODO(sergey): Bring this back. */
+#if 0
+                       /* Face-vertex data */
+                       if (mesh->GetDrawContext()->GetFvarDataTextureBuffer()) {
+                               glActiveTexture(GL_TEXTURE31);
+                               glBindTexture(GL_TEXTURE_BUFFER,
+                                             mesh->GetDrawContext()->GetFvarDataTextureBuffer());
+                               glActiveTexture(GL_TEXTURE0);
+
+                               GLint location = glGetUniformLocation(program, "osd_fvar_count");
+                               if (location != -1) {
+                                       glUniform1i(location, mesh->GetFVarCount());
+                               }
+
+                               location = glGetUniformLocation(program, "osd_active_uv_offset");
+                               if (location != -1) {
+                                       glUniform1i(location,
+                                                   g_active_uv_index * 2);
+                               }
+                       }
+#endif
+
+               }
+               return program;
+       }
+
+       program = g_smooth_fill_program;
+       if (fill_quads) {
+               int model;
+               glGetIntegerv(GL_SHADE_MODEL, &model);
+               if (model == GL_FLAT) {
+                       program = g_flat_fill_program;
+               }
+       }
+       else {
+               glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+               program = g_wireframe_program;
+       }
+
+       bindProgram(mesh, program);
+
+       return program;
+}
+
+static void perform_drawElements(GLuint program,
+                                 int patch_index,
+                                 int num_elements,
+                                 int start_element)
+{
+       int mode = GL_QUADS;
+       if (program) {
+               glUniform1i(glGetUniformLocation(program, "PrimitiveIdBase"),
+                           patch_index);
+       }
+       mode = GL_LINES_ADJACENCY;
+       glDrawElements(mode,
+                      num_elements,
+                      GL_UNSIGNED_INT,
+                      (void *)(start_element * sizeof(unsigned int)));
+}
+
+static void finish_patchDraw(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);
+       }
+}
+
+static void draw_partition_patches_range(PartitionedGLMeshInterface *mesh,
+                                         GLuint program,
+                                         int start_partition,
+                                         int num_partitions)
+{
+#if 0
+       /* Glue patches from all partitions in the range together. */
+       int patch_index = -1, start_element = -1, num_elements = 0;
+       for (int partition = start_partition;
+            partition < start_partition + num_partitions;
+            ++partition)
+       {
+               OsdDrawContext::PatchArrayVector const &patches =
+                       mesh->GetPatchArrays(partition);
+               for (int i = 0; i < (int)patches.size(); ++i) {
+                       OsdDrawContext::PatchArray const &patch = patches[i];
+                       OsdDrawContext::PatchDescriptor desc = patch.GetDescriptor();
+                       OpenSubdiv::FarPatchTables::Type patchType = desc.GetType();
+                       if (patchType == OpenSubdiv::FarPatchTables::QUADS) {
+                               if (start_element == -1) {
+                                       patch_index = patch.GetPatchIndex();
+                                       start_element = patch.GetVertIndex();
+                               }
+
+                               assert(patch.GetVertIndex() == start_element + num_elements);
+                               num_elements += patch.GetNumIndices();
+                       }
+                       else {
+                               assert(!"Discontinuitied are not supported yet.");
+                       }
+               }
+       }
+
+       /* Perform actual draw. */
+       perform_drawElements(program,
+                            patch_index,
+                            num_elements,
+                            start_element);
+#else
+       (void)mesh;
+       (void)program;
+       (void)start_partition;
+       (void)num_partitions;
+#endif
+}
+
+static void draw_all_patches(PartitionedGLMeshInterface *mesh,
+                             GLuint program)
+{
+       const OpenSubdiv::Osd::PatchArrayVector& patches =
+               mesh->GetPatchTable()->GetPatchArrays();
+       for (int i = 0; i < (int)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());
+               }
+    }
+}
+
+void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh,
+                                 int fill_quads,
+                                 int start_partition,
+                                 int num_partitions)
+{
+       PartitionedGLMeshInterface *mesh =
+               (PartitionedGLMeshInterface *)(gl_mesh->descriptor);
+
+       /* Make sure all global invariants are initialized. */
+       openSubdiv_osdGLDisplayInit();
+
+       /* Setup GLSL/OpenGL to draw patches in current context. */
+       GLuint program = preapre_patchDraw(mesh, fill_quads != 0);
+
+       if (start_partition != -1) {
+#if 0
+               draw_partition_patches_range(mesh,
+                                            program,
+                                            start_partition,
+                                            num_partitions);
+#else
+               (void)num_partitions;
+               if(start_partition == 0) {
+                       draw_all_patches(mesh, program);
+               }
+#endif
+       }
+       else {
+               draw_all_patches(mesh, program);
+       }
+
+       /* Finish patch drawing by restoring all changes to the OpenGL context. */
+       finish_patchDraw(fill_quads != 0);
+}
diff --git a/intern/opensubdiv/opensubdiv_intern.h b/intern/opensubdiv/opensubdiv_intern.h
new file mode 100644 (file)
index 0000000..034677f
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * ***** 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
+#  define OPENSUBDIV_VALIDATE_TOPOLOGY
+#endif
+
+#endif  /* __OPENSUBDIV_INTERN_H__ */
diff --git a/intern/opensubdiv/opensubdiv_partitioned.h b/intern/opensubdiv/opensubdiv_partitioned.h
new file mode 100644 (file)
index 0000000..7394a83
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * ***** 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_PATITIONED_H__
+#define __OPENSUBDIV_PATITIONED_H__
+
+#include <opensubdiv/osd/glMesh.h>
+#include <opensubdiv/osd/cpuEvaluator.h>
+#include <opensubdiv/osd/glVertexBuffer.h>
+
+namespace OpenSubdiv {
+namespace OPENSUBDIV_VERSION {
+namespace Osd {
+
+/* TODO(sergey): Re-implement partitioning. */
+
+#if 0
+template <class PATCH_TABLE>
+class PartitionedMeshInterface : public MeshInterface<PATCH_TABLE> {
+       typedef PATCH_TABLE PatchTable;
+       typedef typename PatchTable::VertexBufferBinding VertexBufferBinding;
+
+public:
+};
+
+typedef PartitionedMeshInterface<GLPatchTable> PartitionedGLMeshInterface;
+
+#endif
+
+#if 0
+template <typename VERTEX_BUFFER,
+          typename STENCIL_TABLE,
+          typename EVALUATOR,
+          typename PATCH_TABLE,
+          typename DEVICE_CONTEXT = void>
+class PartitionedMesh : public Mesh<VERTEX_BUFFER,
+                                    STENCIL_TABLE,
+                                    EVALUATOR,
+                                    PATCH_TABLE,
+                                    DEVICE_CONTEXT>
+{
+};
+#endif
+
+#define PartitionedGLMeshInterface GLMeshInterface
+#define PartitionedMesh Mesh
+
+}  /* namespace Osd */
+}  /* namespace OPENSUBDIV_VERSION */
+
+using namespace OPENSUBDIV_VERSION;
+
+}  /* namespace OpenSubdiv */
+
+#endif  /* __OPENSUBDIV_PATITIONED_H__ */
diff --git a/intern/opensubdiv/opensubdiv_utils_capi.cc b/intern/opensubdiv/opensubdiv_utils_capi.cc
new file mode 100644 (file)
index 0000000..5a2d017
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * ***** 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 <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)
+{
+       if (!openSubdiv_supportGPUDisplay()) {
+               return 0;
+       }
+
+       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_ARB_texture_buffer_object) {
+               flags |= OPENSUBDIV_EVALUATOR_GLSL_TRANSFORM_FEEDBACK;
+       }
+#endif  /* OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK */
+
+#ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
+       flags |= OPENSUBDIV_EVALUATOR_GLSL_COMPUTE;
+#endif  /* OPENSUBDIV_HAS_GLSL_COMPUTE */
+
+       return flags;
+}
+
+void openSubdiv_cleanup(void)
+{
+       openSubdiv_osdGLDisplayDeinit();
+}