Fix T77496: Bones Custom Shapes Wires not drawn

Lines loose extraction cannot happen on the fly as the render data isn't
complete. This patch will do the lines loose subbuffer extraction as a
simple task and not on the fly.

This patch introduces 2 sub-types of tasks that are executed single threaded.
`EXTRACT_MESH_EXTRACT` would do the extraction using Mesh/BMesh geometry.
`EXTRACT_LINES_LOOSE` creates the `lines_loose` subbuffer from already cached
`lines` IBO.

Reviewed By: Clément Foucault

Differential Revision: https://developer.blender.org/D7964
This commit is contained in:
Jeroen Bakker 2020-06-15 16:46:56 +02:00 committed by Jeroen Bakker
parent df1ff76ee2
commit 624994caa2
Notes: blender-bot 2023-02-14 08:49:53 +01:00
Referenced by issue #77496, Invisible loose edges on objects used in bone visualization
1 changed files with 69 additions and 36 deletions

View File

@ -4558,10 +4558,16 @@ typedef struct ExtractUserData {
void *user_data;
} ExtractUserData;
typedef enum ExtractTaskDataType {
EXTRACT_MESH_EXTRACT,
EXTRACT_LINES_LOOSE,
} ExtractTaskDataType;
typedef struct ExtractTaskData {
void *next, *prev;
const MeshRenderData *mr;
const MeshExtract *extract;
ExtractTaskDataType tasktype;
eMRIterType iter_type;
int start, end;
/** Decremented each time a task is finished. */
@ -4570,6 +4576,41 @@ typedef struct ExtractTaskData {
ExtractUserData *user_data;
} ExtractTaskData;
static ExtractTaskData *extract_task_data_create_mesh_extract(const MeshRenderData *mr,
const MeshExtract *extract,
void *buf,
int32_t *task_counter)
{
ExtractTaskData *taskdata = MEM_mallocN(sizeof(*taskdata), __func__);
taskdata->next = NULL;
taskdata->prev = NULL;
taskdata->tasktype = EXTRACT_MESH_EXTRACT;
taskdata->mr = mr;
taskdata->extract = extract;
taskdata->buf = buf;
/* ExtractUserData is shared between the iterations as it holds counters to detect if the
* extraction is finished. To make sure the duplication of the userdata does not create a new
* instance of the counters we allocate the userdata in its own container.
*
* This structure makes sure that when extract_init is called, that the user data of all
* iterations are updated. */
taskdata->user_data = MEM_callocN(sizeof(ExtractUserData), __func__);
taskdata->iter_type = mesh_extract_iter_type(extract);
taskdata->task_counter = task_counter;
taskdata->start = 0;
taskdata->end = INT_MAX;
return taskdata;
}
static ExtractTaskData *extract_task_data_create_lines_loose(const MeshRenderData *mr)
{
ExtractTaskData *taskdata = MEM_callocN(sizeof(*taskdata), __func__);
taskdata->tasktype = EXTRACT_LINES_LOOSE;
taskdata->mr = mr;
return taskdata;
}
static void extract_task_data_free(void *data)
{
ExtractTaskData *task_data = data;
@ -4655,23 +4696,30 @@ BLI_INLINE void mesh_extract_iter(const MeshRenderData *mr,
static void extract_init(ExtractTaskData *data)
{
data->user_data->user_data = data->extract->init(data->mr, data->buf);
if (data->tasktype == EXTRACT_MESH_EXTRACT) {
data->user_data->user_data = data->extract->init(data->mr, data->buf);
}
}
static void extract_run(void *__restrict taskdata)
{
ExtractTaskData *data = (ExtractTaskData *)taskdata;
mesh_extract_iter(data->mr,
data->iter_type,
data->start,
data->end,
data->extract,
data->user_data->user_data);
if (data->tasktype == EXTRACT_MESH_EXTRACT) {
mesh_extract_iter(data->mr,
data->iter_type,
data->start,
data->end,
data->extract,
data->user_data->user_data);
/* If this is the last task, we do the finish function. */
int remainin_tasks = atomic_sub_and_fetch_int32(data->task_counter, 1);
if (remainin_tasks == 0 && data->extract->finish != NULL) {
data->extract->finish(data->mr, data->buf, data->user_data->user_data);
/* If this is the last task, we do the finish function. */
int remainin_tasks = atomic_sub_and_fetch_int32(data->task_counter, 1);
if (remainin_tasks == 0 && data->extract->finish != NULL) {
data->extract->finish(data->mr, data->buf, data->user_data->user_data);
}
}
else if (data->tasktype == EXTRACT_LINES_LOOSE) {
extract_lines_loose_subbuffer(data->mr);
}
}
@ -4695,7 +4743,8 @@ typedef struct MeshRenderDataUpdateTaskData {
static void mesh_render_data_update_task_data_free(MeshRenderDataUpdateTaskData *taskdata)
{
BLI_assert(taskdata);
mesh_render_data_free(taskdata->mr);
MeshRenderData *mr = taskdata->mr;
mesh_render_data_free(mr);
MEM_freeN(taskdata);
}
@ -4851,24 +4900,8 @@ static void extract_task_create(struct TaskGraph *task_graph,
}
/* Divide extraction of the VBO/IBO into sensible chunks of works. */
ExtractTaskData *taskdata = MEM_mallocN(sizeof(*taskdata), "ExtractTaskData");
taskdata->next = NULL;
taskdata->prev = NULL;
taskdata->mr = mr;
taskdata->extract = extract;
taskdata->buf = buf;
/* ExtractUserData is shared between the iterations as it holds counters to detect if the
* extraction is finished. To make sure the duplication of the userdata does not create a new
* instance of the counters we allocate the userdata in its own container.
*
* This structure makes sure that when extract_init is called, that the user data of all
* iterations are updated. */
taskdata->user_data = MEM_callocN(sizeof(ExtractUserData), __func__);
taskdata->iter_type = mesh_extract_iter_type(extract);
taskdata->task_counter = task_counter;
taskdata->start = 0;
taskdata->end = INT_MAX;
ExtractTaskData *taskdata = extract_task_data_create_mesh_extract(
mr, extract, buf, task_counter);
/* Simple heuristic. */
const int chunk_size = 8192;
@ -5009,6 +5042,10 @@ void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
TEST_ASSIGN(IBO, ibo, edituv_points);
TEST_ASSIGN(IBO, ibo, edituv_fdots);
if (do_lines_loose_subbuffer) {
iter_flag |= MR_ITER_LEDGE;
}
#undef TEST_ASSIGN
#ifdef DEBUG_TIME
@ -5106,12 +5143,8 @@ void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
}
else {
if (do_lines_loose_subbuffer) {
/* When `lines_loose` is requested without `lines` we can create the sub-buffer on the fly as
* the `lines` buffer should then already be up-to-date.
* (see `DRW_batch_requested(cache->batch.loose_edges, GPU_PRIM_LINES)` in
* `DRW_mesh_batch_cache_create_requested`).
*/
extract_lines_loose_subbuffer(mr);
ExtractTaskData *taskdata = extract_task_data_create_lines_loose(mr);
BLI_addtail(&single_threaded_task_data->task_datas, taskdata);
}
}
EXTRACT(ibo, points);