diff options
Diffstat (limited to 'source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c')
-rw-r--r-- | source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c | 103 |
1 files changed, 98 insertions, 5 deletions
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c index 006cebf4573..2bb55c2d1ed 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c +++ b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c @@ -28,12 +28,15 @@ #include "BLI_sys_types.h" // for intptr_t support #include "BLI_utildefines.h" /* for BLI_assert */ +#include "BLI_listbase.h" #include "BLI_math.h" +#include "BLI_threads.h" #include "CCGSubSurf.h" #include "CCGSubSurf_intern.h" #include "BKE_DerivedMesh.h" +#include "BKE_subsurf.h" #include "DNA_userdef_types.h" @@ -41,6 +44,7 @@ #include "opensubdiv_converter_capi.h" #include "GL/glew.h" +#include "GPU_extensions.h" #define OSD_LOG if (false) printf @@ -236,7 +240,7 @@ bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, bool use_osd_glsl) if (ss->osd_mesh_invalid) { if (ss->osd_mesh != NULL) { - openSubdiv_deleteOsdGLMesh(ss->osd_mesh); + ccgSubSurf__delete_osdGLMesh(ss->osd_mesh); ss->osd_mesh = NULL; } ss->osd_mesh_invalid = false; @@ -314,9 +318,12 @@ int ccgSubSurf_getNumGLMeshBaseFaces(CCGSubSurf *ss) if (ss->osd_topology_refiner != NULL) { topology_refiner = ss->osd_topology_refiner; } - else { + else if (ss->osd_mesh != NULL) { topology_refiner = openSubdiv_getGLMeshTopologyRefiner(ss->osd_mesh); } + else { + return 0; + } return openSubdiv_topologyRefinerGetNumFaces(topology_refiner); } @@ -327,9 +334,12 @@ int ccgSubSurf_getNumGLMeshBaseFaceVerts(CCGSubSurf *ss, int face) if (ss->osd_topology_refiner != NULL) { topology_refiner = ss->osd_topology_refiner; } - else { + else if (ss->osd_mesh != NULL) { topology_refiner = openSubdiv_getGLMeshTopologyRefiner(ss->osd_mesh); } + else { + return 0; + } return openSubdiv_topologyRefinerGetNumFaceVerts(topology_refiner, face); } @@ -891,8 +901,7 @@ void ccgSubSurf__sync_opensubdiv(CCGSubSurf *ss) void ccgSubSurf_free_osd_mesh(CCGSubSurf *ss) { if (ss->osd_mesh != NULL) { - /* TODO(sergey): Make sure free happens form the main thread! */ - openSubdiv_deleteOsdGLMesh(ss->osd_mesh); + ccgSubSurf__delete_osdGLMesh(ss->osd_mesh); ss->osd_mesh = NULL; } if (ss->osd_vao != 0) { @@ -905,10 +914,94 @@ void ccgSubSurf_getMinMax(CCGSubSurf *ss, float r_min[3], float r_max[3]) { int i; BLI_assert(ss->skip_grids == true); + if (ss->osd_num_coarse_coords == 0) { + zero_v3(r_min); + zero_v3(r_max); + } for (i = 0; i < ss->osd_num_coarse_coords; i++) { /* Coarse coordinates has normals interleaved into the array. */ DO_MINMAX(ss->osd_coarse_coords[2 * i], r_min, r_max); } } +/* ** Delayed delete routines ** */ + +typedef struct OsdDeletePendingItem { + struct OsdDeletePendingItem *next, *prev; + OpenSubdiv_GLMesh *osd_mesh; + unsigned int vao; +} OsdDeletePendingItem; + +static SpinLock delete_spin; +static ListBase delete_pool = {NULL, NULL}; + +static void delete_pending_push(OpenSubdiv_GLMesh *osd_mesh, + unsigned int vao) +{ + OsdDeletePendingItem *new_entry = MEM_mallocN(sizeof(OsdDeletePendingItem), + "opensubdiv delete entry"); + new_entry->osd_mesh = osd_mesh; + new_entry->vao = vao; + BLI_spin_lock(&delete_spin); + BLI_addtail(&delete_pool, new_entry); + BLI_spin_unlock(&delete_spin); +} + +void ccgSubSurf__delete_osdGLMesh(OpenSubdiv_GLMesh *osd_mesh) +{ + if (BLI_thread_is_main()) { + openSubdiv_deleteOsdGLMesh(osd_mesh); + } + else { + delete_pending_push(osd_mesh, 0); + } +} + +void ccgSubSurf__delete_vertex_array(unsigned int vao) +{ + if (BLI_thread_is_main()) { + glDeleteVertexArrays(1, &vao); + } + else { + delete_pending_push(NULL, vao); + } +} + +void ccgSubSurf__delete_pending(void) +{ + OsdDeletePendingItem *entry; + BLI_assert(BLI_thread_is_main()); + BLI_spin_lock(&delete_spin); + for (entry = delete_pool.first; entry != NULL; entry = entry->next) { + if (entry->osd_mesh != NULL) { + openSubdiv_deleteOsdGLMesh(entry->osd_mesh); + } + if (entry->vao != 0) { + glDeleteVertexArrays(1, &entry->vao); + } + } + BLI_freelistN(&delete_pool); + BLI_spin_unlock(&delete_spin); +} + +/* ** Public API ** */ + +void BKE_subsurf_osd_init(void) +{ + openSubdiv_init(GPU_legacy_support()); + BLI_spin_init(&delete_spin); +} + +void BKE_subsurf_free_unused_buffers(void) +{ + ccgSubSurf__delete_pending(); +} + +void BKE_subsurf_osd_cleanup(void) +{ + openSubdiv_cleanup(); + ccgSubSurf__delete_pending(); + BLI_spin_end(&delete_spin); +} + #endif /* WITH_OPENSUBDIV */ |