Sculpt: multithread GPU draw buffer filling for workbench

This improves performance of some sculpt tools, particularly those that modify
many vertices like filter and mask tools, or use brushes with large radius.

For mask expand it can make updates up to 2x faster on heavy meshes, but for
most tools it's more on the order of 1-1.1x. There are bigger bottlenecks to
solve, like normal updates.

Ref T70295

Differential Revision: https://developer.blender.org/D5926
This commit is contained in:
Brecht Van Lommel 2019-09-27 22:42:57 +02:00
parent c931a0057f
commit f6fc863acd
Notes: blender-bot 2023-02-14 09:21:21 +01:00
Referenced by issue #70295, Sculpt partial redraw not working
7 changed files with 273 additions and 180 deletions

View File

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

View File

@ -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)
static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict UNUSED(tls))
{
/* can't be done in parallel with OpenGL */
for (int n = 0; n < totnode; n++) {
PBVHNode *node = nodes[n];
/* 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_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;
}
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;
}
node->flag &= ~PBVH_UpdateDrawBuffers;
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);
}
}
}
}
/* 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)
{
/* Update GPU buffers */
PBVHNode **nodes;
int totnode;
BKE_pbvh_search_gather(
bvh, update_search_cb, POINTER_FROM_INT(PBVH_UpdateDrawBuffers), &nodes, &totnode);
pbvh_update_draw_buffers(bvh, nodes, totnode, show_vcol);
if (nodes) {
MEM_freeN(nodes);
PBVHDrawSearchData *data = data_v;
if (data->frustum && !BKE_pbvh_node_frustum_contain_AABB(node, data->frustum)) {
return false;
}
return true;
}
/**
* Version of #BKE_pbvh_draw that runs a callback.
*/
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)
{
PBVHNodeDrawCallbackData draw_data = {
.draw_fn = draw_fn,
.user_data = user_data,
};
PBVHNode **nodes;
int totnode;
if (frustum) {
BKE_pbvh_search_callback(
bvh, BKE_pbvh_node_frustum_contain_AABB, frustum, pbvh_node_draw_cb, &draw_data);
/* 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);
if (totnode) {
pbvh_update_draw_buffers(bvh, nodes, totnode, show_vcol, update_flag);
}
else {
BKE_pbvh_search_callback(bvh, NULL, NULL, pbvh_node_draw_cb, &draw_data);
if (nodes) {
MEM_freeN(nodes);
}
/* 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 (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);
}
}
if (nodes) {
MEM_freeN(nodes);
}
}

View File

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

View File

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

View File

@ -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,27 +538,12 @@ 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(GPU_PBVH_Buffers *buffers,
CCGElem **grids,
const DMFlagMat *grid_flag_mats,
int *grid_indices,
int totgrid,
const CCGKey *key,
const int update_flags)
void GPU_pbvh_grid_buffers_update_free(GPU_PBVH_Buffers *buffers,
const struct DMFlagMat *grid_flag_mats,
int *grid_indices)
{
const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0;
const bool show_vcol = (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0;
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);
@ -570,6 +556,29 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
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,
int *grid_indices,
int totgrid,
const CCGKey *key,
const int update_flags)
{
const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0;
const bool show_vcol = (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0;
bool empty_mask = true;
int i, j, k, x, y;
/* Build VBO */
const int has_mask = key->has_mask;
buffers->smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH;
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()
{
}

View File

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

View File

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