OpenSubdiv: Commit of OpenSubdiv integration into Blender

This commit contains all the remained parts needed for initial integration of
OpenSubdiv into Blender's subdivision surface code. Includes both GPU and CPU
backends which works in the following way:

- When SubSurf modifier is the last in the modifiers stack then GPU pipeline
  of OpenSubdiv is used, making viewport performance as fast as possible.

  This also requires graphscard with GLSL 1.5 support. If this requirement is
  not met, then no GPU pipeline is used at all.

- If SubSurf is not a last modifier or if DerivesMesh is being evaluated for
  rendering then CPU limit evaluation API from OpenSubdiv is used. This only
  replaces the legacy evaluation code from CCGSubSurf_legacy, but keeps CCG
  structures exactly the same as they used to be for ages now.

This integration is fully covered with ifdef and not enabled by default
because there are several TODOs to be solved first:

- Face varying data interpolation is not really cleanly implemented for GPU
  in OpenSubdiv 3.0. It is also not implemented for limit evaluation API.

  This basically means we'll have really hard time supporting UVs.

- Limit evaluation only works with adaptivly subdivided meshes so far, which
  basically means all the points of CCG are pushed to the limit. This gives
  different result from old code.

- There are some serious optimizations possible on the topology refiner
  creation, which would speed up initial OpenSubdiv mesh creation.

- There are some hardcoded asumptions in the GPU and DerivedMesh areas which
  could be generalized.

  That's something where Antony and Campbell can help, making it so the code
  is structured in a way which is reusable by all planned viewport projects.

- There are also some workarounds in the dependency graph to make sure OpenGL
  buffers are only freed from the main thread.

Those who'll be wanting to make experiments with this code should grab dev
branch (NOT master) from

  https://github.com/Nazg-Gul/OpenSubdiv/tree/dev

There are some patches applied in there which we're working on on getting
into upstream.
This commit is contained in:
Sergey Sharybin 2015-07-20 16:08:06 +02:00
parent 2466c4f8ce
commit 3d36489672
53 changed files with 1557 additions and 191 deletions

View File

@ -227,6 +227,8 @@ option(WITH_COMPOSITOR "Enable the tile based nodal compositor" ON)
option(WITH_COMPOSITOR_WERROR "Treat warnings as errors in compositor code" OFF)
mark_as_advanced(WITH_COMPOSITOR_WERROR)
option(WITH_OPENSUBDIV "Enable OpenSubdiv for surface subdivision" OFF)
# GHOST Windowing Library Options
option(WITH_GHOST_DEBUG "Enable debugging output for the GHOST library" OFF)
mark_as_advanced(WITH_GHOST_DEBUG)
@ -1084,6 +1086,18 @@ if(UNIX AND NOT APPLE)
set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -Wl,--version-script='${CMAKE_SOURCE_DIR}/source/creator/blender.map'")
endif()
if(WITH_OPENSUBDIV)
find_package_wrapper(OpenSubdiv)
set(OPENSUBDIV_LIBRARIES ${OPENSUBDIV_LIBRARIES})
set(OPENSUBDIV_LIBPATH) # TODO, remove and reference the absolute path everywhere
if(NOT OPENSUBDIV_FOUND)
set(WITH_OPENSUBDIV OFF)
message(STATUS "OpenSundiv not found")
endif()
endif()
# OpenSuse needs lutil, ArchLinux not, for now keep, can avoid by using --as-needed
list(APPEND PLATFORM_LINKLIBS -lutil -lc -lm)
@ -1504,6 +1518,13 @@ elseif(WIN32)
)
endif()
if(WITH_OPENSUBDIV)
set(OPENSUBDIV_INCLUDE_DIR ${LIBDIR}/opensubdiv/include)
set(OPENSUBDIV_LIBPATH ${LIBDIR}/opensubdiv/lib)
set(OPENSUBDIV_LIBRARIES ${OPENSUBDIV_LIBPATH}/osdCPU.lib ${OPENSUBDIV_LIBPATH}/osdGPU.lib)
find_package(OpenSubdiv)
endif()
if(WITH_SDL)
set(SDL ${LIBDIR}/sdl)
set(SDL_INCLUDE_DIR ${SDL}/include)
@ -1830,6 +1851,17 @@ elseif(APPLE)
endif()
endif()
if(WITH_OPENSUBDIV)
set(OPENSUBDIV ${LIBDIR}/opensubdiv)
set(OPENSUBDIV_LIBPATH ${OPENSUBDIV}/lib)
find_library(OSL_LIB_UTIL NAMES osdutil PATHS ${OPENSUBDIV_LIBPATH})
find_library(OSL_LIB_CPU NAMES osdCPU PATHS ${OPENSUBDIV_LIBPATH})
find_library(OSL_LIB_GPU NAMES osdGPU PATHS ${OPENSUBDIV_LIBPATH})
set(OPENSUBDIV_INCLUDE_DIR ${OPENSUBDIV}/include)
set(OPENSUBDIV_INCLUDE_DIRS ${OPENSUBDIV_INCLUDE_DIR})
list(APPEND OPENSUBDIV_LIBRARIES ${OSL_LIB_UTIL} ${OSL_LIB_CPU} ${OSL_LIB_GPU})
endif()
if(WITH_JACK)
find_library(JACK_FRAMEWORK
NAMES jackmp

View File

@ -766,6 +766,8 @@ if B.targets != ['cudakernels']:
data_to_c_simple("release/datafiles/preview_cycles.blend")
# --- glsl ---
data_to_c_simple("source/blender/gpu/shaders/gpu_shader_geometry.glsl")
data_to_c_simple("source/blender/gpu/shaders/gpu_program_smoke_frag.glsl")
data_to_c_simple("source/blender/gpu/shaders/gpu_program_smoke_color_frag.glsl")
@ -789,6 +791,7 @@ if B.targets != ['cudakernels']:
data_to_c_simple("source/blender/gpu/shaders/gpu_shader_fx_depth_resolve.glsl")
data_to_c_simple("source/blender/gpu/shaders/gpu_shader_fx_vert.glsl")
data_to_c_simple("intern/opencolorio/gpu_shader_display_transform.glsl")
data_to_c_simple("intern/opensubdiv/gpu_shader_opensubd_display.glsl")
# --- blender ---
data_to_c_simple("release/datafiles/bfont.pfb")

View File

@ -370,6 +370,16 @@ function(setup_liblinks
if(WITH_OPENCOLORIO)
target_link_libraries(${target} ${OPENCOLORIO_LIBRARIES})
endif()
if(WITH_OPENSUBDIV)
if(WIN32 AND NOT UNIX)
file_list_suffix(OPENSUBDIV_LIBRARIES_DEBUG "${OPENSUBDIV_LIBRARIES}" "_d")
target_link_libraries_debug(${target} "${OPENSUBDIV_LIBRARIES_DEBUG}")
target_link_libraries_optimized(${target} "${OPENSUBDIV_LIBRARIES}")
unset(OPENSUBDIV_LIBRARIES_DEBUG)
else()
target_link_libraries(${target} ${OPENSUBDIV_LIBRARIES})
endif()
endif()
if(WITH_CYCLES_OSL)
target_link_libraries(${target} ${OSL_LIBRARIES})
endif()
@ -674,6 +684,10 @@ function(SETUP_BLENDER_SORTED_LIBS)
list_insert_after(BLENDER_SORTED_LIBS "ge_logic_ngnetwork" "extern_bullet")
endif()
if(WITH_OPENSUBDIV)
list(APPEND BLENDER_SORTED_LIBS bf_intern_opensubdiv)
endif()
foreach(SORTLIB ${BLENDER_SORTED_LIBS})
set(REMLIB ${SORTLIB})
foreach(SEARCHLIB ${BLENDER_LINK_LIBS})

View File

@ -213,6 +213,12 @@ WITH_BF_FREESTYLE = True
#OpenMP ( will be checked for compiler support and turned off eventually )
WITH_BF_OPENMP = True
WITH_BF_OPENSUBDIV = False
BF_OPENSUBDIV = LIBDIR + '/opensubdiv'
BF_OPENSUBDIV_INC = '${BF_OPENSUBDIV}/include'
BF_OPENSUBDIV_LIB = 'osdCPU osdGPU'
BF_OPENSUBDIV_LIBPATH = '${BF_OPENSUBDIV}/lib'
#Ray trace optimization
WITH_BF_RAYOPTIMIZATION = True
BF_RAYOPTIMIZATION_SSE_FLAGS = []

View File

@ -226,6 +226,14 @@ BF_3DMOUSE_LIB_STATIC = '${BF_3DMOUSE_LIBPATH}/libspnav.a'
#Freestyle
WITH_BF_FREESTYLE = True
WITH_BF_OPENSUBDIV = False
WITH_BF_STATICOPENSUBDIV = False
BF_OPENSUBDIV = '/usr'
BF_OPENSUBDIV_INC = '${BF_OPENSUBDIV}/include'
BF_OPENSUBDIV_LIB = 'osdCPU osdGPU'
BF_OPENSUBDIV_LIB_STATIC = '${BF_OPENSUBDIV_LIBPATH}/libosdGPU.a ${BF_OPENSUBDIV_LIBPATH}/libosdCPU.a'
BF_OPENSUBDIV_LIBPATH = '${BF_OPENSUBDIV}/lib'
##
CC = 'gcc'
CXX = 'g++'

View File

@ -166,6 +166,12 @@ BF_BOOST_LIB = 'boost_date_time-mgw46-mt-s-1_49 boost_filesystem-mgw46-mt-s-1_49
BF_BOOST_LIB_INTERNATIONAL = 'boost_locale-mgw46-mt-s-1_49'
BF_BOOST_LIBPATH = '${BF_BOOST}/lib'
WITH_BF_OPENSUBDIV = False
BF_OPENSUBDIV = LIBDIR + '/opensubdiv'
BF_OPENSUBDIV_INC = '${BF_OPENSUBDIV}/include'
BF_OPENSUBDIV_LIB = 'osdCPU osdGPU'
BF_OPENSUBDIV_LIBPATH = '${BF_OPENSUBDIV}/lib'
#Ray trace optimization
WITH_BF_RAYOPTIMIZATION = True
BF_RAYOPTIMIZATION_SSE_FLAGS = ['-msse']

View File

@ -208,6 +208,12 @@ BF_RAYOPTIMIZATION_SSE_FLAGS = ['/arch:SSE']
#Freestyle
WITH_BF_FREESTYLE = True
WITH_BF_OPENSUBDIV = False
BF_OPENSUBDIV = LIBDIR + '/opensubdiv'
BF_OPENSUBDIV_INC = '${BF_OPENSUBDIV}/include'
BF_OPENSUBDIV_LIB = 'osdCPU osdGPU'
BF_OPENSUBDIV_LIBPATH = '${BF_OPENSUBDIV}/lib'
WITH_BF_STATICOPENGL = False
BF_OPENGL_INC = '${BF_OPENGL}/include'
BF_OPENGL_LIBINC = '${BF_OPENGL}/lib'

View File

@ -165,6 +165,12 @@ BF_BOOST_LIB = 'boost_date_time-mgw47-mt-s-1_49 boost_date_time-mgw47-mt-sd-1_49
BF_BOOST_LIB_INTERNATIONAL = ' boost_locale-mgw47-mt-s-1_49 boost_locale-mgw47-mt-sd-1_49'
BF_BOOST_LIBPATH = '${BF_BOOST}/lib'
WITH_BF_OPENSUBDIV = False
BF_OPENSUBDIV = LIBDIR + '/opensubdiv'
BF_OPENSUBDIV_INC = '${BF_OPENSUBDIV}/include'
BF_OPENSUBDIV_LIB = 'osdCPU osdGPU'
BF_OPENSUBDIV_LIBPATH = '${BF_OPENSUBDIV}/lib'
#Ray trace optimization
WITH_BF_RAYOPTIMIZATION = True
BF_RAYOPTIMIZATION_SSE_FLAGS = ['-mmmx', '-msse', '-msse2']

View File

@ -212,6 +212,12 @@ BF_RAYOPTIMIZATION_SSE_FLAGS = ['']
#Freestyle
WITH_BF_FREESTYLE = True
WITH_BF_OPENSUBDIV = False
BF_OPENSUBDIV = LIBDIR + '/opensubdiv'
BF_OPENSUBDIV_INC = '${BF_OPENSUBDIV}/include'
BF_OPENSUBDIV_LIB = 'osdCPU osdGPU'
BF_OPENSUBDIV_LIBPATH = '${BF_OPENSUBDIV}/lib'
WITH_BF_STATICOPENGL = False
BF_OPENGL_INC = '${BF_OPENGL}/include'
BF_OPENGL_LIBINC = '${BF_OPENGL}/lib'

View File

@ -242,6 +242,11 @@ def setup_staticlibs(lenv):
if lenv['WITH_BF_STATIC3DMOUSE']:
statlibs += Split(lenv['BF_3DMOUSE_LIB_STATIC'])
if lenv['WITH_BF_OPENSUBDIV']:
libincs += Split(lenv['BF_OPENSUBDIV_LIBPATH'])
if lenv['WITH_BF_STATICOPENSUBDIV']:
statlibs += Split(lenv['BF_OPENSUBDIV_LIB_STATIC'])
# setting this last so any overriding of manually libs could be handled
if lenv['OURPLATFORM'] not in ('win32-vc', 'win32-mingw', 'win64-vc', 'linuxcross', 'win64-mingw'):
# We must remove any previous items defining this path, for same reason stated above!
@ -344,6 +349,13 @@ def setup_syslibs(lenv):
if not lenv['WITH_BF_STATICPNG']:
syslibs += Split(lenv['BF_PNG_LIB'])
if lenv['WITH_BF_OPENSUBDIV']:
if not lenv['WITH_BF_STATICOPENSUBDIV']:
if lenv['BF_DEBUG'] and lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc', 'win32-mingw', 'win64-mingw'):
syslibs += [osdlib+'_d' for osdlib in Split(lenv['BF_OPENSUBDIV_LIB'])]
else:
syslibs += Split(lenv['BF_OPENSUBDIV_LIB'])
# Hack to pass OSD libraries to linker before extern_{clew,cuew}
for syslib in create_blender_liblist(lenv, 'system'):
syslibs.append(os.path.basename(syslib))

View File

@ -182,7 +182,8 @@ def validate_arguments(args, bc):
'WITH_BF_BOOST', 'WITH_BF_STATICBOOST', 'BF_BOOST', 'BF_BOOST_INC', 'BF_BOOST_LIB', 'BF_BOOST_LIB_INTERNATIONAL', 'BF_BOOST_LIB_STATIC', 'BF_BOOST_LIBPATH',
'WITH_BF_LIBMV', 'WITH_BF_LIBMV_SCHUR_SPECIALIZATIONS',
'WITH_BF_CYCLES_OSL', 'WITH_BF_STATICOSL', 'BF_OSL', 'BF_OSL_INC', 'BF_OSL_LIB', 'BF_OSL_LIBPATH', 'BF_OSL_LIB_STATIC', 'BF_OSL_COMPILER',
'WITH_BF_LLVM', 'WITH_BF_STATICLLVM', 'BF_LLVM', 'BF_LLVM_LIB', 'BF_LLVM_LIBPATH', 'BF_LLVM_LIB_STATIC', 'BF_PROGRAM_LINKFLAGS'
'WITH_BF_LLVM', 'WITH_BF_STATICLLVM', 'BF_LLVM', 'BF_LLVM_LIB', 'BF_LLVM_LIBPATH', 'BF_LLVM_LIB_STATIC', 'BF_PROGRAM_LINKFLAGS',
'WITH_BF_OPENSUBDIV', 'WITH_BF_STATICOPENSUBDIV', 'BF_OPENSUBDIV', 'BF_OPENSUBDIV_INC', 'BF_OPENSUBDIV_LIB', 'BF_OPENSUBDIV_LIBPATH', 'BF_OPENSUBDIV_LIB_STATIC'
]
# Have options here that scons expects to be lists
@ -656,6 +657,14 @@ def read_opts(env, cfg, args):
('BF_PROGRAM_LINKFLAGS', 'Link flags applied only to final binaries (blender and blenderplayer, not makesrna/makesdna)', ''),
(BoolVariable('WITH_BF_OPENSUBDIV', 'Build with OpenSubdiv library', False)),
(BoolVariable('WITH_BF_STATICOPENSUBDIV', 'Staticly link to OpenColorIO', False)),
('BF_OPENSUBDIV', 'OpenSubdiv root path', ''),
('BF_OPENSUBDIV_INC', 'OpenSubdiv include path', ''),
('BF_OPENSUBDIV_LIB', 'OpenSubdiv library', ''),
('BF_OPENSUBDIV_LIBPATH', 'OpenSubdiv library path', ''),
('BF_OPENSUBDIV_LIB_STATIC', 'OpenSubdiv static library', '')
(BoolVariable('WITH_BF_CPP11', '"Build with C++11 standard enabled, for development use only!', False)),
(BoolVariable('WITH_BF_LEGACY_DEPSGRAPH', 'Build Blender with legacy dependency graph', True)),

View File

@ -78,7 +78,7 @@ if(WITH_LZMA)
add_subdirectory(lzma)
endif()
if(WITH_CYCLES OR WITH_COMPOSITOR)
if(WITH_CYCLES OR WITH_COMPOSITOR OR WITH_OPENSUBDIV)
add_subdirectory(clew)
add_subdirectory(cuew)
endif()

2
extern/SConscript vendored
View File

@ -25,7 +25,7 @@ if env['WITH_BF_ELTOPO']:
if env['WITH_BF_BULLET']:
SConscript(['bullet2/src/SConscript'])
if env['WITH_BF_COMPOSITOR'] or env['WITH_BF_CYCLES']:
if env['WITH_BF_COMPOSITOR'] or env['WITH_BF_CYCLES'] or env['WITH_BF_OPENSUBDIV']:
SConscript (['clew/SConscript'])
SConscript (['cuew/SConscript'])

View File

@ -77,8 +77,11 @@ if(WITH_OPENNL)
add_subdirectory(opennl)
endif()
if(WITH_OPENSUBDIV)
add_subdirectory(opensubdiv)
endif()
# only windows needs utf16 converter
if(WIN32)
add_subdirectory(utfconv)
endif()

View File

@ -63,3 +63,5 @@ if env['WITH_BF_BULLET']:
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'win64-mingw', 'linuxcross', 'win64-vc'):
SConscript(['utfconv/SConscript'])
if env['WITH_BF_OPENSUBDIV']:
SConscript (['opensubdiv/SConscript'])

