Changeset View
Changeset View
Standalone View
Standalone View
source/blender/draw/intern/draw_cache_extract_mesh.c
| Show First 20 Lines • Show All 4,552 Lines • ▼ Show 20 Lines | |||||
| /* ---------------------------------------------------------------------- */ | /* ---------------------------------------------------------------------- */ | ||||
| /** \name ExtractTaskData | /** \name ExtractTaskData | ||||
| * \{ */ | * \{ */ | ||||
| typedef struct ExtractUserData { | typedef struct ExtractUserData { | ||||
| void *user_data; | void *user_data; | ||||
| } ExtractUserData; | } ExtractUserData; | ||||
| typedef enum ExtractTaskDataType { | |||||
| EXTRACT_MESH_EXTRACT, | |||||
| EXTRACT_LINES_LOOSE, | |||||
| } ExtractTaskDataType; | |||||
| typedef struct ExtractTaskData { | typedef struct ExtractTaskData { | ||||
| void *next, *prev; | void *next, *prev; | ||||
| const MeshRenderData *mr; | const MeshRenderData *mr; | ||||
| const MeshExtract *extract; | const MeshExtract *extract; | ||||
| ExtractTaskDataType tasktype; | |||||
| eMRIterType iter_type; | eMRIterType iter_type; | ||||
| int start, end; | int start, end; | ||||
| /** Decremented each time a task is finished. */ | /** Decremented each time a task is finished. */ | ||||
| int32_t *task_counter; | int32_t *task_counter; | ||||
| void *buf; | void *buf; | ||||
| ExtractUserData *user_data; | ExtractUserData *user_data; | ||||
| } ExtractTaskData; | } 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) | static void extract_task_data_free(void *data) | ||||
| { | { | ||||
| ExtractTaskData *task_data = data; | ExtractTaskData *task_data = data; | ||||
| MEM_SAFE_FREE(task_data->user_data); | MEM_SAFE_FREE(task_data->user_data); | ||||
| MEM_freeN(task_data); | MEM_freeN(task_data); | ||||
| } | } | ||||
| BLI_INLINE void mesh_extract_iter(const MeshRenderData *mr, | BLI_INLINE void mesh_extract_iter(const MeshRenderData *mr, | ||||
| ▲ Show 20 Lines • Show All 69 Lines • ▼ Show 20 Lines | case MR_EXTRACT_MESH: | ||||
| } | } | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| static void extract_init(ExtractTaskData *data) | static void extract_init(ExtractTaskData *data) | ||||
| { | { | ||||
| if (data->tasktype == EXTRACT_MESH_EXTRACT) { | |||||
| data->user_data->user_data = data->extract->init(data->mr, data->buf); | data->user_data->user_data = data->extract->init(data->mr, data->buf); | ||||
| } | } | ||||
| } | |||||
| static void extract_run(void *__restrict taskdata) | static void extract_run(void *__restrict taskdata) | ||||
| { | { | ||||
| ExtractTaskData *data = (ExtractTaskData *)taskdata; | ExtractTaskData *data = (ExtractTaskData *)taskdata; | ||||
| if (data->tasktype == EXTRACT_MESH_EXTRACT) { | |||||
| mesh_extract_iter(data->mr, | mesh_extract_iter(data->mr, | ||||
| data->iter_type, | data->iter_type, | ||||
| data->start, | data->start, | ||||
| data->end, | data->end, | ||||
| data->extract, | data->extract, | ||||
| data->user_data->user_data); | data->user_data->user_data); | ||||
| /* If this is the last task, we do the finish function. */ | /* If this is the last task, we do the finish function. */ | ||||
| int remainin_tasks = atomic_sub_and_fetch_int32(data->task_counter, 1); | int remainin_tasks = atomic_sub_and_fetch_int32(data->task_counter, 1); | ||||
| if (remainin_tasks == 0 && data->extract->finish != NULL) { | if (remainin_tasks == 0 && data->extract->finish != NULL) { | ||||
| data->extract->finish(data->mr, data->buf, data->user_data->user_data); | 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); | |||||
| } | |||||
| } | |||||
| static void extract_init_and_run(void *__restrict taskdata) | static void extract_init_and_run(void *__restrict taskdata) | ||||
| { | { | ||||
| extract_init((ExtractTaskData *)taskdata); | extract_init((ExtractTaskData *)taskdata); | ||||
| extract_run(taskdata); | extract_run(taskdata); | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* ---------------------------------------------------------------------- */ | /* ---------------------------------------------------------------------- */ | ||||
| /** \name Task Node - Update Mesh Render Data | /** \name Task Node - Update Mesh Render Data | ||||
| * \{ */ | * \{ */ | ||||
| typedef struct MeshRenderDataUpdateTaskData { | typedef struct MeshRenderDataUpdateTaskData { | ||||
| MeshRenderData *mr; | MeshRenderData *mr; | ||||
| eMRIterType iter_type; | eMRIterType iter_type; | ||||
| eMRDataType data_flag; | eMRDataType data_flag; | ||||
| } MeshRenderDataUpdateTaskData; | } MeshRenderDataUpdateTaskData; | ||||
| static void mesh_render_data_update_task_data_free(MeshRenderDataUpdateTaskData *taskdata) | static void mesh_render_data_update_task_data_free(MeshRenderDataUpdateTaskData *taskdata) | ||||
| { | { | ||||
| BLI_assert(taskdata); | BLI_assert(taskdata); | ||||
| mesh_render_data_free(taskdata->mr); | MeshRenderData *mr = taskdata->mr; | ||||
| mesh_render_data_free(mr); | |||||
| MEM_freeN(taskdata); | MEM_freeN(taskdata); | ||||
| } | } | ||||
| static void mesh_extract_render_data_node_exec(void *__restrict task_data) | static void mesh_extract_render_data_node_exec(void *__restrict task_data) | ||||
| { | { | ||||
| MeshRenderDataUpdateTaskData *update_task_data = task_data; | MeshRenderDataUpdateTaskData *update_task_data = task_data; | ||||
| MeshRenderData *mr = update_task_data->mr; | MeshRenderData *mr = update_task_data->mr; | ||||
| const eMRIterType iter_type = update_task_data->iter_type; | const eMRIterType iter_type = update_task_data->iter_type; | ||||
| ▲ Show 20 Lines • Show All 139 Lines • ▼ Show 20 Lines | static void extract_task_create(struct TaskGraph *task_graph, | ||||
| if (do_hq_normals && (extract == &extract_lnor)) { | if (do_hq_normals && (extract == &extract_lnor)) { | ||||
| extract = &extract_lnor_hq; | extract = &extract_lnor_hq; | ||||
| } | } | ||||
| if (do_hq_normals && (extract == &extract_tan)) { | if (do_hq_normals && (extract == &extract_tan)) { | ||||
| extract = &extract_tan_hq; | extract = &extract_tan_hq; | ||||
| } | } | ||||
| /* Divide extraction of the VBO/IBO into sensible chunks of works. */ | /* Divide extraction of the VBO/IBO into sensible chunks of works. */ | ||||
| ExtractTaskData *taskdata = MEM_mallocN(sizeof(*taskdata), "ExtractTaskData"); | ExtractTaskData *taskdata = extract_task_data_create_mesh_extract( | ||||
| taskdata->next = NULL; | mr, extract, buf, task_counter); | ||||
| 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; | |||||
| /* Simple heuristic. */ | /* Simple heuristic. */ | ||||
| const int chunk_size = 8192; | const int chunk_size = 8192; | ||||
| const bool use_thread = (mr->loop_len + mr->loop_loose_len) > chunk_size; | const bool use_thread = (mr->loop_len + mr->loop_loose_len) > chunk_size; | ||||
| if (use_thread && extract->use_threading) { | if (use_thread && extract->use_threading) { | ||||
| /* Divide task into sensible chunks. */ | /* Divide task into sensible chunks. */ | ||||
| if (taskdata->iter_type & MR_ITER_LOOPTRI) { | if (taskdata->iter_type & MR_ITER_LOOPTRI) { | ||||
| ▲ Show 20 Lines • Show All 124 Lines • ▼ Show 20 Lines | #define TEST_ASSIGN(type, type_lowercase, name) \ | ||||
| TEST_ASSIGN(IBO, ibo, fdots); | TEST_ASSIGN(IBO, ibo, fdots); | ||||
| TEST_ASSIGN(IBO, ibo, lines_paint_mask); | TEST_ASSIGN(IBO, ibo, lines_paint_mask); | ||||
| TEST_ASSIGN(IBO, ibo, lines_adjacency); | TEST_ASSIGN(IBO, ibo, lines_adjacency); | ||||
| TEST_ASSIGN(IBO, ibo, edituv_tris); | TEST_ASSIGN(IBO, ibo, edituv_tris); | ||||
| TEST_ASSIGN(IBO, ibo, edituv_lines); | TEST_ASSIGN(IBO, ibo, edituv_lines); | ||||
| TEST_ASSIGN(IBO, ibo, edituv_points); | TEST_ASSIGN(IBO, ibo, edituv_points); | ||||
| TEST_ASSIGN(IBO, ibo, edituv_fdots); | TEST_ASSIGN(IBO, ibo, edituv_fdots); | ||||
| if (do_lines_loose_subbuffer) { | |||||
| iter_flag |= MR_ITER_LEDGE; | |||||
| } | |||||
| #undef TEST_ASSIGN | #undef TEST_ASSIGN | ||||
| #ifdef DEBUG_TIME | #ifdef DEBUG_TIME | ||||
| double rdata_start = PIL_check_seconds_timer(); | double rdata_start = PIL_check_seconds_timer(); | ||||
| #endif | #endif | ||||
| MeshRenderData *mr = mesh_render_data_create(me, | MeshRenderData *mr = mesh_render_data_create(me, | ||||
| is_editmode, | is_editmode, | ||||
| ▲ Show 20 Lines • Show All 81 Lines • ▼ Show 20 Lines | extract_task_create(task_graph, | ||||
| scene, | scene, | ||||
| mr, | mr, | ||||
| lines_extractor, | lines_extractor, | ||||
| mbc.ibo.lines, | mbc.ibo.lines, | ||||
| &task_counters[counter_used++]); | &task_counters[counter_used++]); | ||||
| } | } | ||||
| else { | else { | ||||
| if (do_lines_loose_subbuffer) { | if (do_lines_loose_subbuffer) { | ||||
| /* When `lines_loose` is requested without `lines` we can create the sub-buffer on the fly as | ExtractTaskData *taskdata = extract_task_data_create_lines_loose(mr); | ||||
| * the `lines` buffer should then already be up-to-date. | BLI_addtail(&single_threaded_task_data->task_datas, taskdata); | ||||
| * (see `DRW_batch_requested(cache->batch.loose_edges, GPU_PRIM_LINES)` in | |||||
| * `DRW_mesh_batch_cache_create_requested`). | |||||
| */ | |||||
| extract_lines_loose_subbuffer(mr); | |||||
| } | } | ||||
| } | } | ||||
| EXTRACT(ibo, points); | EXTRACT(ibo, points); | ||||
| EXTRACT(ibo, fdots); | EXTRACT(ibo, fdots); | ||||
| EXTRACT(ibo, lines_paint_mask); | EXTRACT(ibo, lines_paint_mask); | ||||
| EXTRACT(ibo, lines_adjacency); | EXTRACT(ibo, lines_adjacency); | ||||
| EXTRACT(ibo, edituv_tris); | EXTRACT(ibo, edituv_tris); | ||||
| EXTRACT(ibo, edituv_lines); | EXTRACT(ibo, edituv_lines); | ||||
| ▲ Show 20 Lines • Show All 49 Lines • Show Last 20 Lines | |||||