OpenSubdiv: Add new OpenSubdiv related files

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.
This commit is contained in:
Sergey Sharybin 2015-07-20 15:18:35 +02:00
parent ccc3c2dbda
commit a040157e5d
17 changed files with 3471 additions and 0 deletions

@ -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()

@ -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}")

@ -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])

@ -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

@ -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;
}

@ -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__

@ -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;
}

@ -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__ */

@ -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 */

@ -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__ */

@ -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 */

@ -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__ */

@ -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);
}

@ -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);
}

@ -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__ */

@ -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__ */

@ -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();
}