View File

@ -330,6 +330,10 @@ int openSubdiv_topologyRefnerCompareConverter(
}
}
/* Compare sharpness. */
#if 0
/* TODO(sergey): For some reason shrapness is not being reported correctly
* from the base level, which cuases false-positive topology change detection.
*/
for (int edge = 0; edge < num_edges; ++edge) {
float sharpness = base_level.GetEdgeSharpness(edge);
float conv_sharpness = converter->get_edge_sharpness(converter, edge);
@ -337,5 +341,6 @@ int openSubdiv_topologyRefnerCompareConverter(
return false;
}
}
#endif
return true;
}

View File

@ -558,12 +558,12 @@ static void finish_patchDraw(bool fill_quads)
}
}
#if 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;
@ -596,13 +596,8 @@ static void draw_partition_patches_range(PartitionedGLMeshInterface *mesh,
patch_index,
num_elements,
start_element);
#else
(void)mesh;
(void)program;
(void)start_partition;
(void)num_partitions;
#endif
}
#endif
static void draw_all_patches(PartitionedGLMeshInterface *mesh,
GLuint program)

View File

@ -435,6 +435,10 @@ class USERPREF_PT_system(Panel):
sub.active = system.compute_device_type != 'CPU'
sub.prop(system, "compute_device", text="")
if hasattr(system, "opensubdiv_compute_type"):
col.label(text="OpenSubdiv compute:")
col.row().prop(system, "opensubdiv_compute_type", text="")
# 2. Column
column = split.column()
colsplit = column.split(percentage=0.85)

View File

@ -116,6 +116,12 @@ typedef enum ModifierApplyFlag {
MOD_APPLY_IGNORE_SIMPLIFY = 1 << 3, /* Ignore scene simplification flag and use subdivisions
* level set in multires modifier.
*/
MOD_APPLY_ALLOW_GPU = 1 << 4, /* Allow modifier to be applied and stored in the GPU.
* Used by the viewport in order to be able to have SS
* happening on GPU.
* Render pipeline (including viewport render) should
* have DM on the CPU.
*/
} ModifierApplyFlag;

View File

@ -57,7 +57,8 @@ typedef enum {
SUBSURF_IS_FINAL_CALC = 2,
SUBSURF_FOR_EDIT_MODE = 4,
SUBSURF_IN_EDIT_MODE = 8,
SUBSURF_ALLOC_PAINT_MASK = 16
SUBSURF_ALLOC_PAINT_MASK = 16,
SUBSURF_USE_GPU_BACKEND = 32,
} SubsurfFlags;
struct DerivedMesh *subsurf_make_derived_from_derived(
@ -99,7 +100,7 @@ typedef struct CCGDerivedMesh {
struct CCGSubSurf *ss;
int freeSS;
int drawInteriorEdges, useSubsurfUv;
int drawInteriorEdges, useSubsurfUv, useGpuBackend;
struct {int startVert; struct CCGVert *vert; } *vertMap;
struct {int startVert; int startEdge; struct CCGEdge *edge; } *edgeMap;

View File

@ -62,6 +62,8 @@ set(INC_SYS
set(SRC
intern/CCGSubSurf.c
intern/CCGSubSurf_legacy.c
intern/CCGSubSurf_opensubdiv.c
intern/CCGSubSurf_opensubdiv_converter.c
intern/CCGSubSurf_util.c
intern/DerivedMesh.c
intern/action.c
@ -496,6 +498,14 @@ if(WITH_FREESTYLE)
add_definitions(-DWITH_FREESTYLE)
endif()
if(WITH_OPENSUBDIV)
add_definitions(-DWITH_OPENSUBDIV)
list(APPEND INC_SYS
../../../intern/opensubdiv
${OPENSUBDIV_INCLUDE_DIRS}
)
endif()
## Warnings as errors, this is too strict!
#if(MSVC)
# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX")

View File

@ -168,6 +168,11 @@ if env['WITH_BF_INTERNATIONAL']:
if env['WITH_BF_FREESTYLE']:
defs.append('WITH_FREESTYLE')
if env['WITH_BF_OPENSUBDIV']:
defs.append('WITH_OPENSUBDIV')
incs += ' #intern/opensubdiv'
incs += ' ' + env['BF_OPENSUBDIV_INC']
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
incs += ' ' + env['BF_PTHREADS_INC']
incs += ' ../../../intern/utfconv'

View File

@ -37,6 +37,11 @@
#include "CCGSubSurf_intern.h"
#include "BKE_subsurf.h"
#ifdef WITH_OPENSUBDIV
# include "opensubdiv_capi.h"
# include "opensubdiv_converter_capi.h"
#endif
#include "GL/glew.h"
/***/
@ -299,6 +304,23 @@ CCGSubSurf *ccgSubSurf_new(CCGMeshIFC *ifc, int subdivLevels, CCGAllocatorIFC *a
ss->tempVerts = NULL;
ss->tempEdges = NULL;
#ifdef WITH_OPENSUBDIV
ss->osd_evaluator = NULL;
ss->osd_mesh = NULL;
ss->osd_topology_refiner = NULL;
ss->osd_mesh_invalid = false;
ss->osd_coarse_coords_invalid = false;
ss->osd_vao = 0;
ss->skip_grids = false;
ss->osd_compute = 0;
ss->osd_uvs_invalid = true;
ss->osd_subsurf_uv = 0;
ss->osd_uv_index = -1;
ss->osd_next_face_ptex_index = 0;
ss->osd_coarse_coords = NULL;
ss->osd_num_coarse_coords = 0;
#endif
return ss;
}
}
@ -307,6 +329,24 @@ void ccgSubSurf_free(CCGSubSurf *ss)
{
CCGAllocatorIFC allocatorIFC = ss->allocatorIFC;
CCGAllocatorHDL allocator = ss->allocator;
#ifdef WITH_OPENSUBDIV
if (ss->osd_evaluator != NULL) {
openSubdiv_deleteEvaluatorDescr(ss->osd_evaluator);
}
if (ss->osd_mesh != NULL) {
/* TODO(sergey): Make sure free happens form the main thread! */
openSubdiv_deleteOsdGLMesh(ss->osd_mesh);
}
if (ss->osd_vao != 0) {
glDeleteVertexArrays(1, &ss->osd_vao);
}
if (ss->osd_coarse_coords != NULL) {
MEM_freeN(ss->osd_coarse_coords);
}
if (ss->osd_topology_refiner != NULL) {
openSubdiv_deleteTopologyRefinerDescr(ss->osd_topology_refiner);
}
#endif
if (ss->syncState) {
ccg_ehash_free(ss->oldFMap, (EHEntryFreeFP) _face_free, ss);
@ -467,6 +507,9 @@ CCGError ccgSubSurf_initFullSync(CCGSubSurf *ss)
ss->tempEdges = MEM_mallocN(sizeof(*ss->tempEdges) * ss->lenTempArrays, "CCGSubsurf tempEdges");
ss->syncState = eSyncState_Vert;
#ifdef WITH_OPENSUBDIV
ss->osd_next_face_ptex_index = 0;
#endif
return eCCGError_None;
}
@ -607,6 +650,9 @@ CCGError ccgSubSurf_syncVert(CCGSubSurf *ss, CCGVertHDL vHDL, const void *vertDa
ccg_ehash_insert(ss->vMap, (EHEntry *) v);
v->flags = 0;
}
#ifdef WITH_OPENSUBDIV
v->osd_index = ss->vMap->numEntries - 1;
#endif
}
if (v_r) *v_r = v;
@ -789,6 +835,15 @@ CCGError ccgSubSurf_syncFace(CCGSubSurf *ss, CCGFaceHDL fHDL, int numVerts, CCGV
}
}
}
#ifdef WITH_OPENSUBDIV
f->osd_index = ss->osd_next_face_ptex_index;
if (numVerts == 4) {
ss->osd_next_face_ptex_index++;
}
else {
ss->osd_next_face_ptex_index += numVerts;
}
#endif
}
if (f_r) *f_r = f;
@ -797,7 +852,18 @@ CCGError ccgSubSurf_syncFace(CCGSubSurf *ss, CCGFaceHDL fHDL, int numVerts, CCGV
static void ccgSubSurf__sync(CCGSubSurf *ss)
{
ccgSubSurf__sync_legacy(ss);
#ifdef WITH_OPENSUBDIV
/* TODO(sergey): This is because OSD evaluator does not support
* bilinear subdivision scheme at this moment.
*/
if (ss->meshIFC.simpleSubdiv == false || ss->skip_grids == true) {
ccgSubSurf__sync_opensubdiv(ss);
}
else
#endif
{
ccgSubSurf__sync_legacy(ss);
}
}
CCGError ccgSubSurf_processSync(CCGSubSurf *ss)
@ -1128,15 +1194,39 @@ CCGError ccgSubSurf_stitchFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, in
int ccgSubSurf_getNumVerts(const CCGSubSurf *ss)
{
return ss->vMap->numEntries;
#ifdef WITH_OPENSUBDIV
if (ss->skip_grids) {
return ccgSubSurf__getNumOsdBaseVerts(ss);
}
else
#endif
{
return ss->vMap->numEntries;
}
}
int ccgSubSurf_getNumEdges(const CCGSubSurf *ss)
{
return ss->eMap->numEntries;
#ifdef WITH_OPENSUBDIV
if (ss->skip_grids) {
return ccgSubSurf__getNumOsdBaseEdges(ss);
}
else
#endif
{
return ss->eMap->numEntries;
}
}
int ccgSubSurf_getNumFaces(const CCGSubSurf *ss)
{
return ss->fMap->numEntries;
#ifdef WITH_OPENSUBDIV
if (ss->skip_grids) {
return ccgSubSurf__getNumOsdBaseFaces(ss);
}
else
#endif
{
return ss->fMap->numEntries;
}
}
CCGVert *ccgSubSurf_getVert(CCGSubSurf *ss, CCGVertHDL v)

View File

@ -80,6 +80,9 @@ void ccgSubSurf_free (CCGSubSurf *ss);
CCGError ccgSubSurf_initFullSync (CCGSubSurf *ss);
CCGError ccgSubSurf_initPartialSync (CCGSubSurf *ss);
#ifdef WITH_OPENSUBDIV
CCGError ccgSubSurf_initOpenSubdivSync (CCGSubSurf *ss);
#endif
CCGError ccgSubSurf_syncVert (CCGSubSurf *ss, CCGVertHDL vHDL, const void *vertData, int seam, CCGVert **v_r);
CCGError ccgSubSurf_syncEdge (CCGSubSurf *ss, CCGEdgeHDL eHDL, CCGVertHDL e_vHDL0, CCGVertHDL e_vHDL1, float crease, CCGEdge **e_r);
@ -190,4 +193,47 @@ CCGFace* ccgFaceIterator_getCurrent (CCGFaceIterator *fi);
int ccgFaceIterator_isStopped (CCGFaceIterator *fi);
void ccgFaceIterator_next (CCGFaceIterator *fi);
#ifdef WITH_OPENSUBDIV
struct DerivedMesh;
/* Check if topology changed and evaluators are to be re-created. */
void ccgSubSurf_checkTopologyChanged(CCGSubSurf *ss, struct DerivedMesh *dm);
/* Create topology refiner from give derived mesh which then later will be
* used for GL mesh creation.
*/
void ccgSubSurf_prepareTopologyRefiner(CCGSubSurf *ss, struct DerivedMesh *dm);
/* Make sure GL mesh exists, up to date and ready to draw. */
bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, bool use_osd_glsl);
/* Draw given partitions of the GL mesh.
*
* TODO(sergey): fill_quads is actually an invariant and should be part
* of the prepare routine.
*/
void ccgSubSurf_drawGLMesh(CCGSubSurf *ss, bool fill_quads,
int start_partition, int num_partitions);
/* Controls whether CCG are needed (Cmeaning CPU evaluation) or fully GPU compute
* and draw is allowed.
*/
void ccgSubSurf_setSkipGrids(CCGSubSurf *ss, bool skip_grids);
bool ccgSubSurf_needGrids(CCGSubSurf *ss);
/* Set evaluator's face varying data from UV coordinates.
* Used for CPU evaluation.
*/
void ccgSubSurf_evaluatorSetFVarUV(CCGSubSurf *ss,
struct DerivedMesh *dm,
int layer_index);
/* TODO(sergey): Temporary call to test things. */
void ccgSubSurf_evaluatorFVarUV(CCGSubSurf *ss,
int face_index, int S,
float grid_u, float grid_v,
float uv[2]);
#endif
#endif /* __CCGSUBSURF_H__ */

