diff options
Diffstat (limited to 'source/blender/draw/intern/draw_cache_impl_subdivision.cc')
-rw-r--r-- | source/blender/draw/intern/draw_cache_impl_subdivision.cc | 131 |
1 files changed, 80 insertions, 51 deletions
diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc index a0c7e064e00..cde2b59ea23 100644 --- a/source/blender/draw/intern/draw_cache_impl_subdivision.cc +++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc @@ -39,10 +39,10 @@ #include "opensubdiv_evaluator_capi.h" #include "opensubdiv_topology_refiner_capi.h" -#include "draw_cache_extract.h" +#include "draw_cache_extract.hh" #include "draw_cache_impl.h" #include "draw_cache_inline.h" -#include "mesh_extractors/extract_mesh.h" +#include "mesh_extractors/extract_mesh.hh" extern "C" char datatoc_common_subdiv_custom_data_interp_comp_glsl[]; extern "C" char datatoc_common_subdiv_ibo_lines_comp_glsl[]; @@ -221,7 +221,7 @@ static GPUShader *get_patch_evaluation_shader(int shader_type) "#define OSD_PATCH_BASIS_GLSL\n" "#define OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES\n" "#define FDOTS_EVALUATION\n" - "#define FOTS_NORMALS\n"; + "#define FDOTS_NORMALS\n"; } else if (shader_type == SHADER_PATCH_EVALUATION_ORCO) { defines = @@ -575,6 +575,7 @@ static void draw_subdiv_free_edit_mode_cache(DRWSubdivCache *cache) void draw_subdiv_cache_free(DRWSubdivCache *cache) { GPU_VERTBUF_DISCARD_SAFE(cache->patch_coords); + GPU_VERTBUF_DISCARD_SAFE(cache->corner_patch_coords); GPU_VERTBUF_DISCARD_SAFE(cache->face_ptex_offset_buffer); GPU_VERTBUF_DISCARD_SAFE(cache->subdiv_polygon_offset_buffer); GPU_VERTBUF_DISCARD_SAFE(cache->extra_coarse_face_data); @@ -780,7 +781,7 @@ struct DRWCacheBuildingContext { DRWSubdivCache *cache; - /* Pointers into DRWSubdivCache buffers for easier access during traversal. */ + /* Pointers into #DRWSubdivCache buffers for easier access during traversal. */ CompressedPatchCoord *patch_coords; int *subdiv_loop_vert_index; int *subdiv_loop_subdiv_vert_index; @@ -792,9 +793,9 @@ struct DRWCacheBuildingContext { int *vert_origindex_map; int *edge_origindex_map; - /* Origindex layers from the mesh to directly look up during traversal the origindex from the - * base mesh for edit data so that we do not have to handle yet another GPU buffer and do this in - * the shaders. */ + /* #CD_ORIGINDEX layers from the mesh to directly look up during traversal the original-index + * from the base mesh for edit data so that we do not have to handle yet another GPU buffer and + * do this in the shaders. */ const int *v_origindex; const int *e_origindex; }; @@ -834,6 +835,11 @@ static bool draw_subdiv_topology_info_cb(const SubdivForeachContext *foreach_con cache->patch_coords, get_blender_patch_coords_format(), GPU_USAGE_DYNAMIC); GPU_vertbuf_data_alloc(cache->patch_coords, cache->num_subdiv_loops); + cache->corner_patch_coords = GPU_vertbuf_calloc(); + GPU_vertbuf_init_with_format_ex( + cache->corner_patch_coords, get_blender_patch_coords_format(), GPU_USAGE_DYNAMIC); + GPU_vertbuf_data_alloc(cache->corner_patch_coords, cache->num_subdiv_loops); + cache->verts_orig_index = GPU_vertbuf_calloc(); GPU_vertbuf_init_with_format_ex( cache->verts_orig_index, get_origindex_format(), GPU_USAGE_DYNAMIC); @@ -861,10 +867,10 @@ static bool draw_subdiv_topology_info_cb(const SubdivForeachContext *foreach_con ctx->subdiv_loop_subdiv_edge_index = cache->subdiv_loop_subdiv_edge_index; ctx->subdiv_loop_poly_index = cache->subdiv_loop_poly_index; - ctx->v_origindex = static_cast<int *>( + ctx->v_origindex = static_cast<const int *>( CustomData_get_layer(&ctx->coarse_mesh->vdata, CD_ORIGINDEX)); - ctx->e_origindex = static_cast<int *>( + ctx->e_origindex = static_cast<const int *>( CustomData_get_layer(&ctx->coarse_mesh->edata, CD_ORIGINDEX)); if (cache->num_subdiv_verts) { @@ -1046,14 +1052,10 @@ static void build_vertex_face_adjacency_maps(DRWSubdivCache *cache) static bool draw_subdiv_build_cache(DRWSubdivCache *cache, Subdiv *subdiv, Mesh *mesh_eval, - const Scene *scene, - const SubsurfModifierData *smd, - const bool is_final_render) + const SubsurfRuntimeData *runtime_data) { - const int requested_levels = (is_final_render) ? smd->renderLevels : smd->levels; - const int level = get_render_subsurf_level(&scene->r, requested_levels, is_final_render); SubdivToMeshSettings to_mesh_settings; - to_mesh_settings.resolution = (1 << level) + 1; + to_mesh_settings.resolution = runtime_data->resolution; to_mesh_settings.use_optimal_display = false; if (cache->resolution != to_mesh_settings.resolution) { @@ -1124,6 +1126,31 @@ static bool draw_subdiv_build_cache(DRWSubdivCache *cache, cache->resolution = to_mesh_settings.resolution; cache->num_coarse_poly = mesh_eval->totpoly; + /* To avoid floating point precision issues when evaluating patches at patch boundaries, + * ensure that all loops sharing a vertex use the same patch coordinate. This could cause + * the mesh to not be watertight, leading to shadowing artifacts (see T97877). */ + blender::Vector<int> first_loop_index(cache->num_subdiv_verts, -1); + + /* Save coordinates for corners, as attributes may vary for each loop connected to the same + * vertex. */ + memcpy(GPU_vertbuf_get_data(cache->corner_patch_coords), + cache_building_context.patch_coords, + sizeof(CompressedPatchCoord) * cache->num_subdiv_loops); + + for (int i = 0; i < cache->num_subdiv_loops; i++) { + const int vertex = cache_building_context.subdiv_loop_subdiv_vert_index[i]; + if (first_loop_index[vertex] != -1) { + continue; + } + first_loop_index[vertex] = i; + } + + for (int i = 0; i < cache->num_subdiv_loops; i++) { + const int vertex = cache_building_context.subdiv_loop_subdiv_vert_index[i]; + cache_building_context.patch_coords[i] = + cache_building_context.patch_coords[first_loop_index[vertex]]; + } + /* Cleanup. */ MEM_SAFE_FREE(cache_building_context.vert_origindex_map); MEM_SAFE_FREE(cache_building_context.edge_origindex_map); @@ -1177,8 +1204,8 @@ struct DRWSubdivUboStorage { * of out of bond accesses as compute dispatch are of fixed size. */ uint total_dispatch_size; - int _pad0; - int _pad2; + int is_edit_mode; + int use_hide; int _pad3; }; @@ -1209,6 +1236,8 @@ static void draw_subdiv_init_ubo_storage(const DRWSubdivCache *cache, ubo->coarse_face_hidden_mask = SUBDIV_COARSE_FACE_FLAG_HIDDEN_MASK; ubo->coarse_face_loopstart_mask = SUBDIV_COARSE_FACE_LOOP_START_MASK; ubo->total_dispatch_size = total_dispatch_size; + ubo->is_edit_mode = cache->is_edit_mode; + ubo->use_hide = cache->use_hide; } static void draw_subdiv_ubo_update_and_bind(const DRWSubdivCache *cache, @@ -1405,7 +1434,7 @@ void draw_subdiv_extract_uvs(const DRWSubdivCache *cache, GPU_vertbuf_bind_as_ssbo(src_buffer, binding_point++); GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_handles, binding_point++); GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_quadtree, binding_point++); - GPU_vertbuf_bind_as_ssbo(cache->patch_coords, binding_point++); + GPU_vertbuf_bind_as_ssbo(cache->corner_patch_coords, binding_point++); GPU_vertbuf_bind_as_ssbo(cache->verts_orig_index, binding_point++); GPU_vertbuf_bind_as_ssbo(patch_arrays_buffer, binding_point++); GPU_vertbuf_bind_as_ssbo(patch_index_buffer, binding_point++); @@ -1441,6 +1470,11 @@ void draw_subdiv_interp_custom_data(const DRWSubdivCache *cache, { GPUShader *shader = nullptr; + if (!draw_subdiv_cache_need_polygon_data(cache)) { + /* Happens on meshes with only loose geometry. */ + return; + } + if (dimensions == 1) { shader = get_subdiv_shader(SHADER_COMP_CUSTOM_DATA_INTERP_1D, "#define SUBDIV_POLYGON_OFFSET\n" @@ -1480,7 +1514,7 @@ void draw_subdiv_interp_custom_data(const DRWSubdivCache *cache, GPU_vertbuf_bind_as_ssbo(cache->subdiv_polygon_offset_buffer, binding_point++); GPU_vertbuf_bind_as_ssbo(src_data, binding_point++); GPU_vertbuf_bind_as_ssbo(cache->face_ptex_offset_buffer, binding_point++); - GPU_vertbuf_bind_as_ssbo(cache->patch_coords, binding_point++); + GPU_vertbuf_bind_as_ssbo(cache->corner_patch_coords, binding_point++); GPU_vertbuf_bind_as_ssbo(cache->extra_coarse_face_data, binding_point++); GPU_vertbuf_bind_as_ssbo(dst_data, binding_point++); BLI_assert(binding_point <= MAX_GPU_SUBDIV_SSBOS); @@ -1806,6 +1840,7 @@ void draw_subdiv_build_lnor_buffer(const DRWSubdivCache *cache, GPU_vertbuf_bind_as_ssbo(cache->subdiv_polygon_offset_buffer, binding_point++); GPU_vertbuf_bind_as_ssbo(pos_nor, binding_point++); GPU_vertbuf_bind_as_ssbo(cache->extra_coarse_face_data, binding_point++); + GPU_vertbuf_bind_as_ssbo(cache->verts_orig_index, binding_point++); /* Outputs */ GPU_vertbuf_bind_as_ssbo(lnor, binding_point++); @@ -1974,10 +2009,9 @@ static void draw_subdiv_cache_ensure_mat_offsets(DRWSubdivCache *cache, MEM_freeN(per_polygon_mat_offset); } -static bool draw_subdiv_create_requested_buffers(const Scene *scene, - Object *ob, +static bool draw_subdiv_create_requested_buffers(Object *ob, Mesh *mesh, - struct MeshBatchCache *batch_cache, + MeshBatchCache *batch_cache, MeshBufferCache *mbc, const bool is_editmode, const bool is_paint_mode, @@ -1989,16 +2023,10 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene, const bool use_hide, OpenSubdiv_EvaluatorCache *evaluator_cache) { - SubsurfModifierData *smd = reinterpret_cast<SubsurfModifierData *>( - BKE_modifiers_findby_session_uuid(ob, &mesh->runtime.subsurf_session_uuid)); - BLI_assert(smd); - - const bool is_final_render = DRW_state_is_scene_render(); - - SubdivSettings settings; - BKE_subsurf_modifier_subdiv_settings_init(&settings, smd, is_final_render); + SubsurfRuntimeData *runtime_data = mesh->runtime.subsurf_runtime_data; + BLI_assert(runtime_data && runtime_data->has_gpu_subdiv); - if (settings.level == 0) { + if (runtime_data->settings.level == 0) { return false; } @@ -2009,9 +2037,7 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene, bm = mesh->edit_mesh->bm; } - BKE_subsurf_modifier_ensure_runtime(smd); - - Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(smd, &settings, mesh_eval, true); + Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(runtime_data, mesh_eval, true); if (!subdiv) { return false; } @@ -2019,7 +2045,7 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene, draw_subdiv_invalidate_evaluator_for_orco(subdiv, mesh_eval); if (!BKE_subdiv_eval_begin_from_mesh( - subdiv, mesh_eval, nullptr, SUBDIV_EVALUATOR_TYPE_GLSL_COMPUTE, evaluator_cache)) { + subdiv, mesh_eval, nullptr, SUBDIV_EVALUATOR_TYPE_GPU, evaluator_cache)) { /* This could happen in two situations: * - OpenSubdiv is disabled. * - Something totally bad happened, and OpenSubdiv rejected our @@ -2032,13 +2058,13 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene, } DRWSubdivCache *draw_cache = mesh_batch_cache_ensure_subdiv_cache(batch_cache); - if (!draw_subdiv_build_cache(draw_cache, subdiv, mesh_eval, scene, smd, is_final_render)) { + if (!draw_subdiv_build_cache(draw_cache, subdiv, mesh_eval, runtime_data)) { return false; } /* Edges which do not come from coarse edges should not be drawn in edit mode, only in object * mode when optimal display in turned off. */ - const bool optimal_display = (smd->flags & eSubsurfModifierFlag_ControlEdges) || is_editmode; + const bool optimal_display = runtime_data->use_optimal_display || is_editmode; draw_cache->bm = bm; draw_cache->mesh = mesh_eval; @@ -2046,14 +2072,13 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene, draw_cache->optimal_display = optimal_display; draw_cache->num_subdiv_triangles = tris_count_from_number_of_loops(draw_cache->num_subdiv_loops); - /* Copy topology information for stats display. Use `mesh` directly, as `mesh_eval` could be the - * edit mesh. */ - mesh->runtime.subsurf_totvert = draw_cache->num_subdiv_verts; - mesh->runtime.subsurf_totedge = draw_cache->num_subdiv_edges; - mesh->runtime.subsurf_totpoly = draw_cache->num_subdiv_quads; - mesh->runtime.subsurf_totloop = draw_cache->num_subdiv_loops; + /* Copy topology information for stats display. */ + runtime_data->stats_totvert = draw_cache->num_subdiv_verts; + runtime_data->stats_totedge = draw_cache->num_subdiv_edges; + runtime_data->stats_totpoly = draw_cache->num_subdiv_quads; + runtime_data->stats_totloop = draw_cache->num_subdiv_loops; - draw_cache->use_custom_loop_normals = (smd->flags & eSubsurfModifierFlag_UseCustomNormals) && + draw_cache->use_custom_loop_normals = (runtime_data->use_loop_normals) && (mesh_eval->flag & ME_AUTOSMOOTH) && CustomData_has_layer(&mesh_eval->ldata, CD_CUSTOMLOOPNORMAL); @@ -2065,10 +2090,16 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene, MeshRenderData *mr = mesh_render_data_create( ob, mesh, is_editmode, is_paint_mode, is_mode_active, obmat, do_final, do_uvedit, ts); mr->use_hide = use_hide; + draw_cache->use_hide = use_hide; + + /* Used for setting loop normals flags. Mapped extraction is only used during edit mode. + * See comments in #extract_lnor_iter_poly_mesh. + */ + draw_cache->is_edit_mode = mr->edit_bmesh != nullptr; draw_subdiv_cache_update_extra_coarse_face_data(draw_cache, mesh_eval, mr); - mesh_buffer_cache_create_requested_subdiv(batch_cache, mbc, draw_cache, mr); + blender::draw::mesh_buffer_cache_create_requested_subdiv(batch_cache, mbc, draw_cache, mr); mesh_render_data_free(mr); @@ -2175,10 +2206,9 @@ blender::Span<DRWSubdivLooseVertex> draw_subdiv_cache_get_loose_verts(const DRWS static OpenSubdiv_EvaluatorCache *g_evaluator_cache = nullptr; -void DRW_create_subdivision(const Scene *scene, - Object *ob, +void DRW_create_subdivision(Object *ob, Mesh *mesh, - struct MeshBatchCache *batch_cache, + MeshBatchCache *batch_cache, MeshBufferCache *mbc, const bool is_editmode, const bool is_paint_mode, @@ -2190,7 +2220,7 @@ void DRW_create_subdivision(const Scene *scene, const bool use_hide) { if (g_evaluator_cache == nullptr) { - g_evaluator_cache = openSubdiv_createEvaluatorCache(OPENSUBDIV_EVALUATOR_GLSL_COMPUTE); + g_evaluator_cache = openSubdiv_createEvaluatorCache(OPENSUBDIV_EVALUATOR_GPU); } #undef TIME_SUBDIV @@ -2199,8 +2229,7 @@ void DRW_create_subdivision(const Scene *scene, const double begin_time = PIL_check_seconds_timer(); #endif - if (!draw_subdiv_create_requested_buffers(scene, - ob, + if (!draw_subdiv_create_requested_buffers(ob, mesh, batch_cache, mbc, |