Fix T70390: dyntopo smooth shading broken after recent changes

Made the code fully thread safe now.
This commit is contained in:
Brecht Van Lommel 2019-10-02 18:02:41 +02:00
parent a1f16ba67f
commit de4ebcbe43
Notes: blender-bot 2023-02-14 11:24:03 +01:00
Referenced by issue #70390, Dyntopo smooth shading broken
1 changed files with 124 additions and 151 deletions

View File

@ -729,47 +729,36 @@ GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, BLI_bitmap **grid_hid
/** \name BMesh PBVH
* \{ */
/* Output a BMVert into a VertexBufferFormat array
*
* The vertex is skipped if hidden, otherwise the output goes into
* index '*v_index' in the 'vert_data' array and '*v_index' is
* incremented.
*/
static void gpu_bmesh_vert_to_buffer_copy__gwn(BMVert *v,
GPUVertBuf *vert_buf,
int *v_index,
const float fno[3],
const float *fmask,
const int cd_vert_mask_offset,
const bool show_mask,
const bool show_vcol,
bool *empty_mask)
/* Output a BMVert into a VertexBufferFormat array at v_index. */
static void gpu_bmesh_vert_to_buffer_copy(BMVert *v,
GPUVertBuf *vert_buf,
int v_index,
const float fno[3],
const float *fmask,
const int cd_vert_mask_offset,
const bool show_mask,
const bool show_vcol,
bool *empty_mask)
{
if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
/* Vertex should always be visible if it's used by a visible face. */
BLI_assert(!BM_elem_flag_test(v, BM_ELEM_HIDDEN));
/* Set coord, normal, and mask */
GPU_vertbuf_attr_set(vert_buf, g_vbo_id.pos, *v_index, v->co);
/* Set coord, normal, and mask */
GPU_vertbuf_attr_set(vert_buf, g_vbo_id.pos, v_index, v->co);
short no_short[3];
normal_float_to_short_v3(no_short, fno ? fno : v->no);
GPU_vertbuf_attr_set(vert_buf, g_vbo_id.nor, *v_index, no_short);
short no_short[3];
normal_float_to_short_v3(no_short, fno ? fno : v->no);
GPU_vertbuf_attr_set(vert_buf, g_vbo_id.nor, v_index, no_short);
if (show_mask) {
float effective_mask = fmask ? *fmask : BM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset);
GPU_vertbuf_attr_set(vert_buf, g_vbo_id.msk, *v_index, &effective_mask);
*empty_mask = *empty_mask && (effective_mask == 0.0f);
}
if (show_mask) {
float effective_mask = fmask ? *fmask : BM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset);
GPU_vertbuf_attr_set(vert_buf, g_vbo_id.msk, v_index, &effective_mask);
*empty_mask = *empty_mask && (effective_mask == 0.0f);
}
if (show_vcol) {
static char vcol[4] = {255, 255, 255, 255};
GPU_vertbuf_attr_set(vert_buf, g_vbo_id.col, *v_index, &vcol);
}
/* Assign index for use in the triangle index buffer */
/* note: caller must set: bm->elem_index_dirty |= BM_VERT; */
BM_elem_index_set(v, (*v_index)); /* set_dirty! */
(*v_index)++;
if (show_vcol) {
static char vcol[4] = {255, 255, 255, 255};
GPU_vertbuf_attr_set(vert_buf, g_vbo_id.col, v_index, &vcol);
}
}
@ -839,7 +828,7 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
{
const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0;
const bool show_vcol = (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0;
int tottri, totvert, maxvert = 0;
int tottri, totvert;
bool empty_mask = true;
BMFace *f = NULL;
@ -869,135 +858,118 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
/* Fill vertex buffer */
if (gpu_pbvh_vert_buf_data_set(buffers, totvert)) {
int v_index = 0;
if (buffers->smooth) {
GSetIterator gs_iter;
/* Vertices get an index assigned for use in the triangle
* index buffer */
bm->elem_index_dirty |= BM_VERT;
GSET_ITER (gs_iter, bm_unique_verts) {
gpu_bmesh_vert_to_buffer_copy__gwn(BLI_gsetIterator_getKey(&gs_iter),
buffers->vert_buf,
&v_index,
NULL,
NULL,
cd_vert_mask_offset,
show_mask,
show_vcol,
&empty_mask);
}
GSET_ITER (gs_iter, bm_other_verts) {
gpu_bmesh_vert_to_buffer_copy__gwn(BLI_gsetIterator_getKey(&gs_iter),
buffers->vert_buf,
&v_index,
NULL,
NULL,
cd_vert_mask_offset,
show_mask,
show_vcol,
&empty_mask);
}
maxvert = v_index;
}
else {
GSetIterator gs_iter;
GPUIndexBufBuilder elb_lines;
GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, totvert);
GSET_ITER (gs_iter, bm_faces) {
f = BLI_gsetIterator_getKey(&gs_iter);
BLI_assert(f->len == 3);
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
BMVert *v[3];
float fmask = 0.0f;
int i;
BM_face_as_array_vert_tri(f, v);
/* Average mask value */
for (i = 0; i < 3; i++) {
fmask += BM_ELEM_CD_GET_FLOAT(v[i], cd_vert_mask_offset);
}
fmask /= 3.0f;
GPU_indexbuf_add_line_verts(&elb_lines, v_index + 0, v_index + 1);
GPU_indexbuf_add_line_verts(&elb_lines, v_index + 1, v_index + 2);
GPU_indexbuf_add_line_verts(&elb_lines, v_index + 2, v_index + 0);
for (i = 0; i < 3; i++) {
gpu_bmesh_vert_to_buffer_copy__gwn(v[i],
buffers->vert_buf,
&v_index,
f->no,
&fmask,
cd_vert_mask_offset,
show_mask,
show_vcol,
&empty_mask);
}
}
}
buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines);
buffers->tot_tri = tottri;
}
/* gpu_bmesh_vert_to_buffer_copy sets dirty index values */
bm->elem_index_dirty |= BM_VERT;
}
else {
if (!gpu_pbvh_vert_buf_data_set(buffers, totvert)) {
/* Memory map failed */
return;
}
int v_index = 0;
if (buffers->smooth) {
/* Fill the triangle buffer */
/* Fill the vertex and triangle buffer in one pass over faces. */
GPUIndexBufBuilder elb, elb_lines;
GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tottri, maxvert);
GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, maxvert);
GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tottri, totvert);
GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, totvert);
/* Fill triangle index buffer */
{
GSetIterator gs_iter;
GHash *bm_vert_to_index = BLI_ghash_int_new_ex("bm_vert_to_index", totvert);
GSET_ITER (gs_iter, bm_faces) {
f = BLI_gsetIterator_getKey(&gs_iter);
GSetIterator gs_iter;
GSET_ITER (gs_iter, bm_faces) {
f = BLI_gsetIterator_getKey(&gs_iter);
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
BMVert *v[3];
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
BMVert *v[3];
BM_face_as_array_vert_tri(f, v);
BM_face_as_array_vert_tri(f, v);
uint idx[3];
for (int i = 0; i < 3; i++) {
void **idx_p;
if (!BLI_ghash_ensure_p(bm_vert_to_index, v[i], &idx_p)) {
/* Add vertex to the vertex buffer each time a new one is encountered */
*idx_p = POINTER_FROM_UINT(v_index);
const uint idx[3] = {
BM_elem_index_get(v[0]), BM_elem_index_get(v[1]), BM_elem_index_get(v[2])};
GPU_indexbuf_add_tri_verts(&elb, idx[0], idx[1], idx[2]);
gpu_bmesh_vert_to_buffer_copy(v[i],
buffers->vert_buf,
v_index,
NULL,
NULL,
cd_vert_mask_offset,
show_mask,
show_vcol,
&empty_mask);
GPU_indexbuf_add_line_verts(&elb_lines, idx[0], idx[1]);
GPU_indexbuf_add_line_verts(&elb_lines, idx[1], idx[2]);
GPU_indexbuf_add_line_verts(&elb_lines, idx[2], idx[0]);
idx[i] = v_index;
v_index++;
}
else {
/* Vertex already in the vertex buffer, just get the index. */
idx[i] = POINTER_AS_UINT(*idx_p);
}
}
GPU_indexbuf_add_tri_verts(&elb, idx[0], idx[1], idx[2]);
GPU_indexbuf_add_line_verts(&elb_lines, idx[0], idx[1]);
GPU_indexbuf_add_line_verts(&elb_lines, idx[1], idx[2]);
GPU_indexbuf_add_line_verts(&elb_lines, idx[2], idx[0]);
}
}
BLI_ghash_free(bm_vert_to_index, NULL, NULL);
buffers->tot_tri = tottri;
if (buffers->index_buf == NULL) {
buffers->index_buf = GPU_indexbuf_build(&elb);
}
else {
GPU_indexbuf_build_in_place(&elb, buffers->index_buf);
}
buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines);
}
else {
GSetIterator gs_iter;
GPUIndexBufBuilder elb_lines;
GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, tottri * 3);
GSET_ITER (gs_iter, bm_faces) {
f = BLI_gsetIterator_getKey(&gs_iter);
BLI_assert(f->len == 3);
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
BMVert *v[3];
float fmask = 0.0f;
int i;
BM_face_as_array_vert_tri(f, v);
/* Average mask value */
for (i = 0; i < 3; i++) {
fmask += BM_ELEM_CD_GET_FLOAT(v[i], cd_vert_mask_offset);
}
fmask /= 3.0f;
GPU_indexbuf_add_line_verts(&elb_lines, v_index + 0, v_index + 1);
GPU_indexbuf_add_line_verts(&elb_lines, v_index + 1, v_index + 2);
GPU_indexbuf_add_line_verts(&elb_lines, v_index + 2, v_index + 0);
for (i = 0; i < 3; i++) {
gpu_bmesh_vert_to_buffer_copy(v[i],
buffers->vert_buf,
v_index++,
f->no,
&fmask,
cd_vert_mask_offset,
show_mask,
show_vcol,
&empty_mask);
}
}
buffers->tot_tri = tottri;
if (buffers->index_buf == NULL) {
buffers->index_buf = GPU_indexbuf_build(&elb);
}
else {
GPU_indexbuf_build_in_place(&elb, buffers->index_buf);
}
buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines);
}
buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines);
buffers->tot_tri = tottri;
}
/* Get material index from the last face we iterated on. */
@ -1054,6 +1026,7 @@ void GPU_pbvh_buffers_update_flush(GPU_PBVH_Buffers *buffers)
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 = false;
}
/* Force flushing to the GPU. */