View File

@ -161,6 +161,9 @@ typedef enum {
eSyncState_Edge,
eSyncState_Face,
eSyncState_Partial,
#ifdef WITH_OPENSUBDIV
eSyncState_OpenSubdiv,
#endif
} SyncState;
struct CCGSubSurf {
@ -203,6 +206,60 @@ struct CCGSubSurf {
int lenTempArrays;
CCGVert **tempVerts;
CCGEdge **tempEdges;
#ifdef WITH_OPENSUBDIV
/* Skip grids means no CCG geometry is created and subsurf is possible
* to be completely done on GPU.
*/
bool skip_grids;
/* ** GPU backend. ** */
/* Compute device used by GL mesh. */
short osd_compute;
/* Coarse (base mesh) vertex coordinates.
*
* Filled in from the modifier stack and passed to OpenSubdiv compute
* on mesh display.
*/
float (*osd_coarse_coords)[3];
int osd_num_coarse_coords;
/* Denotes whether coarse positions in the GL mesh are invalid.
* Used to avoid updating GL mesh coords on every redraw.
*/
bool osd_coarse_coords_invalid;
/* GL mesh descriptor, used for refinment and draw. */
struct OpenSubdiv_GLMesh *osd_mesh;
/* Refiner which is used to create GL mesh.
*
* Refiner is created from the modifier stack and used later from the main
* thread to construct GL mesh to avoid threaded access to GL.
*/
struct OpenSubdiv_TopologyRefinerDescr *osd_topology_refiner; /* Only used at synchronization stage. */
/* Denotes whether osd_mesh is invalid now due to topology changes and needs
* to be reconstructed.
*
* Reconstruction happens from main thread due to OpenGL communication.
*/
bool osd_mesh_invalid;
/* Vertex array used for osd_mesh draw. */
unsigned int osd_vao;
/* ** CPU backend. ** */
/* Limit evaluator, used to evaluate CCG. */
struct OpenSubdiv_EvaluatorDescr *osd_evaluator;
/* Next PTex face index, used while CCG synchroization
* to fill in PTex index of CCGFace.
*/
int osd_next_face_ptex_index;
/* ** Needs review. ** */
bool osd_subsurf_uv;
int osd_uv_index;
bool osd_uvs_invalid;
#endif
};
/* ** Utility macros ** */

View File

@ -1621,6 +1621,7 @@ static void mesh_calc_modifiers(
const bool useRenderParams, int useDeform,
const bool need_mapping, CustomDataMask dataMask,
const int index, const bool useCache, const bool build_shapekey_layers,
const bool allow_gpu,
/* return args */
DerivedMesh **r_deform, DerivedMesh **r_final)
{
@ -1663,6 +1664,8 @@ static void mesh_calc_modifiers(
if (useCache)
app_flags |= MOD_APPLY_USECACHE;
if (allow_gpu)
app_flags |= MOD_APPLY_ALLOW_GPU;
if (useDeform)
deform_app_flags |= MOD_APPLY_USECACHE;
@ -2327,9 +2330,9 @@ static void editbmesh_calc_modifiers(
}
if (mti->applyModifierEM)
ndm = modwrap_applyModifierEM(md, ob, em, dm, MOD_APPLY_USECACHE);
ndm = modwrap_applyModifierEM(md, ob, em, dm, MOD_APPLY_USECACHE | MOD_APPLY_ALLOW_GPU);
else
ndm = modwrap_applyModifier(md, ob, dm, MOD_APPLY_USECACHE);
ndm = modwrap_applyModifier(md, ob, dm, MOD_APPLY_USECACHE | MOD_APPLY_ALLOW_GPU);
ASSERT_IS_VALID_DM(ndm);
if (ndm) {
@ -2449,6 +2452,23 @@ static void editbmesh_calc_modifiers(
MEM_freeN(deformedVerts);
}
#ifdef WITH_OPENSUBDIV
/* The idea is to skip CPU-side ORCO calculation when
* we'll be using GPU backend of OpenSubdiv. This is so
* playback performance is kept as high as posssible.
*/
static bool calc_modifiers_skip_orco(const Object *ob)
{
const ModifierData *last_md = ob->modifiers.last;
if (last_md != NULL &&
last_md->type == eModifierType_Subsurf)
{
return true;
}
return false;
}
#endif
static void mesh_build_data(
Scene *scene, Object *ob, CustomDataMask dataMask,
const bool build_shapekey_layers, const bool need_mapping)
@ -2458,8 +2478,15 @@ static void mesh_build_data(
BKE_object_free_derived_caches(ob);
BKE_object_sculpt_modifiers_changed(ob);
#ifdef WITH_OPENSUBDIV
if (calc_modifiers_skip_orco(ob)) {
dataMask &= ~CD_MASK_ORCO;
}
#endif
mesh_calc_modifiers(
scene, ob, NULL, false, 1, need_mapping, dataMask, -1, true, build_shapekey_layers,
true,
&ob->derivedDeform, &ob->derivedFinal);
DM_set_object_boundbox(ob, ob->derivedFinal);
@ -2486,6 +2513,12 @@ static void editbmesh_build_data(Scene *scene, Object *obedit, BMEditMesh *em, C
BKE_editmesh_free_derivedmesh(em);
#ifdef WITH_OPENSUBDIV
if (calc_modifiers_skip_orco(obedit)) {
dataMask &= ~CD_MASK_ORCO;
}
#endif
editbmesh_calc_modifiers(
scene, obedit, em, dataMask,
&em->derivedCage, &em->derivedFinal);
@ -2597,7 +2630,7 @@ DerivedMesh *mesh_create_derived_render(Scene *scene, Object *ob, CustomDataMask
DerivedMesh *final;
mesh_calc_modifiers(
scene, ob, NULL, true, 1, false, dataMask, -1, false, false,
scene, ob, NULL, true, 1, false, dataMask, -1, false, false, false,
NULL, &final);
return final;
@ -2608,7 +2641,7 @@ DerivedMesh *mesh_create_derived_index_render(Scene *scene, Object *ob, CustomDa
DerivedMesh *final;
mesh_calc_modifiers(
scene, ob, NULL, true, 1, false, dataMask, index, false, false,
scene, ob, NULL, true, 1, false, dataMask, index, false, false, false,
NULL, &final);
return final;
@ -2627,7 +2660,7 @@ DerivedMesh *mesh_create_derived_view(
ob->transflag |= OB_NO_PSYS_UPDATE;
mesh_calc_modifiers(
scene, ob, NULL, false, 1, false, dataMask, -1, false, false,
scene, ob, NULL, false, 1, false, dataMask, -1, false, false, false,
NULL, &final);
ob->transflag &= ~OB_NO_PSYS_UPDATE;
@ -2642,7 +2675,7 @@ DerivedMesh *mesh_create_derived_no_deform(
DerivedMesh *final;
mesh_calc_modifiers(
scene, ob, vertCos, false, 0, false, dataMask, -1, false, false,
scene, ob, vertCos, false, 0, false, dataMask, -1, false, false, false,
NULL, &final);
return final;
@ -2655,7 +2688,7 @@ DerivedMesh *mesh_create_derived_no_virtual(
DerivedMesh *final;
mesh_calc_modifiers(
scene, ob, vertCos, false, -1, false, dataMask, -1, false, false,
scene, ob, vertCos, false, -1, false, dataMask, -1, false, false, false,
NULL, &final);
return final;
@ -2668,7 +2701,7 @@ DerivedMesh *mesh_create_derived_physics(
DerivedMesh *final;
mesh_calc_modifiers(
scene, ob, vertCos, false, -1, true, dataMask, -1, false, false,
scene, ob, vertCos, false, -1, true, dataMask, -1, false, false, false,
NULL, &final);
return final;
@ -2682,7 +2715,7 @@ DerivedMesh *mesh_create_derived_no_deform_render(
DerivedMesh *final;
mesh_calc_modifiers(
scene, ob, vertCos, true, 0, false, dataMask, -1, false, false,
scene, ob, vertCos, true, 0, false, dataMask, -1, false, false, false,
NULL, &final);
return final;
@ -3400,9 +3433,18 @@ void DM_set_object_boundbox(Object *ob, DerivedMesh *dm)
{
float min[3], max[3];
INIT_MINMAX(min, max);
dm->getMinMax(dm, min, max);
#ifdef WITH_OPENSUBDIV
/* TODO(sergey): Currently no way to access bounding box from hi-res mesh. */
if (dm->type == DM_TYPE_CCGDM) {
copy_v3_fl3(min, -1.0f, -1.0f, -1.0f);
copy_v3_fl3(max, 1.0f, 1.0f, 1.0f);
}
else
#endif
{
INIT_MINMAX(min, max);
dm->getMinMax(dm, min, max);
}
if (!ob->bb)
ob->bb = MEM_callocN(sizeof(BoundBox), "DM-BoundBox");

View File

@ -89,6 +89,11 @@
#include "BKE_unit.h"
#include "BKE_world.h"
#ifdef WITH_OPENSUBDIV
# include "BKE_modifier.h"
# include "CCGSubSurf.h"
#endif
#include "DEG_depsgraph.h"
#include "RE_engine.h"
@ -1345,6 +1350,11 @@ static void scene_do_rb_simulation_recursive(Scene *scene, float ctime)
*/
#define MBALL_SINGLETHREAD_HACK
/* Need this because CCFDM holds some OpenGL resources. */
#ifdef WITH_OPENSUBDIV
# define OPENSUBDIV_GL_WORKAROUND
#endif
#ifdef WITH_LEGACY_DEPSGRAPH
typedef struct StatisicsEntry {
struct StatisicsEntry *next, *prev;
@ -1546,6 +1556,37 @@ static bool scene_need_update_objects(Main *bmain)
DAG_id_type_tagged(bmain, ID_AR); /* Armature */
}
#ifdef OPENSUBDIV_GL_WORKAROUND
/* CCG DrivedMesh currently hold some OpenGL handles, which could only be
* released from the main thread.
*
* Ideally we need to use gpu_buffer_free, but it's a bit tricky because
* some buffers are only accessible from OpenSubdiv side.
*/
static void scene_free_unused_opensubdiv_cache(Scene *scene)
{
Base *base;
for (base = scene->base.first; base; base = base->next) {
Object *object = base->object;
if (object->type == OB_MESH && object->recalc & OB_RECALC_DATA) {
ModifierData *md = object->modifiers.last;
if (md != NULL && md->type == eModifierType_Subsurf) {
SubsurfModifierData *smd = (SubsurfModifierData *) md;
bool object_in_editmode = object->mode == OB_MODE_EDIT;
if (object_in_editmode && smd->mCache != NULL) {
ccgSubSurf_free(smd->mCache);
smd->mCache = NULL;
}
if (!object_in_editmode && smd->emCache != NULL) {
ccgSubSurf_free(smd->emCache);
smd->emCache = NULL;
}
}
}
}
}
#endif
static void scene_update_objects(EvaluationContext *eval_ctx, Main *bmain, Scene *scene, Scene *scene_parent)
{
TaskScheduler *task_scheduler = BLI_task_scheduler_get();
@ -1564,6 +1605,10 @@ static void scene_update_objects(EvaluationContext *eval_ctx, Main *bmain, Scene
return;
}
#ifdef OPENSUBDIV_GL_WORKAROUND
scene_free_unused_opensubdiv_cache(scene);
#endif
state.eval_ctx = eval_ctx;
state.scene = scene;
state.scene_parent = scene_parent;

View File

@ -77,6 +77,10 @@
#include "CCGSubSurf.h"
#ifdef WITH_OPENSUBDIV
# include "opensubdiv_capi.h"
#endif
/* assumes MLoop's are layed out 4 for each poly, in order */
#define USE_LOOP_LAYOUT_FAST
@ -88,7 +92,8 @@ static ThreadRWMutex origindex_cache_rwlock = BLI_RWLOCK_INITIALIZER;
static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
int drawInteriorEdges,
int useSubsurfUv,
DerivedMesh *dm);
DerivedMesh *dm,
bool use_gpu_backend);
static int ccgDM_use_grid_pbvh(CCGDerivedMesh *ccgdm);
///
@ -268,6 +273,7 @@ static int getFaceIndex(CCGSubSurf *ss, CCGFace *f, int S, int x, int y, int edg
}
}
#ifndef WITH_OPENSUBDIV
static void get_face_uv_map_vert(UvVertMap *vmap, struct MPoly *mpoly, struct MLoop *ml, int fi, CCGVertHDL *fverts)
{
UvMapVert *v, *nv;
@ -409,7 +415,96 @@ static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm,
return 1;
}
#endif /* WITH_OPENSUBDIV */
#ifdef WITH_OPENSUBDIV
static void set_subsurf_ccg_uv(CCGSubSurf *ss,
DerivedMesh *dm,
DerivedMesh *result,
int layer_index)
{
CCGFace **faceMap;
MTFace *tf;
MLoopUV *mluv;
CCGFaceIterator fi;
int index, gridSize, gridFaces, totface, x, y, S;
MLoopUV *dmloopuv = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, layer_index);
/* need to update both CD_MTFACE & CD_MLOOPUV, hrmf, we could get away with
* just tface except applying the modifier then looses subsurf UV */
MTFace *tface = CustomData_get_layer_n(&result->faceData, CD_MTFACE, layer_index);
MLoopUV *mloopuv = CustomData_get_layer_n(&result->loopData, CD_MLOOPUV, layer_index);
if (dmloopuv == NULL || (tface == NULL && mloopuv == NULL)) {
return;
}
ccgSubSurf_evaluatorSetFVarUV(ss, dm, layer_index);
/* get some info from CCGSubSurf */
totface = ccgSubSurf_getNumFaces(ss);
gridSize = ccgSubSurf_getGridSize(ss);
gridFaces = gridSize - 1;
/* make a map from original faces to CCGFaces */
faceMap = MEM_mallocN(totface * sizeof(*faceMap), "facemapuv");
for (ccgSubSurf_initFaceIterator(ss, &fi); !ccgFaceIterator_isStopped(&fi); ccgFaceIterator_next(&fi)) {
CCGFace *f = ccgFaceIterator_getCurrent(&fi);
faceMap[GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f))] = f;
}
/* load coordinates from uvss into tface */
tf = tface;
mluv = mloopuv;
for (index = 0; index < totface; index++) {
CCGFace *f = faceMap[index];
int numVerts = ccgSubSurf_getFaceNumVerts(f);
for (S = 0; S < numVerts; S++) {
for (y = 0; y < gridFaces; y++) {
for (x = 0; x < gridFaces; x++) {
float grid_u = ((float)(x)) / (gridSize - 1),
grid_v = ((float)(y)) / (gridSize - 1);
float uv[2];
/* TODO(sergey): Evaluator all 4 corners. */
ccgSubSurf_evaluatorFVarUV(ss,
index,
S,
grid_u, grid_v,
uv);
if (tf) {
copy_v2_v2(tf->uv[0], uv);
copy_v2_v2(tf->uv[1], uv);
copy_v2_v2(tf->uv[2], uv);
copy_v2_v2(tf->uv[3], uv);
tf++;
}
if (mluv) {
copy_v2_v2(mluv[0].uv, uv);
copy_v2_v2(mluv[1].uv, uv);
copy_v2_v2(mluv[2].uv, uv);
copy_v2_v2(mluv[3].uv, uv);
mluv += 4;
}
}
}
}
}
MEM_freeN(faceMap);
}
static void set_subsurf_uv(CCGSubSurf *ss,
DerivedMesh *dm,
DerivedMesh *result,
int layer_index)
{
if (!ccgSubSurf_needGrids(ss)) {
/* GPU backend is used, no need to evaluate UVs on CPU. */
/* TODO(sergey): Think of how to support edit mode of UVs. */
}
else {
set_subsurf_ccg_uv(ss, dm, result, layer_index);
}
}
#else /* WITH_OPENSUBDIV */
static void set_subsurf_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result, int n)
{
CCGSubSurf *uvss;
@ -490,6 +585,7 @@ static void set_subsurf_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result,
ccgSubSurf_free(uvss);
MEM_freeN(faceMap);
}
#endif /* WITH_OPENSUBDIV */
/* face weighting */
typedef struct FaceVertWeightEntry {
@ -571,8 +667,10 @@ static void free_ss_weights(WeightTable *wtable)
MEM_freeN(wtable->weight_table);
}
static void ss_sync_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm,
float (*vertexCos)[3], int useFlatSubdiv)
static void ss_sync_ccg_from_derivedmesh(CCGSubSurf *ss,
DerivedMesh *dm,
float (*vertexCos)[3],
int useFlatSubdiv)
{
float creaseFactor = (float) ccgSubSurf_getSubdivisionLevels(ss);
#ifndef USE_DYNSIZE
@ -672,6 +770,37 @@ static void ss_sync_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm,
#endif
}
#ifdef WITH_OPENSUBDIV
static void ss_sync_osd_from_derivedmesh(CCGSubSurf *ss,
DerivedMesh *dm)
{
ccgSubSurf_initFullSync(ss);
ccgSubSurf_prepareTopologyRefiner(ss, dm);
ccgSubSurf_processSync(ss);
}
#endif /* WITH_OPENSUBDIV */
static void ss_sync_from_derivedmesh(CCGSubSurf *ss,
DerivedMesh *dm,
float (*vertexCos)[3],
int use_flat_subdiv)
{
#ifdef WITH_OPENSUBDIV
/* Reset all related descriptors if actual mesh topology changed or if
* other evlauation-related settings changed.
*/
ccgSubSurf_checkTopologyChanged(ss, dm);
if (!ccgSubSurf_needGrids(ss)) {
/* TODO(sergey): Use vertex coordinates and flat subdiv flag. */
ss_sync_osd_from_derivedmesh(ss, dm);
}
else
#endif
{
ss_sync_ccg_from_derivedmesh(ss, dm, vertexCos, use_flat_subdiv);
}
}
/***/
static int ccgDM_getVertMapIndex(CCGSubSurf *ss, CCGVert *v)
@ -1651,6 +1780,16 @@ static void ccgDM_drawEdges(DerivedMesh *dm, bool drawLooseEdges, bool drawAllEd
int gridSize = ccgSubSurf_getGridSize(ss);
int useAging;
#ifdef WITH_OPENSUBDIV
if (ccgdm->useGpuBackend) {
/* TODO(sergey): We currently only support all edges drawing. */
if (ccgSubSurf_prepareGLMesh(ss, true)) {
ccgSubSurf_drawGLMesh(ss, false, -1, -1);
}
return;
}
#endif
CCG_key_top_level(&key, ss);
ccgdm_pbvh_update(ccgdm);
@ -1722,6 +1861,13 @@ static void ccgDM_drawLooseEdges(DerivedMesh *dm)
int totedge = ccgSubSurf_getNumEdges(ss);
int i, j, edgeSize = ccgSubSurf_getEdgeSize(ss);
#ifdef WITH_OPENSUBDIV
if (ccgdm->useGpuBackend) {
/* TODO(sergey): Needs implementation. */
return;
}
#endif
CCG_key_top_level(&key, ss);
for (j = 0; j < totedge; j++) {
@ -2301,7 +2447,34 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)
return;
}
#ifdef WITH_OPENSUBDIV
if (ccgdm->useGpuBackend) {
CCGSubSurf *ss = ccgdm->ss;
DMFlagMat *faceFlags = ccgdm->faceFlags;
int new_matnr;
bool draw_smooth;
if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, setMaterial != NULL) == false)) {
return;
}
/* TODO(sergey): Single matierial currently. */
if (faceFlags) {
draw_smooth = (faceFlags[0].flag & ME_SMOOTH);
new_matnr = (faceFlags[0].mat_nr + 1);
}
else {
draw_smooth = true;
new_matnr = 1;
}
if (setMaterial) {
setMaterial(new_matnr, NULL);
}
glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
ccgSubSurf_drawGLMesh(ss, true, -1, -1);
return;
}
#endif
GPU_vertex_setup(dm);
GPU_normal_setup(dm);
GPU_triangle_setup(dm);
@ -2334,6 +2507,30 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
short (*lnors)[4][3] = dm->getTessFaceDataArray(dm, CD_TESSLOOPNORMAL);
int a, i, do_draw, numVerts, matnr, new_matnr, totface;
#ifdef WITH_OPENSUBDIV
if (ccgdm->useGpuBackend) {
int new_matnr;
bool draw_smooth;
GPU_draw_update_fvar_offset(dm);
if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, false) == false)) {
return;
}
/* TODO(sergey): Single matierial currently. */
if (faceFlags) {
draw_smooth = (faceFlags[0].flag & ME_SMOOTH);
new_matnr = (faceFlags[0].mat_nr + 1);
}
else {
draw_smooth = true;
new_matnr = 1;
}
glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
setMaterial(new_matnr, &gattribs);
ccgSubSurf_drawGLMesh(ss, true, -1, -1);
return;
}
#endif
CCG_key_top_level(&key, ss);
ccgdm_pbvh_update(ccgdm);
@ -2506,6 +2703,13 @@ static void ccgDM_drawMappedFacesMat(DerivedMesh *dm,
short (*lnors)[4][3] = dm->getTessFaceDataArray(dm, CD_TESSLOOPNORMAL);
int a, i, numVerts, matnr, new_matnr, totface;
#ifdef WITH_OPENSUBDIV
if (ccgdm->useGpuBackend) {
BLI_assert(!"Not currently supported");
return;
}
#endif
CCG_key_top_level(&key, ss);
ccgdm_pbvh_update(ccgdm);
@ -2678,6 +2882,16 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
int mat_index;
int tot_element, start_element, tot_drawn;
#ifdef WITH_OPENSUBDIV
if (ccgdm->useGpuBackend) {
if (ccgSubSurf_prepareGLMesh(ss, true) == false) {
return;
}
ccgSubSurf_drawGLMesh(ss, true, -1, -1);
return;
}
#endif
CCG_key_top_level(&key, ss);
ccgdm_pbvh_update(ccgdm);
@ -2847,6 +3061,26 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm,
int gridFaces = gridSize - 1, totface;
int prev_mat_nr = -1;
#ifdef WITH_OPENSUBDIV
if (ccgdm->useGpuBackend) {
/* TODO(sergey): This is for cases when vertex colors or weights
* are visualising. Currently we don't have CD layers for this data
* and here we only make it so there's no garbage displayed.
*
* In the future we'll either need to have CD for this data or pass
* this data as face-varying or vertex-varying data in OSD mesh.
*/
if (setDrawOptions == NULL) {
glColor3f(0.8f, 0.8f, 0.8f);
}
if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true) == false)) {
return;
}
ccgSubSurf_drawGLMesh(ss, true, -1, -1);
return;
}
#endif
CCG_key_top_level(&key, ss);
/* currently unused -- each original face is handled separately */
@ -3016,6 +3250,13 @@ static void ccgDM_drawMappedEdges(DerivedMesh *dm,
CCGKey key;
int i, useAging, edgeSize = ccgSubSurf_getEdgeSize(ss);
#ifdef WITH_OPENSUBDIV
if (ccgdm->useGpuBackend) {
BLI_assert(!"Not currently supported");
return;
}
#endif
CCG_key_top_level(&key, ss);
ccgSubSurf_getUseAgeCounts(ss, &useAging, NULL, NULL, NULL);
@ -3051,6 +3292,13 @@ static void ccgDM_drawMappedEdgesInterp(DerivedMesh *dm,
CCGEdgeIterator ei;
int i, useAging, edgeSize = ccgSubSurf_getEdgeSize(ss);
#ifdef WITH_OPENSUBDIV
if (ccgdm->useGpuBackend) {
BLI_assert(!"Not currently supported");
return;
}
#endif
CCG_key_top_level(&key, ss);
ccgSubSurf_getUseAgeCounts(ss, &useAging, NULL, NULL, NULL);
@ -3145,9 +3393,11 @@ static void ccgDM_release(DerivedMesh *dm)
if (ccgdm->pmap_mem) MEM_freeN(ccgdm->pmap_mem);
MEM_freeN(ccgdm->edgeFlags);
MEM_freeN(ccgdm->faceFlags);
MEM_freeN(ccgdm->vertMap);
MEM_freeN(ccgdm->edgeMap);
MEM_freeN(ccgdm->faceMap);
if (ccgdm->useGpuBackend == false) {
MEM_freeN(ccgdm->vertMap);
MEM_freeN(ccgdm->edgeMap);
MEM_freeN(ccgdm->faceMap);
}
MEM_freeN(ccgdm);
}
}
@ -3681,74 +3931,8 @@ static void ccgDM_calcNormals(DerivedMesh *dm)
dm->dirty &= ~DM_DIRTY_NORMALS;
}
static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
int drawInteriorEdges,
int useSubsurfUv,
DerivedMesh *dm)
static void set_default_ccgdm_callbacks(CCGDerivedMesh *ccgdm)
{
CCGDerivedMesh *ccgdm = MEM_callocN(sizeof(*ccgdm), "ccgdm");
CCGVertIterator vi;
CCGEdgeIterator ei;
CCGFaceIterator fi;
int index, totvert, totedge, totface;
int i;
int vertNum, edgeNum, faceNum;
int *vertOrigIndex, *faceOrigIndex, *polyOrigIndex, *base_polyOrigIndex, *edgeOrigIndex;
short *edgeFlags;
DMFlagMat *faceFlags;
int *polyidx = NULL;
#ifndef USE_DYNSIZE
int *loopidx = NULL, *vertidx = NULL;
BLI_array_declare(loopidx);
BLI_array_declare(vertidx);
#endif
int loopindex, loopindex2;
int edgeSize;
int gridSize;
int gridFaces, gridCuts;
/*int gridSideVerts;*/
int gridSideEdges;
int numTex, numCol;
int hasPCol, hasOrigSpace;
int gridInternalEdges;
WeightTable wtable = {NULL};
/* MCol *mcol; */ /* UNUSED */
MEdge *medge = NULL;
/* MFace *mface = NULL; */
MPoly *mpoly = NULL;
bool has_edge_cd;
DM_from_template(&ccgdm->dm, dm, DM_TYPE_CCGDM,
ccgSubSurf_getNumFinalVerts(ss),
ccgSubSurf_getNumFinalEdges(ss),
ccgSubSurf_getNumFinalFaces(ss),
ccgSubSurf_getNumFinalFaces(ss) * 4,
ccgSubSurf_getNumFinalFaces(ss));
CustomData_free_layer_active(&ccgdm->dm.polyData, CD_NORMAL,
ccgdm->dm.numPolyData);
numTex = CustomData_number_of_layers(&ccgdm->dm.loopData, CD_MLOOPUV);
numCol = CustomData_number_of_layers(&ccgdm->dm.loopData, CD_MLOOPCOL);
hasPCol = CustomData_has_layer(&ccgdm->dm.loopData, CD_PREVIEW_MLOOPCOL);
hasOrigSpace = CustomData_has_layer(&ccgdm->dm.loopData, CD_ORIGSPACE_MLOOP);
if (
(numTex && CustomData_number_of_layers(&ccgdm->dm.faceData, CD_MTFACE) != numTex) ||
(numCol && CustomData_number_of_layers(&ccgdm->dm.faceData, CD_MCOL) != numCol) ||
(hasPCol && !CustomData_has_layer(&ccgdm->dm.faceData, CD_PREVIEW_MCOL)) ||
(hasOrigSpace && !CustomData_has_layer(&ccgdm->dm.faceData, CD_ORIGSPACE)) )
{
CustomData_from_bmeshpoly(&ccgdm->dm.faceData,
&ccgdm->dm.polyData,
&ccgdm->dm.loopData,
ccgSubSurf_getNumFinalFaces(ss));
}
/* We absolutely need that layer, else it's no valid tessellated data! */
polyidx = CustomData_add_layer(&ccgdm->dm.faceData, CD_ORIGINDEX, CD_CALLOC,
NULL, ccgSubSurf_getNumFinalFaces(ss));
ccgdm->dm.getMinMax = ccgDM_getMinMax;
ccgdm->dm.getNumVerts = ccgDM_getNumVerts;
ccgdm->dm.getNumEdges = ccgDM_getNumEdges;
@ -3801,7 +3985,7 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
ccgdm->dm.foreachMappedEdge = ccgDM_foreachMappedEdge;
ccgdm->dm.foreachMappedLoop = ccgDM_foreachMappedLoop;
ccgdm->dm.foreachMappedFaceCenter = ccgDM_foreachMappedFaceCenter;
ccgdm->dm.drawVerts = ccgDM_drawVerts;
ccgdm->dm.drawEdges = ccgDM_drawEdges;
ccgdm->dm.drawLooseEdges = ccgDM_drawLooseEdges;
@ -3820,14 +4004,22 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
ccgdm->dm.copy_gpu_data = ccgDM_copy_gpu_data;
ccgdm->dm.release = ccgDM_release;
ccgdm->ss = ss;
ccgdm->drawInteriorEdges = drawInteriorEdges;
ccgdm->useSubsurfUv = useSubsurfUv;
}
static void create_ccgdm_maps(CCGDerivedMesh *ccgdm,
CCGSubSurf *ss)
{
CCGVertIterator vi;
CCGEdgeIterator ei;
CCGFaceIterator fi;
int totvert, totedge, totface;
totvert = ccgSubSurf_getNumVerts(ss);
ccgdm->vertMap = MEM_mallocN(totvert * sizeof(*ccgdm->vertMap), "vertMap");
for (ccgSubSurf_initVertIterator(ss, &vi); !ccgVertIterator_isStopped(&vi); ccgVertIterator_next(&vi)) {
for (ccgSubSurf_initVertIterator(ss, &vi);
!ccgVertIterator_isStopped(&vi);
ccgVertIterator_next(&vi))
{
CCGVert *v = ccgVertIterator_getCurrent(&vi);
ccgdm->vertMap[GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v))].vert = v;
@ -3835,7 +4027,10 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
totedge = ccgSubSurf_getNumEdges(ss);
ccgdm->edgeMap = MEM_mallocN(totedge * sizeof(*ccgdm->edgeMap), "edgeMap");
for (ccgSubSurf_initEdgeIterator(ss, &ei); !ccgEdgeIterator_isStopped(&ei); ccgEdgeIterator_next(&ei)) {
for (ccgSubSurf_initEdgeIterator(ss, &ei);
!ccgEdgeIterator_isStopped(&ei);
ccgEdgeIterator_next(&ei))
{
CCGEdge *e = ccgEdgeIterator_getCurrent(&ei);
ccgdm->edgeMap[GET_INT_FROM_POINTER(ccgSubSurf_getEdgeEdgeHandle(e))].edge = e;
@ -3843,13 +4038,60 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
totface = ccgSubSurf_getNumFaces(ss);
ccgdm->faceMap = MEM_mallocN(totface * sizeof(*ccgdm->faceMap), "faceMap");
for (ccgSubSurf_initFaceIterator(ss, &fi); !ccgFaceIterator_isStopped(&fi); ccgFaceIterator_next(&fi)) {
for (ccgSubSurf_initFaceIterator(ss, &fi);
!ccgFaceIterator_isStopped(&fi);
ccgFaceIterator_next(&fi))
{
CCGFace *f = ccgFaceIterator_getCurrent(&fi);
ccgdm->faceMap[GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f))].face = f;
}
}
ccgdm->reverseFaceMap = MEM_callocN(sizeof(int) * ccgSubSurf_getNumFinalFaces(ss), "reverseFaceMap");
/* Fill in all geometry arrays making it possible to access any
* hires data from the CPU.
*/
static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm,
CCGSubSurf *ss,
DerivedMesh *dm,
bool useSubsurfUv)
{
const int totvert = ccgSubSurf_getNumVerts(ss);
const int totedge = ccgSubSurf_getNumEdges(ss);
const int totface = ccgSubSurf_getNumFaces(ss);
int index;
int i;
int vertNum = 0, edgeNum = 0, faceNum = 0;
int *vertOrigIndex, *faceOrigIndex, *polyOrigIndex, *base_polyOrigIndex, *edgeOrigIndex;
short *edgeFlags = ccgdm->edgeFlags;
DMFlagMat *faceFlags = ccgdm->faceFlags;
int *polyidx = NULL;
#ifndef USE_DYNSIZE
int *loopidx = NULL, *vertidx = NULL;
BLI_array_declare(loopidx);
BLI_array_declare(vertidx);
#endif
int loopindex, loopindex2;
int edgeSize;
int gridSize;
int gridFaces, gridCuts;
int gridSideEdges;
int numTex, numCol;
int hasPCol, hasOrigSpace;
int gridInternalEdges;
WeightTable wtable = {NULL};
MEdge *medge = NULL;
MPoly *mpoly = NULL;
bool has_edge_cd;
numTex = CustomData_number_of_layers(&ccgdm->dm.loopData, CD_MLOOPUV);
numCol = CustomData_number_of_layers(&ccgdm->dm.loopData, CD_MLOOPCOL);
hasPCol = CustomData_has_layer(&ccgdm->dm.loopData, CD_PREVIEW_MLOOPCOL);
hasOrigSpace = CustomData_has_layer(&ccgdm->dm.loopData, CD_ORIGSPACE_MLOOP);
/* We absolutely need that layer, else it's no valid tessellated data! */
polyidx = CustomData_add_layer(&ccgdm->dm.faceData, CD_ORIGINDEX, CD_CALLOC,
NULL, ccgSubSurf_getNumFinalFaces(ss));
edgeSize = ccgSubSurf_getEdgeSize(ss);
gridSize = ccgSubSurf_getGridSize(ss);
@ -3857,11 +4099,7 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
gridCuts = gridSize - 2;
/*gridInternalVerts = gridSideVerts * gridSideVerts; - as yet, unused */
gridSideEdges = gridSize - 1;
gridInternalEdges = (gridSideEdges - 1) * gridSideEdges * 2;
vertNum = 0;
edgeNum = 0;
faceNum = 0;
gridInternalEdges = (gridSideEdges - 1) * gridSideEdges * 2;
/* mvert = dm->getVertArray(dm); */ /* UNUSED */
medge = dm->getEdgeArray(dm);
@ -3869,10 +4107,6 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
base_polyOrigIndex = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX);
/*CDDM hack*/
edgeFlags = ccgdm->edgeFlags = MEM_callocN(sizeof(short) * totedge, "edgeFlags");
faceFlags = ccgdm->faceFlags = MEM_callocN(sizeof(DMFlagMat) * totface, "faceFlags");
vertOrigIndex = DM_get_vert_data_layer(&ccgdm->dm, CD_ORIGINDEX);
edgeOrigIndex = DM_get_edge_data_layer(&ccgdm->dm, CD_ORIGINDEX);
@ -3902,13 +4136,12 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
#ifdef USE_DYNSIZE
int loopidx[numVerts], vertidx[numVerts];
#endif
w = get_ss_weights(&wtable, gridCuts, numVerts);
ccgdm->faceMap[index].startVert = vertNum;
ccgdm->faceMap[index].startEdge = edgeNum;
ccgdm->faceMap[index].startFace = faceNum;
faceFlags->flag = mpoly ? mpoly[origIndex].flag : 0;
faceFlags->mat_nr = mpoly ? mpoly[origIndex].mat_nr : 0;
faceFlags++;
@ -3932,7 +4165,6 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
CCGVert *v = ccgSubSurf_getFaceVert(f, s);
vertidx[s] = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v));
}
/*I think this is for interpolating the center vert?*/
w2 = w; // + numVerts*(g2_wid-1) * (g2_wid-1); //numVerts*((g2_wid-1) * g2_wid+g2_wid-1);
@ -4003,7 +4235,7 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
CustomData_interp(&dm->loopData, &ccgdm->dm.loopData,
loopidx, w2, NULL, numVerts, loopindex2);
loopindex2++;
w2 = w + s * numVerts * g2_wid * g2_wid + ((y) * g2_wid + (x + 1)) * numVerts;
CustomData_interp(&dm->loopData, &ccgdm->dm.loopData,
loopidx, w2, NULL, numVerts, loopindex2);
@ -4016,7 +4248,7 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
ccg_loops_to_corners(&ccgdm->dm.faceData, &ccgdm->dm.loopData,
&ccgdm->dm.polyData, loopindex2 - 4, faceNum, faceNum,
numTex, numCol, hasPCol, hasOrigSpace);
/*set original index data*/
if (faceOrigIndex) {
/* reference the index in 'polyOrigIndex' */
@ -4123,26 +4355,149 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
vertNum++;
}
ccgdm->dm.numVertData = vertNum;
ccgdm->dm.numEdgeData = edgeNum;
ccgdm->dm.numTessFaceData = faceNum;
ccgdm->dm.numLoopData = loopindex2;
ccgdm->dm.numPolyData = faceNum;
/* All tessellated CD layers were updated! */
ccgdm->dm.dirty &= ~DM_DIRTY_TESS_CDLAYERS;
#ifndef USE_DYNSIZE
BLI_array_free(vertidx);
BLI_array_free(loopidx);
#endif
free_ss_weights(&wtable);
BLI_assert(vertNum == ccgSubSurf_getNumFinalVerts(ss));
BLI_assert(edgeNum == ccgSubSurf_getNumFinalEdges(ss));
BLI_assert(loopindex2 == ccgSubSurf_getNumFinalFaces(ss) * 4);
BLI_assert(faceNum == ccgSubSurf_getNumFinalFaces(ss));
}
/* Fill in only geometry arrays needed for the GPU tessellation. */
static void set_ccgdm_gpu_geometry(CCGDerivedMesh *ccgdm,
CCGSubSurf *ss,
DerivedMesh *dm)
{
const int totface = ccgSubSurf_getNumFaces(ss);
MPoly *mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
int index;
DMFlagMat *faceFlags = ccgdm->faceFlags;
for (index = 0; index < totface; index++) {
faceFlags->flag = mpoly ? mpoly[index].flag : 0;
faceFlags->mat_nr = mpoly ? mpoly[index].mat_nr : 0;
faceFlags++;
}
/* TODO(sergey): Fill in edge flags. */
}
static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
int drawInteriorEdges,
int useSubsurfUv,
DerivedMesh *dm,
bool use_gpu_backend)
{
const int totedge = ccgSubSurf_getNumEdges(ss);
const int totface = ccgSubSurf_getNumFaces(ss);
CCGDerivedMesh *ccgdm = MEM_callocN(sizeof(*ccgdm), "ccgdm");
int numTex, numCol;
int hasPCol, hasOrigSpace;
if (use_gpu_backend == false) {
DM_from_template(&ccgdm->dm, dm, DM_TYPE_CCGDM,
ccgSubSurf_getNumFinalVerts(ss),
ccgSubSurf_getNumFinalEdges(ss),
ccgSubSurf_getNumFinalFaces(ss),
ccgSubSurf_getNumFinalFaces(ss) * 4,
ccgSubSurf_getNumFinalFaces(ss));
numTex = CustomData_number_of_layers(&ccgdm->dm.loopData,
CD_MLOOPUV);
numCol = CustomData_number_of_layers(&ccgdm->dm.loopData,
CD_MLOOPCOL);
hasPCol = CustomData_has_layer(&ccgdm->dm.loopData,
CD_PREVIEW_MLOOPCOL);
hasOrigSpace = CustomData_has_layer(&ccgdm->dm.loopData,
CD_ORIGSPACE_MLOOP);
if (
(numTex && CustomData_number_of_layers(&ccgdm->dm.faceData,
CD_MTFACE) != numTex) ||
(numCol && CustomData_number_of_layers(&ccgdm->dm.faceData,
CD_MCOL) != numCol) ||
(hasPCol && !CustomData_has_layer(&ccgdm->dm.faceData,
CD_PREVIEW_MCOL)) ||
(hasOrigSpace && !CustomData_has_layer(&ccgdm->dm.faceData,
CD_ORIGSPACE)) )
{
CustomData_from_bmeshpoly(&ccgdm->dm.faceData,
&ccgdm->dm.polyData,
&ccgdm->dm.loopData,
ccgSubSurf_getNumFinalFaces(ss));
}
CustomData_free_layer_active(&ccgdm->dm.polyData, CD_NORMAL,
ccgdm->dm.numPolyData);
ccgdm->reverseFaceMap =
MEM_callocN(sizeof(int) * ccgSubSurf_getNumFinalFaces(ss),
"reverseFaceMap");
create_ccgdm_maps(ccgdm, ss);
}
else {
DM_from_template(&ccgdm->dm, dm, DM_TYPE_CCGDM,
0, 0, 0, 0, dm->getNumPolys(dm));
CustomData_copy_data(&dm->polyData,
&ccgdm->dm.polyData,
0, 0, dm->getNumPolys(dm));
}
set_default_ccgdm_callbacks(ccgdm);
ccgdm->ss = ss;
ccgdm->drawInteriorEdges = drawInteriorEdges;
ccgdm->useSubsurfUv = useSubsurfUv;
ccgdm->useGpuBackend = use_gpu_backend;
/* CDDM hack. */
ccgdm->edgeFlags = MEM_callocN(sizeof(short) * totedge, "edgeFlags");
ccgdm->faceFlags = MEM_callocN(sizeof(DMFlagMat) * totface, "faceFlags");
if (use_gpu_backend == false) {
set_ccgdm_all_geometry(ccgdm, ss, dm, useSubsurfUv != 0);
}
else {
set_ccgdm_gpu_geometry(ccgdm, ss, dm);
}
ccgdm->dm.numVertData = ccgSubSurf_getNumFinalVerts(ss);
ccgdm->dm.numEdgeData = ccgSubSurf_getNumFinalEdges(ss);
ccgdm->dm.numTessFaceData = ccgSubSurf_getNumFinalFaces(ss);
ccgdm->dm.numLoopData = ccgdm->dm.numTessFaceData * 4;
ccgdm->dm.numPolyData = ccgdm->dm.numTessFaceData;
/* All tessellated CD layers were updated! */
ccgdm->dm.dirty &= ~DM_DIRTY_TESS_CDLAYERS;
return ccgdm;
}
/***/
static bool subsurf_use_gpu_backend(SubsurfFlags flags)
{
#ifdef WITH_OPENSUBDIV
/* Use GPU backend if it's a last modifier in the stack
* and user choosed to use any of the OSD compute devices,
* but also check if GPU has all needed features.
*/
return
(flags & SUBSURF_USE_GPU_BACKEND) != 0 &&
(U.opensubdiv_compute_type != USER_OPENSUBDIV_COMPUTE_NONE) &&
(openSubdiv_supportGPUDisplay());
#else
(void)flags;
return false;
#endif
}
struct DerivedMesh *subsurf_make_derived_from_derived(
struct DerivedMesh *dm,
struct SubsurfModifierData *smd,
@ -4154,18 +4509,28 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
int useSubsurfUv = smd->flags & eSubsurfModifierFlag_SubsurfUv;
int drawInteriorEdges = !(smd->flags & eSubsurfModifierFlag_ControlEdges);
CCGDerivedMesh *result;
bool use_gpu_backend = subsurf_use_gpu_backend(flags);
/* note: editmode calculation can only run once per
* modifier stack evaluation (uses freed cache) [#36299] */
if (flags & SUBSURF_FOR_EDIT_MODE) {
int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels, false) : smd->levels;
smd->emCache = _getSubSurf(smd->emCache, levels, 3, useSimple | useAging | CCG_CALC_NORMALS);
ss_sync_from_derivedmesh(smd->emCache, dm, vertCos, useSimple);
/* TODO(sergey): Same as emCache below. */
if ((flags & SUBSURF_IN_EDIT_MODE) && smd->mCache) {
ccgSubSurf_free(smd->mCache);
smd->mCache = NULL;
}
smd->emCache = _getSubSurf(smd->emCache, levels, 3, useSimple | useAging | CCG_CALC_NORMALS);
#ifdef WITH_OPENSUBDIV
ccgSubSurf_setSkipGrids(smd->emCache, use_gpu_backend);
#endif
ss_sync_from_derivedmesh(smd->emCache, dm, vertCos, useSimple);
result = getCCGDerivedMesh(smd->emCache,
drawInteriorEdges,
useSubsurfUv, dm);
useSubsurfUv, dm, use_gpu_backend);
}
else if (flags & SUBSURF_USE_RENDER_PARAMS) {
/* Do not use cache in render mode. */
@ -4180,7 +4545,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple);
result = getCCGDerivedMesh(ss,
drawInteriorEdges, useSubsurfUv, dm);
drawInteriorEdges, useSubsurfUv, dm, false);
result->freeSS = 1;
}
@ -4212,23 +4577,41 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
result = getCCGDerivedMesh(smd->mCache,
drawInteriorEdges,
useSubsurfUv, dm);
useSubsurfUv, dm, false);
}
else {
CCGFlags ccg_flags = useSimple | CCG_USE_ARENA | CCG_CALC_NORMALS;
CCGSubSurf *prevSS = NULL;
if (smd->mCache && (flags & SUBSURF_IS_FINAL_CALC)) {
#ifdef WITH_OPENSUBDIV
/* With OpenSubdiv enabled we always tries to re-use previos
* subsurf structure in order to save computation time since
* re-creation is rather a complicated business.
*
* TODO(sergey): There was a good eason why final calculation
* used to free entirely cached subsurf structure. reason of
* this is to be investiated still to be sure we don't have
* regressions here.
*/
prevSS = smd->mCache;
#else
ccgSubSurf_free(smd->mCache);
smd->mCache = NULL;
#endif
}
if (flags & SUBSURF_ALLOC_PAINT_MASK)
ccg_flags |= CCG_ALLOC_MASK;
ss = _getSubSurf(NULL, levels, 3, ccg_flags);
ss = _getSubSurf(prevSS, levels, 3, ccg_flags);
#ifdef WITH_OPENSUBDIV
ccgSubSurf_setSkipGrids(ss, use_gpu_backend);
#endif
ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple);
result = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm);
result = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm, use_gpu_backend);
if (flags & SUBSURF_IS_FINAL_CALC)
smd->mCache = ss;

