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:
parent
ccc3c2dbda
commit
a040157e5d
111
build_files/cmake/Modules/FindOpenSubdiv.cmake
Normal file
111
build_files/cmake/Modules/FindOpenSubdiv.cmake
Normal file
@ -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()
|
90
intern/opensubdiv/CMakeLists.txt
Normal file
90
intern/opensubdiv/CMakeLists.txt
Normal file
@ -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}")
|
67
intern/opensubdiv/SConscript
Normal file
67
intern/opensubdiv/SConscript
Normal file
@ -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])
|
335
intern/opensubdiv/gpu_shader_opensubd_display.glsl
Normal file
335
intern/opensubdiv/gpu_shader_opensubd_display.glsl
Normal file
@ -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
|
303
intern/opensubdiv/opensubdiv_capi.cc
Normal file
303
intern/opensubdiv/opensubdiv_capi.cc
Normal file
@ -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;
|
||||
}
|
150
intern/opensubdiv/opensubdiv_capi.h
Normal file
150
intern/opensubdiv/opensubdiv_capi.h
Normal file
@ -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__
|
341
intern/opensubdiv/opensubdiv_converter.cc
Normal file
341
intern/opensubdiv/opensubdiv_converter.cc
Normal file
@ -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;
|
||||
}
|
120
intern/opensubdiv/opensubdiv_converter_capi.h
Normal file
120
intern/opensubdiv/opensubdiv_converter_capi.h
Normal file
@ -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__ */
|
237
intern/opensubdiv/opensubdiv_device_context_cuda.cc
Normal file
237
intern/opensubdiv/opensubdiv_device_context_cuda.cc
Normal file
@ -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 */
|
54
intern/opensubdiv/opensubdiv_device_context_cuda.h
Normal file
54
intern/opensubdiv/opensubdiv_device_context_cuda.h
Normal file
@ -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__ */
|
251
intern/opensubdiv/opensubdiv_device_context_opencl.cc
Normal file
251
intern/opensubdiv/opensubdiv_device_context_opencl.cc
Normal file
@ -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 */
|
58
intern/opensubdiv/opensubdiv_device_context_opencl.h
Normal file
58
intern/opensubdiv/opensubdiv_device_context_opencl.h
Normal file
@ -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__ */
|
499
intern/opensubdiv/opensubdiv_evaluator_capi.cc
Normal file
499
intern/opensubdiv/opensubdiv_evaluator_capi.cc
Normal file
@ -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);
|
||||
}
|
659
intern/opensubdiv/opensubdiv_gpu_capi.cc
Normal file
659
intern/opensubdiv/opensubdiv_gpu_capi.cc
Normal file
@ -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);
|
||||
}
|
36
intern/opensubdiv/opensubdiv_intern.h
Normal file
36
intern/opensubdiv/opensubdiv_intern.h
Normal file
@ -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__ */
|
77
intern/opensubdiv/opensubdiv_partitioned.h
Normal file
77
intern/opensubdiv/opensubdiv_partitioned.h
Normal file
@ -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__ */
|
83
intern/opensubdiv/opensubdiv_utils_capi.cc
Normal file
83
intern/opensubdiv/opensubdiv_utils_capi.cc
Normal file
@ -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();
|
||||
}
|
Loading…
Reference in New Issue
Block a user