diff options
-rw-r--r-- | source/blender/blenkernel/BKE_pbvh.h | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/pbvh.c | 247 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_manager_data.c | 19 | ||||
-rw-r--r-- | source/blender/gpu/GPU_buffers.h | 20 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_buffers.c | 151 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_init_exit.c | 4 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_private.h | 4 |
7 files changed, 270 insertions, 177 deletions
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index 563546251bf..fa773ce78d9 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -173,6 +173,7 @@ bool BKE_pbvh_node_find_nearest_to_ray(PBVH *bvh, /* Drawing */ void BKE_pbvh_draw_cb(PBVH *bvh, + bool show_vcol, PBVHFrustumPlanes *frustum, void (*draw_fn)(void *user_data, struct GPU_PBVH_Buffers *buffers), void *user_data); @@ -266,7 +267,6 @@ void BKE_pbvh_bmesh_after_stroke(PBVH *bvh); void BKE_pbvh_update_bounds(PBVH *bvh, int flags); void BKE_pbvh_update_normals(PBVH *bvh, struct SubdivCCG *subdiv_ccg); -void BKE_pbvh_update_draw_buffers(PBVH *bvh, bool show_vcol); void BKE_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3]); void BKE_pbvh_get_grid_updates(PBVH *bvh, bool clear, void ***r_gridfaces, int *r_totface); void BKE_pbvh_grids_update(PBVH *bvh, diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index bfc513454b4..50ea4fb0b36 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -988,6 +988,7 @@ typedef struct PBVHUpdateData { float (*vnors)[3]; int flag; + bool show_vcol; } PBVHUpdateData; static void pbvh_update_normals_accum_task_cb(void *__restrict userdata, @@ -1148,71 +1149,105 @@ static int pbvh_get_buffers_update_flags(PBVH *bvh, bool show_vcol) return update_flags; } -static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode, bool show_vcol) -{ - /* can't be done in parallel with OpenGL */ - for (int n = 0; n < totnode; n++) { - PBVHNode *node = nodes[n]; - - if (node->flag & PBVH_RebuildDrawBuffers) { - GPU_pbvh_buffers_free(node->draw_buffers); - switch (bvh->type) { - case PBVH_GRIDS: - node->draw_buffers = GPU_pbvh_grid_buffers_build(node->totprim, bvh->grid_hidden); - break; - case PBVH_FACES: - node->draw_buffers = GPU_pbvh_mesh_buffers_build(node->face_vert_indices, - bvh->mpoly, - bvh->mloop, - bvh->looptri, - bvh->verts, - node->prim_indices, - node->totprim); - break; - case PBVH_BMESH: - node->draw_buffers = GPU_pbvh_bmesh_buffers_build(bvh->flags & - PBVH_DYNTOPO_SMOOTH_SHADING); - break; - } - - node->flag &= ~PBVH_RebuildDrawBuffers; - } +static void pbvh_update_draw_buffer_cb(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + /* Create and update draw buffers. The functions called here must not + * do any OpenGL calls. Flags are not cleared immediately, that happens + * after GPU_pbvh_buffer_flush() which does the final OpenGL calls. */ + PBVHUpdateData *data = userdata; + PBVH *bvh = data->bvh; + PBVHNode *node = data->nodes[n]; - if (node->flag & PBVH_UpdateDrawBuffers) { - const int update_flags = pbvh_get_buffers_update_flags(bvh, show_vcol); - switch (bvh->type) { - case PBVH_GRIDS: - GPU_pbvh_grid_buffers_update(node->draw_buffers, - bvh->grids, - bvh->grid_flag_mats, - node->prim_indices, - node->totprim, - &bvh->gridkey, - update_flags); - break; - case PBVH_FACES: - GPU_pbvh_mesh_buffers_update(node->draw_buffers, - bvh->verts, - node->vert_indices, - node->uniq_verts + node->face_verts, - CustomData_get_layer(bvh->vdata, CD_PAINT_MASK), - CustomData_get_layer(bvh->ldata, CD_MLOOPCOL), - node->face_vert_indices, - update_flags); - break; - case PBVH_BMESH: - GPU_pbvh_bmesh_buffers_update(node->draw_buffers, - bvh->bm, - node->bm_faces, - node->bm_unique_verts, - node->bm_other_verts, - update_flags); - break; + if (node->flag & PBVH_RebuildDrawBuffers) { + switch (bvh->type) { + case PBVH_GRIDS: + node->draw_buffers = GPU_pbvh_grid_buffers_build(node->totprim, bvh->grid_hidden); + break; + case PBVH_FACES: + node->draw_buffers = GPU_pbvh_mesh_buffers_build(node->face_vert_indices, + bvh->mpoly, + bvh->mloop, + bvh->looptri, + bvh->verts, + node->prim_indices, + node->totprim); + break; + case PBVH_BMESH: + node->draw_buffers = GPU_pbvh_bmesh_buffers_build(bvh->flags & + PBVH_DYNTOPO_SMOOTH_SHADING); + break; + } + } + + if (node->flag & PBVH_UpdateDrawBuffers) { + const int update_flags = pbvh_get_buffers_update_flags(bvh, data->show_vcol); + switch (bvh->type) { + case PBVH_GRIDS: + GPU_pbvh_grid_buffers_update(node->draw_buffers, + bvh->grids, + bvh->grid_flag_mats, + node->prim_indices, + node->totprim, + &bvh->gridkey, + update_flags); + break; + case PBVH_FACES: + GPU_pbvh_mesh_buffers_update(node->draw_buffers, + bvh->verts, + node->vert_indices, + node->uniq_verts + node->face_verts, + CustomData_get_layer(bvh->vdata, CD_PAINT_MASK), + CustomData_get_layer(bvh->ldata, CD_MLOOPCOL), + node->face_vert_indices, + update_flags); + break; + case PBVH_BMESH: + GPU_pbvh_bmesh_buffers_update(node->draw_buffers, + bvh->bm, + node->bm_faces, + node->bm_unique_verts, + node->bm_other_verts, + update_flags); + break; + } + } +} + +static void pbvh_update_draw_buffers( + PBVH *bvh, PBVHNode **nodes, int totnode, bool show_vcol, int update_flag) +{ + if ((update_flag & PBVH_RebuildDrawBuffers) || ELEM(bvh->type, PBVH_GRIDS, PBVH_BMESH)) { + /* Free buffers uses OpenGL, so not in parallel. */ + for (int n = 0; n < totnode; n++) { + PBVHNode *node = nodes[n]; + if (node->flag & PBVH_RebuildDrawBuffers) { + GPU_pbvh_buffers_free(node->draw_buffers); + node->draw_buffers = NULL; + } + else if ((node->flag & PBVH_UpdateDrawBuffers) && node->draw_buffers) { + if (bvh->type == PBVH_GRIDS) { + GPU_pbvh_grid_buffers_update_free( + node->draw_buffers, bvh->grid_flag_mats, node->prim_indices); + } + else if (bvh->type == PBVH_BMESH) { + GPU_pbvh_bmesh_buffers_update_free(node->draw_buffers); + } } - - node->flag &= ~PBVH_UpdateDrawBuffers; } } + + /* Parallel creation and update of draw buffers. */ + PBVHUpdateData data = { + .bvh = bvh, + .nodes = nodes, + .show_vcol = show_vcol, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, pbvh_update_draw_buffer_cb, &settings); } static int pbvh_flush_bb(PBVH *bvh, PBVHNode *node, int flag) @@ -1568,8 +1603,8 @@ void BKE_pbvh_node_get_bm_orco_data(PBVHNode *node, /** * \note doing a full search on all vertices here seems expensive, - * however this is important to avoid having to recalculate boundbox & sync the buffers to the GPU - * (which is far more expensive!) See: T47232. + * however this is important to avoid having to recalculate boundbox & sync the buffers to the + * GPU (which is far more expensive!) See: T47232. */ bool BKE_pbvh_node_vert_update_check_any(PBVH *bvh, PBVHNode *node) { @@ -2216,20 +2251,6 @@ bool BKE_pbvh_node_frustum_exclude_AABB(PBVHNode *node, void *data) return test_frustum_aabb(bb_min, bb_max, data) != ISECT_INSIDE; } -typedef struct PBVHNodeDrawCallbackData { - void (*draw_fn)(void *user_data, GPU_PBVH_Buffers *buffers); - void *user_data; -} PBVHNodeDrawCallbackData; - -static void pbvh_node_draw_cb(PBVHNode *node, void *data_v) -{ - PBVHNodeDrawCallbackData *data = data_v; - - if (!(node->flag & PBVH_FullyHidden)) { - data->draw_fn(data->user_data, node->draw_buffers); - } -} - void BKE_pbvh_update_normals(PBVH *bvh, struct SubdivCCG *subdiv_ccg) { /* Update normals */ @@ -2260,41 +2281,67 @@ void BKE_pbvh_update_normals(PBVH *bvh, struct SubdivCCG *subdiv_ccg) } } -void BKE_pbvh_update_draw_buffers(PBVH *bvh, bool show_vcol) +/** + * PBVH drawing, updating draw buffers as needed and culling any nodes outside + * the specified frustum. + */ +typedef struct PBVHDrawSearchData { + PBVHFrustumPlanes *frustum; +} PBVHDrawSearchData; + +static bool pbvh_draw_search_cb(PBVHNode *node, void *data_v) +{ + PBVHDrawSearchData *data = data_v; + if (data->frustum && !BKE_pbvh_node_frustum_contain_AABB(node, data->frustum)) { + return false; + } + + return true; +} + +void BKE_pbvh_draw_cb(PBVH *bvh, + bool show_vcol, + PBVHFrustumPlanes *frustum, + void (*draw_fn)(void *user_data, GPU_PBVH_Buffers *buffers), + void *user_data) { - /* Update GPU buffers */ PBVHNode **nodes; int totnode; - BKE_pbvh_search_gather( - bvh, update_search_cb, POINTER_FROM_INT(PBVH_UpdateDrawBuffers), &nodes, &totnode); + /* Update all draw buffers. */ + const int update_flag = PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers; + BKE_pbvh_search_gather(bvh, update_search_cb, POINTER_FROM_INT(update_flag), &nodes, &totnode); - pbvh_update_draw_buffers(bvh, nodes, totnode, show_vcol); + if (totnode) { + pbvh_update_draw_buffers(bvh, nodes, totnode, show_vcol, update_flag); + } if (nodes) { MEM_freeN(nodes); } -} -/** - * Version of #BKE_pbvh_draw that runs a callback. - */ -void BKE_pbvh_draw_cb(PBVH *bvh, - PBVHFrustumPlanes *frustum, - void (*draw_fn)(void *user_data, GPU_PBVH_Buffers *buffers), - void *user_data) -{ - PBVHNodeDrawCallbackData draw_data = { - .draw_fn = draw_fn, - .user_data = user_data, - }; + /* Gather visible nodes. */ + PBVHDrawSearchData data = {.frustum = frustum}; + BKE_pbvh_search_gather(bvh, pbvh_draw_search_cb, &data, &nodes, &totnode); + + /* Draw. */ + for (int a = 0; a < totnode; a++) { + PBVHNode *node = nodes[a]; - if (frustum) { - BKE_pbvh_search_callback( - bvh, BKE_pbvh_node_frustum_contain_AABB, frustum, pbvh_node_draw_cb, &draw_data); + if (node->flag & PBVH_UpdateDrawBuffers) { + /* Flush buffers uses OpenGL, so not in parallel. */ + GPU_pbvh_buffers_update_flush(node->draw_buffers); + } + + node->flag &= ~(PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers); + + if (!(node->flag & PBVH_FullyHidden)) { + draw_fn(user_data, node->draw_buffers); + } } - else { - BKE_pbvh_search_callback(bvh, NULL, NULL, pbvh_node_draw_cb, &draw_data); + + if (nodes) { + MEM_freeN(nodes); } } diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c index 78353a58e33..e978ae44bcd 100644 --- a/source/blender/draw/intern/draw_manager_data.c +++ b/source/blender/draw/intern/draw_manager_data.c @@ -834,14 +834,14 @@ static float sculpt_debug_colors[9][4] = { static void sculpt_draw_cb(DRWSculptCallbackData *scd, GPU_PBVH_Buffers *buffers) { - GPUBatch *geom = GPU_pbvh_buffers_batch_get(buffers, scd->fast_mode, scd->use_wire); - short index = 0; - /* Meh... use_mask is a bit misleading here. */ if (scd->use_mask && !GPU_pbvh_buffers_has_mask(buffers)) { return; } + GPUBatch *geom = GPU_pbvh_buffers_batch_get(buffers, scd->fast_mode, scd->use_wire); + short index = 0; + if (scd->use_mats) { index = GPU_pbvh_buffers_material_index_get(buffers); } @@ -906,25 +906,28 @@ static void drw_sculpt_generate_calls(DRWSculptCallbackData *scd, bool use_vcol) return; } + const DRWContextState *drwctx = DRW_context_state_get(); + RegionView3D *rv3d = drwctx->rv3d; + + /* Frustum planes to show only visible PBVH nodes. */ float planes[6][4]; drw_sculpt_get_frustum_planes(scd->ob, planes); PBVHFrustumPlanes frustum = {.planes = planes, .num_planes = 6}; + /* Fast mode to show low poly multires while navigating. */ scd->fast_mode = false; - - const DRWContextState *drwctx = DRW_context_state_get(); if (drwctx->evil_C != NULL) { Paint *p = BKE_paint_get_active_from_context(drwctx->evil_C); if (p && (p->flags & PAINT_FAST_NAVIGATE)) { - scd->fast_mode = (drwctx->rv3d->rflag & RV3D_NAVIGATING) != 0; + scd->fast_mode = rv3d && (rv3d->rflag & RV3D_NAVIGATING); } } Mesh *mesh = scd->ob->data; BKE_pbvh_update_normals(pbvh, mesh->runtime.subdiv_ccg); - BKE_pbvh_update_draw_buffers(pbvh, use_vcol); - BKE_pbvh_draw_cb(pbvh, &frustum, (void (*)(void *, GPU_PBVH_Buffers *))sculpt_draw_cb, scd); + BKE_pbvh_draw_cb( + pbvh, use_vcol, &frustum, (void (*)(void *, GPU_PBVH_Buffers *))sculpt_draw_cb, scd); if (SCULPT_DEBUG_BUFFERS) { int debug_node_nr = 0; diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h index 9009c134837..552bad2b0d6 100644 --- a/source/blender/gpu/GPU_buffers.h +++ b/source/blender/gpu/GPU_buffers.h @@ -41,7 +41,8 @@ struct PBVH; /* Buffers for drawing from PBVH grids. */ typedef struct GPU_PBVH_Buffers GPU_PBVH_Buffers; -/* build */ +/* Build must be called once before using the other functions, used every time + * mesh topology changes. Threaded. */ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3], const struct MPoly *mpoly, const struct MLoop *mloop, @@ -54,8 +55,13 @@ GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, unsigned int **grid_h GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading); -/* update */ +/* Free part of data for update. Not thread safe, must run in OpenGL main thread. */ +void GPU_pbvh_bmesh_buffers_update_free(GPU_PBVH_Buffers *buffers); +void GPU_pbvh_grid_buffers_update_free(GPU_PBVH_Buffers *buffers, + const struct DMFlagMat *grid_flag_mats, + int *grid_indices); +/* Update mesh buffers without topology changes. Threaded. */ enum { GPU_PBVH_BUFFERS_SHOW_MASK = (1 << 1), GPU_PBVH_BUFFERS_SHOW_VCOL = (1 << 1), @@ -85,6 +91,12 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers, const struct CCGKey *key, const int update_flags); +/* Finish update. Not thread safe, must run in OpenGL main thread. */ +void GPU_pbvh_buffers_update_flush(GPU_PBVH_Buffers *buffers); + +/* Free buffers. Not thread safe, must run in OpenGL main thread. */ +void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers); + /* draw */ struct GPUBatch *GPU_pbvh_buffers_batch_get(GPU_PBVH_Buffers *buffers, bool fast, bool wires); @@ -92,8 +104,4 @@ short GPU_pbvh_buffers_material_index_get(GPU_PBVH_Buffers *buffers); bool GPU_pbvh_buffers_has_mask(GPU_PBVH_Buffers *buffers); -void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers); - -void GPU_pbvh_fix_linking(void); - #endif diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index 3511c7438cb..cf9a8142530 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -45,6 +45,8 @@ #include "GPU_buffers.h" #include "GPU_batch.h" +#include "gpu_private.h" + #include "bmesh.h" /* XXX: the rest of the code in this file is used for optimized PBVH @@ -78,6 +80,7 @@ struct GPU_PBVH_Buffers { int totgrid; bool use_bmesh; + bool clear_bmesh_on_flush; uint tot_tri, tot_quad; @@ -91,8 +94,9 @@ struct GPU_PBVH_Buffers { }; static struct { + GPUVertFormat format; uint pos, nor, msk, col; -} g_vbo_id = {0}; +} g_vbo_id = {{0}}; /** \} */ @@ -100,6 +104,27 @@ static struct { /** \name PBVH Utils * \{ */ +void gpu_pbvh_init() +{ + /* Initialize vertex buffer (match 'VertexBufferFormat'). */ + if (g_vbo_id.format.attr_len == 0) { + g_vbo_id.pos = GPU_vertformat_attr_add( + &g_vbo_id.format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + g_vbo_id.nor = GPU_vertformat_attr_add( + &g_vbo_id.format, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); + /* TODO: Do not allocate these `.msk` and `.col` when they are not used. */ + g_vbo_id.msk = GPU_vertformat_attr_add( + &g_vbo_id.format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + g_vbo_id.col = GPU_vertformat_attr_add( + &g_vbo_id.format, "ac", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); + } +} + +void gpu_pbvh_exit() +{ + /* Nothing to do. */ +} + /* Allocates a non-initialized buffer to be sent to GPU. * Return is false it indicates that the memory map failed. */ static bool gpu_pbvh_vert_buf_data_set(GPU_PBVH_Buffers *buffers, uint vert_len) @@ -110,14 +135,7 @@ static bool gpu_pbvh_vert_buf_data_set(GPU_PBVH_Buffers *buffers, uint vert_len) #if 0 if (buffers->vert_buf == NULL) { /* Initialize vertex buffer (match 'VertexBufferFormat'). */ - static GPUVertFormat format = {0}; - if (format.attr_len == 0) { - g_vbo_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - g_vbo_id.nor = GPU_vertformat_attr_add( - &format, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); - g_vbo_id.msk = GPU_vertformat_attr_add(&format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); - } - buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&format, GPU_USAGE_DYNAMIC); + buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&g_vbo_id.format, GPU_USAGE_DYNAMIC); GPU_vertbuf_data_alloc(buffers->vert_buf, vert_len); } else if (vert_len != buffers->vert_buf->vertex_len) { @@ -126,30 +144,16 @@ static bool gpu_pbvh_vert_buf_data_set(GPU_PBVH_Buffers *buffers, uint vert_len) #else if (buffers->vert_buf == NULL) { /* Initialize vertex buffer (match 'VertexBufferFormat'). */ - static GPUVertFormat format = {0}; - if (format.attr_len == 0) { - g_vbo_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - g_vbo_id.nor = GPU_vertformat_attr_add( - &format, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); - /* TODO: Do not allocate these `.msk` and `.col` when they are not used. */ - g_vbo_id.msk = GPU_vertformat_attr_add(&format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); - g_vbo_id.col = GPU_vertformat_attr_add( - &format, "ac", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); - } - buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&format, GPU_USAGE_STATIC); + buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&g_vbo_id.format, GPU_USAGE_STATIC); } GPU_vertbuf_data_alloc(buffers->vert_buf, vert_len); #endif + return buffers->vert_buf->data != NULL; } static void gpu_pbvh_batch_init(GPU_PBVH_Buffers *buffers, GPUPrimType prim) { - /* force flushing to the GPU */ - if (buffers->vert_buf->data) { - GPU_vertbuf_use(buffers->vert_buf); - } - if (buffers->triangles == NULL) { buffers->triangles = GPU_batch_create(prim, buffers->vert_buf, @@ -180,6 +184,7 @@ static void gpu_pbvh_batch_init(GPU_PBVH_Buffers *buffers, GPUPrimType prim) /** \name Mesh PBVH * \{ */ +/* Threaded - do not call any functions that use OpenGL calls! */ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers, const MVert *mvert, const int *vert_indices, @@ -298,6 +303,7 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers, buffers->mvert = mvert; } +/* Threaded - do not call any functions that use OpenGL calls! */ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3], const MPoly *mpoly, const MLoop *mloop, @@ -336,11 +342,6 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3], return buffers; } - GPU_BATCH_DISCARD_SAFE(buffers->triangles); - GPU_BATCH_DISCARD_SAFE(buffers->lines); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf); - /* An element index buffer is used for smooth shading, but flat * shading requires separate vertex normals so an index buffer * can't be used there. */ @@ -537,6 +538,27 @@ static void gpu_pbvh_grid_fill_index_buffers( buffers->index_lines_buf_fast = GPU_indexbuf_build(&elb_lines_fast); } +void GPU_pbvh_grid_buffers_update_free(GPU_PBVH_Buffers *buffers, + const struct DMFlagMat *grid_flag_mats, + int *grid_indices) +{ + const bool smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH; + + if (buffers->smooth != smooth) { + buffers->smooth = smooth; + GPU_BATCH_DISCARD_SAFE(buffers->triangles); + GPU_BATCH_DISCARD_SAFE(buffers->triangles_fast); + GPU_BATCH_DISCARD_SAFE(buffers->lines); + GPU_BATCH_DISCARD_SAFE(buffers->lines_fast); + + GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf); + GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf_fast); + GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf); + GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf_fast); + } +} + +/* Threaded - do not call any functions that use OpenGL calls! */ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers, CCGElem **grids, const DMFlagMat *grid_flag_mats, @@ -550,26 +572,13 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers, bool empty_mask = true; int i, j, k, x, y; - const bool smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH; - /* Build VBO */ const int has_mask = key->has_mask; - uint vert_per_grid = (smooth) ? key->grid_area : (SQUARE(key->grid_size - 1) * 4); - uint vert_count = totgrid * vert_per_grid; - - if (buffers->smooth != smooth) { - buffers->smooth = smooth; - GPU_BATCH_DISCARD_SAFE(buffers->triangles); - GPU_BATCH_DISCARD_SAFE(buffers->triangles_fast); - GPU_BATCH_DISCARD_SAFE(buffers->lines); - GPU_BATCH_DISCARD_SAFE(buffers->lines_fast); + buffers->smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH; - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf_fast); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf_fast); - } + uint vert_per_grid = (buffers->smooth) ? key->grid_area : (SQUARE(key->grid_size - 1) * 4); + uint vert_count = totgrid * vert_per_grid; if (buffers->index_buf == NULL) { uint visible_quad_len = BKE_pbvh_count_grid_quads( @@ -692,6 +701,7 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers, buffers->show_mask = !empty_mask; } +/* Threaded - do not call any functions that use OpenGL calls! */ GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, BLI_bitmap **grid_hidden) { GPU_PBVH_Buffers *buffers; @@ -796,8 +806,24 @@ static int gpu_bmesh_face_visible_count(GSet *bm_faces) return totface; } +void GPU_pbvh_bmesh_buffers_update_free(GPU_PBVH_Buffers *buffers) +{ + if (buffers->smooth) { + /* Smooth needs to recreate index buffer, so we have to invalidate the batch. */ + GPU_BATCH_DISCARD_SAFE(buffers->triangles); + GPU_BATCH_DISCARD_SAFE(buffers->lines); + GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf); + GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf); + } + else { + GPU_BATCH_DISCARD_SAFE(buffers->lines); + GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf); + } +} + /* Creates a vertex buffer (coordinate, normal, color) and, if smooth - * shading, an element index buffer. */ + * shading, an element index buffer. + * Threaded - do not call any functions that use OpenGL calls! */ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers, BMesh *bm, GSet *bm_faces, @@ -815,17 +841,10 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers, tottri = gpu_bmesh_face_visible_count(bm_faces); if (buffers->smooth) { - /* Smooth needs to recreate index buffer, so we have to invalidate the batch. */ - GPU_BATCH_DISCARD_SAFE(buffers->triangles); - GPU_BATCH_DISCARD_SAFE(buffers->lines); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf); /* Count visible vertices */ totvert = gpu_bmesh_vert_visible_count(bm_unique_verts, bm_other_verts); } else { - GPU_BATCH_DISCARD_SAFE(buffers->lines); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf); totvert = tottri * 3; } @@ -834,9 +853,7 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers, /* Node is just hidden. */ } else { - GPU_BATCH_DISCARD_SAFE(buffers->triangles); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf); - GPU_VERTBUF_DISCARD_SAFE(buffers->vert_buf); + buffers->clear_bmesh_on_flush = true; } buffers->tot_tri = 0; return; @@ -991,6 +1008,7 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers, /** \name Generic * \{ */ +/* Threaded - do not call any functions that use OpenGL calls! */ GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading) { GPU_PBVH_Buffers *buffers; @@ -1023,6 +1041,21 @@ short GPU_pbvh_buffers_material_index_get(GPU_PBVH_Buffers *buffers) return buffers->material_index; } +void GPU_pbvh_buffers_update_flush(GPU_PBVH_Buffers *buffers) +{ + /* Free empty bmesh node buffers. */ + if (buffers->clear_bmesh_on_flush) { + GPU_BATCH_DISCARD_SAFE(buffers->triangles); + GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf); + GPU_VERTBUF_DISCARD_SAFE(buffers->vert_buf); + } + + /* Force flushing to the GPU. */ + if (buffers->vert_buf && buffers->vert_buf->data) { + GPU_vertbuf_use(buffers->vert_buf); + } +} + void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers) { if (buffers) { @@ -1041,7 +1074,3 @@ void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers) } /** \} */ - -void GPU_pbvh_fix_linking() -{ -} diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c index 2f84a1cbd27..0009e7d8c47 100644 --- a/source/blender/gpu/intern/gpu_init_exit.c +++ b/source/blender/gpu/intern/gpu_init_exit.c @@ -62,11 +62,13 @@ void GPU_init(void) immInit(); } - GPU_pbvh_fix_linking(); + gpu_pbvh_init(); } void GPU_exit(void) { + gpu_pbvh_exit(); + if (!G.background) { immDestroy(); } diff --git a/source/blender/gpu/intern/gpu_private.h b/source/blender/gpu/intern/gpu_private.h index 43b2da13e28..b9af8f1b38c 100644 --- a/source/blender/gpu/intern/gpu_private.h +++ b/source/blender/gpu/intern/gpu_private.h @@ -33,4 +33,8 @@ void gpu_debug_exit(void); void gpu_framebuffer_module_init(void); void gpu_framebuffer_module_exit(void); +/* gpu_pbvh.c */ +void gpu_pbvh_init(void); +void gpu_pbvh_exit(void); + #endif /* __GPU_PRIVATE_H__ */ |