View File

@ -92,6 +92,7 @@ set(SRC
intern/gpu_private.h
)
data_to_c_simple(shaders/gpu_shader_geometry.glsl SRC)
data_to_c_simple(shaders/gpu_program_smoke_frag.glsl SRC)
data_to_c_simple(shaders/gpu_program_smoke_color_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_material.glsl SRC)
@ -127,6 +128,9 @@ if(WITH_IMAGE_DDS)
add_definitions(-DWITH_DDS)
endif()
if(WITH_OPENSUBDIV)
add_definitions(-DWITH_OPENSUBDIV)
endif()
blender_add_lib(bf_gpu "${SRC}" "${INC}" "${INC_SYS}")

View File

@ -148,6 +148,11 @@ void GPU_create_smoke(struct SmokeModifierData *smd, int highres);
/* Delayed free of OpenGL buffers by main thread */
void GPU_free_unused_buffers(void);
#ifdef WITH_OPENSUBDIV
struct DerivedMesh;
void GPU_draw_update_fvar_offset(struct DerivedMesh *dm);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -206,8 +206,8 @@ GPUBlendMode GPU_material_alpha_blend(GPUMaterial *material, float obcol[4]);
/* High level functions to create and use GPU materials */
GPUMaterial *GPU_material_world(struct Scene *scene, struct World *wo);
GPUMaterial *GPU_material_from_blender(struct Scene *scene, struct Material *ma);
GPUMaterial *GPU_material_matcap(struct Scene *scene, struct Material *ma);
GPUMaterial *GPU_material_from_blender(struct Scene *scene, struct Material *ma, bool use_opensubdiv);
GPUMaterial *GPU_material_matcap(struct Scene *scene, struct Material *ma, bool use_opensubdiv);
void GPU_material_free(struct ListBase *gpumaterial);
void GPU_materials_free(void);
@ -322,6 +322,12 @@ typedef struct GPUParticleInfo
float angular_velocity[3];
} GPUParticleInfo;
#ifdef WITH_OPENSUBDIV
struct DerivedMesh;
void GPU_material_update_fvar_offset(GPUMaterial *gpu_material,
struct DerivedMesh *dm);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -60,9 +60,13 @@ if env['WITH_BF_SMOKE']:
if env['WITH_BF_DDS']:
defs.append('WITH_DDS')
if env['WITH_BF_OPENSUBDIV']:
defs.append('WITH_OPENSUBDIV')
# generated data files
import os
sources.extend((
os.path.join(env['DATA_SOURCES'], "gpu_shader_geometry.glsl.c"),
os.path.join(env['DATA_SOURCES'], "gpu_program_smoke_frag.glsl.c"),
os.path.join(env['DATA_SOURCES'], "gpu_program_smoke_color_frag.glsl.c"),
os.path.join(env['DATA_SOURCES'], "gpu_shader_simple_frag.glsl.c"),

View File

@ -56,7 +56,7 @@
extern char datatoc_gpu_shader_material_glsl[];
extern char datatoc_gpu_shader_vertex_glsl[];
extern char datatoc_gpu_shader_vertex_world_glsl[];
extern char datatoc_gpu_shader_geometry_glsl[];
static char *glsl_material_library = NULL;
@ -531,8 +531,19 @@ static int codegen_print_uniforms_functions(DynStr *ds, ListBase *nodes)
}
}
else if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) {
#ifdef WITH_OPENSUBDIV
bool skip_opensubdiv = input->attribtype == CD_TANGENT;
if (skip_opensubdiv) {
BLI_dynstr_appendf(ds, "#ifndef USE_OPENSUBDIV\n");
}
#endif
BLI_dynstr_appendf(ds, "varying %s var%d;\n",
GPU_DATATYPE_STR[input->type], input->attribid);
#ifdef WITH_OPENSUBDIV
if (skip_opensubdiv) {
BLI_dynstr_appendf(ds, "#endif\n");
}
#endif
}
}
}
@ -633,6 +644,12 @@ static char *code_generate_fragment(ListBase *nodes, GPUOutput *output)
char *code;
int builtins;
#ifdef WITH_OPENSUBDIV
GPUNode *node;
GPUInput *input;
#endif
#if 0
BLI_dynstr_append(ds, FUNCTION_PROTOTYPES);
#endif
@ -650,7 +667,35 @@ static char *code_generate_fragment(ListBase *nodes, GPUOutput *output)
if (builtins & GPU_VIEW_NORMAL)
BLI_dynstr_append(ds, "\tvec3 facingnormal = (gl_FrontFacing)? varnormal: -varnormal;\n");
/* Calculate tangent space. */
#ifdef WITH_OPENSUBDIV
{
bool has_tangent = false;
for (node = nodes->first; node; node = node->next) {
for (input = node->inputs.first; input; input = input->next) {
if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) {
if (input->attribtype == CD_TANGENT) {
BLI_dynstr_appendf(ds, "#ifdef USE_OPENSUBDIV\n");
BLI_dynstr_appendf(ds, "\t%s var%d;\n",
GPU_DATATYPE_STR[input->type],
input->attribid);
if (has_tangent == false) {
BLI_dynstr_appendf(ds, "\tvec3 Q1 = dFdx(inpt.v.position.xyz);\n");
BLI_dynstr_appendf(ds, "\tvec3 Q2 = dFdy(inpt.v.position.xyz);\n");
BLI_dynstr_appendf(ds, "\tvec2 st1 = dFdx(inpt.v.uv);\n");
BLI_dynstr_appendf(ds, "\tvec2 st2 = dFdy(inpt.v.uv);\n");
BLI_dynstr_appendf(ds, "\tvec3 T = normalize(Q1 * st2.t - Q2 * st1.t);\n");
}
BLI_dynstr_appendf(ds, "\tvar%d = vec4(T, 1.0);\n", input->attribid);
BLI_dynstr_appendf(ds, "#endif\n");
}
}
}
}
}
#endif
codegen_declare_tmps(ds, nodes);
codegen_call_functions(ds, nodes, output);
@ -678,10 +723,21 @@ static char *code_generate_vertex(ListBase *nodes, const GPUMatType type)
for (node = nodes->first; node; node = node->next) {
for (input = node->inputs.first; input; input = input->next) {
if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) {
#ifdef WITH_OPENSUBDIV
bool skip_opensubdiv = ELEM(input->attribtype, CD_MTFACE, CD_TANGENT);
if (skip_opensubdiv) {
BLI_dynstr_appendf(ds, "#ifndef USE_OPENSUBDIV\n");
}
#endif
BLI_dynstr_appendf(ds, "attribute %s att%d;\n",
GPU_DATATYPE_STR[input->type], input->attribid);
BLI_dynstr_appendf(ds, "varying %s var%d;\n",
GPU_DATATYPE_STR[input->type], input->attribid);
#ifdef WITH_OPENSUBDIV
if (skip_opensubdiv) {
BLI_dynstr_appendf(ds, "#endif\n");
}
#endif
}
}
}
@ -706,11 +762,29 @@ static char *code_generate_vertex(ListBase *nodes, const GPUMatType type)
for (input = node->inputs.first; input; input = input->next)
if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) {
if (input->attribtype == CD_TANGENT) { /* silly exception */
#ifdef WITH_OPENSUBDIV
BLI_dynstr_appendf(ds, "#ifndef USE_OPENSUBDIV\n");
#endif
BLI_dynstr_appendf(ds, "\tvar%d.xyz = normalize(gl_NormalMatrix * att%d.xyz);\n", input->attribid, input->attribid);
BLI_dynstr_appendf(ds, "\tvar%d.w = att%d.w;\n", input->attribid, input->attribid);
#ifdef WITH_OPENSUBDIV
BLI_dynstr_appendf(ds, "#endif\n");
#endif
}
else
else {
#ifdef WITH_OPENSUBDIV
bool is_mtface = input->attribtype == CD_MTFACE;
if (is_mtface) {
BLI_dynstr_appendf(ds, "#ifndef USE_OPENSUBDIV\n");
}
#endif
BLI_dynstr_appendf(ds, "\tvar%d = att%d;\n", input->attribid, input->attribid);
#ifdef WITH_OPENSUBDIV
if (is_mtface) {
BLI_dynstr_appendf(ds, "#endif\n");
}
#endif
}
}
/* unfortunately special handling is needed here because we abuse gl_Color/gl_SecondaryColor flat shading */
else if (input->source == GPU_SOURCE_OPENGL_BUILTIN) {
@ -738,6 +812,61 @@ static char *code_generate_vertex(ListBase *nodes, const GPUMatType type)
return code;
}
static char *code_generate_geometry(ListBase *nodes, bool use_opensubdiv)
{
#ifdef WITH_OPENSUBDIV
if (use_opensubdiv) {
DynStr *ds = BLI_dynstr_new();
GPUNode *node;
GPUInput *input;
char *code;
/* Generate varying declarations. */
for (node = nodes->first; node; node = node->next) {
for (input = node->inputs.first; input; input = input->next) {
if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) {
if (input->attribtype == CD_MTFACE) {
BLI_dynstr_appendf(ds, "varying %s var%d;\n",
GPU_DATATYPE_STR[input->type],
input->attribid);
BLI_dynstr_appendf(ds, "uniform int fvar%d_offset;\n",
input->attribid);
}
}
}
}
BLI_dynstr_append(ds, datatoc_gpu_shader_geometry_glsl);
/* Generate varying assignments. */
for (node = nodes->first; node; node = node->next) {
for (input = node->inputs.first; input; input = input->next) {
if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) {
if (input->attribtype == CD_MTFACE) {
BLI_dynstr_appendf(ds,
"\tINTERP_FACE_VARYING_2(var%d, "
"fvar%d_offset, st);\n",
input->attribid,
input->attribid);
}
}
}
}
BLI_dynstr_append(ds, "}\n\n");
code = BLI_dynstr_get_cstring(ds);
BLI_dynstr_free(ds);
//if (G.debug & G_DEBUG) printf("%s\n", code);
return code;
}
#else
UNUSED_VARS(nodes, use_opensubdiv);
#endif
return NULL;
}
void GPU_code_generate_glsl_lib(void)
{
DynStr *ds;
@ -786,8 +915,28 @@ static void gpu_nodes_extract_dynamic_inputs(GPUPass *pass, ListBase *nodes)
/* attributes don't need to be bound, they already have
* an id that the drawing functions will use */
if (input->source == GPU_SOURCE_ATTRIB ||
input->source == GPU_SOURCE_BUILTIN ||
if (input->source == GPU_SOURCE_ATTRIB) {
#ifdef WITH_OPENSUBDIV
/* We do need mtface attributes for later, so we can
* update face-varuing variables offset in the texture
* buffer for proper sampling from the shader.
*
* We don't do anything about attribute itself, we
* only use it to learn which uniform name is to be
* updated.
*
* TODO(sergey): We can add ad extra uniform input
* for the offset, which will be purely internal and
* which would avoid having such an exceptions.
*/
if (input->attribtype != CD_MTFACE) {
continue;
}
#else
continue;
#endif
}
if (input->source == GPU_SOURCE_BUILTIN ||
input->source == GPU_SOURCE_OPENGL_BUILTIN)
{
continue;
@ -811,6 +960,14 @@ static void gpu_nodes_extract_dynamic_inputs(GPUPass *pass, ListBase *nodes)
if (extract)
input->shaderloc = GPU_shader_get_uniform(shader, input->shadername);
#ifdef WITH_OPENSUBDIV
if (input->source == GPU_SOURCE_ATTRIB &&
input->attribtype == CD_MTFACE)
{
extract = 1;
}
#endif
/* extract nodes */
if (extract) {
BLI_remlink(&node->inputs, input);
@ -1432,11 +1589,11 @@ static void gpu_nodes_prune(ListBase *nodes, GPUNodeLink *outlink)
GPUPass *GPU_generate_pass(ListBase *nodes, GPUNodeLink *outlink,
GPUVertexAttribs *attribs, int *builtins,
const GPUMatType type, const char *UNUSED(name))
const GPUMatType type, const char *UNUSED(name), const bool use_opensubdiv)
{
GPUShader *shader;
GPUPass *pass;
char *vertexcode, *fragmentcode;
char *vertexcode, *geometrycode, *fragmentcode;
#if 0
if (!FUNCTION_LIB) {
@ -1454,7 +1611,8 @@ GPUPass *GPU_generate_pass(ListBase *nodes, GPUNodeLink *outlink,
/* generate code and compile with opengl */
fragmentcode = code_generate_fragment(nodes, outlink->output);
vertexcode = code_generate_vertex(nodes, type);
shader = GPU_shader_create(vertexcode, fragmentcode, NULL, glsl_material_library, NULL, 0, 0, 0);
geometrycode = code_generate_geometry(nodes, use_opensubdiv);
shader = GPU_shader_create(vertexcode, fragmentcode, geometrycode, glsl_material_library, NULL, 0, 0, 0);
/* failed? */
if (!shader) {
@ -1474,6 +1632,7 @@ GPUPass *GPU_generate_pass(ListBase *nodes, GPUNodeLink *outlink,
pass->output = outlink->output;
pass->shader = shader;
pass->fragmentcode = fragmentcode;
pass->geometrycode = geometrycode;
pass->vertexcode = vertexcode;
pass->libcode = glsl_material_library;
@ -1490,8 +1649,9 @@ void GPU_pass_free(GPUPass *pass)
gpu_inputs_free(&pass->inputs);
if (pass->fragmentcode)
MEM_freeN(pass->fragmentcode);
if (pass->geometrycode)
MEM_freeN(pass->geometrycode);
if (pass->vertexcode)
MEM_freeN(pass->vertexcode);
MEM_freeN(pass);
}

View File

@ -161,6 +161,7 @@ struct GPUPass {
struct GPUOutput *output;
struct GPUShader *shader;
char *fragmentcode;
char *geometrycode;
char *vertexcode;
const char *libcode;
};
@ -170,7 +171,7 @@ typedef struct GPUPass GPUPass;
GPUPass *GPU_generate_pass(ListBase *nodes, struct GPUNodeLink *outlink,
struct GPUVertexAttribs *attribs, int *builtin,
const GPUMatType type, const char *name);
const GPUMatType type, const char *name, const bool use_opensubdiv);
struct GPUShader *GPU_pass_shader(GPUPass *pass);

View File

@ -71,6 +71,7 @@
#include "BKE_node.h"
#include "BKE_object.h"
#include "BKE_scene.h"
#include "BKE_subsurf.h"
#include "BKE_DerivedMesh.h"
#include "GPU_buffers.h"
@ -82,6 +83,13 @@
#include "smoke_API.h"
#ifdef WITH_OPENSUBDIV
# include "DNA_mesh_types.h"
# include "BKE_editmesh.h"
# include "gpu_codegen.h"
#endif
extern Material defmaterial; /* from material.c */
/* Text Rendering */
@ -1357,7 +1365,7 @@ void GPU_free_images_old(void)
{
Image *ima;
static int lasttime = 0;
int ctime = PIL_check_seconds_timer_i();
int ctime = (int)PIL_check_seconds_timer();
/*
* Run garbage collector once for every collecting period of time
@ -1433,6 +1441,7 @@ static struct GPUMaterialState {
int lastmatnr, lastretval;
GPUBlendMode lastalphablend;
bool is_opensubdiv;
} GMS = {NULL};
/* fixed function material, alpha handed by caller */
@ -1519,6 +1528,27 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O
const bool gamma = BKE_scene_check_color_management_enabled(scene);
const bool new_shading_nodes = BKE_scene_use_new_shading_nodes(scene);
const bool use_matcap = (v3d->flag2 & V3D_SHOW_SOLID_MATCAP) != 0; /* assumes v3d->defmaterial->preview is set */
bool use_opensubdiv = false;
#ifdef WITH_OPENSUBDIV
{
DerivedMesh *derivedFinal = NULL;
Mesh *me = ob->data;
BMEditMesh *em = me->edit_btmesh;
if (em != NULL) {
derivedFinal = em->derivedFinal;
}
else {
derivedFinal = ob->derivedFinal;
}
if (derivedFinal != NULL && derivedFinal->type == DM_TYPE_CCGDM) {
CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) derivedFinal;
use_opensubdiv = ccgdm->useGpuBackend;
}
}
#endif
#ifdef WITH_GAMEENGINE
if (rv3d->rflag & RV3D_IS_GAME_ENGINE) {
@ -1541,6 +1571,7 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O
GMS.gob = ob;
GMS.gscene = scene;
GMS.is_opensubdiv = use_opensubdiv;
GMS.totmat = use_matcap ? 1 : ob->totcol + 1; /* materials start from 1, default material is 0 */
GMS.glay = (v3d->localvd)? v3d->localvd->lay: v3d->lay; /* keep lamps visible in local view */
GMS.gscenelock = (v3d->scenelock != 0);
@ -1572,7 +1603,7 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O
/* viewport material, setup in space_view3d, defaults to matcap using ma->preview now */
if (use_matcap) {
GMS.gmatbuf[0] = v3d->defmaterial;
GPU_material_matcap(scene, v3d->defmaterial);
GPU_material_matcap(scene, v3d->defmaterial, use_opensubdiv);
/* do material 1 too, for displists! */
memcpy(&GMS.matbuf[1], &GMS.matbuf[0], sizeof(GPUMaterialFixed));
@ -1590,7 +1621,7 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O
if (glsl) {
GMS.gmatbuf[0] = &defmaterial;
GPU_material_from_blender(GMS.gscene, &defmaterial);
GPU_material_from_blender(GMS.gscene, &defmaterial, GMS.is_opensubdiv);
}
GMS.alphablend[0] = GPU_BLEND_SOLID;
@ -1604,7 +1635,7 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O
if (ma == NULL) ma = &defmaterial;
/* create glsl material if requested */
gpumat = glsl? GPU_material_from_blender(GMS.gscene, ma): NULL;
gpumat = glsl? GPU_material_from_blender(GMS.gscene, ma, GMS.is_opensubdiv): NULL;
if (gpumat) {
/* do glsl only if creating it succeed, else fallback */
@ -1708,7 +1739,7 @@ int GPU_enable_material(int nr, void *attribs)
/* unbind glsl material */
if (GMS.gboundmat) {
if (GMS.is_alpha_pass) glDepthMask(0);
GPU_material_unbind(GPU_material_from_blender(GMS.gscene, GMS.gboundmat));
GPU_material_unbind(GPU_material_from_blender(GMS.gscene, GMS.gboundmat, GMS.is_opensubdiv));
GMS.gboundmat = NULL;
}
@ -1735,7 +1766,7 @@ int GPU_enable_material(int nr, void *attribs)
float auto_bump_scale;
gpumat = GPU_material_from_blender(GMS.gscene, mat);
gpumat = GPU_material_from_blender(GMS.gscene, mat, GMS.is_opensubdiv);
GPU_material_vertex_attributes(gpumat, gattribs);
if (GMS.dob)
@ -1802,7 +1833,7 @@ void GPU_disable_material(void)
glDisable(GL_CULL_FACE);
if (GMS.is_alpha_pass) glDepthMask(0);
GPU_material_unbind(GPU_material_from_blender(GMS.gscene, GMS.gboundmat));
GPU_material_unbind(GPU_material_from_blender(GMS.gscene, GMS.gboundmat, GMS.is_opensubdiv));
GMS.gboundmat = NULL;
}
@ -2108,3 +2139,31 @@ void GPU_state_init(void)
gpu_multisample(false);
}
#ifdef WITH_OPENSUBDIV
/* Update face-varying variables offset which might be
* different from mesh to mesh sharing the same material.
*/
void GPU_draw_update_fvar_offset(DerivedMesh *dm)
{
int i;
/* Sanity check to be sure we only do this for OpenSubdiv draw. */
BLI_assert(dm->type == DM_TYPE_CCGDM);
BLI_assert(GMS.is_opensubdiv);
for (i = 0; i < GMS.totmat; ++i) {
Material *material = GMS.gmatbuf[i];
GPUMaterial *gpu_material;
if (material == NULL) {
continue;
}
gpu_material = GPU_material_from_blender(GMS.gscene,
material,
GMS.is_opensubdiv);
GPU_material_update_fvar_offset(gpu_material, dm);
}
}
#endif

View File

@ -61,8 +61,9 @@
# include "BLI_winstuff.h"
#endif
#define MAX_DEFINE_LENGTH 72
#define MAX_EXT_DEFINE_LENGTH 280
/* TODO(sergey): Find better default values for this constants. */
#define MAX_DEFINE_LENGTH 1024
#define MAX_EXT_DEFINE_LENGTH 1024
/* Extensions support */
@ -1528,8 +1529,14 @@ static void shader_print_errors(const char *task, const char *log, const char **
fprintf(stderr, "%s\n", log);
}
static const char *gpu_shader_version(void)
static const char *gpu_shader_version(bool use_opensubdiv)
{
#ifdef WITH_OPENSUBDIV
if (use_opensubdiv) {
return "#version 150";
}
#endif
/* turn on glsl 1.30 for bicubic bump mapping and ATI clipping support */
if (GLEW_VERSION_3_0 &&
(GPU_bicubic_bump_support() || GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)))
@ -1543,9 +1550,15 @@ static const char *gpu_shader_version(void)
static void gpu_shader_standard_extensions(char defines[MAX_EXT_DEFINE_LENGTH])
{
#ifdef WITH_OPENSUBDIV
strcat(defines, "#extension GL_ARB_texture_query_lod: enable\n"
"#extension GL_ARB_gpu_shader5 : enable\n"
"#extension GL_ARB_explicit_attrib_location : require\n");
#else
/* need this extension for high quality bump mapping */
if (GPU_bicubic_bump_support())
strcat(defines, "#extension GL_ARB_texture_query_lod: enable\n");
#endif
if (GPU_geometry_shader_support())
strcat(defines, "#extension GL_EXT_geometry_shader4: enable\n");
@ -1556,7 +1569,8 @@ static void gpu_shader_standard_extensions(char defines[MAX_EXT_DEFINE_LENGTH])
}
}
static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH])
static void gpu_shader_standard_defines(bool use_opensubdiv,
char defines[MAX_DEFINE_LENGTH])
{
/* some useful defines to detect GPU type */
if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) {
@ -1571,6 +1585,28 @@ static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH])
if (GPU_bicubic_bump_support())
strcat(defines, "#define BUMP_BICUBIC\n");
#ifdef WITH_OPENSUBDIV
/* TODO(sergey): Check whether we actually compiling shader for
* the OpenSubdiv mesh.
*/
if (use_opensubdiv) {
strcat(defines, "#define USE_OPENSUBDIV\n");
/* TODO(sergey): not strictly speaking a define, but this is
* a global typedef which we don't have better place to define
* in yet.
*/
strcat(defines, "struct VertexData {\n"
" vec4 position;\n"
" vec3 normal;\n"
" vec2 uv;"
"};\n");
}
#else
UNUSED_VARS(use_opensubdiv);
#endif
return;
}
@ -1640,6 +1676,15 @@ void GPU_program_parameter_4f(GPUProgram *program, unsigned int location, float
GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const char *geocode, const char *libcode, const char *defines, int input, int output, int number)
{
#ifdef WITH_OPENSUBDIF
/* TODO(sergey): used to add #version 150 to the geometry shader.
* Could safely be renamed to "use_geometry_code" since it's evry much
* liely any of geometry code will want to use GLSL 1.5.
*/
bool use_opensubdiv = geocode != NULL;
#else
bool use_opensubdiv = false;
#endif
GLint status;
GLcharARB log[5000];
GLsizei length = 0;
@ -1671,7 +1716,7 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const
return NULL;
}
gpu_shader_standard_defines(standard_defines);
gpu_shader_standard_defines(use_opensubdiv, standard_defines);
gpu_shader_standard_extensions(standard_extensions);
if (vertexcode) {
@ -1679,7 +1724,7 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const
/* custom limit, may be too small, beware */
int num_source = 0;
source[num_source++] = gpu_shader_version();
source[num_source++] = gpu_shader_version(use_opensubdiv);
source[num_source++] = standard_extensions;
source[num_source++] = standard_defines;
@ -1702,13 +1747,25 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const
}
if (fragcode) {
const char *source[6];
const char *source[7];
int num_source = 0;
source[num_source++] = gpu_shader_version();
source[num_source++] = gpu_shader_version(use_opensubdiv);
source[num_source++] = standard_extensions;
source[num_source++] = standard_defines;
#ifdef WITH_OPENSUBDIV
/* TODO(sergey): Move to fragment shader source code generation. */
if (use_opensubdiv) {
source[num_source++] =
"#ifdef USE_OPENSUBDIV\n"
"in block {\n"
" VertexData v;\n"
"} inpt;\n"
"#endif\n";
}
#endif
if (defines) source[num_source++] = defines;
if (libcode) source[num_source++] = libcode;
source[num_source++] = fragcode;
@ -1732,7 +1789,7 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const
const char *source[6];
int num_source = 0;
source[num_source++] = gpu_shader_version();
source[num_source++] = gpu_shader_version(use_opensubdiv);
source[num_source++] = standard_extensions;
source[num_source++] = standard_defines;
@ -1753,7 +1810,9 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const
return NULL;
}
GPU_shader_geometry_stage_primitive_io(shader, input, output, number);
if (!use_opensubdiv) {
GPU_shader_geometry_stage_primitive_io(shader, input, output, number);
}
}
@ -1762,6 +1821,18 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const
glAttachObjectARB(shader->object, lib->lib);
#endif
#ifdef WITH_OPENSUBDIV
if (use_opensubdiv) {
glBindAttribLocation(shader->object, 0, "position");
glBindAttribLocation(shader->object, 1, "normal");
GPU_shader_geometry_stage_primitive_io(shader,
GL_LINES_ADJACENCY_EXT,
GL_TRIANGLE_STRIP,
4);
}
#endif
glLinkProgramARB(shader->object);
glGetObjectParameterivARB(shader->object, GL_OBJECT_LINK_STATUS_ARB, &status);
if (!status) {
@ -1775,6 +1846,15 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const
return NULL;
}
#ifdef WITH_OPENSUBDIV
/* TODO(sergey): Find a better place for this. */
{
glProgramUniform1i(shader->object,
glGetUniformLocation(shader->object, "FVarDataBuffer"),
31); /* GL_TEXTURE31 */
}
#endif
return shader;
}

View File

@ -119,6 +119,8 @@ struct GPUMaterial {
ListBase lamps;
bool bound;
bool is_opensubdiv;
};
struct GPULamp {
@ -223,7 +225,8 @@ static int GPU_material_construct_end(GPUMaterial *material, const char *passnam
outlink = material->outlink;
material->pass = GPU_generate_pass(&material->nodes, outlink,
&material->attribs, &material->builtins, material->type, passname);
&material->attribs, &material->builtins, material->type,
passname, material->is_opensubdiv);
if (!material->pass)
return 0;
@ -1673,21 +1676,27 @@ static GPUNodeLink *gpu_material_preview_matcap(GPUMaterial *mat, Material *ma)
}
/* new solid draw mode with glsl matcaps */
GPUMaterial *GPU_material_matcap(Scene *scene, Material *ma)
GPUMaterial *GPU_material_matcap(Scene *scene, Material *ma, bool use_opensubdiv)
{
GPUMaterial *mat;
GPUNodeLink *outlink;
LinkData *link;
for (link = ma->gpumaterial.first; link; link = link->next)
if (((GPUMaterial*)link->data)->scene == scene)
return link->data;
for (link = ma->gpumaterial.first; link; link = link->next) {
GPUMaterial *current_material = (GPUMaterial*)link->data;
if (current_material->scene == scene &&
current_material->is_opensubdiv == use_opensubdiv)
{
return current_material;
}
}
/* allocate material */
mat = GPU_material_construct_begin(ma);
mat->scene = scene;
mat->type = GPU_MATERIAL_TYPE_MESH;
mat->is_opensubdiv = use_opensubdiv;
if (ma->preview && ma->preview->rect[0]) {
outlink = gpu_material_preview_matcap(mat, ma);
}
@ -1749,20 +1758,26 @@ GPUMaterial *GPU_material_world(struct Scene *scene, struct World *wo)
}
GPUMaterial *GPU_material_from_blender(Scene *scene, Material *ma)
GPUMaterial *GPU_material_from_blender(Scene *scene, Material *ma, bool use_opensubdiv)
{
GPUMaterial *mat;
GPUNodeLink *outlink;
LinkData *link;
for (link = ma->gpumaterial.first; link; link = link->next)
if (((GPUMaterial*)link->data)->scene == scene)
return link->data;
for (link = ma->gpumaterial.first; link; link = link->next) {
GPUMaterial *current_material = (GPUMaterial*)link->data;
if (current_material->scene == scene &&
current_material->is_opensubdiv == use_opensubdiv)
{
return current_material;
}
}
/* allocate material */
mat = GPU_material_construct_begin(ma);
mat->scene = scene;
mat->type = GPU_MATERIAL_TYPE_MESH;
mat->is_opensubdiv = use_opensubdiv;
/* render pipeline option */
if (ma->mode & MA_TRANSP)
@ -2250,7 +2265,8 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma)
if (!GPU_glsl_support())
return NULL;
mat = GPU_material_from_blender(scene, ma);
/* TODO(sergey): How to detemine whether we need OSD or not here? */
mat = GPU_material_from_blender(scene, ma, false);
pass = (mat)? mat->pass: NULL;
if (pass && pass->fragmentcode && pass->vertexcode) {
@ -2421,3 +2437,54 @@ void GPU_free_shader_export(GPUShaderExport *shader)
MEM_freeN(shader);
}
#ifdef WITH_OPENSUBDIV
void GPU_material_update_fvar_offset(GPUMaterial *gpu_material,
DerivedMesh *dm)
{
GPUPass *pass = gpu_material->pass;
GPUShader *shader = (pass != NULL ? pass->shader : NULL);
ListBase *inputs = (pass != NULL ? &pass->inputs : NULL);
GPUInput *input;
if (shader == NULL) {
return;
}
GPU_shader_bind(shader);
for (input = inputs->first;
input != NULL;
input = input->next)
{
if (input->source == GPU_SOURCE_ATTRIB &&
input->attribtype == CD_MTFACE)
{
char name[64];
/* TODO(sergey): This will work for until names are
* consistent, we'll need to solve this somehow in the future.
*/
int layer_index;
int location;
if (input->attribname[0] != '\0') {
layer_index = CustomData_get_named_layer(&dm->loopData,
CD_MLOOPUV,
input->attribname);
}
else {
layer_index = CustomData_get_active_layer(&dm->loopData,
CD_MLOOPUV);
}
BLI_snprintf(name, sizeof(name),
"fvar%d_offset",
input->attribid);
location = GPU_shader_get_uniform(shader, name);
/* Multiply by 2 because we're offseting U and V variables. */
GPU_shader_uniform_int(shader, location, layer_index * 2);
}
}
GPU_shader_unbind();
}
#endif

View File

@ -152,7 +152,8 @@ static GPUShader *gpu_simple_shader(int options)
datatoc_gpu_shader_simple_vert_glsl,
datatoc_gpu_shader_simple_frag_glsl,
NULL,
NULL, defines, 0, 0, 0);
NULL,
defines, 0, 0, 0);
if (shader) {
/* set texture map to first texture unit */

View File

@ -2593,6 +2593,7 @@ void material_preview_matcap(vec4 color, sampler2D ima, vec4 N, vec4 mask, out v
vec3 normal;
vec2 tex;
#ifndef USE_OPENSUBDIV
/* remap to 0.0 - 1.0 range. This is done because OpenGL 2.0 clamps colors
* between shader stages and we want the full range of the normal */
normal = vec3(2.0, 2.0, 2.0) * vec3(N.x, N.y, N.z) - vec3(1.0, 1.0, 1.0);
@ -2600,6 +2601,10 @@ void material_preview_matcap(vec4 color, sampler2D ima, vec4 N, vec4 mask, out v
normal.z = 0.0;
}
normal = normalize(normal);
#else
normal = inpt.v.normal;
mask = vec4(1.0, 1.0, 1.0, 1.0);
#endif
tex.x = 0.5 + 0.49 * normal.x;
tex.y = 0.5 + 0.49 * normal.y;

View File

@ -1,3 +1,11 @@
#ifdef USE_OPENSUBDIV
in vec3 normal;
in vec4 position;
out block {
VertexData v;
} outpt;
#endif
varying vec3 varposition;
varying vec3 varnormal;
@ -8,10 +16,15 @@ varying float gl_ClipDistance[6];
void main()
{
vec4 co = gl_ModelViewMatrix * gl_Vertex;
#ifndef USE_OPENSUBDIV
vec4 position = gl_Vertex;
vec3 normal = gl_Normal;
#endif
vec4 co = gl_ModelViewMatrix * position;
varposition = co.xyz;
varnormal = normalize(gl_NormalMatrix * gl_Normal);
varnormal = normalize(gl_NormalMatrix * normal);
gl_Position = gl_ProjectionMatrix * co;
#ifdef CLIP_WORKAROUND
@ -24,3 +37,7 @@ void main()
gl_ClipVertex = co;
#endif
#ifdef USE_OPENSUBDIV
outpt.v.position = co;
outpt.v.normal = varnormal;
#endif

View File

@ -561,6 +561,9 @@ typedef struct UserDef {
short pie_menu_threshold; /* pie menu distance from center before a direction is set */
struct WalkNavigation walk_navigation;
short opensubdiv_compute_type;
char pad5[6];
} UserDef;
extern UserDef U; /* from blenkernel blender.c */
@ -883,6 +886,16 @@ typedef enum eUserpref_VirtualPixel {
VIRTUAL_PIXEL_DOUBLE = 1,
} eUserpref_VirtualPixel;
typedef enum eOpensubdiv_Computee_Type {
USER_OPENSUBDIV_COMPUTE_NONE = 0,
USER_OPENSUBDIV_COMPUTE_CPU = 1,
USER_OPENSUBDIV_COMPUTE_OPENMP = 2,
USER_OPENSUBDIV_COMPUTE_OPENCL = 3,
USER_OPENSUBDIV_COMPUTE_CUDA = 4,
USER_OPENSUBDIV_COMPUTE_GLSL_TRANSFORM_FEEDBACK = 5,
USER_OPENSUBDIV_COMPUTE_GLSL_COMPUTE = 6,
} eOpensubdiv_Computee_Type;
#ifdef __cplusplus
}
#endif

View File

@ -139,6 +139,10 @@ if env['WITH_BF_FREESTYLE']:
defs.append('WITH_FREESTYLE')
incs += ' ../freestyle'
if env['WITH_BF_OPENSUBDIV']:
incs += ' #/intern/opensubdiv'
defs.append('WITH_OPENSUBDIV')
if env['OURPLATFORM'] == 'linux':
cflags='-pthread'

View File

@ -300,6 +300,13 @@ if(WITH_FREESTYLE)
add_definitions(-DWITH_FREESTYLE)
endif()
if(WITH_OPENSUBDIV)
list(APPEND INC
../../../../intern/opensubdiv
)
add_definitions(-DWITH_OPENSUBDIV)
endif()
# Build makesrna executable
blender_include_dirs(
.

View File

@ -154,6 +154,10 @@ if env['WITH_BF_FREESTYLE']:
defs.append('WITH_FREESTYLE')
incs += ' ../../freestyle'
if env['WITH_BF_OPENSUBDIV']:
defs.append('WITH_OPENSUBDIV')
incs += ' #intern/opensubdiv'
if env['OURPLATFORM'] == 'linux':
cflags='-pthread'

View File

@ -61,6 +61,19 @@ static EnumPropertyItem compute_device_type_items[] = {
};
#endif
#ifdef WITH_OPENSUBDIV
static EnumPropertyItem opensubdiv_compute_type_items[] = {
{USER_OPENSUBDIV_COMPUTE_NONE, "NONE", 0, "None", ""},
{USER_OPENSUBDIV_COMPUTE_CPU, "CPU", 0, "CPU", ""},
{USER_OPENSUBDIV_COMPUTE_OPENMP, "OPENMP", 0, "OpenMP", ""},
{USER_OPENSUBDIV_COMPUTE_OPENCL, "OPENCL", 0, "OpenCL", ""},
{USER_OPENSUBDIV_COMPUTE_CUDA, "CUDA", 0, "CUDA", ""},
{USER_OPENSUBDIV_COMPUTE_GLSL_TRANSFORM_FEEDBACK, "GLSL_TRANSFORM_FEEDBACL", 0, "GLSL Transform Feedback", ""},
{USER_OPENSUBDIV_COMPUTE_GLSL_COMPUTE, "GLSL_COMPUTE", 0, "GLSL Compute", ""},
{ 0, NULL, 0, NULL, NULL}
};
#endif
static EnumPropertyItem audio_device_items[] = {
{0, "NONE", 0, "None", "Null device - there will be no audio output"},
#ifdef WITH_SDL
@ -106,6 +119,10 @@ EnumPropertyItem navigation_mode_items[] = {
#include "CCL_api.h"
#ifdef WITH_OPENSUBDIV
# include "opensubdiv_capi.h"
#endif
#ifdef WITH_SDL_DYNLOAD
# include "sdlew.h"
#endif
@ -538,6 +555,54 @@ static EnumPropertyItem *rna_userdef_compute_device_itemf(bContext *UNUSED(C), P
}
#endif
#ifdef WITH_OPENSUBDIV
static EnumPropertyItem *rna_userdef_opensubdiv_compute_type_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop), bool *r_free)
{
EnumPropertyItem *item = NULL;
int totitem = 0;
int evaluators = openSubdiv_getAvailableEvaluators();
RNA_enum_items_add_value(&item, &totitem, opensubdiv_compute_type_items, USER_OPENSUBDIV_COMPUTE_NONE);
#define APPEND_COMPUTE(compute) \
if (evaluators & OPENSUBDIV_EVALUATOR_## compute) { \
RNA_enum_items_add_value(&item, &totitem, opensubdiv_compute_type_items, USER_OPENSUBDIV_COMPUTE_ ## compute); \
} ((void)0)
APPEND_COMPUTE(CPU);
APPEND_COMPUTE(OPENMP);
APPEND_COMPUTE(OPENCL);
APPEND_COMPUTE(CUDA);
APPEND_COMPUTE(GLSL_TRANSFORM_FEEDBACK);
APPEND_COMPUTE(GLSL_COMPUTE);
#undef APPEND_COMPUTE
RNA_enum_item_end(&item, &totitem);
*r_free = true;
return item;
}
static void rna_userdef_opensubdiv_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
{
Object *object;
for (object = bmain->object.first;
object;
object = object->id.next)
{
if (object->derivedFinal != NULL &&
object->derivedFinal->type == DM_TYPE_CCGDM)
{
DAG_id_tag_update(&object->id, OB_RECALC_OB);
}
}
}
#endif
static EnumPropertyItem *rna_userdef_audio_device_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop), bool *r_free)
{
@ -4204,6 +4269,16 @@ static void rna_def_userdef_system(BlenderRNA *brna)
RNA_def_property_enum_funcs(prop, "rna_userdef_compute_device_get", NULL, "rna_userdef_compute_device_itemf");
RNA_def_property_ui_text(prop, "Compute Device", "Device to use for computation");
#endif
#ifdef WITH_OPENSUBDIV
prop = RNA_def_property(srna, "opensubdiv_compute_type", PROP_ENUM, PROP_NONE);
RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT);
RNA_def_property_enum_sdna(prop, NULL, "opensubdiv_compute_type");
RNA_def_property_enum_items(prop, opensubdiv_compute_type_items);
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_userdef_opensubdiv_compute_type_itemf");
RNA_def_property_ui_text(prop, "OpenSubdiv Compute Type", "Type of computer backend used with OpenSubdiv");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_PROPERTIES, "rna_userdef_opensubdiv_update");
#endif
}
static void rna_def_userdef_input(BlenderRNA *brna)

View File

@ -151,4 +151,8 @@ if(WITH_OPENNL)
)
endif()
if(WITH_OPENSUBDIV)
add_definitions(-DWITH_OPENSUBDIV)
endif()
blender_add_lib(bf_modifiers "${SRC}" "${INC}" "${INC_SYS}")

View File

@ -101,17 +101,33 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
const bool useRenderParams = (flag & MOD_APPLY_RENDER) != 0;
const bool isFinalCalc = (flag & MOD_APPLY_USECACHE) != 0;
#ifdef WITH_OPENSUBDIV
const bool allow_gpu = (flag & MOD_APPLY_ALLOW_GPU) != 0;
const bool do_cddm_convert = useRenderParams;
#else
const bool do_cddm_convert = useRenderParams || !isFinalCalc;
#endif
if (useRenderParams)
subsurf_flags |= SUBSURF_USE_RENDER_PARAMS;
if (isFinalCalc)
subsurf_flags |= SUBSURF_IS_FINAL_CALC;
if (ob->mode & OB_MODE_EDIT)
subsurf_flags |= SUBSURF_IN_EDIT_MODE;
#ifdef WITH_OPENSUBDIV
/* TODO(sergey): Not entirely correct, modifiers on top of subsurf
* could be disabled.
*/
if (md->next == NULL && allow_gpu && do_cddm_convert == false) {
subsurf_flags |= SUBSURF_USE_GPU_BACKEND;
}
#endif
result = subsurf_make_derived_from_derived(derivedData, smd, NULL, subsurf_flags);
result->cd_flag = derivedData->cd_flag;
if (useRenderParams || !isFinalCalc) {
if (do_cddm_convert) {
DerivedMesh *cddm = CDDM_copy(result);
result->release(result);
result = cddm;
@ -129,6 +145,15 @@ static DerivedMesh *applyModifierEM(ModifierData *md, Object *UNUSED(ob),
DerivedMesh *result;
/* 'orco' using editmode flags would cause cache to be used twice in editbmesh_calc_modifiers */
SubsurfFlags ss_flags = (flag & MOD_APPLY_ORCO) ? 0 : (SUBSURF_FOR_EDIT_MODE | SUBSURF_IN_EDIT_MODE);
#ifdef WITH_OPENSUBDIV
const bool allow_gpu = (flag & MOD_APPLY_ALLOW_GPU) != 0;
/* TODO(sergey): Not entirely correct, modifiers on top of subsurf
* could be disabled.
*/
if (md->next == NULL && allow_gpu) {
ss_flags |= SUBSURF_USE_GPU_BACKEND;
}
#endif
result = subsurf_make_derived_from_derived(derivedData, smd, NULL, ss_flags);

View File

@ -138,6 +138,13 @@ if(WITH_BUILDINFO)
add_definitions(-DWITH_BUILDINFO)
endif()
if(WITH_OPENSUBDIV)
add_definitions(-DWITH_OPENSUBDIV)
list(APPEND INC
../../../intern/opensubdiv
)
endif()
if(WIN32)
if(WITH_INPUT_IME)
add_definitions(-DWITH_INPUT_IME)

View File

@ -86,4 +86,8 @@ if env['WITH_BF_PYTHON_SECURITY']:
if env['OURPLATFORM'] in ('linux', 'openbsd3', 'sunos5', 'freebsd7', 'freebsd8', 'freebsd9', 'aix4', 'aix5'):
defs.append("WITH_X11")
if env['WITH_BF_OPENSUBDIV']:
defs.append("WITH_OPENSUBDIV")
incs += ' #intern/opensubdiv'
env.BlenderLib ( 'bf_windowmanager', sources, Split(incs), defines=defs, libtype=['core'], priority=[5] )

View File

@ -117,6 +117,10 @@
#include "BKE_sound.h"
#include "COM_compositor.h"
#ifdef WITH_OPENSUBDIV
# include "opensubdiv_capi.h"
#endif
static void wm_init_reports(bContext *C)
{
ReportList *reports = CTX_wm_reports(C);
@ -525,6 +529,10 @@ void WM_exit_ext(bContext *C, const bool do_python)
(void)do_python;
#endif
#ifdef WITH_OPENSUBDIV
openSubdiv_cleanup();
#endif
if (!G.background) {
GPU_global_buffer_pool_free();
GPU_free_unused_buffers();

View File

@ -211,6 +211,10 @@ endif()
list(APPEND BLENDER_SORTED_LIBS bf_intern_locale)
endif()
if(WITH_OPENSUBDIV)
list(APPEND BLENDER_SORTED_LIBS bf_intern_opensubdiv)
endif()
foreach(SORTLIB ${BLENDER_SORTED_LIBS})
set(REMLIB ${SORTLIB})
foreach(SEARCHLIB ${BLENDER_LINK_LIBS})

View File

@ -62,7 +62,7 @@ BL_BlenderShader::~BL_BlenderShader()
void BL_BlenderShader::ReloadMaterial()
{
mGPUMat = (mMat) ? GPU_material_from_blender(mBlenderScene, mMat) : NULL;
mGPUMat = (mMat) ? GPU_material_from_blender(mBlenderScene, mMat, false) : NULL;
}
void BL_BlenderShader::SetProg(bool enable, double time, RAS_IRasterizer* rasty)

View File

@ -236,7 +236,7 @@ void RAS_StorageIM::IndexPrimitivesInternal(RAS_MeshSlot& ms, bool multi)
Material* blmat = current_polymat->GetBlenderMaterial();
Scene* blscene = current_polymat->GetBlenderScene();
if (!wireframe && blscene && blmat)
GPU_material_vertex_attributes(GPU_material_from_blender(blscene, blmat), &current_gpu_attribs);
GPU_material_vertex_attributes(GPU_material_from_blender(blscene, blmat, false), &current_gpu_attribs);
else
memset(&current_gpu_attribs, 0, sizeof(current_gpu_attribs));
// DM draw can mess up blending mode, restore at the end