diff options
Diffstat (limited to 'source/blender/draw')
34 files changed, 3626 insertions, 2545 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 045adf4b380..ee5b2c549a5 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -31,6 +31,7 @@ set(INC ../depsgraph ../editors/include ../editors/space_view3d + ../functions ../gpu ../imbuf ../makesdna @@ -50,7 +51,9 @@ set(INC set(SRC intern/draw_cache.c - intern/draw_cache_extract_mesh.c + intern/draw_cache_extract_mesh_extractors.c + intern/draw_cache_extract_mesh_render_data.c + intern/draw_cache_extract_mesh.cc intern/draw_cache_impl_curve.cc intern/draw_cache_impl_displist.c intern/draw_cache_impl_gpencil.c @@ -146,6 +149,7 @@ set(SRC engines/overlay/overlay_image.c engines/overlay/overlay_lattice.c engines/overlay/overlay_metaball.c + engines/overlay/overlay_mode_transfer.c engines/overlay/overlay_motion_path.c engines/overlay/overlay_outline.c engines/overlay/overlay_paint.c @@ -321,6 +325,7 @@ data_to_c_simple(intern/shaders/common_globals_lib.glsl SRC) data_to_c_simple(intern/shaders/common_pointcloud_lib.glsl SRC) data_to_c_simple(intern/shaders/common_hair_lib.glsl SRC) data_to_c_simple(intern/shaders/common_hair_refine_vert.glsl SRC) +data_to_c_simple(intern/shaders/common_hair_refine_comp.glsl SRC) data_to_c_simple(intern/shaders/common_math_lib.glsl SRC) data_to_c_simple(intern/shaders/common_math_geom_lib.glsl SRC) data_to_c_simple(intern/shaders/common_view_lib.glsl SRC) diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c index cba86d058ea..e23a5a81169 100644 --- a/source/blender/draw/engines/eevee/eevee_lights.c +++ b/source/blender/draw/engines/eevee/eevee_lights.c @@ -96,7 +96,7 @@ static float light_shape_power_get(const Light *la, const EEVEE_Light *evli) } } else if (ELEM(la->type, LA_SPOT, LA_LOCAL)) { - power = 1.0f / (4.0f * evli->radius * evli->radius * M_PI * M_PI); /* 1/(4*r²*Pi²) */ + power = 1.0f / (4.0f * evli->radius * evli->radius * M_PI * M_PI); /* `1/(4*(r^2)*(Pi^2))` */ /* for point lights (a.k.a radius == 0.0) */ // power = M_PI * M_PI * 0.78; /* XXX : Empirical, Fit cycles power */ @@ -106,7 +106,7 @@ static float light_shape_power_get(const Light *la, const EEVEE_Light *evli) /* Make illumination power closer to cycles for bigger radii. Cycles uses a cos^3 term that we * cannot reproduce so we account for that by scaling the light power. This function is the * result of a rough manual fitting. */ - power += 1.0f / (2.0f * M_PI); /* power *= 1 + r²/2 */ + power += 1.0f / (2.0f * M_PI); /* `power *= 1 + (r^2)/2` */ } return power; } @@ -257,7 +257,7 @@ void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) float power = max_fff(UNPACK3(evli->color)) * evli->volume; if (power > 0.0f && evli->light_type != LA_SUN) { /* The limit of the power attenuation function when the distance to the light goes to 0 is - * 2 / r² where r is the light radius. We need to find the right radius that emits at most + * `2 / r^2` where r is the light radius. We need to find the right radius that emits at most * the volume light upper bound. Inverting the function we get: */ float min_radius = 1.0f / sqrtf(0.5f * upper_bound / power); /* Square it here to avoid a multiplication inside the shader. */ diff --git a/source/blender/draw/engines/eevee/eevee_renderpasses.c b/source/blender/draw/engines/eevee/eevee_renderpasses.c index 5739024993e..5ada53ab98c 100644 --- a/source/blender/draw/engines/eevee/eevee_renderpasses.c +++ b/source/blender/draw/engines/eevee/eevee_renderpasses.c @@ -79,7 +79,7 @@ bool EEVEE_renderpasses_only_first_sample_pass_active(EEVEE_Data *vedata) * type the rest of the bits are used for the name hash. */ int EEVEE_renderpasses_aov_hash(const ViewLayerAOV *aov) { - int hash = BLI_hash_string(aov->name); + int hash = BLI_hash_string(aov->name) << 1; SET_FLAG_FROM_TEST(hash, aov->type == AOV_TYPE_COLOR, EEVEE_AOV_HASH_COLOR_TYPE_MASK); return hash; } diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl index fdbb70e917d..05496ad4ab0 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -138,30 +138,55 @@ void accumulate_light(vec3 light, float fac, inout vec4 accum) /* Same thing as Cycles without the comments to make it shorter. */ vec3 ensure_valid_reflection(vec3 Ng, vec3 I, vec3 N) { - vec3 R; - float NI = dot(N, I); - float NgR, threshold; - /* Check if the incident ray is coming from behind normal N. */ - if (NI > 0.0) { - /* Normal reflection. */ - R = (2.0 * NI) * N - I; - NgR = dot(Ng, R); - /* Reflection rays may always be at least as shallow as the incoming ray. */ - threshold = min(0.9 * dot(Ng, I), 0.01); - if (NgR >= threshold) { - return N; + vec3 R = -reflect(I, N); + + /* Reflection rays may always be at least as shallow as the incoming ray. */ + float threshold = min(0.9 * dot(Ng, I), 0.025); + if (dot(Ng, R) >= threshold) { + return N; + } + + float NdotNg = dot(N, Ng); + vec3 X = normalize(N - NdotNg * Ng); + + float Ix = dot(I, X), Iz = dot(I, Ng); + float Ix2 = sqr(Ix), Iz2 = sqr(Iz); + float a = Ix2 + Iz2; + + float b = sqrt(Ix2 * (a - sqr(threshold))); + float c = Iz * threshold + a; + + float fac = 0.5 / a; + float N1_z2 = fac * (b + c), N2_z2 = fac * (-b + c); + bool valid1 = (N1_z2 > 1e-5) && (N1_z2 <= (1.0 + 1e-5)); + bool valid2 = (N2_z2 > 1e-5) && (N2_z2 <= (1.0 + 1e-5)); + + vec2 N_new; + if (valid1 && valid2) { + /* If both are possible, do the expensive reflection-based check. */ + vec2 N1 = vec2(safe_sqrt(1.0 - N1_z2), safe_sqrt(N1_z2)); + vec2 N2 = vec2(safe_sqrt(1.0 - N2_z2), safe_sqrt(N2_z2)); + + float R1 = 2.0 * (N1.x * Ix + N1.y * Iz) * N1.y - Iz; + float R2 = 2.0 * (N2.x * Ix + N2.y * Iz) * N2.y - Iz; + + valid1 = (R1 >= 1e-5); + valid2 = (R2 >= 1e-5); + if (valid1 && valid2) { + N_new = (R1 < R2) ? N1 : N2; } + else { + N_new = (R1 > R2) ? N1 : N2; + } + } + else if (valid1 || valid2) { + float Nz2 = valid1 ? N1_z2 : N2_z2; + N_new = vec2(safe_sqrt(1.0 - Nz2), safe_sqrt(Nz2)); } else { - /* Bad incident. */ - R = -I; - NgR = dot(Ng, R); - threshold = 0.01; + return Ng; } - /* Lift the reflection above the threshold. */ - R = R + Ng * (threshold - NgR); - /* Find a bisector. */ - return safe_normalize(I * length(R) + R * length(I)); + return N_new.x * X + N_new.y * Ng; } /* ----------- Cone angle Approximation --------- */ diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c index adb70f97585..af8b029a08e 100644 --- a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c +++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c @@ -274,7 +274,13 @@ GPENCIL_tLayer *gpencil_layer_cache_add(GPENCIL_PrivateData *pd, const bool override_vertcol = (pd->v3d_color_type != -1); const bool is_vert_col_mode = (pd->v3d_color_type == V3D_SHADING_VERTEX_COLOR) || GPENCIL_VERTEX_MODE(gpd) || pd->is_render; - bool is_masked = (gpl->flag & GP_LAYER_USE_MASK) && !BLI_listbase_is_empty(&gpl->mask_layers); + const bool is_viewlayer_render = pd->is_render && (gpl->viewlayername[0] != '\0') && + STREQ(pd->view_layer->name, gpl->viewlayername); + const bool disable_masks_render = is_viewlayer_render && + (gpl->flag & GP_LAYER_DISABLE_MASKS_IN_VIEWLAYER); + bool is_masked = disable_masks_render ? false : + (gpl->flag & GP_LAYER_USE_MASK) && + !BLI_listbase_is_empty(&gpl->mask_layers); float vert_col_opacity = (override_vertcol) ? (is_vert_col_mode ? pd->vertex_paint_opacity : 0.0f) : diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h index 5ceb909bc88..34fe29055d6 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.h +++ b/source/blender/draw/engines/gpencil/gpencil_engine.h @@ -297,7 +297,9 @@ typedef struct GPENCIL_PrivateData { int v3d_color_type; /* Current frame */ int cfra; - /* If we are rendering for final render (F12). */ + /* If we are rendering for final render (F12). + * NOTE: set to false for viewport and opengl rendering (including VSE scene rendering), but set + * to true when rendering in `OB_RENDER` shading mode (viewport or opengl rendering) */ bool is_render; /* If we are in viewport display (used for VFX). */ bool is_viewport; diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl index 7412959a30b..ac48b94fea9 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl @@ -442,6 +442,10 @@ void stroke_vertex() if (is_dot) { # ifdef GP_MATERIAL_BUFFER_LEN int alignement = GP_FLAG(m) & GP_STROKE_ALIGNMENT; + /* For one point strokes use object aligment. */ + if (ma.x == -1 && ma2.x == -1 && alignement == GP_STROKE_ALIGNMENT_STROKE) { + alignement = GP_STROKE_ALIGNMENT_OBJECT; + } # endif vec2 x_axis; diff --git a/source/blender/draw/engines/overlay/overlay_edit_mesh.c b/source/blender/draw/engines/overlay/overlay_edit_mesh.c index 40a9dbe01c0..7639911286f 100644 --- a/source/blender/draw/engines/overlay/overlay_edit_mesh.c +++ b/source/blender/draw/engines/overlay/overlay_edit_mesh.c @@ -149,7 +149,7 @@ void OVERLAY_edit_mesh_cache_init(OVERLAY_Data *vedata) DRWState state_common = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA; /* Faces */ - /* Cage geom needs to be offsetted to avoid Z-fighting. */ + /* Cage geom needs an offset applied to avoid Z-fighting. */ for (int j = 0; j < 2; j++) { DRWPass **edit_face_ps = (j == 0) ? &psl->edit_mesh_faces_ps[i] : &psl->edit_mesh_faces_cage_ps[i]; @@ -197,7 +197,7 @@ void OVERLAY_edit_mesh_cache_init(OVERLAY_Data *vedata) grp = pd->edit_mesh_skin_roots_grp[i] = DRW_shgroup_create(sh, psl->edit_mesh_verts_ps[i]); DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); } - /* Facedots */ + /* Face-dots */ if (select_face && show_face_dots) { sh = OVERLAY_shader_edit_mesh_facedot(); grp = pd->edit_mesh_facedots_grp[i] = DRW_shgroup_create(sh, psl->edit_mesh_verts_ps[i]); diff --git a/source/blender/draw/engines/overlay/overlay_engine.c b/source/blender/draw/engines/overlay/overlay_engine.c index b8f721946f2..19f822e3f68 100644 --- a/source/blender/draw/engines/overlay/overlay_engine.c +++ b/source/blender/draw/engines/overlay/overlay_engine.c @@ -207,6 +207,7 @@ static void OVERLAY_cache_init(void *vedata) OVERLAY_armature_cache_init(vedata); OVERLAY_background_cache_init(vedata); OVERLAY_fade_cache_init(vedata); + OVERLAY_mode_transfer_cache_init(vedata); OVERLAY_extra_cache_init(vedata); OVERLAY_facing_cache_init(vedata); OVERLAY_gpencil_cache_init(vedata); @@ -323,6 +324,7 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob) !is_select; const bool draw_fade = draw_surface && (pd->overlay.flag & V3D_OVERLAY_FADE_INACTIVE) && overlay_should_fade_object(ob, draw_ctx->obact); + const bool draw_mode_transfer = draw_surface && (pd->overlay.flag & V3D_OVERLAY_MODE_TRANSFER); const bool draw_bones = (pd->overlay.flag & V3D_OVERLAY_HIDE_BONES) == 0; const bool draw_wires = draw_surface && has_surface && (pd->wireframe_mode || !pd->hide_overlays); @@ -349,6 +351,9 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob) if (draw_facing) { OVERLAY_facing_cache_populate(vedata, ob); } + if (draw_mode_transfer) { + OVERLAY_mode_transfer_cache_populate(vedata, ob); + } if (draw_wires) { OVERLAY_wireframe_cache_populate(vedata, ob, dupli, do_init); } @@ -504,6 +509,7 @@ static void OVERLAY_cache_finish(void *vedata) {GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), GPU_ATTACHMENT_TEXTURE(dtxl->color)}); } + OVERLAY_mode_transfer_cache_finish(vedata); OVERLAY_antialiasing_cache_finish(vedata); OVERLAY_armature_cache_finish(vedata); OVERLAY_image_cache_finish(vedata); @@ -566,6 +572,7 @@ static void OVERLAY_draw_scene(void *vedata) OVERLAY_image_draw(vedata); OVERLAY_fade_draw(vedata); OVERLAY_facing_draw(vedata); + OVERLAY_mode_transfer_draw(vedata); OVERLAY_extra_blend_draw(vedata); OVERLAY_volume_draw(vedata); @@ -605,6 +612,7 @@ static void OVERLAY_draw_scene(void *vedata) OVERLAY_fade_infront_draw(vedata); OVERLAY_facing_infront_draw(vedata); + OVERLAY_mode_transfer_infront_draw(vedata); if (DRW_state_is_fbo()) { GPU_framebuffer_bind(fbl->overlay_line_in_front_fb); diff --git a/source/blender/draw/engines/overlay/overlay_mode_transfer.c b/source/blender/draw/engines/overlay/overlay_mode_transfer.c new file mode 100644 index 00000000000..253f606b086 --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_mode_transfer.c @@ -0,0 +1,159 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2021, Blender Foundation. + */ + +/** \file + * \ingroup draw_engine + */ + +#include "BKE_paint.h" +#include "DRW_render.h" + +#include "ED_view3d.h" + +#include "PIL_time.h" +#include "UI_resources.h" + +#include "overlay_private.h" + +void OVERLAY_mode_transfer_cache_init(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + OVERLAY_PrivateData *pd = vedata->stl->pd; + + pd->mode_transfer.time = PIL_check_seconds_timer(); + + for (int i = 0; i < 2; i++) { + /* Non Meshes Pass (Camera, empties, lights ...) */ + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA; + DRW_PASS_CREATE(psl->mode_transfer_ps[i], state | pd->clipping_state); + } +} + +#define MODE_TRANSFER_FLASH_LENGTH 0.55f +/* TODO(pablodp606): Remove this option for 3.0 if fade in/out is not used. */ +#define MODE_TRANSFER_FLASH_FADE 0.0f +#define MODE_TRANSFER_FLASH_MAX_ALPHA 0.25f + +static bool mode_transfer_is_animation_running(const float anim_time) +{ + return anim_time >= 0.0f && anim_time <= MODE_TRANSFER_FLASH_LENGTH; +} + +static float mode_transfer_alpha_for_animation_time_get(const float anim_time) +{ + if (anim_time > MODE_TRANSFER_FLASH_LENGTH) { + return 0.0f; + } + + if (anim_time < 0.0f) { + return 0.0f; + } + + if (MODE_TRANSFER_FLASH_FADE <= 0.0f) { + return (1.0f - (anim_time / MODE_TRANSFER_FLASH_LENGTH)) * MODE_TRANSFER_FLASH_MAX_ALPHA; + } + + const float flash_fade_in_time = MODE_TRANSFER_FLASH_LENGTH * MODE_TRANSFER_FLASH_FADE; + const float flash_fade_out_time = MODE_TRANSFER_FLASH_LENGTH - flash_fade_in_time; + + float alpha = 0.0f; + if (anim_time < flash_fade_in_time) { + alpha = anim_time / flash_fade_in_time; + } + else { + const float fade_out_anim_time = anim_time - flash_fade_in_time; + alpha = 1.0f - (fade_out_anim_time / flash_fade_out_time); + } + + return alpha * MODE_TRANSFER_FLASH_MAX_ALPHA; +} + +void OVERLAY_mode_transfer_cache_populate(OVERLAY_Data *vedata, Object *ob) +{ + OVERLAY_PrivateData *pd = vedata->stl->pd; + OVERLAY_PassList *psl = vedata->psl; + + if (pd->xray_enabled) { + return; + } + + const float animation_time = pd->mode_transfer.time - + ob->runtime.overlay_mode_transfer_start_time; + + if (!mode_transfer_is_animation_running(animation_time)) { + return; + } + + const DRWContextState *draw_ctx = DRW_context_state_get(); + const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && + !DRW_state_is_image_render(); + const bool is_xray = (ob->dtx & OB_DRAW_IN_FRONT) != 0; + + DRWShadingGroup *mode_transfer_grp[2]; + + for (int i = 0; i < 2; i++) { + GPUShader *sh = OVERLAY_shader_uniform_color(); + mode_transfer_grp[i] = DRW_shgroup_create(sh, psl->mode_transfer_ps[i]); + DRW_shgroup_uniform_block(mode_transfer_grp[i], "globalsBlock", G_draw.block_ubo); + + float color[4]; + UI_GetThemeColor3fv(TH_VERTEX_SELECT, color); + color[3] = mode_transfer_alpha_for_animation_time_get(animation_time); + srgb_to_linearrgb_v4(color, color); + DRW_shgroup_uniform_vec4_copy(mode_transfer_grp[i], "color", color); + } + + if (!pd->use_in_front) { + mode_transfer_grp[IN_FRONT] = mode_transfer_grp[NOT_IN_FRONT]; + } + + pd->mode_transfer.any_animated = true; + + if (use_sculpt_pbvh) { + DRW_shgroup_call_sculpt(mode_transfer_grp[is_xray], ob, false, false); + } + else { + struct GPUBatch *geom = DRW_cache_object_surface_get(ob); + if (geom) { + DRW_shgroup_call(mode_transfer_grp[is_xray], geom, ob); + } + } +} + +void OVERLAY_mode_transfer_draw(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + + DRW_draw_pass(psl->mode_transfer_ps[NOT_IN_FRONT]); +} + +void OVERLAY_mode_transfer_infront_draw(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + + DRW_draw_pass(psl->mode_transfer_ps[IN_FRONT]); +} + +void OVERLAY_mode_transfer_cache_finish(OVERLAY_Data *vedata) +{ + OVERLAY_PrivateData *pd = vedata->stl->pd; + if (pd->mode_transfer.any_animated) { + DRW_viewport_request_redraw(); + } + pd->mode_transfer.any_animated = false; +} diff --git a/source/blender/draw/engines/overlay/overlay_motion_path.c b/source/blender/draw/engines/overlay/overlay_motion_path.c index 48b7b53a5ba..a92f11aca38 100644 --- a/source/blender/draw/engines/overlay/overlay_motion_path.c +++ b/source/blender/draw/engines/overlay/overlay_motion_path.c @@ -190,7 +190,7 @@ static void motion_path_cache(OVERLAY_Data *vedata, bool is_keyframe = (mpv->flag & MOTIONPATH_VERT_KEY) != 0; if ((show_keyframes && show_keyframes_no && is_keyframe) || (show_frame_no && (i == 0))) { - numstr_len = BLI_snprintf(numstr, sizeof(numstr), " %d", frame); + numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), " %d", frame); DRW_text_cache_add( dt, mpv->co, numstr, numstr_len, 0, 0, txt_flag, (is_keyframe) ? col_kf : col); } @@ -200,7 +200,7 @@ static void motion_path_cache(OVERLAY_Data *vedata, /* Only draw frame number if several consecutive highlighted points * don't occur on same point. */ if ((equals_v3v3(mpv->co, mpvP->co) == 0) || (equals_v3v3(mpv->co, mpvN->co) == 0)) { - numstr_len = BLI_snprintf(numstr, sizeof(numstr), " %d", frame); + numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), " %d", frame); DRW_text_cache_add(dt, mpv->co, numstr, numstr_len, 0, 0, txt_flag, col); } } diff --git a/source/blender/draw/engines/overlay/overlay_private.h b/source/blender/draw/engines/overlay/overlay_private.h index db43136e308..969289a3219 100644 --- a/source/blender/draw/engines/overlay/overlay_private.h +++ b/source/blender/draw/engines/overlay/overlay_private.h @@ -107,6 +107,7 @@ typedef struct OVERLAY_PassList { DRWPass *gpencil_canvas_ps; DRWPass *facing_ps[2]; DRWPass *fade_ps[2]; + DRWPass *mode_transfer_ps[2]; DRWPass *grid_ps; DRWPass *image_background_ps; DRWPass *image_background_scene_ps; @@ -282,6 +283,7 @@ typedef struct OVERLAY_PrivateData { DRWShadingGroup *extra_grid_grp; DRWShadingGroup *facing_grp[2]; DRWShadingGroup *fade_grp[2]; + DRWShadingGroup *flash_grp[2]; DRWShadingGroup *motion_path_lines_grp; DRWShadingGroup *motion_path_points_grp; DRWShadingGroup *outlines_grp; @@ -414,6 +416,10 @@ typedef struct OVERLAY_PrivateData { struct { DRWCallBuffer *handle[2]; } mball; + struct { + double time; + bool any_animated; + } mode_transfer; } OVERLAY_PrivateData; /* Transient data */ typedef struct OVERLAY_StorageList { @@ -607,6 +613,12 @@ void OVERLAY_fade_cache_populate(OVERLAY_Data *vedata, Object *ob); void OVERLAY_fade_draw(OVERLAY_Data *vedata); void OVERLAY_fade_infront_draw(OVERLAY_Data *vedata); +void OVERLAY_mode_transfer_cache_init(OVERLAY_Data *vedata); +void OVERLAY_mode_transfer_cache_populate(OVERLAY_Data *vedata, Object *ob); +void OVERLAY_mode_transfer_draw(OVERLAY_Data *vedata); +void OVERLAY_mode_transfer_infront_draw(OVERLAY_Data *vedata); +void OVERLAY_mode_transfer_cache_finish(OVERLAY_Data *vedata); + void OVERLAY_grid_init(OVERLAY_Data *vedata); void OVERLAY_grid_cache_init(OVERLAY_Data *vedata); void OVERLAY_grid_draw(OVERLAY_Data *vedata); diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index 2545cfa65dc..5071658fd82 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -438,6 +438,10 @@ void DRW_shgroup_call_range( void DRW_shgroup_call_instance_range( DRWShadingGroup *shgroup, Object *ob, struct GPUBatch *geom, uint i_sta, uint i_ct); +void DRW_shgroup_call_compute(DRWShadingGroup *shgroup, + int groups_x_len, + int groups_y_len, + int groups_z_len); void DRW_shgroup_call_procedural_points(DRWShadingGroup *sh, Object *ob, uint point_count); void DRW_shgroup_call_procedural_lines(DRWShadingGroup *sh, Object *ob, uint line_count); void DRW_shgroup_call_procedural_triangles(DRWShadingGroup *sh, Object *ob, uint tri_count); @@ -575,6 +579,9 @@ void DRW_shgroup_uniform_vec4_array_copy(DRWShadingGroup *shgroup, const char *name, const float (*value)[4], int arraysize); +void DRW_shgroup_vertex_buffer(DRWShadingGroup *shgroup, + const char *name, + struct GPUVertBuf *vertex_buffer); bool DRW_shgroup_is_empty(DRWShadingGroup *shgroup); diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h index bbb97fc09a3..810deaec349 100644 --- a/source/blender/draw/intern/draw_cache_extract.h +++ b/source/blender/draw/intern/draw_cache_extract.h @@ -24,6 +24,10 @@ struct TaskGraph; +#include "GPU_batch.h" +#include "GPU_index_buffer.h" +#include "GPU_vertex_buffer.h" + /* Vertex Group Selection and display options */ typedef struct DRW_MeshWeightState { int defgroup_active; @@ -64,13 +68,13 @@ typedef struct DRW_MeshCDMask { * bit-wise and atomic operations are used to compare and update the struct. * See `mesh_cd_layers_type_*` functions. */ BLI_STATIC_ASSERT(sizeof(DRW_MeshCDMask) <= sizeof(uint64_t), "DRW_MeshCDMask exceeds 64 bits") - typedef enum eMRIterType { MR_ITER_LOOPTRI = 1 << 0, MR_ITER_POLY = 1 << 1, MR_ITER_LEDGE = 1 << 2, MR_ITER_LVERT = 1 << 3, } eMRIterType; +ENUM_OPERATORS(eMRIterType, MR_ITER_LVERT) typedef enum eMRDataType { MR_DATA_POLY_NOR = 1 << 1, @@ -79,12 +83,11 @@ typedef enum eMRDataType { /** Force loop normals calculation. */ MR_DATA_TAN_LOOP_NOR = 1 << 4, } eMRDataType; +ENUM_OPERATORS(eMRDataType, MR_DATA_TAN_LOOP_NOR) -typedef enum eMRExtractType { - MR_EXTRACT_BMESH, - MR_EXTRACT_MAPPED, - MR_EXTRACT_MESH, -} eMRExtractType; +#ifdef __cplusplus +extern "C" { +#endif BLI_INLINE int mesh_render_mat_len_get(Mesh *me) { @@ -150,6 +153,18 @@ typedef struct MeshBufferCache { GPUIndexBuf **tris_per_mat; } MeshBufferCache; +/** + * Data that are kept around between extractions to reduce rebuilding time. + * + * - Loose geometry. + */ +typedef struct MeshBufferExtractionCache { + int edge_loose_len; + int vert_loose_len; + int *lverts; + int *ledges; +} MeshBufferExtractionCache; + typedef enum DRWBatchFlag { MBC_SURFACE = (1 << 0), MBC_SURFACE_WEIGHTS = (1 << 1), @@ -195,6 +210,10 @@ typedef enum DRWBatchFlag { typedef struct MeshBatchCache { MeshBufferCache final, cage, uv_cage; + MeshBufferExtractionCache final_extraction_cache; + MeshBufferExtractionCache cage_extraction_cache; + MeshBufferExtractionCache uv_cage_extraction_cache; + struct { /* Surfaces / Render */ GPUBatch *surface; @@ -264,9 +283,14 @@ typedef struct MeshBatchCache { bool no_loose_wire; } MeshBatchCache; +#define MBC_BATCH_LEN (sizeof(((MeshBatchCache){0}).batch) / sizeof(void *)) +#define MBC_VBO_LEN (sizeof(((MeshBufferCache){0}).vbo) / sizeof(void *)) +#define MBC_IBO_LEN (sizeof(((MeshBufferCache){0}).ibo) / sizeof(void *)) + void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, MeshBatchCache *cache, - MeshBufferCache mbc, + MeshBufferCache *mbc, + MeshBufferExtractionCache *extraction_cache, Mesh *me, const bool is_editmode, const bool is_paint_mode, @@ -275,7 +299,10 @@ void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, const bool do_final, const bool do_uvedit, const bool use_subsurf_fdots, - const DRW_MeshCDMask *cd_layer_used, const Scene *scene, const ToolSettings *ts, const bool use_hide); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.cc b/source/blender/draw/intern/draw_cache_extract_mesh.cc new file mode 100644 index 00000000000..fca40206659 --- /dev/null +++ b/source/blender/draw/intern/draw_cache_extract_mesh.cc @@ -0,0 +1,1004 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017 by Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup draw + * + * \brief Extraction of Mesh data into VBO to feed to GPU. + */ +#include "MEM_guardedalloc.h" + +#include "atomic_ops.h" + +#include "DNA_mesh_types.h" +#include "DNA_scene_types.h" + +#include "BLI_task.h" +#include "BLI_vector.hh" + +#include "BKE_editmesh.h" + +#include "GPU_capabilities.h" + +#include "draw_cache_extract.h" +#include "draw_cache_extract_mesh_private.h" +#include "draw_cache_inline.h" + +// #define DEBUG_TIME + +#ifdef DEBUG_TIME +# include "PIL_time_utildefines.h" +#endif + +#define CHUNK_SIZE 8192 + +namespace blender::draw { + +/* ---------------------------------------------------------------------- */ +/** \name Mesh Elements Extract Struct + * \{ */ + +struct ExtractorRunData { + /* Extractor where this run data belongs to. */ + const MeshExtract *extractor; + /* During iteration the VBO/IBO that is being build. */ + void *buffer = nullptr; + /* User data during iteration. Created in MeshExtract.init and passed along to other MeshExtract + * functions. */ + void *user_data = nullptr; + + ExtractorRunData(const MeshExtract *extractor) : extractor(extractor) + { + } +}; + +class ExtractorRunDatas : public Vector<ExtractorRunData> { + public: + void filter_into(ExtractorRunDatas &result, eMRIterType iter_type) const + { + for (const ExtractorRunData &data : *this) { + const MeshExtract *extractor = data.extractor; + if ((iter_type & MR_ITER_LOOPTRI) && extractor->iter_looptri_bm) { + BLI_assert(extractor->iter_looptri_mesh); + result.append(data); + continue; + } + if ((iter_type & MR_ITER_POLY) && extractor->iter_poly_bm) { + BLI_assert(extractor->iter_poly_mesh); + result.append(data); + continue; + } + if ((iter_type & MR_ITER_LEDGE) && extractor->iter_ledge_bm) { + BLI_assert(extractor->iter_ledge_mesh); + result.append(data); + continue; + } + if ((iter_type & MR_ITER_LVERT) && extractor->iter_lvert_bm) { + BLI_assert(extractor->iter_lvert_mesh); + result.append(data); + continue; + } + } + } + + void filter_threaded_extractors_into(ExtractorRunDatas &result) + { + for (const ExtractorRunData &data : *this) { + const MeshExtract *extractor = data.extractor; + if (extractor->use_threading) { + result.append(extractor); + } + } + } + + eMRIterType iter_types() + { + eMRIterType iter_type = static_cast<eMRIterType>(0); + + for (const ExtractorRunData &data : *this) { + const MeshExtract *extractor = data.extractor; + iter_type |= mesh_extract_iter_type(extractor); + } + return iter_type; + } + + eMRDataType data_types() + { + eMRDataType data_type = static_cast<eMRDataType>(0); + for (const ExtractorRunData &data : *this) { + const MeshExtract *extractor = data.extractor; + data_type |= extractor->data_type; + } + return data_type; + } +}; + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Extract + * \{ */ + +BLI_INLINE void extract_init(const MeshRenderData *mr, + struct MeshBatchCache *cache, + ExtractorRunDatas &extractors, + MeshBufferCache *mbc) +{ + /* Multi thread. */ + for (ExtractorRunData &run_data : extractors) { + const MeshExtract *extractor = run_data.extractor; + run_data.buffer = mesh_extract_buffer_get(extractor, mbc); + run_data.user_data = extractor->init(mr, cache, run_data.buffer); + } +} + +BLI_INLINE void extract_iter_looptri_bm(const MeshRenderData *mr, + const ExtractTriBMesh_Params *params, + const ExtractorRunDatas &all_extractors) +{ + ExtractorRunDatas extractors; + all_extractors.filter_into(extractors, MR_ITER_LOOPTRI); + + EXTRACT_TRIS_LOOPTRI_FOREACH_BM_BEGIN(elt, elt_index, params) + { + for (ExtractorRunData &run_data : extractors) { + run_data.extractor->iter_looptri_bm(mr, elt, elt_index, run_data.user_data); + } + } + EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END; +} + +BLI_INLINE void extract_iter_looptri_mesh(const MeshRenderData *mr, + const ExtractTriMesh_Params *params, + const ExtractorRunDatas &all_extractors) +{ + ExtractorRunDatas extractors; + all_extractors.filter_into(extractors, MR_ITER_LOOPTRI); + + EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_BEGIN(mlt, mlt_index, params) + { + for (ExtractorRunData &run_data : extractors) { + run_data.extractor->iter_looptri_mesh(mr, mlt, mlt_index, run_data.user_data); + } + } + EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END; +} + +BLI_INLINE void extract_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + const ExtractorRunDatas &all_extractors) +{ + ExtractorRunDatas extractors; + all_extractors.filter_into(extractors, MR_ITER_POLY); + + EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr) + { + for (ExtractorRunData &run_data : extractors) { + run_data.extractor->iter_poly_bm(mr, f, f_index, run_data.user_data); + } + } + EXTRACT_POLY_FOREACH_BM_END; +} + +BLI_INLINE void extract_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + const ExtractorRunDatas &all_extractors) +{ + ExtractorRunDatas extractors; + all_extractors.filter_into(extractors, MR_ITER_POLY); + + EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr) + { + for (ExtractorRunData &run_data : extractors) { + run_data.extractor->iter_poly_mesh(mr, mp, mp_index, run_data.user_data); + } + } + EXTRACT_POLY_FOREACH_MESH_END; +} + +BLI_INLINE void extract_iter_ledge_bm(const MeshRenderData *mr, + const ExtractLEdgeBMesh_Params *params, + const ExtractorRunDatas &all_extractors) +{ + ExtractorRunDatas extractors; + all_extractors.filter_into(extractors, MR_ITER_LEDGE); + + EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params) + { + for (ExtractorRunData &run_data : extractors) { + run_data.extractor->iter_ledge_bm(mr, eed, ledge_index, run_data.user_data); + } + } + EXTRACT_LEDGE_FOREACH_BM_END; +} + +BLI_INLINE void extract_iter_ledge_mesh(const MeshRenderData *mr, + const ExtractLEdgeMesh_Params *params, + const ExtractorRunDatas &all_extractors) +{ + ExtractorRunDatas extractors; + all_extractors.filter_into(extractors, MR_ITER_LEDGE); + + EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr) + { + for (ExtractorRunData &run_data : extractors) { + run_data.extractor->iter_ledge_mesh(mr, med, ledge_index, run_data.user_data); + } + } + EXTRACT_LEDGE_FOREACH_MESH_END; +} + +BLI_INLINE void extract_iter_lvert_bm(const MeshRenderData *mr, + const ExtractLVertBMesh_Params *params, + const ExtractorRunDatas &all_extractors) +{ + ExtractorRunDatas extractors; + all_extractors.filter_into(extractors, MR_ITER_LVERT); + + EXTRACT_LVERT_FOREACH_BM_BEGIN(eve, lvert_index, params) + { + for (ExtractorRunData &run_data : extractors) { + run_data.extractor->iter_lvert_bm(mr, eve, lvert_index, run_data.user_data); + } + } + EXTRACT_LVERT_FOREACH_BM_END; +} + +BLI_INLINE void extract_iter_lvert_mesh(const MeshRenderData *mr, + const ExtractLVertMesh_Params *params, + const ExtractorRunDatas &all_extractors) +{ + ExtractorRunDatas extractors; + all_extractors.filter_into(extractors, MR_ITER_LVERT); + + EXTRACT_LVERT_FOREACH_MESH_BEGIN(mv, lvert_index, params, mr) + { + for (ExtractorRunData &run_data : extractors) { + run_data.extractor->iter_lvert_mesh(mr, mv, lvert_index, run_data.user_data); + } + } + EXTRACT_LVERT_FOREACH_MESH_END; +} + +BLI_INLINE void extract_finish(const MeshRenderData *mr, + struct MeshBatchCache *cache, + const ExtractorRunDatas &extractors) +{ + for (const ExtractorRunData &run_data : extractors) { + const MeshExtract *extractor = run_data.extractor; + if (extractor->finish) { + extractor->finish(mr, cache, run_data.buffer, run_data.user_data); + } + } +} + +/* Single Thread. */ +BLI_INLINE void extract_run_and_finish_init(const MeshRenderData *mr, + struct MeshBatchCache *cache, + ExtractorRunDatas &extractors, + eMRIterType iter_type, + MeshBufferCache *mbc) +{ + extract_init(mr, cache, extractors, mbc); + + bool is_mesh = mr->extract_type != MR_EXTRACT_BMESH; + if (iter_type & MR_ITER_LOOPTRI) { + if (is_mesh) { + ExtractTriMesh_Params params; + params.mlooptri = mr->mlooptri; + params.tri_range[0] = 0; + params.tri_range[1] = mr->tri_len; + extract_iter_looptri_mesh(mr, ¶ms, extractors); + } + else { + ExtractTriBMesh_Params params; + params.looptris = mr->edit_bmesh->looptris; + params.tri_range[0] = 0; + params.tri_range[1] = mr->tri_len; + extract_iter_looptri_bm(mr, ¶ms, extractors); + } + } + if (iter_type & MR_ITER_POLY) { + if (is_mesh) { + ExtractPolyMesh_Params params; + params.poly_range[0] = 0; + params.poly_range[1] = mr->poly_len; + extract_iter_poly_mesh(mr, ¶ms, extractors); + } + else { + ExtractPolyBMesh_Params params; + params.poly_range[0] = 0; + params.poly_range[1] = mr->poly_len; + extract_iter_poly_bm(mr, ¶ms, extractors); + } + } + if (iter_type & MR_ITER_LEDGE) { + if (is_mesh) { + ExtractLEdgeMesh_Params params; + params.ledge = mr->ledges; + params.ledge_range[0] = 0; + params.ledge_range[1] = mr->edge_loose_len; + extract_iter_ledge_mesh(mr, ¶ms, extractors); + } + else { + ExtractLEdgeBMesh_Params params; + params.ledge = mr->ledges; + params.ledge_range[0] = 0; + params.ledge_range[1] = mr->edge_loose_len; + extract_iter_ledge_bm(mr, ¶ms, extractors); + } + } + if (iter_type & MR_ITER_LVERT) { + if (is_mesh) { + ExtractLVertMesh_Params params; + params.lvert = mr->lverts; + params.lvert_range[0] = 0; + params.lvert_range[1] = mr->vert_loose_len; + extract_iter_lvert_mesh(mr, ¶ms, extractors); + } + else { + ExtractLVertBMesh_Params params; + params.lvert = mr->lverts; + params.lvert_range[0] = 0; + params.lvert_range[1] = mr->vert_loose_len; + extract_iter_lvert_bm(mr, ¶ms, extractors); + } + } + extract_finish(mr, cache, extractors); +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name ExtractTaskData + * \{ */ +struct ExtractTaskData { + const MeshRenderData *mr = nullptr; + MeshBatchCache *cache = nullptr; + /* #UserData is shared between the iterations as it holds counters to detect if the + * extraction is finished. To make sure the duplication of the user_data does not create a new + * instance of the counters we allocate the user_data in its own container. + * + * This structure makes sure that when extract_init is called, that the user data of all + * iterations are updated. */ + + ExtractorRunDatas *extractors = nullptr; + MeshBufferCache *mbc = nullptr; + int32_t *task_counter = nullptr; + + eMRIterType iter_type; + int start = 0; + int end = INT_MAX; + /** Decremented each time a task is finished. */ + + ExtractTaskData(const MeshRenderData *mr, + struct MeshBatchCache *cache, + ExtractorRunDatas *extractors, + MeshBufferCache *mbc, + int32_t *task_counter) + : mr(mr), cache(cache), extractors(extractors), mbc(mbc), task_counter(task_counter) + { + iter_type = extractors->iter_types(); + }; + + ExtractTaskData(const ExtractTaskData &src) = default; + + ~ExtractTaskData() + { + delete extractors; + } + +#ifdef WITH_CXX_GUARDEDALLOC + MEM_CXX_CLASS_ALLOC_FUNCS("DRW:ExtractTaskData") +#endif +}; + +static ExtractTaskData *extract_extract_iter_task_data_create_mesh(const MeshRenderData *mr, + MeshBatchCache *cache, + ExtractorRunDatas *extractors, + MeshBufferCache *mbc, + int32_t *task_counter) + +{ + ExtractTaskData *taskdata = new ExtractTaskData(mr, cache, extractors, mbc, task_counter); + return taskdata; +} + +static void extract_task_data_free(void *data) +{ + ExtractTaskData *task_data = static_cast<ExtractTaskData *>(data); + delete task_data; +} + +static void extract_task_data_free_ex(void *data) +{ + ExtractTaskData *task_data = static_cast<ExtractTaskData *>(data); + task_data->extractors = nullptr; + delete task_data; +} + +BLI_INLINE void mesh_extract_iter(const MeshRenderData *mr, + const eMRIterType iter_type, + int start, + int end, + ExtractorRunDatas &extractors) +{ + switch (mr->extract_type) { + case MR_EXTRACT_BMESH: + if (iter_type & MR_ITER_LOOPTRI) { + ExtractTriBMesh_Params params; + params.looptris = mr->edit_bmesh->looptris; + params.tri_range[0] = start; + params.tri_range[1] = min_ii(mr->tri_len, end); + extract_iter_looptri_bm(mr, ¶ms, extractors); + } + if (iter_type & MR_ITER_POLY) { + ExtractPolyBMesh_Params params; + params.poly_range[0] = start; + params.poly_range[1] = min_ii(mr->poly_len, end); + extract_iter_poly_bm(mr, ¶ms, extractors); + } + if (iter_type & MR_ITER_LEDGE) { + ExtractLEdgeBMesh_Params params; + params.ledge = mr->ledges; + params.ledge_range[0] = start; + params.ledge_range[1] = min_ii(mr->edge_loose_len, end); + extract_iter_ledge_bm(mr, ¶ms, extractors); + } + if (iter_type & MR_ITER_LVERT) { + ExtractLVertBMesh_Params params; + params.lvert = mr->lverts; + params.lvert_range[0] = start; + params.lvert_range[1] = min_ii(mr->vert_loose_len, end); + extract_iter_lvert_bm(mr, ¶ms, extractors); + } + break; + case MR_EXTRACT_MAPPED: + case MR_EXTRACT_MESH: + if (iter_type & MR_ITER_LOOPTRI) { + ExtractTriMesh_Params params; + params.mlooptri = mr->mlooptri; + params.tri_range[0] = start; + params.tri_range[1] = min_ii(mr->tri_len, end); + extract_iter_looptri_mesh(mr, ¶ms, extractors); + } + if (iter_type & MR_ITER_POLY) { + ExtractPolyMesh_Params params; + params.poly_range[0] = start; + params.poly_range[1] = min_ii(mr->poly_len, end); + extract_iter_poly_mesh(mr, ¶ms, extractors); + } + if (iter_type & MR_ITER_LEDGE) { + ExtractLEdgeMesh_Params params; + params.ledge = mr->ledges; + params.ledge_range[0] = start; + params.ledge_range[1] = min_ii(mr->edge_loose_len, end); + extract_iter_ledge_mesh(mr, ¶ms, extractors); + } + if (iter_type & MR_ITER_LVERT) { + ExtractLVertMesh_Params params; + params.lvert = mr->lverts; + params.lvert_range[0] = start; + params.lvert_range[1] = min_ii(mr->vert_loose_len, end); + extract_iter_lvert_mesh(mr, ¶ms, extractors); + } + break; + } +} + +static void extract_task_init(ExtractTaskData *data) +{ + extract_init(data->mr, data->cache, *data->extractors, data->mbc); +} + +static void extract_task_run(void *__restrict taskdata) +{ + ExtractTaskData *data = (ExtractTaskData *)taskdata; + mesh_extract_iter(data->mr, data->iter_type, data->start, data->end, *data->extractors); + + /* 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) { + extract_finish(data->mr, data->cache, *data->extractors); + } +} + +static void extract_task_init_and_run(void *__restrict taskdata) +{ + ExtractTaskData *data = (ExtractTaskData *)taskdata; + extract_run_and_finish_init( + data->mr, data->cache, *data->extractors, data->iter_type, data->mbc); +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Task Node - Update Mesh Render Data + * \{ */ +struct MeshRenderDataUpdateTaskData { + MeshRenderData *mr = nullptr; + eMRIterType iter_type; + eMRDataType data_flag; + + ~MeshRenderDataUpdateTaskData() + { + mesh_render_data_free(mr); + } + +#ifdef WITH_CXX_GUARDEDALLOC + MEM_CXX_CLASS_ALLOC_FUNCS("DRW:MeshRenderDataUpdateTaskData") +#endif +}; + +static void mesh_render_data_update_task_data_free(MeshRenderDataUpdateTaskData *taskdata) +{ + BLI_assert(taskdata); + delete taskdata; +} + +static void mesh_extract_render_data_node_exec(void *__restrict task_data) +{ + MeshRenderDataUpdateTaskData *update_task_data = static_cast<MeshRenderDataUpdateTaskData *>( + task_data); + MeshRenderData *mr = update_task_data->mr; + const eMRIterType iter_type = update_task_data->iter_type; + const eMRDataType data_flag = update_task_data->data_flag; + + mesh_render_data_update_normals(mr, data_flag); + mesh_render_data_update_looptris(mr, iter_type, data_flag); +} + +static struct TaskNode *mesh_extract_render_data_node_create(struct TaskGraph *task_graph, + MeshRenderData *mr, + const eMRIterType iter_type, + const eMRDataType data_flag) +{ + MeshRenderDataUpdateTaskData *task_data = new (MeshRenderDataUpdateTaskData); + task_data->mr = mr; + task_data->iter_type = iter_type; + task_data->data_flag = data_flag; + + struct TaskNode *task_node = BLI_task_graph_node_create( + task_graph, + mesh_extract_render_data_node_exec, + task_data, + (TaskGraphNodeFreeFunction)mesh_render_data_update_task_data_free); + return task_node; +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Task Node - Extract Single Threaded + * \{ */ + +static struct TaskNode *extract_single_threaded_task_node_create(struct TaskGraph *task_graph, + ExtractTaskData *task_data) +{ + struct TaskNode *task_node = BLI_task_graph_node_create( + task_graph, + extract_task_init_and_run, + task_data, + (TaskGraphNodeFreeFunction)extract_task_data_free); + return task_node; +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Task Node - UserData Initializer + * \{ */ +struct UserDataInitTaskData { + ExtractTaskData *td; + int32_t task_counter = 0; + + ~UserDataInitTaskData() + { + extract_task_data_free(td); + } + +#ifdef WITH_CXX_GUARDEDALLOC + MEM_CXX_CLASS_ALLOC_FUNCS("DRW:UserDataInitTaskData") +#endif +}; + +static void user_data_init_task_data_free(UserDataInitTaskData *taskdata) +{ + delete taskdata; +} + +static void user_data_init_task_data_exec(void *__restrict task_data) +{ + UserDataInitTaskData *extract_task_data = static_cast<UserDataInitTaskData *>(task_data); + ExtractTaskData *taskdata_base = extract_task_data->td; + extract_task_init(taskdata_base); +} + +static struct TaskNode *user_data_init_task_node_create(struct TaskGraph *task_graph, + UserDataInitTaskData *task_data) +{ + struct TaskNode *task_node = BLI_task_graph_node_create( + task_graph, + user_data_init_task_data_exec, + task_data, + (TaskGraphNodeFreeFunction)user_data_init_task_data_free); + return task_node; +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Extract Loop + * \{ */ + +static void extract_range_task_create(struct TaskGraph *task_graph, + struct TaskNode *task_node_user_data_init, + ExtractTaskData *taskdata, + const eMRIterType type, + int start, + int length) +{ + taskdata = new ExtractTaskData(*taskdata); + atomic_add_and_fetch_int32(taskdata->task_counter, 1); + taskdata->iter_type = type; + taskdata->start = start; + taskdata->end = start + length; + struct TaskNode *task_node = BLI_task_graph_node_create( + task_graph, extract_task_run, taskdata, extract_task_data_free_ex); + BLI_task_graph_edge_create(task_node_user_data_init, task_node); +} + +static int extract_range_task_num_elements_get(const MeshRenderData *mr, + const eMRIterType iter_type) +{ + /* Divide task into sensible chunks. */ + int iter_len = 0; + if (iter_type & MR_ITER_LOOPTRI) { + iter_len += mr->tri_len; + } + if (iter_type & MR_ITER_POLY) { + iter_len += mr->poly_len; + } + if (iter_type & MR_ITER_LEDGE) { + iter_len += mr->edge_loose_len; + } + if (iter_type & MR_ITER_LVERT) { + iter_len += mr->vert_loose_len; + } + return iter_len; +} + +static int extract_range_task_chunk_size_get(const MeshRenderData *mr, + const eMRIterType iter_type, + const int num_threads) +{ + /* Divide task into sensible chunks. */ + const int num_elements = extract_range_task_num_elements_get(mr, iter_type); + int range_len = (num_elements + num_threads) / num_threads; + CLAMP_MIN(range_len, CHUNK_SIZE); + return range_len; +} + +static void extract_task_in_ranges_create(struct TaskGraph *task_graph, + struct TaskNode *task_node_user_data_init, + ExtractTaskData *taskdata_base, + const int num_threads) +{ + const MeshRenderData *mr = taskdata_base->mr; + const int range_len = extract_range_task_chunk_size_get( + mr, taskdata_base->iter_type, num_threads); + + if (taskdata_base->iter_type & MR_ITER_LOOPTRI) { + for (int i = 0; i < mr->tri_len; i += range_len) { + extract_range_task_create( + task_graph, task_node_user_data_init, taskdata_base, MR_ITER_LOOPTRI, i, range_len); + } + } + if (taskdata_base->iter_type & MR_ITER_POLY) { + for (int i = 0; i < mr->poly_len; i += range_len) { + extract_range_task_create( + task_graph, task_node_user_data_init, taskdata_base, MR_ITER_POLY, i, range_len); + } + } + if (taskdata_base->iter_type & MR_ITER_LEDGE) { + for (int i = 0; i < mr->edge_loose_len; i += range_len) { + extract_range_task_create( + task_graph, task_node_user_data_init, taskdata_base, MR_ITER_LEDGE, i, range_len); + } + } + if (taskdata_base->iter_type & MR_ITER_LVERT) { + for (int i = 0; i < mr->vert_loose_len; i += range_len) { + extract_range_task_create( + task_graph, task_node_user_data_init, taskdata_base, MR_ITER_LVERT, i, range_len); + } + } +} + +static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, + MeshBatchCache *cache, + MeshBufferCache *mbc, + MeshBufferExtractionCache *extraction_cache, + Mesh *me, + + const bool is_editmode, + const bool is_paint_mode, + const bool is_mode_active, + const float obmat[4][4], + const bool do_final, + const bool do_uvedit, + const bool use_subsurf_fdots, + const Scene *scene, + const ToolSettings *ts, + const bool use_hide) +{ + /* For each mesh where batches needs to be updated a sub-graph will be added to the task_graph. + * This sub-graph starts with an extract_render_data_node. This fills/converts the required + * data from Mesh. + * + * Small extractions and extractions that can't be multi-threaded are grouped in a single + * `extract_single_threaded_task_node`. + * + * Other extractions will create a node for each loop exceeding 8192 items. these nodes are + * linked to the `user_data_init_task_node`. the `user_data_init_task_node` prepares the + * user_data needed for the extraction based on the data extracted from the mesh. + * counters are used to check if the finalize of a task has to be called. + * + * Mesh extraction sub graph + * + * +----------------------+ + * +-----> | extract_task1_loop_1 | + * | +----------------------+ + * +------------------+ +----------------------+ +----------------------+ + * | mesh_render_data | --> | | --> | extract_task1_loop_2 | + * +------------------+ | | +----------------------+ + * | | | +----------------------+ + * | | user_data_init | --> | extract_task2_loop_1 | + * v | | +----------------------+ + * +------------------+ | | +----------------------+ + * | single_threaded | | | --> | extract_task2_loop_2 | + * +------------------+ +----------------------+ +----------------------+ + * | +----------------------+ + * +-----> | extract_task2_loop_3 | + * +----------------------+ + */ + const bool do_hq_normals = (scene->r.perf_flag & SCE_PERF_HQ_NORMALS) != 0 || + GPU_use_hq_normals_workaround(); + + /* Create an array containing all the extractors that needs to be executed. */ + ExtractorRunDatas extractors; + +#define EXTRACT_ADD_REQUESTED(type, type_lowercase, name) \ + do { \ + if (DRW_##type_lowercase##_requested(mbc->type_lowercase.name)) { \ + const MeshExtract *extractor = mesh_extract_override_get(&extract_##name, do_hq_normals); \ + extractors.append(extractor); \ + } \ + } while (0) + + EXTRACT_ADD_REQUESTED(VBO, vbo, pos_nor); + EXTRACT_ADD_REQUESTED(VBO, vbo, lnor); + EXTRACT_ADD_REQUESTED(VBO, vbo, uv); + EXTRACT_ADD_REQUESTED(VBO, vbo, tan); + EXTRACT_ADD_REQUESTED(VBO, vbo, vcol); + EXTRACT_ADD_REQUESTED(VBO, vbo, sculpt_data); + EXTRACT_ADD_REQUESTED(VBO, vbo, orco); + EXTRACT_ADD_REQUESTED(VBO, vbo, edge_fac); + EXTRACT_ADD_REQUESTED(VBO, vbo, weights); + EXTRACT_ADD_REQUESTED(VBO, vbo, edit_data); + EXTRACT_ADD_REQUESTED(VBO, vbo, edituv_data); + EXTRACT_ADD_REQUESTED(VBO, vbo, edituv_stretch_area); + EXTRACT_ADD_REQUESTED(VBO, vbo, edituv_stretch_angle); + EXTRACT_ADD_REQUESTED(VBO, vbo, mesh_analysis); + EXTRACT_ADD_REQUESTED(VBO, vbo, fdots_pos); + EXTRACT_ADD_REQUESTED(VBO, vbo, fdots_nor); + EXTRACT_ADD_REQUESTED(VBO, vbo, fdots_uv); + EXTRACT_ADD_REQUESTED(VBO, vbo, fdots_edituv_data); + EXTRACT_ADD_REQUESTED(VBO, vbo, poly_idx); + EXTRACT_ADD_REQUESTED(VBO, vbo, edge_idx); + EXTRACT_ADD_REQUESTED(VBO, vbo, vert_idx); + EXTRACT_ADD_REQUESTED(VBO, vbo, fdot_idx); + EXTRACT_ADD_REQUESTED(VBO, vbo, skin_roots); + + EXTRACT_ADD_REQUESTED(IBO, ibo, tris); + if (DRW_ibo_requested(mbc->ibo.lines)) { + const MeshExtract *extractor; + if (mbc->ibo.lines_loose != nullptr) { + /* Update #lines_loose ibo. */ + extractor = &extract_lines_with_lines_loose; + } + else { + extractor = &extract_lines; + } + extractors.append(extractor); + } + else if (DRW_ibo_requested(mbc->ibo.lines_loose)) { + /* Note: #ibo.lines must have been created first. */ + const MeshExtract *extractor = &extract_lines_loose_only; + extractors.append(extractor); + } + EXTRACT_ADD_REQUESTED(IBO, ibo, points); + EXTRACT_ADD_REQUESTED(IBO, ibo, fdots); + EXTRACT_ADD_REQUESTED(IBO, ibo, lines_paint_mask); + EXTRACT_ADD_REQUESTED(IBO, ibo, lines_adjacency); + EXTRACT_ADD_REQUESTED(IBO, ibo, edituv_tris); + EXTRACT_ADD_REQUESTED(IBO, ibo, edituv_lines); + EXTRACT_ADD_REQUESTED(IBO, ibo, edituv_points); + EXTRACT_ADD_REQUESTED(IBO, ibo, edituv_fdots); + +#undef EXTRACT_ADD_REQUESTED + + if (extractors.is_empty()) { + return; + } + +#ifdef DEBUG_TIME + double rdata_start = PIL_check_seconds_timer(); +#endif + + eMRIterType iter_type = extractors.iter_types(); + eMRDataType data_flag = extractors.data_types(); + + MeshRenderData *mr = mesh_render_data_create(me, + extraction_cache, + is_editmode, + is_paint_mode, + is_mode_active, + obmat, + do_final, + do_uvedit, + ts, + iter_type); + mr->use_hide = use_hide; + mr->use_subsurf_fdots = use_subsurf_fdots; + mr->use_final_mesh = do_final; + +#ifdef DEBUG_TIME + double rdata_end = PIL_check_seconds_timer(); +#endif + + struct TaskNode *task_node_mesh_render_data = mesh_extract_render_data_node_create( + task_graph, mr, iter_type, data_flag); + + /* Simple heuristic. */ + const bool use_thread = (mr->loop_len + mr->loop_loose_len) > CHUNK_SIZE; + + if (use_thread) { + uint single_threaded_extractors_len = 0; + + /* First run the requested extractors that do not support asynchronous ranges. */ + for (const ExtractorRunData &run_data : extractors) { + const MeshExtract *extractor = run_data.extractor; + if (!extractor->use_threading) { + ExtractorRunDatas *single_threaded_extractors = new ExtractorRunDatas(); + single_threaded_extractors->append(extractor); + ExtractTaskData *taskdata = extract_extract_iter_task_data_create_mesh( + mr, cache, single_threaded_extractors, mbc, nullptr); + struct TaskNode *task_node = extract_single_threaded_task_node_create(task_graph, + taskdata); + BLI_task_graph_edge_create(task_node_mesh_render_data, task_node); + single_threaded_extractors_len++; + } + } + + /* Distribute the remaining extractors into ranges per core. */ + ExtractorRunDatas *multi_threaded_extractors = new ExtractorRunDatas(); + extractors.filter_threaded_extractors_into(*multi_threaded_extractors); + if (!multi_threaded_extractors->is_empty()) { + /* + * Determine the number of thread to use for multithreading. + * Thread can be used for single threaded tasks. These typically take longer to execute so + * fill the rest of the threads for range operations. + */ + int num_threads = BLI_task_scheduler_num_threads(); + num_threads -= single_threaded_extractors_len % num_threads; + + UserDataInitTaskData *user_data_init_task_data = new UserDataInitTaskData(); + struct TaskNode *task_node_user_data_init = user_data_init_task_node_create( + task_graph, user_data_init_task_data); + + user_data_init_task_data->td = extract_extract_iter_task_data_create_mesh( + mr, cache, multi_threaded_extractors, mbc, &user_data_init_task_data->task_counter); + + extract_task_in_ranges_create( + task_graph, task_node_user_data_init, user_data_init_task_data->td, num_threads); + + BLI_task_graph_edge_create(task_node_mesh_render_data, task_node_user_data_init); + } + else { + /* No tasks created freeing extractors list. */ + delete multi_threaded_extractors; + } + } + else { + /* Run all requests on the same thread. */ + ExtractorRunDatas *extractors_copy = new ExtractorRunDatas(extractors); + ExtractTaskData *taskdata = extract_extract_iter_task_data_create_mesh( + mr, cache, extractors_copy, mbc, nullptr); + + struct TaskNode *task_node = extract_single_threaded_task_node_create(task_graph, taskdata); + BLI_task_graph_edge_create(task_node_mesh_render_data, task_node); + } + + /* Trigger the sub-graph for this mesh. */ + BLI_task_graph_node_push_work(task_node_mesh_render_data); + +#ifdef DEBUG_TIME + BLI_task_graph_work_and_wait(task_graph); + double end = PIL_check_seconds_timer(); + + static double avg = 0; + static double avg_fps = 0; + static double avg_rdata = 0; + static double end_prev = 0; + + if (end_prev == 0) { + end_prev = end; + } + + avg = avg * 0.95 + (end - rdata_end) * 0.05; + avg_fps = avg_fps * 0.95 + (end - end_prev) * 0.05; + avg_rdata = avg_rdata * 0.95 + (rdata_end - rdata_start) * 0.05; + + printf( + "rdata %.0fms iter %.0fms (frame %.0fms)\n", avg_rdata * 1000, avg * 1000, avg_fps * 1000); + + end_prev = end; +#endif +} + +} // namespace blender::draw + +extern "C" { +void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, + MeshBatchCache *cache, + MeshBufferCache *mbc, + MeshBufferExtractionCache *extraction_cache, + Mesh *me, + + const bool is_editmode, + const bool is_paint_mode, + const bool is_mode_active, + const float obmat[4][4], + const bool do_final, + const bool do_uvedit, + const bool use_subsurf_fdots, + const Scene *scene, + const ToolSettings *ts, + const bool use_hide) +{ + blender::draw::mesh_buffer_cache_create_requested(task_graph, + cache, + mbc, + extraction_cache, + me, + is_editmode, + is_paint_mode, + is_mode_active, + obmat, + do_final, + do_uvedit, + use_subsurf_fdots, + scene, + ts, + use_hide); +} + +} // extern "C" + +/** \} */ diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.c b/source/blender/draw/intern/draw_cache_extract_mesh_extractors.c index f167ea3d540..0a3945291bb 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh.c +++ b/source/blender/draw/intern/draw_cache_extract_mesh_extractors.c @@ -13,7 +13,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2017 by Blender Foundation. + * The Original Code is Copyright (C) 2021 by Blender Foundation. * All rights reserved. */ @@ -25,773 +25,82 @@ #include "MEM_guardedalloc.h" -#include "BLI_alloca.h" -#include "BLI_bitmap.h" -#include "BLI_buffer.h" +#include "atomic_ops.h" + +#include "DNA_object_types.h" + #include "BLI_edgehash.h" #include "BLI_jitter_2d.h" -#include "BLI_math_bits.h" -#include "BLI_math_vector.h" +#include "BLI_kdopbvh.h" #include "BLI_string.h" -#include "BLI_task.h" -#include "BLI_utildefines.h" - -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_object_types.h" -#include "DNA_scene_types.h" #include "BKE_bvhutils.h" -#include "BKE_customdata.h" #include "BKE_deform.h" #include "BKE_editmesh.h" #include "BKE_editmesh_bvh.h" #include "BKE_editmesh_cache.h" #include "BKE_editmesh_tangent.h" #include "BKE_mesh.h" -#include "BKE_mesh_runtime.h" #include "BKE_mesh_tangent.h" -#include "BKE_modifier.h" -#include "BKE_object_deform.h" #include "BKE_paint.h" -#include "atomic_ops.h" - -#include "bmesh.h" +#include "ED_uvedit.h" -#include "GPU_batch.h" #include "GPU_capabilities.h" -#include "DRW_render.h" - -#include "ED_mesh.h" -#include "ED_uvedit.h" - +#include "draw_cache_extract_mesh_private.h" #include "draw_cache_impl.h" -#include "draw_cache_inline.h" - -#include "draw_cache_extract.h" - -// #define DEBUG_TIME - -#ifdef DEBUG_TIME -# include "PIL_time_utildefines.h" -#endif - -/* ---------------------------------------------------------------------- */ -/** \name Mesh/BMesh Interface (indirect, partially cached access to complex data). - * \{ */ - -typedef struct MeshRenderData { - eMRExtractType extract_type; - - int poly_len, edge_len, vert_len, loop_len; - int edge_loose_len; - int vert_loose_len; - int loop_loose_len; - int tri_len; - int mat_len; - - bool use_hide; - bool use_subsurf_fdots; - bool use_final_mesh; - - /** Use for #MeshStatVis calculation which use world-space coords. */ - float obmat[4][4]; - - const ToolSettings *toolsettings; - /** Edit Mesh */ - BMEditMesh *edit_bmesh; - BMesh *bm; - EditMeshData *edit_data; - - /* For deformed edit-mesh data. */ - /* Use for #ME_WRAPPER_TYPE_BMESH. */ - const float (*bm_vert_coords)[3]; - const float (*bm_vert_normals)[3]; - const float (*bm_poly_normals)[3]; - const float (*bm_poly_centers)[3]; - - int *v_origindex, *e_origindex, *p_origindex; - int crease_ofs; - int bweight_ofs; - int freestyle_edge_ofs; - int freestyle_face_ofs; - /** Mesh */ - Mesh *me; - const MVert *mvert; - const MEdge *medge; - const MLoop *mloop; - const MPoly *mpoly; - BMVert *eve_act; - BMEdge *eed_act; - BMFace *efa_act; - BMFace *efa_act_uv; - /* Data created on-demand (usually not for #BMesh based data). */ - MLoopTri *mlooptri; - float (*loop_normals)[3]; - float (*poly_normals)[3]; - int *lverts, *ledges; -} MeshRenderData; - -static void mesh_render_data_update_loose_geom(MeshRenderData *mr, - const eMRIterType iter_type, - const eMRDataType UNUSED(data_flag)) -{ - if (mr->extract_type != MR_EXTRACT_BMESH) { - /* Mesh */ - if (iter_type & (MR_ITER_LEDGE | MR_ITER_LVERT)) { - mr->vert_loose_len = 0; - mr->edge_loose_len = 0; - - BLI_bitmap *lvert_map = BLI_BITMAP_NEW(mr->vert_len, __func__); - - mr->ledges = MEM_mallocN(mr->edge_len * sizeof(int), __func__); - const MEdge *med = mr->medge; - for (int med_index = 0; med_index < mr->edge_len; med_index++, med++) { - if (med->flag & ME_LOOSEEDGE) { - mr->ledges[mr->edge_loose_len++] = med_index; - } - /* Tag verts as not loose. */ - BLI_BITMAP_ENABLE(lvert_map, med->v1); - BLI_BITMAP_ENABLE(lvert_map, med->v2); - } - if (mr->edge_loose_len < mr->edge_len) { - mr->ledges = MEM_reallocN(mr->ledges, mr->edge_loose_len * sizeof(*mr->ledges)); - } - - mr->lverts = MEM_mallocN(mr->vert_len * sizeof(*mr->lverts), __func__); - for (int v = 0; v < mr->vert_len; v++) { - if (!BLI_BITMAP_TEST(lvert_map, v)) { - mr->lverts[mr->vert_loose_len++] = v; - } - } - if (mr->vert_loose_len < mr->vert_len) { - mr->lverts = MEM_reallocN(mr->lverts, mr->vert_loose_len * sizeof(*mr->lverts)); - } - - MEM_freeN(lvert_map); - - mr->loop_loose_len = mr->vert_loose_len + (mr->edge_loose_len * 2); - } - } - else { - /* #BMesh */ - BMesh *bm = mr->bm; - if (iter_type & (MR_ITER_LEDGE | MR_ITER_LVERT)) { - int elem_id; - BMIter iter; - BMVert *eve; - BMEdge *ede; - mr->vert_loose_len = 0; - mr->edge_loose_len = 0; - - mr->lverts = MEM_mallocN(mr->vert_len * sizeof(*mr->lverts), __func__); - BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, elem_id) { - if (eve->e == NULL) { - mr->lverts[mr->vert_loose_len++] = elem_id; - } - } - if (mr->vert_loose_len < mr->vert_len) { - mr->lverts = MEM_reallocN(mr->lverts, mr->vert_loose_len * sizeof(*mr->lverts)); - } - - mr->ledges = MEM_mallocN(mr->edge_len * sizeof(*mr->ledges), __func__); - BM_ITER_MESH_INDEX (ede, &iter, bm, BM_EDGES_OF_MESH, elem_id) { - if (ede->l == NULL) { - mr->ledges[mr->edge_loose_len++] = elem_id; - } - } - if (mr->edge_loose_len < mr->edge_len) { - mr->ledges = MEM_reallocN(mr->ledges, mr->edge_loose_len * sizeof(*mr->ledges)); - } - - mr->loop_loose_len = mr->vert_loose_len + mr->edge_loose_len * 2; - } - } -} - -/** - * Part of the creation of the #MeshRenderData that happens in a thread. - */ -static void mesh_render_data_update_looptris(MeshRenderData *mr, - const eMRIterType iter_type, - const eMRDataType data_flag) -{ - Mesh *me = mr->me; - if (mr->extract_type != MR_EXTRACT_BMESH) { - /* Mesh */ - if ((iter_type & MR_ITER_LOOPTRI) || (data_flag & MR_DATA_LOOPTRI)) { - mr->mlooptri = MEM_mallocN(sizeof(*mr->mlooptri) * mr->tri_len, "MR_DATATYPE_LOOPTRI"); - BKE_mesh_recalc_looptri( - me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, mr->mlooptri); - } - } - else { - /* #BMesh */ - if ((iter_type & MR_ITER_LOOPTRI) || (data_flag & MR_DATA_LOOPTRI)) { - /* Edit mode ensures this is valid, no need to calculate. */ - BLI_assert((mr->bm->totloop == 0) || (mr->edit_bmesh->looptris != NULL)); - } - } -} - -static void mesh_render_data_update_normals(MeshRenderData *mr, - const eMRIterType UNUSED(iter_type), - const eMRDataType data_flag) -{ - Mesh *me = mr->me; - const bool is_auto_smooth = (me->flag & ME_AUTOSMOOTH) != 0; - const float split_angle = is_auto_smooth ? me->smoothresh : (float)M_PI; - - if (mr->extract_type != MR_EXTRACT_BMESH) { - /* Mesh */ - if (data_flag & (MR_DATA_POLY_NOR | MR_DATA_LOOP_NOR | MR_DATA_TAN_LOOP_NOR)) { - mr->poly_normals = MEM_mallocN(sizeof(*mr->poly_normals) * mr->poly_len, __func__); - BKE_mesh_calc_normals_poly((MVert *)mr->mvert, - NULL, - mr->vert_len, - mr->mloop, - mr->mpoly, - mr->loop_len, - mr->poly_len, - mr->poly_normals, - true); - } - if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) { - mr->loop_normals = MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__); - short(*clnors)[2] = CustomData_get_layer(&mr->me->ldata, CD_CUSTOMLOOPNORMAL); - BKE_mesh_normals_loop_split(mr->me->mvert, - mr->vert_len, - mr->me->medge, - mr->edge_len, - mr->me->mloop, - mr->loop_normals, - mr->loop_len, - mr->me->mpoly, - mr->poly_normals, - mr->poly_len, - is_auto_smooth, - split_angle, - NULL, - clnors, - NULL); - } - } - else { - /* #BMesh */ - if (data_flag & MR_DATA_POLY_NOR) { - /* Use #BMFace.no instead. */ - } - if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) { - - const float(*vert_coords)[3] = NULL; - const float(*vert_normals)[3] = NULL; - const float(*poly_normals)[3] = NULL; - - if (mr->edit_data && mr->edit_data->vertexCos) { - vert_coords = mr->bm_vert_coords; - vert_normals = mr->bm_vert_normals; - poly_normals = mr->bm_poly_normals; - } - - mr->loop_normals = MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__); - const int clnors_offset = CustomData_get_offset(&mr->bm->ldata, CD_CUSTOMLOOPNORMAL); - BM_loops_calc_normal_vcos(mr->bm, - vert_coords, - vert_normals, - poly_normals, - is_auto_smooth, - split_angle, - mr->loop_normals, - NULL, - NULL, - clnors_offset, - false); - } - } -} - -/** - * \param is_mode_active: When true, use the modifiers from the edit-data, - * otherwise don't use modifiers as they are not from this object. - */ -static MeshRenderData *mesh_render_data_create(Mesh *me, - const bool is_editmode, - const bool is_paint_mode, - const bool is_mode_active, - const float obmat[4][4], - const bool do_final, - const bool do_uvedit, - const DRW_MeshCDMask *UNUSED(cd_used), - const ToolSettings *ts, - const eMRIterType iter_type, - const eMRDataType data_flag) -{ - MeshRenderData *mr = MEM_callocN(sizeof(*mr), __func__); - mr->toolsettings = ts; - mr->mat_len = mesh_render_mat_len_get(me); - - copy_m4_m4(mr->obmat, obmat); - - if (is_editmode) { - BLI_assert(me->edit_mesh->mesh_eval_cage && me->edit_mesh->mesh_eval_final); - mr->bm = me->edit_mesh->bm; - mr->edit_bmesh = me->edit_mesh; - mr->me = (do_final) ? me->edit_mesh->mesh_eval_final : me->edit_mesh->mesh_eval_cage; - mr->edit_data = is_mode_active ? mr->me->runtime.edit_data : NULL; - - if (mr->edit_data) { - EditMeshData *emd = mr->edit_data; - if (emd->vertexCos) { - BKE_editmesh_cache_ensure_vert_normals(mr->edit_bmesh, emd); - BKE_editmesh_cache_ensure_poly_normals(mr->edit_bmesh, emd); - } - - mr->bm_vert_coords = mr->edit_data->vertexCos; - mr->bm_vert_normals = mr->edit_data->vertexNos; - mr->bm_poly_normals = mr->edit_data->polyNos; - mr->bm_poly_centers = mr->edit_data->polyCos; - } - - bool has_mdata = is_mode_active && (mr->me->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA); - bool use_mapped = is_mode_active && - (has_mdata && !do_uvedit && mr->me && !mr->me->runtime.is_original); - - int bm_ensure_types = BM_VERT | BM_EDGE | BM_LOOP | BM_FACE; - - BM_mesh_elem_index_ensure(mr->bm, bm_ensure_types); - BM_mesh_elem_table_ensure(mr->bm, bm_ensure_types & ~BM_LOOP); - - mr->efa_act_uv = EDBM_uv_active_face_get(mr->edit_bmesh, false, false); - mr->efa_act = BM_mesh_active_face_get(mr->bm, false, true); - mr->eed_act = BM_mesh_active_edge_get(mr->bm); - mr->eve_act = BM_mesh_active_vert_get(mr->bm); - - mr->crease_ofs = CustomData_get_offset(&mr->bm->edata, CD_CREASE); - mr->bweight_ofs = CustomData_get_offset(&mr->bm->edata, CD_BWEIGHT); -#ifdef WITH_FREESTYLE - mr->freestyle_edge_ofs = CustomData_get_offset(&mr->bm->edata, CD_FREESTYLE_EDGE); - mr->freestyle_face_ofs = CustomData_get_offset(&mr->bm->pdata, CD_FREESTYLE_FACE); -#endif - - if (use_mapped) { - mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX); - mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX); - mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX); - - use_mapped = (mr->v_origindex || mr->e_origindex || mr->p_origindex); - } - - mr->extract_type = use_mapped ? MR_EXTRACT_MAPPED : MR_EXTRACT_BMESH; - /* Seems like the mesh_eval_final do not have the right origin indices. - * Force not mapped in this case. */ - if (has_mdata && do_final && me->edit_mesh->mesh_eval_final != me->edit_mesh->mesh_eval_cage) { - // mr->edit_bmesh = NULL; - mr->extract_type = MR_EXTRACT_MESH; - } - } - else { - mr->me = me; - mr->edit_bmesh = NULL; - - bool use_mapped = is_paint_mode && mr->me && !mr->me->runtime.is_original; - if (use_mapped) { - mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX); - mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX); - mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX); - - use_mapped = (mr->v_origindex || mr->e_origindex || mr->p_origindex); - } - - mr->extract_type = use_mapped ? MR_EXTRACT_MAPPED : MR_EXTRACT_MESH; - } - - if (mr->extract_type != MR_EXTRACT_BMESH) { - /* Mesh */ - mr->vert_len = mr->me->totvert; - mr->edge_len = mr->me->totedge; - mr->loop_len = mr->me->totloop; - mr->poly_len = mr->me->totpoly; - mr->tri_len = poly_to_tri_count(mr->poly_len, mr->loop_len); - - mr->mvert = CustomData_get_layer(&mr->me->vdata, CD_MVERT); - mr->medge = CustomData_get_layer(&mr->me->edata, CD_MEDGE); - mr->mloop = CustomData_get_layer(&mr->me->ldata, CD_MLOOP); - mr->mpoly = CustomData_get_layer(&mr->me->pdata, CD_MPOLY); - - mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX); - mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX); - mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX); - } - else { - /* #BMesh */ - BMesh *bm = mr->bm; - - mr->vert_len = bm->totvert; - mr->edge_len = bm->totedge; - mr->loop_len = bm->totloop; - mr->poly_len = bm->totface; - mr->tri_len = poly_to_tri_count(mr->poly_len, mr->loop_len); - } - mesh_render_data_update_loose_geom(mr, iter_type, data_flag); - - return mr; -} - -static void mesh_render_data_free(MeshRenderData *mr) +void *mesh_extract_buffer_get(const MeshExtract *extractor, MeshBufferCache *mbc) { - MEM_SAFE_FREE(mr->mlooptri); - MEM_SAFE_FREE(mr->poly_normals); - MEM_SAFE_FREE(mr->loop_normals); - - MEM_SAFE_FREE(mr->lverts); - MEM_SAFE_FREE(mr->ledges); - - MEM_freeN(mr); + /* NOTE: POINTER_OFFSET on windows platforms casts internally to `void *`, but on GCC/CLANG to + * `MeshBufferCache *`. What shows a different usage versus intent. */ + void **buffer_ptr = (void **)POINTER_OFFSET(mbc, extractor->mesh_buffer_offset); + void *buffer = *buffer_ptr; + BLI_assert(buffer); + return buffer; } -BLI_INLINE BMFace *bm_original_face_get(const MeshRenderData *mr, int idx) +eMRIterType mesh_extract_iter_type(const MeshExtract *ext) { - return ((mr->p_origindex != NULL) && (mr->p_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ? - BM_face_at_index(mr->bm, mr->p_origindex[idx]) : - NULL; -} - -BLI_INLINE BMEdge *bm_original_edge_get(const MeshRenderData *mr, int idx) -{ - return ((mr->e_origindex != NULL) && (mr->e_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ? - BM_edge_at_index(mr->bm, mr->e_origindex[idx]) : - NULL; -} - -BLI_INLINE BMVert *bm_original_vert_get(const MeshRenderData *mr, int idx) -{ - return ((mr->v_origindex != NULL) && (mr->v_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ? - BM_vert_at_index(mr->bm, mr->v_origindex[idx]) : - NULL; -} - -BLI_INLINE const float *bm_vert_co_get(const MeshRenderData *mr, const BMVert *eve) -{ - const float(*vert_coords)[3] = mr->bm_vert_coords; - if (vert_coords != NULL) { - return vert_coords[BM_elem_index_get(eve)]; - } - - UNUSED_VARS(mr); - return eve->co; -} - -BLI_INLINE const float *bm_vert_no_get(const MeshRenderData *mr, const BMVert *eve) -{ - const float(*vert_normals)[3] = mr->bm_vert_normals; - if (vert_normals != NULL) { - return vert_normals[BM_elem_index_get(eve)]; - } - - UNUSED_VARS(mr); - return eve->no; -} - -BLI_INLINE const float *bm_face_no_get(const MeshRenderData *mr, const BMFace *efa) -{ - const float(*poly_normals)[3] = mr->bm_poly_normals; - if (poly_normals != NULL) { - return poly_normals[BM_elem_index_get(efa)]; - } - - UNUSED_VARS(mr); - return efa->no; + eMRIterType type = 0; + SET_FLAG_FROM_TEST(type, (ext->iter_looptri_bm || ext->iter_looptri_mesh), MR_ITER_LOOPTRI); + SET_FLAG_FROM_TEST(type, (ext->iter_poly_bm || ext->iter_poly_mesh), MR_ITER_POLY); + SET_FLAG_FROM_TEST(type, (ext->iter_ledge_bm || ext->iter_ledge_mesh), MR_ITER_LEDGE); + SET_FLAG_FROM_TEST(type, (ext->iter_lvert_bm || ext->iter_lvert_mesh), MR_ITER_LVERT); + return type; } -/** \} */ - /* ---------------------------------------------------------------------- */ -/** \name Mesh Elements Extract: Loop Triangles +/** \name Override extractors + * Extractors can be overridden. When overridden a specialized version is used. The next functions + * would check for any needed overrides and usage of the specialized version. * \{ */ -typedef struct ExtractTriBMesh_Params { - BMLoop *(*looptris)[3]; - int tri_range[2]; -} ExtractTriBMesh_Params; -typedef void(ExtractTriBMeshFn)(const MeshRenderData *mr, - const ExtractTriBMesh_Params *params, - void *data); - -#define EXTRACT_TRIS_LOOPTRI_FOREACH_BM_BEGIN(elem_tri, index_tri, params) \ - CHECK_TYPE(params, const ExtractTriBMesh_Params *); \ - { \ - const int _tri_index_end = (params)->tri_range[1]; \ - BMLoop **elem_tri = (params)->looptris[(params)->tri_range[0]]; \ - for (int index_tri = (params)->tri_range[0]; index_tri < _tri_index_end; \ - index_tri += 1, elem_tri += 3) -#define EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END } - -typedef struct ExtractTriMesh_Params { - const MLoopTri *mlooptri; - int tri_range[2]; -} ExtractTriMesh_Params; -typedef void(ExtractTriMeshFn)(const MeshRenderData *mr, - const ExtractTriMesh_Params *params, - void *data); - -#define EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_BEGIN(elem_tri, index_tri, params) \ - CHECK_TYPE(params, const ExtractTriMesh_Params *); \ - { \ - const int _tri_index_end = (params)->tri_range[1]; \ - const MLoopTri *elem_tri = &(params)->mlooptri[(params)->tri_range[0]]; \ - for (int index_tri = (params)->tri_range[0]; index_tri < _tri_index_end; \ - index_tri += 1, elem_tri += 1) -#define EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END } - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Mesh Elements Extract: Polygons, Loops - * \{ */ - -typedef struct ExtractPolyBMesh_Params { - BMLoop *(*looptris)[3]; - int poly_range[2]; -} ExtractPolyBMesh_Params; -typedef void(ExtractPolyBMeshFn)(const MeshRenderData *mr, - const ExtractPolyBMesh_Params *params, - void *data); - -#define EXTRACT_POLY_FOREACH_BM_BEGIN(elem_poly, index_poly, params, mr) \ - CHECK_TYPE(params, const ExtractPolyBMesh_Params *); \ - { \ - BLI_assert((mr->bm->elem_table_dirty & BM_FACE) == 0); \ - BMFace **_ftable = mr->bm->ftable; \ - const int _poly_index_end = (params)->poly_range[1]; \ - for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \ - index_poly += 1) { \ - BMFace *elem_poly = _ftable[index_poly]; \ - (void)elem_poly; - -#define EXTRACT_POLY_FOREACH_BM_END \ - } \ - } - -/* Iterate over polygon and loop. */ -#define EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(elem_loop, index_loop, params, mr) \ - CHECK_TYPE(params, const ExtractPolyBMesh_Params *); \ - { \ - BLI_assert((mr->bm->elem_table_dirty & BM_FACE) == 0); \ - BMFace **_ftable = mr->bm->ftable; \ - const int _poly_index_end = (params)->poly_range[1]; \ - for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \ - index_poly += 1) { \ - BMFace *elem_face = _ftable[index_poly]; \ - BMLoop *elem_loop, *l_first; \ - elem_loop = l_first = BM_FACE_FIRST_LOOP(elem_face); \ - do { \ - const int index_loop = BM_elem_index_get(elem_loop); \ - (void)index_loop; /* Quiet warning when unused. */ - -#define EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(elem_loop) \ - } \ - while ((elem_loop = elem_loop->next) != l_first) \ - ; \ - } \ - } - -typedef struct ExtractPolyMesh_Params { - int poly_range[2]; -} ExtractPolyMesh_Params; -typedef void(ExtractPolyMeshFn)(const MeshRenderData *mr, - const ExtractPolyMesh_Params *params, - void *data); - -#define EXTRACT_POLY_FOREACH_MESH_BEGIN(elem_poly, index_poly, params, mr) \ - CHECK_TYPE(params, const ExtractPolyMesh_Params *); \ - { \ - const MPoly *_mpoly = mr->mpoly; \ - const int _poly_index_end = (params)->poly_range[1]; \ - for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \ - index_poly += 1) { \ - const MPoly *elem_poly = &_mpoly[index_poly]; \ - (void)elem_poly; - -#define EXTRACT_POLY_FOREACH_MESH_END \ - } \ - } - -/* Iterate over polygon and loop. */ -#define EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN( \ - elem_poly, index_poly, elem_loop, index_loop, params, mr) \ - CHECK_TYPE(params, const ExtractPolyMesh_Params *); \ - { \ - const MPoly *_mpoly = mr->mpoly; \ - const MLoop *_mloop = mr->mloop; \ - const int _poly_index_end = (params)->poly_range[1]; \ - for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \ - index_poly += 1) { \ - const MPoly *elem_poly = &_mpoly[index_poly]; \ - const int _index_end = elem_poly->loopstart + elem_poly->totloop; \ - for (int index_loop = elem_poly->loopstart; index_loop < _index_end; index_loop += 1) { \ - const MLoop *elem_loop = &_mloop[index_loop]; \ - (void)elem_loop; - -#define EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END \ - } \ - } \ +static const MeshExtract *mesh_extract_override_hq_normals(const MeshExtract *extractor) +{ + if (extractor == &extract_pos_nor) { + return &extract_pos_nor_hq; } - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Mesh Elements Extract: Loose Edges - * \{ */ - -typedef struct ExtractLEdgeBMesh_Params { - const int *ledge; - int ledge_range[2]; -} ExtractLEdgeBMesh_Params; -typedef void(ExtractLEdgeBMeshFn)(const MeshRenderData *mr, - const ExtractLEdgeBMesh_Params *params, - void *data); - -#define EXTRACT_LEDGE_FOREACH_BM_BEGIN(elem_edge, index_ledge, params) \ - CHECK_TYPE(params, const ExtractLEdgeBMesh_Params *); \ - { \ - BLI_assert((mr->bm->elem_table_dirty & BM_EDGE) == 0); \ - BMEdge **_etable = mr->bm->etable; \ - const int *_ledge = (params)->ledge; \ - const int _ledge_index_end = (params)->ledge_range[1]; \ - for (int index_ledge = (params)->ledge_range[0]; index_ledge < _ledge_index_end; \ - index_ledge += 1) { \ - BMEdge *elem_edge = _etable[_ledge[index_ledge]]; \ - (void)elem_edge; /* Quiet warning when unused. */ \ - { -#define EXTRACT_LEDGE_FOREACH_BM_END \ - } \ - } \ - } - -typedef struct ExtractLEdgeMesh_Params { - const int *ledge; - int ledge_range[2]; -} ExtractLEdgeMesh_Params; -typedef void(ExtractLEdgeMeshFn)(const MeshRenderData *mr, - const ExtractLEdgeMesh_Params *params, - void *data); - -#define EXTRACT_LEDGE_FOREACH_MESH_BEGIN(elem_edge, index_ledge, params, mr) \ - CHECK_TYPE(params, const ExtractLEdgeMesh_Params *); \ - { \ - const MEdge *_medge = mr->medge; \ - const int *_ledge = (params)->ledge; \ - const int _ledge_index_end = (params)->ledge_range[1]; \ - for (int index_ledge = (params)->ledge_range[0]; index_ledge < _ledge_index_end; \ - index_ledge += 1) { \ - const MEdge *elem_edge = &_medge[_ledge[index_ledge]]; \ - (void)elem_edge; /* Quiet warning when unused. */ \ - { -#define EXTRACT_LEDGE_FOREACH_MESH_END \ - } \ - } \ + if (extractor == &extract_lnor) { + return &extract_lnor_hq; } - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Mesh Elements Extract: Loose Vertices - * \{ */ - -typedef struct ExtractLVertBMesh_Params { - const int *lvert; - int lvert_range[2]; -} ExtractLVertBMesh_Params; -typedef void(ExtractLVertBMeshFn)(const MeshRenderData *mr, - const ExtractLVertBMesh_Params *params, - void *data); - -#define EXTRACT_LVERT_FOREACH_BM_BEGIN(elem_vert, index_lvert, params) \ - CHECK_TYPE(params, const ExtractLVertBMesh_Params *); \ - { \ - BLI_assert((mr->bm->elem_table_dirty & BM_FACE) == 0); \ - BMVert **vtable = mr->bm->vtable; \ - const int *lverts = (params)->lvert; \ - const int _lvert_index_end = (params)->lvert_range[1]; \ - for (int index_lvert = (params)->lvert_range[0]; index_lvert < _lvert_index_end; \ - index_lvert += 1) { \ - BMVert *elem_vert = vtable[lverts[index_lvert]]; \ - (void)elem_vert; /* Quiet warning when unused. */ \ - { -#define EXTRACT_LVERT_FOREACH_BM_END \ - } \ - } \ - } - -typedef struct ExtractLVertMesh_Params { - const int *lvert; - int lvert_range[2]; -} ExtractLVertMesh_Params; -typedef void(ExtractLVertMeshFn)(const MeshRenderData *mr, - const ExtractLVertMesh_Params *params, - void *data); - -#define EXTRACT_LVERT_FOREACH_MESH_BEGIN(elem, index_lvert, params, mr) \ - CHECK_TYPE(params, const ExtractLVertMesh_Params *); \ - { \ - const MVert *mvert = mr->mvert; \ - const int *lverts = (params)->lvert; \ - const int _lvert_index_end = (params)->lvert_range[1]; \ - for (int index_lvert = (params)->lvert_range[0]; index_lvert < _lvert_index_end; \ - index_lvert += 1) { \ - const MVert *elem = &mvert[lverts[index_lvert]]; \ - (void)elem; /* Quiet warning when unused. */ \ - { -#define EXTRACT_LVERT_FOREACH_MESH_END \ - } \ - } \ + if (extractor == &extract_tan) { + return &extract_tan_hq; } + if (extractor == &extract_fdots_nor) { + return &extract_fdots_nor_hq; + } + return extractor; +} -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Mesh Elements Extract Struct - * \{ */ - -typedef void *(ExtractInitFn)(const MeshRenderData *mr, - struct MeshBatchCache *cache, - void *buffer); -typedef void(ExtractFinishFn)(const MeshRenderData *mr, - struct MeshBatchCache *cache, - void *buffer, - void *data); - -typedef struct MeshExtract { - /** Executed on main thread and return user data for iteration functions. */ - ExtractInitFn *init; - /** Executed on one (or more if use_threading) worker thread(s). */ - ExtractTriBMeshFn *iter_looptri_bm; - ExtractTriMeshFn *iter_looptri_mesh; - ExtractPolyBMeshFn *iter_poly_bm; - ExtractPolyMeshFn *iter_poly_mesh; - ExtractLEdgeBMeshFn *iter_ledge_bm; - ExtractLEdgeMeshFn *iter_ledge_mesh; - ExtractLVertBMeshFn *iter_lvert_bm; - ExtractLVertMeshFn *iter_lvert_mesh; - /** Executed on one worker thread after all elements iterations. */ - ExtractFinishFn *finish; - /** Used to request common data. */ - const eMRDataType data_flag; - /** Used to know if the element callbacks are thread-safe and can be parallelized. */ - const bool use_threading; -} MeshExtract; - -BLI_INLINE eMRIterType mesh_extract_iter_type(const MeshExtract *ext) +const MeshExtract *mesh_extract_override_get(const MeshExtract *extractor, + const bool do_hq_normals) { - eMRIterType type = 0; - SET_FLAG_FROM_TEST(type, (ext->iter_looptri_bm || ext->iter_looptri_mesh), MR_ITER_LOOPTRI); - SET_FLAG_FROM_TEST(type, (ext->iter_poly_bm || ext->iter_poly_mesh), MR_ITER_POLY); - SET_FLAG_FROM_TEST(type, (ext->iter_ledge_bm || ext->iter_ledge_mesh), MR_ITER_LEDGE); - SET_FLAG_FROM_TEST(type, (ext->iter_lvert_bm || ext->iter_lvert_mesh), MR_ITER_LVERT); - return type; + if (do_hq_normals) { + extractor = mesh_extract_override_hq_normals(extractor); + } + return extractor; } /** \} */ @@ -855,69 +164,65 @@ static void *extract_tris_init(const MeshRenderData *mr, } static void extract_tris_iter_looptri_bm(const MeshRenderData *mr, - const struct ExtractTriBMesh_Params *params, + BMLoop **elt, + const int UNUSED(elt_index), void *_data) { MeshExtract_Tri_Data *data = _data; const int mat_last = mr->mat_len - 1; - EXTRACT_TRIS_LOOPTRI_FOREACH_BM_BEGIN(elt, _elt_index, params) - { - if (!BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN)) { - int *mat_tri_ofs = data->tri_mat_end; - const int mat = min_ii(elt[0]->f->mat_nr, mat_last); - GPU_indexbuf_set_tri_verts(&data->elb, - mat_tri_ofs[mat]++, - BM_elem_index_get(elt[0]), - BM_elem_index_get(elt[1]), - BM_elem_index_get(elt[2])); - } + + if (!BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN)) { + int *mat_tri_ofs = data->tri_mat_end; + const int mat = min_ii(elt[0]->f->mat_nr, mat_last); + GPU_indexbuf_set_tri_verts(&data->elb, + mat_tri_ofs[mat]++, + BM_elem_index_get(elt[0]), + BM_elem_index_get(elt[1]), + BM_elem_index_get(elt[2])); } - EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END; } static void extract_tris_iter_looptri_mesh(const MeshRenderData *mr, - const struct ExtractTriMesh_Params *params, + const MLoopTri *mlt, + const int UNUSED(elt_index), void *_data) { MeshExtract_Tri_Data *data = _data; const int mat_last = mr->mat_len - 1; - EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_BEGIN(mlt, _mlt_index, params) - { - const MPoly *mp = &mr->mpoly[mlt->poly]; - if (!(mr->use_hide && (mp->flag & ME_HIDE))) { - int *mat_tri_ofs = data->tri_mat_end; - const int mat = min_ii(mp->mat_nr, mat_last); - GPU_indexbuf_set_tri_verts( - &data->elb, mat_tri_ofs[mat]++, mlt->tri[0], mlt->tri[1], mlt->tri[2]); - } + const MPoly *mp = &mr->mpoly[mlt->poly]; + if (!(mr->use_hide && (mp->flag & ME_HIDE))) { + int *mat_tri_ofs = data->tri_mat_end; + const int mat = min_ii(mp->mat_nr, mat_last); + GPU_indexbuf_set_tri_verts( + &data->elb, mat_tri_ofs[mat]++, mlt->tri[0], mlt->tri[1], mlt->tri[2]); } - EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END; } static void extract_tris_finish(const MeshRenderData *mr, struct MeshBatchCache *cache, - void *ibo, + void *buf, void *_data) { + GPUIndexBuf *ibo = buf; MeshExtract_Tri_Data *data = _data; GPU_indexbuf_build_in_place(&data->elb, ibo); /* Create ibo sub-ranges. Always do this to avoid error when the standard surface batch * is created before the surfaces-per-material. */ if (mr->use_final_mesh && cache->final.tris_per_mat) { - MeshBufferCache *mbc = &cache->final; + MeshBufferCache *mbc_final = &cache->final; for (int i = 0; i < mr->mat_len; i++) { /* These IBOs have not been queried yet but we create them just in case they are needed * later since they are not tracked by mesh_buffer_cache_create_requested(). */ - if (mbc->tris_per_mat[i] == NULL) { - mbc->tris_per_mat[i] = GPU_indexbuf_calloc(); + if (mbc_final->tris_per_mat[i] == NULL) { + mbc_final->tris_per_mat[i] = GPU_indexbuf_calloc(); } /* Multiply by 3 because these are triangle indices. */ const int mat_start = data->tri_mat_start[i]; const int mat_end = data->tri_mat_end[i]; const int start = mat_start * 3; const int len = (mat_end - mat_start) * 3; - GPU_indexbuf_create_subrange_in_place(mbc->tris_per_mat[i], ibo, start, len); + GPU_indexbuf_create_subrange_in_place(mbc_final->tris_per_mat[i], ibo, start, len); } } MEM_freeN(data->tri_mat_start); @@ -925,13 +230,14 @@ static void extract_tris_finish(const MeshRenderData *mr, MEM_freeN(data); } -static const MeshExtract extract_tris = { +const MeshExtract extract_tris = { .init = extract_tris_init, .iter_looptri_bm = extract_tris_iter_looptri_bm, .iter_looptri_mesh = extract_tris_iter_looptri_mesh, .finish = extract_tris_finish, - .data_flag = 0, + .data_type = 0, .use_threading = false, + .mesh_buffer_offset = offsetof(MeshBufferCache, ibo.tris), }; /** \} */ @@ -951,138 +257,124 @@ static void *extract_lines_init(const MeshRenderData *mr, return elb; } -static void extract_lines_iter_poly_bm(const MeshRenderData *mr, - const ExtractPolyBMesh_Params *params, +static void extract_lines_iter_poly_bm(const MeshRenderData *UNUSED(mr), + BMFace *f, + const int UNUSED(f_index), void *elb) { - /* Using poly & loop iterator would complicate accessing the adjacent loop. */ - EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr) - { - BMLoop *l_iter, *l_first; - /* Use #BMLoop.prev to match mesh order (to avoid minor differences in data extraction). */ - l_iter = l_first = BM_FACE_FIRST_LOOP(f)->prev; - do { - if (!BM_elem_flag_test(l_iter->e, BM_ELEM_HIDDEN)) { - GPU_indexbuf_set_line_verts(elb, - BM_elem_index_get(l_iter->e), - BM_elem_index_get(l_iter), - BM_elem_index_get(l_iter->next)); - } - else { - GPU_indexbuf_set_line_restart(elb, BM_elem_index_get(l_iter->e)); - } - } while ((l_iter = l_iter->next) != l_first); - } - EXTRACT_POLY_FOREACH_BM_END; + BMLoop *l_iter, *l_first; + /* Use #BMLoop.prev to match mesh order (to avoid minor differences in data extraction). */ + l_iter = l_first = BM_FACE_FIRST_LOOP(f)->prev; + do { + if (!BM_elem_flag_test(l_iter->e, BM_ELEM_HIDDEN)) { + GPU_indexbuf_set_line_verts(elb, + BM_elem_index_get(l_iter->e), + BM_elem_index_get(l_iter), + BM_elem_index_get(l_iter->next)); + } + else { + GPU_indexbuf_set_line_restart(elb, BM_elem_index_get(l_iter->e)); + } + } while ((l_iter = l_iter->next) != l_first); } static void extract_lines_iter_poly_mesh(const MeshRenderData *mr, - const ExtractPolyMesh_Params *params, + const MPoly *mp, + const int UNUSED(mp_index), void *elb) { /* Using poly & loop iterator would complicate accessing the adjacent loop. */ const MLoop *mloop = mr->mloop; const MEdge *medge = mr->medge; if (mr->use_hide || (mr->extract_type == MR_EXTRACT_MAPPED) || (mr->e_origindex != NULL)) { - EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr) - { - const int ml_index_last = mp->loopstart + (mp->totloop - 1); - int ml_index = ml_index_last, ml_index_next = mp->loopstart; - do { - const MLoop *ml = &mloop[ml_index]; - const MEdge *med = &medge[ml->e]; - if (!((mr->use_hide && (med->flag & ME_HIDE)) || - ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) && - (mr->e_origindex[ml->e] == ORIGINDEX_NONE)))) { - GPU_indexbuf_set_line_verts(elb, ml->e, ml_index, ml_index_next); - } - else { - GPU_indexbuf_set_line_restart(elb, ml->e); - } - } while ((ml_index = ml_index_next++) != ml_index_last); - } - EXTRACT_POLY_FOREACH_MESH_END; + const int ml_index_last = mp->loopstart + (mp->totloop - 1); + int ml_index = ml_index_last, ml_index_next = mp->loopstart; + do { + const MLoop *ml = &mloop[ml_index]; + const MEdge *med = &medge[ml->e]; + if (!((mr->use_hide && (med->flag & ME_HIDE)) || + ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) && + (mr->e_origindex[ml->e] == ORIGINDEX_NONE)))) { + GPU_indexbuf_set_line_verts(elb, ml->e, ml_index, ml_index_next); + } + else { + GPU_indexbuf_set_line_restart(elb, ml->e); + } + } while ((ml_index = ml_index_next++) != ml_index_last); } else { - EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr) - { - const int ml_index_last = mp->loopstart + (mp->totloop - 1); - int ml_index = ml_index_last, ml_index_next = mp->loopstart; - do { - const MLoop *ml = &mloop[ml_index]; - GPU_indexbuf_set_line_verts(elb, ml->e, ml_index, ml_index_next); - } while ((ml_index = ml_index_next++) != ml_index_last); - } - EXTRACT_POLY_FOREACH_MESH_END; + const int ml_index_last = mp->loopstart + (mp->totloop - 1); + int ml_index = ml_index_last, ml_index_next = mp->loopstart; + do { + const MLoop *ml = &mloop[ml_index]; + GPU_indexbuf_set_line_verts(elb, ml->e, ml_index, ml_index_next); + } while ((ml_index = ml_index_next++) != ml_index_last); } } static void extract_lines_iter_ledge_bm(const MeshRenderData *mr, - const ExtractLEdgeBMesh_Params *params, + BMEdge *eed, + const int ledge_index, void *elb) { - EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params) - { - const int l_index_offset = mr->edge_len + ledge_index; - if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { - const int l_index = mr->loop_len + ledge_index * 2; - GPU_indexbuf_set_line_verts(elb, l_index_offset, l_index, l_index + 1); - } - else { - GPU_indexbuf_set_line_restart(elb, l_index_offset); - } - /* Don't render the edge twice. */ - GPU_indexbuf_set_line_restart(elb, BM_elem_index_get(eed)); + const int l_index_offset = mr->edge_len + ledge_index; + if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { + const int l_index = mr->loop_len + ledge_index * 2; + GPU_indexbuf_set_line_verts(elb, l_index_offset, l_index, l_index + 1); + } + else { + GPU_indexbuf_set_line_restart(elb, l_index_offset); } - EXTRACT_LEDGE_FOREACH_BM_END; + /* Don't render the edge twice. */ + GPU_indexbuf_set_line_restart(elb, BM_elem_index_get(eed)); } static void extract_lines_iter_ledge_mesh(const MeshRenderData *mr, - const ExtractLEdgeMesh_Params *params, + const MEdge *med, + const uint ledge_index, void *elb) { - EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr) - { - const int l_index_offset = mr->edge_len + ledge_index; - const int e_index = mr->ledges[ledge_index]; - if (!((mr->use_hide && (med->flag & ME_HIDE)) || - ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) && - (mr->e_origindex[e_index] == ORIGINDEX_NONE)))) { - const int l_index = mr->loop_len + ledge_index * 2; - GPU_indexbuf_set_line_verts(elb, l_index_offset, l_index, l_index + 1); - } - else { - GPU_indexbuf_set_line_restart(elb, l_index_offset); - } - /* Don't render the edge twice. */ - GPU_indexbuf_set_line_restart(elb, e_index); + const int l_index_offset = mr->edge_len + ledge_index; + const int e_index = mr->ledges[ledge_index]; + if (!((mr->use_hide && (med->flag & ME_HIDE)) || + ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) && + (mr->e_origindex[e_index] == ORIGINDEX_NONE)))) { + const int l_index = mr->loop_len + ledge_index * 2; + GPU_indexbuf_set_line_verts(elb, l_index_offset, l_index, l_index + 1); + } + else { + GPU_indexbuf_set_line_restart(elb, l_index_offset); } - EXTRACT_LEDGE_FOREACH_MESH_END; + /* Don't render the edge twice. */ + GPU_indexbuf_set_line_restart(elb, e_index); } static void extract_lines_finish(const MeshRenderData *UNUSED(mr), struct MeshBatchCache *UNUSED(cache), - void *ibo, + void *buf, void *elb) { + GPUIndexBuf *ibo = buf; GPU_indexbuf_build_in_place(elb, ibo); MEM_freeN(elb); } -static const MeshExtract extract_lines = { +const MeshExtract extract_lines = { .init = extract_lines_init, .iter_poly_bm = extract_lines_iter_poly_bm, .iter_poly_mesh = extract_lines_iter_poly_mesh, .iter_ledge_bm = extract_lines_iter_ledge_bm, .iter_ledge_mesh = extract_lines_iter_ledge_mesh, .finish = extract_lines_finish, - .data_flag = 0, + .data_type = 0, .use_threading = false, + .mesh_buffer_offset = offsetof(MeshBufferCache, ibo.lines), }; + /** \} */ /* ---------------------------------------------------------------------- */ -/** \name Extract Loose Edges Sub Buffer +/** \name Extract Lines and Loose Edges Sub Buffer * \{ */ static void extract_lines_loose_subbuffer(const MeshRenderData *mr, struct MeshBatchCache *cache) @@ -1098,24 +390,47 @@ static void extract_lines_loose_subbuffer(const MeshRenderData *mr, struct MeshB static void extract_lines_with_lines_loose_finish(const MeshRenderData *mr, struct MeshBatchCache *cache, - void *ibo, + void *buf, void *elb) { + GPUIndexBuf *ibo = buf; GPU_indexbuf_build_in_place(elb, ibo); extract_lines_loose_subbuffer(mr, cache); MEM_freeN(elb); } -static const MeshExtract extract_lines_with_lines_loose = { +const MeshExtract extract_lines_with_lines_loose = { .init = extract_lines_init, .iter_poly_bm = extract_lines_iter_poly_bm, .iter_poly_mesh = extract_lines_iter_poly_mesh, .iter_ledge_bm = extract_lines_iter_ledge_bm, .iter_ledge_mesh = extract_lines_iter_ledge_mesh, .finish = extract_lines_with_lines_loose_finish, - .data_flag = 0, + .data_type = 0, .use_threading = false, -}; + .mesh_buffer_offset = offsetof(MeshBufferCache, ibo.lines)}; + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Extract Loose Edges Sub Buffer + * \{ */ + +static void *extract_lines_loose_only_init(const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buf) +{ + BLI_assert(buf == cache->final.ibo.lines_loose); + UNUSED_VARS_NDEBUG(buf); + extract_lines_loose_subbuffer(mr, cache); + return NULL; +} + +const MeshExtract extract_lines_loose_only = { + .init = extract_lines_loose_only_init, + .data_type = 0, + .use_threading = false, + .mesh_buffer_offset = offsetof(MeshBufferCache, ibo.lines_loose)}; /** \} */ @@ -1159,86 +474,81 @@ BLI_INLINE void vert_set_mesh(GPUIndexBufBuilder *elb, } } -static void extract_points_iter_poly_bm(const MeshRenderData *mr, - const ExtractPolyBMesh_Params *params, +static void extract_points_iter_poly_bm(const MeshRenderData *UNUSED(mr), + BMFace *f, + const int UNUSED(f_index), void *elb) { - EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) - { - vert_set_bm(elb, l->v, l_index); - } - EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + const int l_index = BM_elem_index_get(l_iter); + + vert_set_bm(elb, l_iter->v, l_index); + } while ((l_iter = l_iter->next) != l_first); } static void extract_points_iter_poly_mesh(const MeshRenderData *mr, - const ExtractPolyMesh_Params *params, + const MPoly *mp, + const int UNUSED(mp_index), void *elb) { - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) - { + const MLoop *mloop = mr->mloop; + const int ml_index_end = mp->loopstart + mp->totloop; + for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { + const MLoop *ml = &mloop[ml_index]; vert_set_mesh(elb, mr, ml->v, ml_index); } - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static void extract_points_iter_ledge_bm(const MeshRenderData *mr, - const ExtractLEdgeBMesh_Params *params, + BMEdge *eed, + const int ledge_index, void *elb) { - EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params) - { - vert_set_bm(elb, eed->v1, mr->loop_len + (ledge_index * 2)); - vert_set_bm(elb, eed->v2, mr->loop_len + (ledge_index * 2) + 1); - } - EXTRACT_LEDGE_FOREACH_BM_END; + vert_set_bm(elb, eed->v1, mr->loop_len + (ledge_index * 2)); + vert_set_bm(elb, eed->v2, mr->loop_len + (ledge_index * 2) + 1); } static void extract_points_iter_ledge_mesh(const MeshRenderData *mr, - const ExtractLEdgeMesh_Params *params, + const MEdge *med, + const uint ledge_index, void *elb) { - EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr) - { - vert_set_mesh(elb, mr, med->v1, mr->loop_len + (ledge_index * 2)); - vert_set_mesh(elb, mr, med->v2, mr->loop_len + (ledge_index * 2) + 1); - } - EXTRACT_LEDGE_FOREACH_MESH_END; + vert_set_mesh(elb, mr, med->v1, mr->loop_len + (ledge_index * 2)); + vert_set_mesh(elb, mr, med->v2, mr->loop_len + (ledge_index * 2) + 1); } static void extract_points_iter_lvert_bm(const MeshRenderData *mr, - const ExtractLVertBMesh_Params *params, + BMVert *eve, + const int lvert_index, void *elb) { const int offset = mr->loop_len + (mr->edge_loose_len * 2); - EXTRACT_LVERT_FOREACH_BM_BEGIN(eve, lvert_index, params) - { - vert_set_bm(elb, eve, offset + lvert_index); - } - EXTRACT_LVERT_FOREACH_BM_END; + vert_set_bm(elb, eve, offset + lvert_index); } static void extract_points_iter_lvert_mesh(const MeshRenderData *mr, - const ExtractLVertMesh_Params *params, + const MVert *UNUSED(mv), + const int lvert_index, void *elb) { const int offset = mr->loop_len + (mr->edge_loose_len * 2); - EXTRACT_LVERT_FOREACH_MESH_BEGIN(mv, lvert_index, params, mr) - { - vert_set_mesh(elb, mr, mr->lverts[lvert_index], offset + lvert_index); - } - EXTRACT_LVERT_FOREACH_MESH_END; + + vert_set_mesh(elb, mr, mr->lverts[lvert_index], offset + lvert_index); } static void extract_points_finish(const MeshRenderData *UNUSED(mr), struct MeshBatchCache *UNUSED(cache), - void *ibo, + void *buf, void *elb) { + GPUIndexBuf *ibo = buf; GPU_indexbuf_build_in_place(elb, ibo); MEM_freeN(elb); } -static const MeshExtract extract_points = { +const MeshExtract extract_points = { .init = extract_points_init, .iter_poly_bm = extract_points_iter_poly_bm, .iter_poly_mesh = extract_points_iter_poly_mesh, @@ -1247,14 +557,15 @@ static const MeshExtract extract_points = { .iter_lvert_bm = extract_points_iter_lvert_bm, .iter_lvert_mesh = extract_points_iter_lvert_mesh, .finish = extract_points_finish, - .data_flag = 0, + .data_type = 0, .use_threading = false, + .mesh_buffer_offset = offsetof(MeshBufferCache, ibo.points), }; /** \} */ /* ---------------------------------------------------------------------- */ -/** \name Extract Facedots Indices +/** \name Extract Face-dots Indices * \{ */ static void *extract_fdots_init(const MeshRenderData *mr, @@ -1266,70 +577,66 @@ static void *extract_fdots_init(const MeshRenderData *mr, return elb; } -static void extract_fdots_iter_poly_bm(const MeshRenderData *mr, - const ExtractPolyBMesh_Params *params, +static void extract_fdots_iter_poly_bm(const MeshRenderData *UNUSED(mr), + BMFace *f, + const int f_index, void *elb) { - EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr) - { - if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { - GPU_indexbuf_set_point_vert(elb, f_index, f_index); - } - else { - GPU_indexbuf_set_point_restart(elb, f_index); - } + if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { + GPU_indexbuf_set_point_vert(elb, f_index, f_index); + } + else { + GPU_indexbuf_set_point_restart(elb, f_index); } - EXTRACT_POLY_FOREACH_BM_END; } static void extract_fdots_iter_poly_mesh(const MeshRenderData *mr, - const ExtractPolyMesh_Params *params, + const MPoly *mp, + const int mp_index, void *elb) { if (mr->use_subsurf_fdots) { /* Check #ME_VERT_FACEDOT. */ - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) - { + const MLoop *mloop = mr->mloop; + const int ml_index_end = mp->loopstart + mp->totloop; + for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { + const MLoop *ml = &mloop[ml_index]; const MVert *mv = &mr->mvert[ml->v]; if ((mv->flag & ME_VERT_FACEDOT) && !(mr->use_hide && (mp->flag & ME_HIDE))) { GPU_indexbuf_set_point_vert(elb, mp_index, mp_index); - } - else { - GPU_indexbuf_set_point_restart(elb, mp_index); + return; } } - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; + GPU_indexbuf_set_point_restart(elb, mp_index); } else { - EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr) - { - if (!(mr->use_hide && (mp->flag & ME_HIDE))) { - GPU_indexbuf_set_point_vert(elb, mp_index, mp_index); - } - else { - GPU_indexbuf_set_point_restart(elb, mp_index); - } + if (!(mr->use_hide && (mp->flag & ME_HIDE))) { + GPU_indexbuf_set_point_vert(elb, mp_index, mp_index); + } + else { + GPU_indexbuf_set_point_restart(elb, mp_index); } - EXTRACT_POLY_FOREACH_MESH_END; } } static void extract_fdots_finish(const MeshRenderData *UNUSED(mr), struct MeshBatchCache *UNUSED(cache), - void *ibo, + void *buf, void *elb) { + GPUIndexBuf *ibo = buf; GPU_indexbuf_build_in_place(elb, ibo); MEM_freeN(elb); } -static const MeshExtract extract_fdots = { +const MeshExtract extract_fdots = { .init = extract_fdots_init, .iter_poly_bm = extract_fdots_iter_poly_bm, .iter_poly_mesh = extract_fdots_iter_poly_mesh, .finish = extract_fdots_finish, - .data_flag = 0, + .data_type = 0, .use_threading = false, + .mesh_buffer_offset = offsetof(MeshBufferCache, ibo.fdots), }; /** \} */ @@ -1346,7 +653,7 @@ typedef struct MeshExtract_LinePaintMask_Data { static void *extract_lines_paint_mask_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), - void *UNUSED(buf)) + void *UNUSED(ibo)) { size_t bitmap_size = BLI_BITMAP_SIZE(mr->edge_len); MeshExtract_LinePaintMask_Data *data = MEM_callocN(sizeof(*data) + bitmap_size, __func__); @@ -1355,12 +662,16 @@ static void *extract_lines_paint_mask_init(const MeshRenderData *mr, } static void extract_lines_paint_mask_iter_poly_mesh(const MeshRenderData *mr, - const ExtractPolyMesh_Params *params, + const MPoly *mp, + const int UNUSED(mp_index), void *_data) { MeshExtract_LinePaintMask_Data *data = _data; - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) - { + const MLoop *mloop = mr->mloop; + const int ml_index_end = mp->loopstart + mp->totloop; + for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { + const MLoop *ml = &mloop[ml_index]; + const int e_index = ml->e; const MEdge *me = &mr->medge[e_index]; if (!((mr->use_hide && (me->flag & ME_HIDE)) || @@ -1390,26 +701,26 @@ static void extract_lines_paint_mask_iter_poly_mesh(const MeshRenderData *mr, GPU_indexbuf_set_line_restart(&data->elb, e_index); } } - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } + static void extract_lines_paint_mask_finish(const MeshRenderData *UNUSED(mr), struct MeshBatchCache *UNUSED(cache), - void *ibo, + void *buf, void *_data) { + GPUIndexBuf *ibo = buf; MeshExtract_LinePaintMask_Data *data = _data; - GPU_indexbuf_build_in_place(&data->elb, ibo); MEM_freeN(data); } -static const MeshExtract extract_lines_paint_mask = { +const MeshExtract extract_lines_paint_mask = { .init = extract_lines_paint_mask_init, .iter_poly_mesh = extract_lines_paint_mask_iter_poly_mesh, .finish = extract_lines_paint_mask_finish, - .data_flag = 0, + .data_type = 0, .use_threading = false, -}; + .mesh_buffer_offset = offsetof(MeshBufferCache, ibo.lines_paint_mask)}; /** \} */ @@ -1487,49 +798,44 @@ BLI_INLINE void lines_adjacency_triangle( } static void extract_lines_adjacency_iter_looptri_bm(const MeshRenderData *UNUSED(mr), - const struct ExtractTriBMesh_Params *params, + BMLoop **elt, + const int UNUSED(elt_index), void *data) { - EXTRACT_TRIS_LOOPTRI_FOREACH_BM_BEGIN(elt, _elt_index, params) - { - if (!BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN)) { - lines_adjacency_triangle(BM_elem_index_get(elt[0]->v), - BM_elem_index_get(elt[1]->v), - BM_elem_index_get(elt[2]->v), - BM_elem_index_get(elt[0]), - BM_elem_index_get(elt[1]), - BM_elem_index_get(elt[2]), - data); - } + if (!BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN)) { + lines_adjacency_triangle(BM_elem_index_get(elt[0]->v), + BM_elem_index_get(elt[1]->v), + BM_elem_index_get(elt[2]->v), + BM_elem_index_get(elt[0]), + BM_elem_index_get(elt[1]), + BM_elem_index_get(elt[2]), + data); } - EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END; } static void extract_lines_adjacency_iter_looptri_mesh(const MeshRenderData *mr, - const struct ExtractTriMesh_Params *params, + const MLoopTri *mlt, + const int UNUSED(elt_index), void *data) { - EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_BEGIN(mlt, _mlt_index, params) - { - const MPoly *mp = &mr->mpoly[mlt->poly]; - if (!(mr->use_hide && (mp->flag & ME_HIDE))) { - lines_adjacency_triangle(mr->mloop[mlt->tri[0]].v, - mr->mloop[mlt->tri[1]].v, - mr->mloop[mlt->tri[2]].v, - mlt->tri[0], - mlt->tri[1], - mlt->tri[2], - data); - } + const MPoly *mp = &mr->mpoly[mlt->poly]; + if (!(mr->use_hide && (mp->flag & ME_HIDE))) { + lines_adjacency_triangle(mr->mloop[mlt->tri[0]].v, + mr->mloop[mlt->tri[1]].v, + mr->mloop[mlt->tri[2]].v, + mlt->tri[0], + mlt->tri[1], + mlt->tri[2], + data); } - EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END; } static void extract_lines_adjacency_finish(const MeshRenderData *UNUSED(mr), struct MeshBatchCache *cache, - void *ibo, + void *buf, void *_data) { + GPUIndexBuf *ibo = buf; MeshExtract_LineAdjacency_Data *data = _data; /* Create edges for remaining non manifold edges. */ EdgeHashIterator *ehi = BLI_edgehashIterator_new(data->eh); @@ -1559,14 +865,14 @@ static void extract_lines_adjacency_finish(const MeshRenderData *UNUSED(mr), #undef NO_EDGE -static const MeshExtract extract_lines_adjacency = { +const MeshExtract extract_lines_adjacency = { .init = extract_lines_adjacency_init, .iter_looptri_bm = extract_lines_adjacency_iter_looptri_bm, .iter_looptri_mesh = extract_lines_adjacency_iter_looptri_mesh, .finish = extract_lines_adjacency_finish, - .data_flag = 0, + .data_type = 0, .use_threading = false, -}; + .mesh_buffer_offset = offsetof(MeshBufferCache, ibo.lines_adjacency)}; /** \} */ @@ -1598,56 +904,51 @@ BLI_INLINE void edituv_tri_add( } static void extract_edituv_tris_iter_looptri_bm(const MeshRenderData *UNUSED(mr), - const struct ExtractTriBMesh_Params *params, + BMLoop **elt, + const int UNUSED(elt_index), void *data) { - EXTRACT_TRIS_LOOPTRI_FOREACH_BM_BEGIN(elt, _elt_index, params) - { - edituv_tri_add(data, - BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN), - BM_elem_flag_test(elt[0]->f, BM_ELEM_SELECT), - BM_elem_index_get(elt[0]), - BM_elem_index_get(elt[1]), - BM_elem_index_get(elt[2])); - } - EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END; + edituv_tri_add(data, + BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN), + BM_elem_flag_test(elt[0]->f, BM_ELEM_SELECT), + BM_elem_index_get(elt[0]), + BM_elem_index_get(elt[1]), + BM_elem_index_get(elt[2])); } static void extract_edituv_tris_iter_looptri_mesh(const MeshRenderData *mr, - const struct ExtractTriMesh_Params *params, + const MLoopTri *mlt, + const int UNUSED(elt_index), void *data) { - EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_BEGIN(mlt, _mlt_index, params) - { - const MPoly *mp = &mr->mpoly[mlt->poly]; - edituv_tri_add(data, - (mp->flag & ME_HIDE) != 0, - (mp->flag & ME_FACE_SEL) != 0, - mlt->tri[0], - mlt->tri[1], - mlt->tri[2]); - } - EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END; + const MPoly *mp = &mr->mpoly[mlt->poly]; + edituv_tri_add(data, + (mp->flag & ME_HIDE) != 0, + (mp->flag & ME_FACE_SEL) != 0, + mlt->tri[0], + mlt->tri[1], + mlt->tri[2]); } static void extract_edituv_tris_finish(const MeshRenderData *UNUSED(mr), struct MeshBatchCache *UNUSED(cache), - void *ibo, + void *buf, void *data) { + GPUIndexBuf *ibo = buf; MeshExtract_EditUvElem_Data *extract_data = data; GPU_indexbuf_build_in_place(&extract_data->elb, ibo); MEM_freeN(extract_data); } -static const MeshExtract extract_edituv_tris = { +const MeshExtract extract_edituv_tris = { .init = extract_edituv_tris_init, .iter_looptri_bm = extract_edituv_tris_iter_looptri_bm, .iter_looptri_mesh = extract_edituv_tris_iter_looptri_mesh, .finish = extract_edituv_tris_finish, - .data_flag = 0, + .data_type = 0, .use_threading = false, -}; + .mesh_buffer_offset = offsetof(MeshBufferCache, ibo.edituv_tris)}; /** \} */ @@ -1674,27 +975,34 @@ BLI_INLINE void edituv_edge_add( } } -static void extract_edituv_lines_iter_poly_bm(const MeshRenderData *mr, - const ExtractPolyBMesh_Params *params, +static void extract_edituv_lines_iter_poly_bm(const MeshRenderData *UNUSED(mr), + BMFace *f, + const int UNUSED(f_index), void *data) { - EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(loop, l_index, params, mr) - { + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + const int l_index = BM_elem_index_get(l_iter); + edituv_edge_add(data, - BM_elem_flag_test(loop->f, BM_ELEM_HIDDEN), - BM_elem_flag_test(loop->f, BM_ELEM_SELECT), + BM_elem_flag_test_bool(f, BM_ELEM_HIDDEN), + BM_elem_flag_test_bool(f, BM_ELEM_SELECT), l_index, - BM_elem_index_get(loop->next)); - } - EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(loop); + BM_elem_index_get(l_iter->next)); + } while ((l_iter = l_iter->next) != l_first); } static void extract_edituv_lines_iter_poly_mesh(const MeshRenderData *mr, - const ExtractPolyMesh_Params *params, + const MPoly *mp, + const int UNUSED(mp_index), void *data) { - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) - { + const MLoop *mloop = mr->mloop; + const int ml_index_end = mp->loopstart + mp->totloop; + for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { + const MLoop *ml = &mloop[ml_index]; + const int ml_index_last = mp->totloop + mp->loopstart - 1; const int ml_index_next = (ml_index == ml_index_last) ? mp->loopstart : (ml_index + 1); const bool real_edge = (mr->e_origindex == NULL || mr->e_origindex[ml->e] != ORIGINDEX_NONE); @@ -1704,27 +1012,27 @@ static void extract_edituv_lines_iter_poly_mesh(const MeshRenderData *mr, ml_index, ml_index_next); } - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static void extract_edituv_lines_finish(const MeshRenderData *UNUSED(mr), struct MeshBatchCache *UNUSED(cache), - void *ibo, + void *buf, void *data) { + GPUIndexBuf *ibo = buf; MeshExtract_EditUvElem_Data *extract_data = data; GPU_indexbuf_build_in_place(&extract_data->elb, ibo); MEM_freeN(extract_data); } -static const MeshExtract extract_edituv_lines = { +const MeshExtract extract_edituv_lines = { .init = extract_edituv_lines_init, .iter_poly_bm = extract_edituv_lines_iter_poly_bm, .iter_poly_mesh = extract_edituv_lines_iter_poly_mesh, .finish = extract_edituv_lines_finish, - .data_flag = 0, + .data_type = 0, .use_threading = false, -}; + .mesh_buffer_offset = offsetof(MeshBufferCache, ibo.edituv_lines)}; /** \} */ @@ -1753,57 +1061,62 @@ BLI_INLINE void edituv_point_add(MeshExtract_EditUvElem_Data *data, } } -static void extract_edituv_points_iter_poly_bm(const MeshRenderData *mr, - const ExtractPolyBMesh_Params *params, +static void extract_edituv_points_iter_poly_bm(const MeshRenderData *UNUSED(mr), + BMFace *f, + const int UNUSED(f_index), void *data) { - EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) - { - edituv_point_add(data, - BM_elem_flag_test(l->f, BM_ELEM_HIDDEN), - BM_elem_flag_test(l->f, BM_ELEM_SELECT), - l_index); - } - EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + const int l_index = BM_elem_index_get(l_iter); + + edituv_point_add( + data, BM_elem_flag_test(f, BM_ELEM_HIDDEN), BM_elem_flag_test(f, BM_ELEM_SELECT), l_index); + } while ((l_iter = l_iter->next) != l_first); } static void extract_edituv_points_iter_poly_mesh(const MeshRenderData *mr, - const ExtractPolyMesh_Params *params, + const MPoly *mp, + const int UNUSED(mp_index), void *data) { - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) - { + const MLoop *mloop = mr->mloop; + const int ml_index_end = mp->loopstart + mp->totloop; + for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { + const MLoop *ml = &mloop[ml_index]; + const bool real_vert = (mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) && mr->v_origindex[ml->v] != ORIGINDEX_NONE); edituv_point_add( data, ((mp->flag & ME_HIDE) != 0) || !real_vert, (mp->flag & ME_FACE_SEL) != 0, ml_index); } - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static void extract_edituv_points_finish(const MeshRenderData *UNUSED(mr), struct MeshBatchCache *UNUSED(cache), - void *ibo, + void *buf, void *data) { + GPUIndexBuf *ibo = buf; MeshExtract_EditUvElem_Data *extract_data = data; GPU_indexbuf_build_in_place(&extract_data->elb, ibo); MEM_freeN(extract_data); } -static const MeshExtract extract_edituv_points = { +const MeshExtract extract_edituv_points = { .init = extract_edituv_points_init, .iter_poly_bm = extract_edituv_points_iter_poly_bm, .iter_poly_mesh = extract_edituv_points_iter_poly_mesh, .finish = extract_edituv_points_finish, - .data_flag = 0, + .data_type = 0, .use_threading = false, -}; + .mesh_buffer_offset = offsetof(MeshBufferCache, ibo.edituv_points)}; /** \} */ /* ---------------------------------------------------------------------- */ -/** \name Extract Edit UV Facedots Indices +/** \name Extract Edit UV Face-dots Indices * \{ */ static void *extract_edituv_fdots_init(const MeshRenderData *mr, @@ -1830,26 +1143,29 @@ BLI_INLINE void edituv_facedot_add(MeshExtract_EditUvElem_Data *data, } } -static void extract_edituv_fdots_iter_poly_bm(const MeshRenderData *mr, - const ExtractPolyBMesh_Params *params, +static void extract_edituv_fdots_iter_poly_bm(const MeshRenderData *UNUSED(mr), + BMFace *f, + const int f_index, void *data) { - EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr) - { - edituv_facedot_add( - data, BM_elem_flag_test(f, BM_ELEM_HIDDEN), BM_elem_flag_test(f, BM_ELEM_SELECT), f_index); - } - EXTRACT_POLY_FOREACH_BM_END; + edituv_facedot_add(data, + BM_elem_flag_test_bool(f, BM_ELEM_HIDDEN), + BM_elem_flag_test_bool(f, BM_ELEM_SELECT), + f_index); } static void extract_edituv_fdots_iter_poly_mesh(const MeshRenderData *mr, - const ExtractPolyMesh_Params *params, + const MPoly *mp, + const int mp_index, void *data) { if (mr->use_subsurf_fdots) { /* Check #ME_VERT_FACEDOT. */ - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) - { + const MLoop *mloop = mr->mloop; + const int ml_index_end = mp->loopstart + mp->totloop; + for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { + const MLoop *ml = &mloop[ml_index]; + const bool real_fdot = (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex && mr->p_origindex[mp_index] != ORIGINDEX_NONE); const bool subd_fdot = (!mr->use_subsurf_fdots || @@ -1859,40 +1175,34 @@ static void extract_edituv_fdots_iter_poly_mesh(const MeshRenderData *mr, (mp->flag & ME_FACE_SEL) != 0, mp_index); } - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } else { - EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr) - { - const bool real_fdot = (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex && - mr->p_origindex[mp_index] != ORIGINDEX_NONE); - edituv_facedot_add(data, - ((mp->flag & ME_HIDE) != 0) || !real_fdot, - (mp->flag & ME_FACE_SEL) != 0, - mp_index); - } - EXTRACT_POLY_FOREACH_MESH_END; + const bool real_fdot = (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex && + mr->p_origindex[mp_index] != ORIGINDEX_NONE); + edituv_facedot_add( + data, ((mp->flag & ME_HIDE) != 0) || !real_fdot, (mp->flag & ME_FACE_SEL) != 0, mp_index); } } static void extract_edituv_fdots_finish(const MeshRenderData *UNUSED(mr), struct MeshBatchCache *UNUSED(cache), - void *ibo, + void *buf, void *_data) { + GPUIndexBuf *ibo = buf; MeshExtract_EditUvElem_Data *data = _data; GPU_indexbuf_build_in_place(&data->elb, ibo); MEM_freeN(data); } -static const MeshExtract extract_edituv_fdots = { +const MeshExtract extract_edituv_fdots = { .init = extract_edituv_fdots_init, .iter_poly_bm = extract_edituv_fdots_iter_poly_bm, .iter_poly_mesh = extract_edituv_fdots_iter_poly_mesh, .finish = extract_edituv_fdots_finish, - .data_flag = 0, + .data_type = 0, .use_threading = false, -}; + .mesh_buffer_offset = offsetof(MeshBufferCache, ibo.edituv_fdots)}; /** \} */ @@ -1914,6 +1224,7 @@ static void *extract_pos_nor_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf) { + GPUVertBuf *vbo = buf; static GPUVertFormat format = {0}; if (format.attr_len == 0) { /* WARNING Adjust #PosNorLoop struct accordingly. */ @@ -1921,7 +1232,6 @@ static void *extract_pos_nor_init(const MeshRenderData *mr, GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); GPU_vertformat_alias_add(&format, "vnor"); } - GPUVertBuf *vbo = buf; GPU_vertbuf_init_with_format(vbo, &format); GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len); @@ -1949,28 +1259,34 @@ static void *extract_pos_nor_init(const MeshRenderData *mr, } static void extract_pos_nor_iter_poly_bm(const MeshRenderData *mr, - const ExtractPolyBMesh_Params *params, + BMFace *f, + const int UNUSED(f_index), void *_data) { MeshExtract_PosNor_Data *data = _data; - EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) - { + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + const int l_index = BM_elem_index_get(l_iter); PosNorLoop *vert = &data->vbo_data[l_index]; - copy_v3_v3(vert->pos, bm_vert_co_get(mr, l->v)); - vert->nor = data->normals[BM_elem_index_get(l->v)].low; - BMFace *efa = l->f; - vert->nor.w = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0; - } - EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); + copy_v3_v3(vert->pos, bm_vert_co_get(mr, l_iter->v)); + vert->nor = data->normals[BM_elem_index_get(l_iter->v)].low; + vert->nor.w = BM_elem_flag_test(f, BM_ELEM_HIDDEN) ? -1 : 0; + } while ((l_iter = l_iter->next) != l_first); } static void extract_pos_nor_iter_poly_mesh(const MeshRenderData *mr, - const ExtractPolyMesh_Params *params, + const MPoly *mp, + const int UNUSED(mp_index), void *_data) { MeshExtract_PosNor_Data *data = _data; - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) - { + + const MLoop *mloop = mr->mloop; + const int ml_index_end = mp->loopstart + mp->totloop; + for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { + const MLoop *ml = &mloop[ml_index]; + PosNorLoop *vert = &data->vbo_data[ml_index]; const MVert *mv = &mr->mvert[ml->v]; copy_v3_v3(vert->pos, mv->co); @@ -1988,85 +1304,75 @@ static void extract_pos_nor_iter_poly_mesh(const MeshRenderData *mr, vert->nor.w = 0; } } - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static void extract_pos_nor_iter_ledge_bm(const MeshRenderData *mr, - const ExtractLEdgeBMesh_Params *params, + BMEdge *eed, + const int ledge_index, void *_data) { MeshExtract_PosNor_Data *data = _data; - EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params) - { - int l_index = mr->loop_len + ledge_index * 2; - PosNorLoop *vert = &data->vbo_data[l_index]; - copy_v3_v3(vert[0].pos, bm_vert_co_get(mr, eed->v1)); - copy_v3_v3(vert[1].pos, bm_vert_co_get(mr, eed->v2)); - vert[0].nor = data->normals[BM_elem_index_get(eed->v1)].low; - vert[1].nor = data->normals[BM_elem_index_get(eed->v2)].low; - } - EXTRACT_LEDGE_FOREACH_BM_END; + + int l_index = mr->loop_len + ledge_index * 2; + PosNorLoop *vert = &data->vbo_data[l_index]; + copy_v3_v3(vert[0].pos, bm_vert_co_get(mr, eed->v1)); + copy_v3_v3(vert[1].pos, bm_vert_co_get(mr, eed->v2)); + vert[0].nor = data->normals[BM_elem_index_get(eed->v1)].low; + vert[1].nor = data->normals[BM_elem_index_get(eed->v2)].low; } static void extract_pos_nor_iter_ledge_mesh(const MeshRenderData *mr, - const ExtractLEdgeMesh_Params *params, + const MEdge *med, + const uint ledge_index, void *_data) { MeshExtract_PosNor_Data *data = _data; - EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr) - { - const int ml_index = mr->loop_len + ledge_index * 2; - PosNorLoop *vert = &data->vbo_data[ml_index]; - copy_v3_v3(vert[0].pos, mr->mvert[med->v1].co); - copy_v3_v3(vert[1].pos, mr->mvert[med->v2].co); - vert[0].nor = data->normals[med->v1].low; - vert[1].nor = data->normals[med->v2].low; - } - EXTRACT_LEDGE_FOREACH_MESH_END; + const int ml_index = mr->loop_len + ledge_index * 2; + PosNorLoop *vert = &data->vbo_data[ml_index]; + copy_v3_v3(vert[0].pos, mr->mvert[med->v1].co); + copy_v3_v3(vert[1].pos, mr->mvert[med->v2].co); + vert[0].nor = data->normals[med->v1].low; + vert[1].nor = data->normals[med->v2].low; } static void extract_pos_nor_iter_lvert_bm(const MeshRenderData *mr, - const ExtractLVertBMesh_Params *params, + BMVert *eve, + const int lvert_index, void *_data) { MeshExtract_PosNor_Data *data = _data; const int offset = mr->loop_len + (mr->edge_loose_len * 2); - EXTRACT_LVERT_FOREACH_BM_BEGIN(eve, lvert_index, params) - { - const int l_index = offset + lvert_index; - PosNorLoop *vert = &data->vbo_data[l_index]; - copy_v3_v3(vert->pos, bm_vert_co_get(mr, eve)); - vert->nor = data->normals[BM_elem_index_get(eve)].low; - } - EXTRACT_LVERT_FOREACH_BM_END; + + const int l_index = offset + lvert_index; + PosNorLoop *vert = &data->vbo_data[l_index]; + copy_v3_v3(vert->pos, bm_vert_co_get(mr, eve)); + vert->nor = data->normals[BM_elem_index_get(eve)].low; } static void extract_pos_nor_iter_lvert_mesh(const MeshRenderData *mr, - const ExtractLVertMesh_Params *params, + const MVert *mv, + const int lvert_index, void *_data) { MeshExtract_PosNor_Data *data = _data; const int offset = mr->loop_len + (mr->edge_loose_len * 2); - EXTRACT_LVERT_FOREACH_MESH_BEGIN(mv, lvert_index, params, mr) - { - const int ml_index = offset + lvert_index; - const int v_index = mr->lverts[lvert_index]; - PosNorLoop *vert = &data->vbo_data[ml_index]; - copy_v3_v3(vert->pos, mv->co); - vert->nor = data->normals[v_index].low; - } - EXTRACT_LVERT_FOREACH_MESH_END; + + const int ml_index = offset + lvert_index; + const int v_index = mr->lverts[lvert_index]; + PosNorLoop *vert = &data->vbo_data[ml_index]; + copy_v3_v3(vert->pos, mv->co); + vert->nor = data->normals[v_index].low; } static void extract_pos_nor_finish(const MeshRenderData *UNUSED(mr), struct MeshBatchCache *UNUSED(cache), - void *UNUSED(vbo), + void *UNUSED(buf), void *data) { MEM_freeN(data); } -static const MeshExtract extract_pos_nor = { +const MeshExtract extract_pos_nor = { .init = extract_pos_nor_init, .iter_poly_bm = extract_pos_nor_iter_poly_bm, .iter_poly_mesh = extract_pos_nor_iter_poly_mesh, @@ -2075,9 +1381,11 @@ static const MeshExtract extract_pos_nor = { .iter_lvert_bm = extract_pos_nor_iter_lvert_bm, .iter_lvert_mesh = extract_pos_nor_iter_lvert_mesh, .finish = extract_pos_nor_finish, - .data_flag = 0, + .data_type = 0, .use_threading = true, + .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.pos_nor), }; + /** \} */ /* ---------------------------------------------------------------------- */ @@ -2098,6 +1406,7 @@ static void *extract_pos_nor_hq_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf) { + GPUVertBuf *vbo = buf; static GPUVertFormat format = {0}; if (format.attr_len == 0) { /* WARNING Adjust #PosNorHQLoop struct accordingly. */ @@ -2105,7 +1414,6 @@ static void *extract_pos_nor_hq_init(const MeshRenderData *mr, GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); GPU_vertformat_alias_add(&format, "vnor"); } - GPUVertBuf *vbo = buf; GPU_vertbuf_init_with_format(vbo, &format); GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len); @@ -2133,29 +1441,35 @@ static void *extract_pos_nor_hq_init(const MeshRenderData *mr, } static void extract_pos_nor_hq_iter_poly_bm(const MeshRenderData *mr, - const ExtractPolyBMesh_Params *params, + BMFace *f, + const int UNUSED(f_index), void *_data) { MeshExtract_PosNorHQ_Data *data = _data; - EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) - { + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + const int l_index = BM_elem_index_get(l_iter); PosNorHQLoop *vert = &data->vbo_data[l_index]; - copy_v3_v3(vert->pos, bm_vert_co_get(mr, l->v)); - copy_v3_v3_short(vert->nor, data->normals[BM_elem_index_get(l->v)].high); + copy_v3_v3(vert->pos, bm_vert_co_get(mr, l_iter->v)); + copy_v3_v3_short(vert->nor, data->normals[BM_elem_index_get(l_iter->v)].high); - BMFace *efa = l->f; + BMFace *efa = l_iter->f; vert->nor[3] = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0; - } - EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); + } while ((l_iter = l_iter->next) != l_first); } static void extract_pos_nor_hq_iter_poly_mesh(const MeshRenderData *mr, - const ExtractPolyMesh_Params *params, + const MPoly *mp, + const int UNUSED(mp_index), void *_data) { MeshExtract_PosNorHQ_Data *data = _data; - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) - { + const MLoop *mloop = mr->mloop; + const int ml_index_end = mp->loopstart + mp->totloop; + for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { + const MLoop *ml = &mloop[ml_index]; + PosNorHQLoop *vert = &data->vbo_data[ml_index]; const MVert *mv = &mr->mvert[ml->v]; copy_v3_v3(vert->pos, mv->co); @@ -2174,91 +1488,80 @@ static void extract_pos_nor_hq_iter_poly_mesh(const MeshRenderData *mr, vert->nor[3] = 0; } } - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static void extract_pos_nor_hq_iter_ledge_bm(const MeshRenderData *mr, - const ExtractLEdgeBMesh_Params *params, + BMEdge *eed, + const int ledge_index, void *_data) { MeshExtract_PosNorHQ_Data *data = _data; - EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params) - { - int l_index = mr->loop_len + ledge_index * 2; - PosNorHQLoop *vert = &data->vbo_data[l_index]; - copy_v3_v3(vert[0].pos, bm_vert_co_get(mr, eed->v1)); - copy_v3_v3(vert[1].pos, bm_vert_co_get(mr, eed->v2)); - copy_v3_v3_short(vert[0].nor, data->normals[BM_elem_index_get(eed->v1)].high); - vert[0].nor[3] = 0; - copy_v3_v3_short(vert[1].nor, data->normals[BM_elem_index_get(eed->v2)].high); - vert[1].nor[3] = 0; - } - EXTRACT_LEDGE_FOREACH_BM_END; + int l_index = mr->loop_len + ledge_index * 2; + PosNorHQLoop *vert = &data->vbo_data[l_index]; + copy_v3_v3(vert[0].pos, bm_vert_co_get(mr, eed->v1)); + copy_v3_v3(vert[1].pos, bm_vert_co_get(mr, eed->v2)); + copy_v3_v3_short(vert[0].nor, data->normals[BM_elem_index_get(eed->v1)].high); + vert[0].nor[3] = 0; + copy_v3_v3_short(vert[1].nor, data->normals[BM_elem_index_get(eed->v2)].high); + vert[1].nor[3] = 0; } static void extract_pos_nor_hq_iter_ledge_mesh(const MeshRenderData *mr, - const ExtractLEdgeMesh_Params *params, + const MEdge *med, + const uint ledge_index, void *_data) { MeshExtract_PosNorHQ_Data *data = _data; - EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr) - { - const int ml_index = mr->loop_len + ledge_index * 2; - PosNorHQLoop *vert = &data->vbo_data[ml_index]; - copy_v3_v3(vert[0].pos, mr->mvert[med->v1].co); - copy_v3_v3(vert[1].pos, mr->mvert[med->v2].co); - copy_v3_v3_short(vert[0].nor, data->normals[med->v1].high); - vert[0].nor[3] = 0; - copy_v3_v3_short(vert[1].nor, data->normals[med->v2].high); - vert[1].nor[3] = 0; - } - EXTRACT_LEDGE_FOREACH_MESH_END; + const int ml_index = mr->loop_len + ledge_index * 2; + PosNorHQLoop *vert = &data->vbo_data[ml_index]; + copy_v3_v3(vert[0].pos, mr->mvert[med->v1].co); + copy_v3_v3(vert[1].pos, mr->mvert[med->v2].co); + copy_v3_v3_short(vert[0].nor, data->normals[med->v1].high); + vert[0].nor[3] = 0; + copy_v3_v3_short(vert[1].nor, data->normals[med->v2].high); + vert[1].nor[3] = 0; } static void extract_pos_nor_hq_iter_lvert_bm(const MeshRenderData *mr, - const ExtractLVertBMesh_Params *params, + BMVert *eve, + const int lvert_index, void *_data) { MeshExtract_PosNorHQ_Data *data = _data; const int offset = mr->loop_len + (mr->edge_loose_len * 2); - EXTRACT_LVERT_FOREACH_BM_BEGIN(eve, lvert_index, params) - { - const int l_index = offset + lvert_index; - PosNorHQLoop *vert = &data->vbo_data[l_index]; - copy_v3_v3(vert->pos, bm_vert_co_get(mr, eve)); - copy_v3_v3_short(vert->nor, data->normals[BM_elem_index_get(eve)].high); - vert->nor[3] = 0; - } - EXTRACT_LVERT_FOREACH_BM_END; + + const int l_index = offset + lvert_index; + PosNorHQLoop *vert = &data->vbo_data[l_index]; + copy_v3_v3(vert->pos, bm_vert_co_get(mr, eve)); + copy_v3_v3_short(vert->nor, data->normals[BM_elem_index_get(eve)].high); + vert->nor[3] = 0; } static void extract_pos_nor_hq_iter_lvert_mesh(const MeshRenderData *mr, - const ExtractLVertMesh_Params *params, + const MVert *mv, + const int lvert_index, void *_data) { MeshExtract_PosNorHQ_Data *data = _data; const int offset = mr->loop_len + (mr->edge_loose_len * 2); - EXTRACT_LVERT_FOREACH_MESH_BEGIN(mv, lvert_index, params, mr) - { - const int ml_index = offset + lvert_index; - const int v_index = mr->lverts[lvert_index]; - PosNorHQLoop *vert = &data->vbo_data[ml_index]; - copy_v3_v3(vert->pos, mv->co); - copy_v3_v3_short(vert->nor, data->normals[v_index].high); - vert->nor[3] = 0; - } - EXTRACT_LVERT_FOREACH_MESH_END; + + const int ml_index = offset + lvert_index; + const int v_index = mr->lverts[lvert_index]; + PosNorHQLoop *vert = &data->vbo_data[ml_index]; + copy_v3_v3(vert->pos, mv->co); + copy_v3_v3_short(vert->nor, data->normals[v_index].high); + vert->nor[3] = 0; } static void extract_pos_nor_hq_finish(const MeshRenderData *UNUSED(mr), struct MeshBatchCache *UNUSED(cache), - void *UNUSED(vbo), + void *UNUSED(buf), void *data) { MEM_freeN(data); } -static const MeshExtract extract_pos_nor_hq = { +const MeshExtract extract_pos_nor_hq = { .init = extract_pos_nor_hq_init, .iter_poly_bm = extract_pos_nor_hq_iter_poly_bm, .iter_poly_mesh = extract_pos_nor_hq_iter_poly_mesh, @@ -2267,9 +1570,9 @@ static const MeshExtract extract_pos_nor_hq = { .iter_lvert_bm = extract_pos_nor_hq_iter_lvert_bm, .iter_lvert_mesh = extract_pos_nor_hq_iter_lvert_mesh, .finish = extract_pos_nor_hq_finish, - .data_flag = 0, + .data_type = 0, .use_threading = true, -}; + .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.pos_nor)}; /** \} */ /* ---------------------------------------------------------------------- */ @@ -2284,12 +1587,12 @@ static void *extract_lnor_hq_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf) { + GPUVertBuf *vbo = buf; static GPUVertFormat format = {0}; if (format.attr_len == 0) { GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); GPU_vertformat_alias_add(&format, "lnor"); } - GPUVertBuf *vbo = buf; GPU_vertbuf_init_with_format(vbo, &format); GPU_vertbuf_data_alloc(vbo, mr->loop_len); @@ -2297,36 +1600,37 @@ static void *extract_lnor_hq_init(const MeshRenderData *mr, } static void extract_lnor_hq_iter_poly_bm(const MeshRenderData *mr, - const ExtractPolyBMesh_Params *params, + BMFace *f, + const int UNUSED(f_index), void *data) { - if (mr->loop_normals) { - EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(_l, l_index, params, mr) - { + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + const int l_index = BM_elem_index_get(l_iter); + if (mr->loop_normals) { normal_float_to_short_v3(&((gpuHQNor *)data)[l_index].x, mr->loop_normals[l_index]); } - EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(_l); - } - else { - EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) - { - if (BM_elem_flag_test(l->f, BM_ELEM_SMOOTH)) { - normal_float_to_short_v3(&((gpuHQNor *)data)[l_index].x, bm_vert_no_get(mr, l->v)); + else { + if (BM_elem_flag_test(f, BM_ELEM_SMOOTH)) { + normal_float_to_short_v3(&((gpuHQNor *)data)[l_index].x, bm_vert_no_get(mr, l_iter->v)); } else { - normal_float_to_short_v3(&((gpuHQNor *)data)[l_index].x, bm_face_no_get(mr, l->f)); + normal_float_to_short_v3(&((gpuHQNor *)data)[l_index].x, bm_face_no_get(mr, f)); } } - EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); - } + } while ((l_iter = l_iter->next) != l_first); } static void extract_lnor_hq_iter_poly_mesh(const MeshRenderData *mr, - const ExtractPolyMesh_Params *params, + const MPoly *mp, + const int mp_index, void *data) { - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) - { + const MLoop *mloop = mr->mloop; + const int ml_index_end = mp->loopstart + mp->totloop; + for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { + const MLoop *ml = &mloop[ml_index]; gpuHQNor *lnor_data = &((gpuHQNor *)data)[ml_index]; if (mr->loop_normals) { normal_float_to_short_v3(&lnor_data->x, mr->loop_normals[ml_index]); @@ -2352,15 +1656,15 @@ static void extract_lnor_hq_iter_poly_mesh(const MeshRenderData *mr, lnor_data->w = 0; } } - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } -static const MeshExtract extract_lnor_hq = { +const MeshExtract extract_lnor_hq = { .init = extract_lnor_hq_init, .iter_poly_bm = extract_lnor_hq_iter_poly_bm, .iter_poly_mesh = extract_lnor_hq_iter_poly_mesh, - .data_flag = MR_DATA_LOOP_NOR, + .data_type = MR_DATA_LOOP_NOR, .use_threading = true, + .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.lnor), }; /** \} */ @@ -2372,12 +1676,12 @@ static void *extract_lnor_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf) { + GPUVertBuf *vbo = buf; static GPUVertFormat format = {0}; if (format.attr_len == 0) { GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); GPU_vertformat_alias_add(&format, "lnor"); } - GPUVertBuf *vbo = buf; GPU_vertbuf_init_with_format(vbo, &format); GPU_vertbuf_data_alloc(vbo, mr->loop_len); @@ -2385,40 +1689,39 @@ static void *extract_lnor_init(const MeshRenderData *mr, } static void extract_lnor_iter_poly_bm(const MeshRenderData *mr, - const ExtractPolyBMesh_Params *params, + BMFace *f, + const int UNUSED(f_index), void *data) { - if (mr->loop_normals) { - EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) - { + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + const int l_index = BM_elem_index_get(l_iter); + if (mr->loop_normals) { ((GPUPackedNormal *)data)[l_index] = GPU_normal_convert_i10_v3(mr->loop_normals[l_index]); - BMFace *efa = l->f; - ((GPUPackedNormal *)data)[l_index].w = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0; } - EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); - } - else { - EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) - { - if (BM_elem_flag_test(l->f, BM_ELEM_SMOOTH)) { - ((GPUPackedNormal *)data)[l_index] = GPU_normal_convert_i10_v3(bm_vert_no_get(mr, l->v)); + else { + if (BM_elem_flag_test(f, BM_ELEM_SMOOTH)) { + ((GPUPackedNormal *)data)[l_index] = GPU_normal_convert_i10_v3( + bm_vert_no_get(mr, l_iter->v)); } else { - ((GPUPackedNormal *)data)[l_index] = GPU_normal_convert_i10_v3(bm_face_no_get(mr, l->f)); + ((GPUPackedNormal *)data)[l_index] = GPU_normal_convert_i10_v3(bm_face_no_get(mr, f)); } - BMFace *efa = l->f; - ((GPUPackedNormal *)data)[l_index].w = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0; } - EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); - } + ((GPUPackedNormal *)data)[l_index].w = BM_elem_flag_test(f, BM_ELEM_HIDDEN) ? -1 : 0; + } while ((l_iter = l_iter->next) != l_first); } static void extract_lnor_iter_poly_mesh(const MeshRenderData *mr, - const ExtractPolyMesh_Params *params, + const MPoly *mp, + const int mp_index, void *data) { - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) - { + const MLoop *mloop = mr->mloop; + const int ml_index_end = mp->loopstart + mp->totloop; + for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { + const MLoop *ml = &mloop[ml_index]; GPUPackedNormal *lnor_data = &((GPUPackedNormal *)data)[ml_index]; if (mr->loop_normals) { *lnor_data = GPU_normal_convert_i10_v3(mr->loop_normals[ml_index]); @@ -2444,15 +1747,15 @@ static void extract_lnor_iter_poly_mesh(const MeshRenderData *mr, lnor_data->w = 0; } } - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } -static const MeshExtract extract_lnor = { +const MeshExtract extract_lnor = { .init = extract_lnor_init, .iter_poly_bm = extract_lnor_iter_poly_bm, .iter_poly_mesh = extract_lnor_iter_poly_mesh, - .data_flag = MR_DATA_LOOP_NOR, + .data_type = MR_DATA_LOOP_NOR, .use_threading = true, + .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.lnor), }; /** \} */ @@ -2463,6 +1766,7 @@ static const MeshExtract extract_lnor = { static void *extract_uv_init(const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf) { + GPUVertBuf *vbo = buf; GPUVertFormat format = {0}; GPU_vertformat_deinterleave(&format); @@ -2512,7 +1816,6 @@ static void *extract_uv_init(const MeshRenderData *mr, struct MeshBatchCache *ca v_len = 1; } - GPUVertBuf *vbo = buf; GPU_vertbuf_init_with_format(vbo, &format); GPU_vertbuf_data_alloc(vbo, v_len); @@ -2545,10 +1848,11 @@ static void *extract_uv_init(const MeshRenderData *mr, struct MeshBatchCache *ca return NULL; } -static const MeshExtract extract_uv = { +const MeshExtract extract_uv = { .init = extract_uv_init, - .data_flag = 0, + .data_type = 0, .use_threading = false, + .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.uv), }; /** \} */ @@ -2557,10 +1861,10 @@ static const MeshExtract extract_uv = { /** \name Extract Tangent layers * \{ */ -static void extract_tan_ex(const MeshRenderData *mr, - struct MeshBatchCache *cache, - GPUVertBuf *vbo, - const bool do_hq) +static void extract_tan_ex_init(const MeshRenderData *mr, + struct MeshBatchCache *cache, + GPUVertBuf *vbo, + const bool do_hq) { GPUVertCompType comp_type = do_hq ? GPU_COMP_I16 : GPU_COMP_I10; GPUVertFetchMode fetch_mode = GPU_FETCH_INT_TO_FLOAT_UNIT; @@ -2731,14 +2035,15 @@ static void extract_tan_ex(const MeshRenderData *mr, static void *extract_tan_init(const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf) { - extract_tan_ex(mr, cache, buf, false); + extract_tan_ex_init(mr, cache, buf, false); return NULL; } -static const MeshExtract extract_tan = { +const MeshExtract extract_tan = { .init = extract_tan_init, - .data_flag = MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR | MR_DATA_LOOPTRI, + .data_type = MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR | MR_DATA_LOOPTRI, .use_threading = false, + .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.tan), }; /** \} */ @@ -2749,13 +2054,13 @@ static const MeshExtract extract_tan = { static void *extract_tan_hq_init(const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf) { - extract_tan_ex(mr, cache, buf, true); + extract_tan_ex_init(mr, cache, buf, true); return NULL; } -static const MeshExtract extract_tan_hq = { +const MeshExtract extract_tan_hq = { .init = extract_tan_hq_init, - .data_flag = MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR | MR_DATA_LOOPTRI, + .data_type = MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR | MR_DATA_LOOPTRI, .use_threading = false, }; @@ -2769,6 +2074,7 @@ static void *extract_sculpt_data_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf) { + GPUVertBuf *vbo = buf; GPUVertFormat format = {0}; CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; @@ -2783,7 +2089,6 @@ static void *extract_sculpt_data_init(const MeshRenderData *mr, GPU_vertformat_attr_add(&format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); } - GPUVertBuf *vbo = buf; GPU_vertbuf_init_with_format(vbo, &format); GPU_vertbuf_data_alloc(vbo, mr->loop_len); @@ -2852,12 +2157,12 @@ static void *extract_sculpt_data_init(const MeshRenderData *mr, return NULL; } -static const MeshExtract extract_sculpt_data = { +const MeshExtract extract_sculpt_data = { .init = extract_sculpt_data_init, - .data_flag = 0, + .data_type = 0, /* TODO: enable threading. */ .use_threading = false, -}; + .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.sculpt_data)}; /** \} */ @@ -2867,6 +2172,7 @@ static const MeshExtract extract_sculpt_data = { static void *extract_vcol_init(const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf) { + GPUVertBuf *vbo = buf; GPUVertFormat format = {0}; GPU_vertformat_deinterleave(&format); @@ -2928,7 +2234,6 @@ static void *extract_vcol_init(const MeshRenderData *mr, struct MeshBatchCache * } } - GPUVertBuf *vbo = buf; GPU_vertbuf_init_with_format(vbo, &format); GPU_vertbuf_data_alloc(vbo, mr->loop_len); @@ -3001,10 +2306,11 @@ static void *extract_vcol_init(const MeshRenderData *mr, struct MeshBatchCache * return NULL; } -static const MeshExtract extract_vcol = { +const MeshExtract extract_vcol = { .init = extract_vcol_init, - .data_flag = 0, + .data_type = 0, .use_threading = false, + .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.vcol), }; /** \} */ @@ -3022,6 +2328,7 @@ static void *extract_orco_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf) { + GPUVertBuf *vbo = buf; static GPUVertFormat format = {0}; if (format.attr_len == 0) { /* FIXME(fclem): We use the last component as a way to differentiate from generic vertex @@ -3031,7 +2338,6 @@ static void *extract_orco_init(const MeshRenderData *mr, GPU_vertformat_attr_add(&format, "orco", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); } - GPUVertBuf *vbo = buf; GPU_vertbuf_init_with_format(vbo, &format); GPU_vertbuf_data_alloc(vbo, mr->loop_len); @@ -3045,32 +2351,36 @@ static void *extract_orco_init(const MeshRenderData *mr, return data; } -static void extract_orco_iter_poly_bm(const MeshRenderData *mr, - const ExtractPolyBMesh_Params *params, +static void extract_orco_iter_poly_bm(const MeshRenderData *UNUSED(mr), + BMFace *f, + const int UNUSED(f_index), void *data) { MeshExtract_Orco_Data *orco_data = (MeshExtract_Orco_Data *)data; - EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(loop, l_index, params, mr) - { + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + const int l_index = BM_elem_index_get(l_iter); float *loop_orco = orco_data->vbo_data[l_index]; - copy_v3_v3(loop_orco, orco_data->orco[BM_elem_index_get(loop->v)]); + copy_v3_v3(loop_orco, orco_data->orco[BM_elem_index_get(l_iter->v)]); loop_orco[3] = 0.0; /* Tag as not a generic attribute. */ - } - EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(loop); + } while ((l_iter = l_iter->next) != l_first); } static void extract_orco_iter_poly_mesh(const MeshRenderData *mr, - const ExtractPolyMesh_Params *params, + const MPoly *mp, + const int UNUSED(mp_index), void *data) { - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) - { + const MLoop *mloop = mr->mloop; + const int ml_index_end = mp->loopstart + mp->totloop; + for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { + const MLoop *ml = &mloop[ml_index]; MeshExtract_Orco_Data *orco_data = (MeshExtract_Orco_Data *)data; float *loop_orco = orco_data->vbo_data[ml_index]; copy_v3_v3(loop_orco, orco_data->orco[ml->v]); loop_orco[3] = 0.0; /* Tag as not a generic attribute. */ } - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static void extract_orco_finish(const MeshRenderData *UNUSED(mr), @@ -3081,13 +2391,14 @@ static void extract_orco_finish(const MeshRenderData *UNUSED(mr), MEM_freeN(data); } -static const MeshExtract extract_orco = { +const MeshExtract extract_orco = { .init = extract_orco_init, .iter_poly_bm = extract_orco_iter_poly_bm, .iter_poly_mesh = extract_orco_iter_poly_mesh, .finish = extract_orco_finish, - .data_flag = 0, + .data_type = 0, .use_threading = true, + .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.orco), }; /** \} */ @@ -3124,11 +2435,12 @@ static void *extract_edge_fac_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf) { + GPUVertBuf *vbo = buf; static GPUVertFormat format = {0}; if (format.attr_len == 0) { GPU_vertformat_attr_add(&format, "wd", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT); } - GPUVertBuf *vbo = buf; + GPU_vertbuf_init_with_format(vbo, &format); GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len); @@ -3159,43 +2471,47 @@ static void *extract_edge_fac_init(const MeshRenderData *mr, } static void extract_edge_fac_iter_poly_bm(const MeshRenderData *mr, - const ExtractPolyBMesh_Params *params, + BMFace *f, + const int UNUSED(f_index), void *_data) { MeshExtract_EdgeFac_Data *data = _data; - EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) - { - if (BM_edge_is_manifold(l->e)) { - float ratio = loop_edge_factor_get(bm_face_no_get(mr, l->f), - bm_vert_co_get(mr, l->v), - bm_vert_no_get(mr, l->v), - bm_vert_co_get(mr, l->next->v)); + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + const int l_index = BM_elem_index_get(l_iter); + + if (BM_edge_is_manifold(l_iter->e)) { + float ratio = loop_edge_factor_get(bm_face_no_get(mr, f), + bm_vert_co_get(mr, l_iter->v), + bm_vert_no_get(mr, l_iter->v), + bm_vert_co_get(mr, l_iter->next->v)); data->vbo_data[l_index] = ratio * 253 + 1; } else { data->vbo_data[l_index] = 255; } - } - EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); + } while ((l_iter = l_iter->next) != l_first); } static void extract_edge_fac_iter_poly_mesh(const MeshRenderData *mr, - const ExtractPolyMesh_Params *params, + const MPoly *mp, + const int mp_index, void *_data) { MeshExtract_EdgeFac_Data *data = (MeshExtract_EdgeFac_Data *)_data; - if (data->use_edge_render) { - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) - { + const MLoop *mloop = mr->mloop; + const int ml_index_end = mp->loopstart + mp->totloop; + for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { + const MLoop *ml = &mloop[ml_index]; + + if (data->use_edge_render) { const MEdge *med = &mr->medge[ml->e]; data->vbo_data[ml_index] = (med->flag & ME_EDGERENDER) ? 255 : 0; } - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; - } - else { - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) - { + else { + /* Count loop per edge to detect non-manifold. */ if (data->edge_loop_count[ml->e] < 3) { data->edge_loop_count[ml->e]++; @@ -3217,34 +2533,28 @@ static void extract_edge_fac_iter_poly_mesh(const MeshRenderData *mr, data->vbo_data[ml_index] = 255; } } - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } } static void extract_edge_fac_iter_ledge_bm(const MeshRenderData *mr, - const ExtractLEdgeBMesh_Params *params, + BMEdge *UNUSED(eed), + const int ledge_index, void *_data) { MeshExtract_EdgeFac_Data *data = _data; - EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params) - { - data->vbo_data[mr->loop_len + (ledge_index * 2) + 0] = 255; - data->vbo_data[mr->loop_len + (ledge_index * 2) + 1] = 255; - } - EXTRACT_LEDGE_FOREACH_BM_END; + data->vbo_data[mr->loop_len + (ledge_index * 2) + 0] = 255; + data->vbo_data[mr->loop_len + (ledge_index * 2) + 1] = 255; } static void extract_edge_fac_iter_ledge_mesh(const MeshRenderData *mr, - const ExtractLEdgeMesh_Params *params, + const MEdge *UNUSED(med), + const uint ledge_index, void *_data) { MeshExtract_EdgeFac_Data *data = _data; - EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr) - { - data->vbo_data[mr->loop_len + ledge_index * 2 + 0] = 255; - data->vbo_data[mr->loop_len + ledge_index * 2 + 1] = 255; - } - EXTRACT_LEDGE_FOREACH_MESH_END; + + data->vbo_data[mr->loop_len + ledge_index * 2 + 0] = 255; + data->vbo_data[mr->loop_len + ledge_index * 2 + 1] = 255; } static void extract_edge_fac_finish(const MeshRenderData *mr, @@ -3252,10 +2562,10 @@ static void extract_edge_fac_finish(const MeshRenderData *mr, void *buf, void *_data) { + GPUVertBuf *vbo = buf; MeshExtract_EdgeFac_Data *data = _data; if (GPU_crappy_amd_driver()) { - GPUVertBuf *vbo = (GPUVertBuf *)buf; /* Some AMD drivers strangely crash with VBO's with a one byte format. * To workaround we reinitialize the VBO with another format and convert * all bytes to floats. */ @@ -3281,16 +2591,16 @@ static void extract_edge_fac_finish(const MeshRenderData *mr, MEM_freeN(data); } -static const MeshExtract extract_edge_fac = { +const MeshExtract extract_edge_fac = { .init = extract_edge_fac_init, .iter_poly_bm = extract_edge_fac_iter_poly_bm, .iter_poly_mesh = extract_edge_fac_iter_poly_mesh, .iter_ledge_bm = extract_edge_fac_iter_ledge_bm, .iter_ledge_mesh = extract_edge_fac_iter_ledge_mesh, .finish = extract_edge_fac_finish, - .data_flag = MR_DATA_POLY_NOR, + .data_type = MR_DATA_POLY_NOR, .use_threading = false, -}; + .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edge_fac)}; /** \} */ /* ---------------------------------------------------------------------- */ @@ -3361,11 +2671,11 @@ static void *extract_weights_init(const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf) { + GPUVertBuf *vbo = buf; static GPUVertFormat format = {0}; if (format.attr_len == 0) { GPU_vertformat_attr_add(&format, "weight", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); } - GPUVertBuf *vbo = buf; GPU_vertbuf_init_with_format(vbo, &format); GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len); @@ -3389,48 +2699,44 @@ static void *extract_weights_init(const MeshRenderData *mr, return data; } -static void extract_weights_iter_poly_bm(const MeshRenderData *mr, - const ExtractPolyBMesh_Params *params, +static void extract_weights_iter_poly_bm(const MeshRenderData *UNUSED(mr), + BMFace *f, + const int UNUSED(f_index), void *_data) { MeshExtract_Weight_Data *data = _data; - if (data->cd_ofs != -1) { - EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) - { - const MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(l->v, data->cd_ofs); + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + const int l_index = BM_elem_index_get(l_iter); + if (data->cd_ofs != -1) { + const MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(l_iter->v, data->cd_ofs); data->vbo_data[l_index] = evaluate_vertex_weight(dvert, data->wstate); } - EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); - } - else { - EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) - { + else { data->vbo_data[l_index] = evaluate_vertex_weight(NULL, data->wstate); } - EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); - } + } while ((l_iter = l_iter->next) != l_first); } static void extract_weights_iter_poly_mesh(const MeshRenderData *mr, - const ExtractPolyMesh_Params *params, + const MPoly *mp, + const int UNUSED(mp_index), void *_data) { MeshExtract_Weight_Data *data = _data; - if (data->dvert != NULL) { - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) - { + const MLoop *mloop = mr->mloop; + const int ml_index_end = mp->loopstart + mp->totloop; + for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { + const MLoop *ml = &mloop[ml_index]; + if (data->dvert != NULL) { const MDeformVert *dvert = &data->dvert[ml->v]; data->vbo_data[ml_index] = evaluate_vertex_weight(dvert, data->wstate); } - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; - } - else { - const MDeformVert *dvert = NULL; - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) - { + else { + const MDeformVert *dvert = NULL; data->vbo_data[ml_index] = evaluate_vertex_weight(dvert, data->wstate); } - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } } @@ -3442,13 +2748,14 @@ static void extract_weights_finish(const MeshRenderData *UNUSED(mr), MEM_freeN(data); } -static const MeshExtract extract_weights = { +const MeshExtract extract_weights = { .init = extract_weights_init, .iter_poly_bm = extract_weights_iter_poly_bm, .iter_poly_mesh = extract_weights_iter_poly_mesh, .finish = extract_weights_finish, - .data_flag = 0, + .data_type = 0, .use_threading = true, + .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.weights), }; /** \} */ @@ -3599,40 +2906,45 @@ static void *extract_edit_data_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf) { + GPUVertBuf *vbo = buf; static GPUVertFormat format = {0}; if (format.attr_len == 0) { /* WARNING: Adjust #EditLoopData struct accordingly. */ GPU_vertformat_attr_add(&format, "data", GPU_COMP_U8, 4, GPU_FETCH_INT); GPU_vertformat_alias_add(&format, "flag"); } - GPUVertBuf *vbo = buf; GPU_vertbuf_init_with_format(vbo, &format); GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len); return GPU_vertbuf_get_data(vbo); } static void extract_edit_data_iter_poly_bm(const MeshRenderData *mr, - const ExtractPolyBMesh_Params *params, + BMFace *f, + const int UNUSED(f_index), void *_data) { + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + const int l_index = BM_elem_index_get(l_iter); - EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) - { EditLoopData *data = (EditLoopData *)_data + l_index; memset(data, 0x0, sizeof(*data)); - mesh_render_data_face_flag(mr, l->f, -1, data); - mesh_render_data_edge_flag(mr, l->e, data); - mesh_render_data_vert_flag(mr, l->v, data); - } - EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); + mesh_render_data_face_flag(mr, f, -1, data); + mesh_render_data_edge_flag(mr, l_iter->e, data); + mesh_render_data_vert_flag(mr, l_iter->v, data); + } while ((l_iter = l_iter->next) != l_first); } static void extract_edit_data_iter_poly_mesh(const MeshRenderData *mr, - const ExtractPolyMesh_Params *params, + const MPoly *mp, + const int mp_index, void *_data) { - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) - { + const MLoop *mloop = mr->mloop; + const int ml_index_end = mp->loopstart + mp->totloop; + for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { + const MLoop *ml = &mloop[ml_index]; EditLoopData *data = (EditLoopData *)_data + ml_index; memset(data, 0x0, sizeof(*data)); BMFace *efa = bm_original_face_get(mr, mp_index); @@ -3648,84 +2960,72 @@ static void extract_edit_data_iter_poly_mesh(const MeshRenderData *mr, mesh_render_data_vert_flag(mr, eve, data); } } - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static void extract_edit_data_iter_ledge_bm(const MeshRenderData *mr, - const ExtractLEdgeBMesh_Params *params, + BMEdge *eed, + const int ledge_index, void *_data) { - EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params) - { - EditLoopData *data = (EditLoopData *)_data + mr->loop_len + (ledge_index * 2); - memset(data, 0x0, sizeof(*data) * 2); - mesh_render_data_edge_flag(mr, eed, &data[0]); - data[1] = data[0]; - mesh_render_data_vert_flag(mr, eed->v1, &data[0]); - mesh_render_data_vert_flag(mr, eed->v2, &data[1]); - } - EXTRACT_LEDGE_FOREACH_BM_END; + EditLoopData *data = (EditLoopData *)_data + mr->loop_len + (ledge_index * 2); + memset(data, 0x0, sizeof(*data) * 2); + mesh_render_data_edge_flag(mr, eed, &data[0]); + data[1] = data[0]; + mesh_render_data_vert_flag(mr, eed->v1, &data[0]); + mesh_render_data_vert_flag(mr, eed->v2, &data[1]); } static void extract_edit_data_iter_ledge_mesh(const MeshRenderData *mr, - const ExtractLEdgeMesh_Params *params, + const MEdge *med, + const uint ledge_index, void *_data) { - EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr) - { - EditLoopData *data = (EditLoopData *)_data + mr->loop_len + ledge_index * 2; - memset(data, 0x0, sizeof(*data) * 2); - const int e_index = mr->ledges[ledge_index]; - BMEdge *eed = bm_original_edge_get(mr, e_index); - BMVert *eve1 = bm_original_vert_get(mr, med->v1); - BMVert *eve2 = bm_original_vert_get(mr, med->v2); - if (eed) { - mesh_render_data_edge_flag(mr, eed, &data[0]); - data[1] = data[0]; - } - if (eve1) { - mesh_render_data_vert_flag(mr, eve1, &data[0]); - } - if (eve2) { - mesh_render_data_vert_flag(mr, eve2, &data[1]); - } + EditLoopData *data = (EditLoopData *)_data + mr->loop_len + ledge_index * 2; + memset(data, 0x0, sizeof(*data) * 2); + const int e_index = mr->ledges[ledge_index]; + BMEdge *eed = bm_original_edge_get(mr, e_index); + BMVert *eve1 = bm_original_vert_get(mr, med->v1); + BMVert *eve2 = bm_original_vert_get(mr, med->v2); + if (eed) { + mesh_render_data_edge_flag(mr, eed, &data[0]); + data[1] = data[0]; + } + if (eve1) { + mesh_render_data_vert_flag(mr, eve1, &data[0]); + } + if (eve2) { + mesh_render_data_vert_flag(mr, eve2, &data[1]); } - EXTRACT_LEDGE_FOREACH_MESH_END; } static void extract_edit_data_iter_lvert_bm(const MeshRenderData *mr, - const ExtractLVertBMesh_Params *params, + BMVert *eve, + const int lvert_index, void *_data) { const int offset = mr->loop_len + (mr->edge_loose_len * 2); - EXTRACT_LVERT_FOREACH_BM_BEGIN(eve, lvert_index, params) - { - EditLoopData *data = (EditLoopData *)_data + offset + lvert_index; - memset(data, 0x0, sizeof(*data)); - mesh_render_data_vert_flag(mr, eve, data); - } - EXTRACT_LVERT_FOREACH_BM_END; + EditLoopData *data = (EditLoopData *)_data + offset + lvert_index; + memset(data, 0x0, sizeof(*data)); + mesh_render_data_vert_flag(mr, eve, data); } static void extract_edit_data_iter_lvert_mesh(const MeshRenderData *mr, - const ExtractLVertMesh_Params *params, + const MVert *UNUSED(mv), + const int lvert_index, void *_data) { const int offset = mr->loop_len + (mr->edge_loose_len * 2); - EXTRACT_LVERT_FOREACH_MESH_BEGIN(mv, lvert_index, params, mr) - { - EditLoopData *data = (EditLoopData *)_data + offset + lvert_index; - memset(data, 0x0, sizeof(*data)); - const int v_index = mr->lverts[lvert_index]; - BMVert *eve = bm_original_vert_get(mr, v_index); - if (eve) { - mesh_render_data_vert_flag(mr, eve, data); - } + + EditLoopData *data = (EditLoopData *)_data + offset + lvert_index; + memset(data, 0x0, sizeof(*data)); + const int v_index = mr->lverts[lvert_index]; + BMVert *eve = bm_original_vert_get(mr, v_index); + if (eve) { + mesh_render_data_vert_flag(mr, eve, data); } - EXTRACT_LVERT_FOREACH_MESH_END; } -static const MeshExtract extract_edit_data = { +const MeshExtract extract_edit_data = { .init = extract_edit_data_init, .iter_poly_bm = extract_edit_data_iter_poly_bm, .iter_poly_mesh = extract_edit_data_iter_poly_mesh, @@ -3733,9 +3033,9 @@ static const MeshExtract extract_edit_data = { .iter_ledge_mesh = extract_edit_data_iter_ledge_mesh, .iter_lvert_bm = extract_edit_data_iter_lvert_bm, .iter_lvert_mesh = extract_edit_data_iter_lvert_mesh, - .data_flag = 0, + .data_type = 0, .use_threading = true, -}; + .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edit_data)}; /** \} */ @@ -3752,6 +3052,7 @@ static void *extract_edituv_data_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf) { + GPUVertBuf *vbo = buf; static GPUVertFormat format = {0}; if (format.attr_len == 0) { /* WARNING: Adjust #EditLoopData struct accordingly. */ @@ -3759,7 +3060,6 @@ static void *extract_edituv_data_init(const MeshRenderData *mr, GPU_vertformat_alias_add(&format, "flag"); } - GPUVertBuf *vbo = buf; GPU_vertbuf_init_with_format(vbo, &format); GPU_vertbuf_data_alloc(vbo, mr->loop_len); @@ -3772,28 +3072,34 @@ static void *extract_edituv_data_init(const MeshRenderData *mr, } static void extract_edituv_data_iter_poly_bm(const MeshRenderData *mr, - const ExtractPolyBMesh_Params *params, + BMFace *f, + const int UNUSED(f_index), void *_data) { - EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) - { + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + const int l_index = BM_elem_index_get(l_iter); MeshExtract_EditUVData_Data *data = _data; EditLoopData *eldata = &data->vbo_data[l_index]; memset(eldata, 0x0, sizeof(*eldata)); - mesh_render_data_loop_flag(mr, l, data->cd_ofs, eldata); - mesh_render_data_face_flag(mr, l->f, data->cd_ofs, eldata); - mesh_render_data_loop_edge_flag(mr, l, data->cd_ofs, eldata); - } - EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); + mesh_render_data_loop_flag(mr, l_iter, data->cd_ofs, eldata); + mesh_render_data_face_flag(mr, f, data->cd_ofs, eldata); + mesh_render_data_loop_edge_flag(mr, l_iter, data->cd_ofs, eldata); + } while ((l_iter = l_iter->next) != l_first); } static void extract_edituv_data_iter_poly_mesh(const MeshRenderData *mr, - const ExtractPolyMesh_Params *params, + const MPoly *mp, + const int mp_index, void *_data) { MeshExtract_EditUVData_Data *data = _data; - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) - { + const MLoop *mloop = mr->mloop; + const int ml_index_end = mp->loopstart + mp->totloop; + for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { + const MLoop *ml = &mloop[ml_index]; + EditLoopData *eldata = &data->vbo_data[ml_index]; memset(eldata, 0x0, sizeof(*eldata)); BMFace *efa = bm_original_face_get(mr, mp_index); @@ -3823,7 +3129,6 @@ static void extract_edituv_data_iter_poly_mesh(const MeshRenderData *mr, } } } - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static void extract_edituv_data_finish(const MeshRenderData *UNUSED(mr), @@ -3834,14 +3139,14 @@ static void extract_edituv_data_finish(const MeshRenderData *UNUSED(mr), MEM_freeN(data); } -static const MeshExtract extract_edituv_data = { +const MeshExtract extract_edituv_data = { .init = extract_edituv_data_init, .iter_poly_bm = extract_edituv_data_iter_poly_bm, .iter_poly_mesh = extract_edituv_data_iter_poly_mesh, .finish = extract_edituv_data_finish, - .data_flag = 0, + .data_type = 0, .use_threading = true, -}; + .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edituv_data)}; /** \} */ @@ -3853,12 +3158,12 @@ static void *extract_edituv_stretch_area_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf) { + GPUVertBuf *vbo = buf; static GPUVertFormat format = {0}; if (format.attr_len == 0) { GPU_vertformat_attr_add(&format, "ratio", GPU_COMP_I16, 1, GPU_FETCH_INT_TO_FLOAT_UNIT); } - GPUVertBuf *vbo = buf; GPU_vertbuf_init_with_format(vbo, &format); GPU_vertbuf_data_alloc(vbo, mr->loop_len); @@ -3880,11 +3185,12 @@ BLI_INLINE float area_ratio_to_stretch(float ratio, float tot_ratio, float inv_t return (ratio > 1.0f) ? (1.0f / ratio) : ratio; } -static void mesh_edituv_stretch_area_finish(const MeshRenderData *mr, - struct MeshBatchCache *cache, - void *buf, - void *UNUSED(data)) +static void extract_edituv_stretch_area_finish(const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buf, + void *UNUSED(data)) { + GPUVertBuf *vbo = buf; float tot_area = 0.0f, tot_uv_area = 0.0f; float *area_ratio = MEM_mallocN(sizeof(float) * mr->poly_len, __func__); @@ -3926,7 +3232,6 @@ static void mesh_edituv_stretch_area_finish(const MeshRenderData *mr, } /* Copy face data for each loop. */ - GPUVertBuf *vbo = buf; uint16_t *loop_stretch = (uint16_t *)GPU_vertbuf_get_data(vbo); if (mr->extract_type == MR_EXTRACT_BMESH) { @@ -3952,12 +3257,12 @@ static void mesh_edituv_stretch_area_finish(const MeshRenderData *mr, MEM_freeN(area_ratio); } -static const MeshExtract extract_edituv_stretch_area = { +const MeshExtract extract_edituv_stretch_area = { .init = extract_edituv_stretch_area_init, - .finish = mesh_edituv_stretch_area_finish, - .data_flag = 0, + .finish = extract_edituv_stretch_area_finish, + .data_type = 0, .use_threading = false, -}; + .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edituv_stretch_area)}; /** \} */ @@ -4023,6 +3328,7 @@ static void *extract_edituv_stretch_angle_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf) { + GPUVertBuf *vbo = buf; static GPUVertFormat format = {0}; if (format.attr_len == 0) { /* Waning: adjust #UVStretchAngle struct accordingly. */ @@ -4030,7 +3336,6 @@ static void *extract_edituv_stretch_angle_init(const MeshRenderData *mr, GPU_vertformat_attr_add(&format, "uv_angles", GPU_COMP_I16, 2, GPU_FETCH_INT_TO_FLOAT_UNIT); } - GPUVertBuf *vbo = buf; GPU_vertbuf_init_with_format(vbo, &format); GPU_vertbuf_data_alloc(vbo, mr->loop_len); @@ -4049,21 +3354,24 @@ static void *extract_edituv_stretch_angle_init(const MeshRenderData *mr, } static void extract_edituv_stretch_angle_iter_poly_bm(const MeshRenderData *mr, - const ExtractPolyBMesh_Params *params, + BMFace *f, + const int UNUSED(f_index), void *_data) { MeshExtract_StretchAngle_Data *data = _data; float(*auv)[2] = data->auv, *last_auv = data->last_auv; float(*av)[3] = data->av, *last_av = data->last_av; - EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) - { + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + const int l_index = BM_elem_index_get(l_iter); + const MLoopUV *luv, *luv_next; - BMLoop *l_next = l->next; - BMFace *efa = l->f; - if (l == BM_FACE_FIRST_LOOP(efa)) { + BMLoop *l_next = l_iter->next; + if (l_iter == BM_FACE_FIRST_LOOP(f)) { /* First loop in face. */ - BMLoop *l_tmp = l->prev; - BMLoop *l_next_tmp = l; + BMLoop *l_tmp = l_iter->prev; + BMLoop *l_next_tmp = l_iter; luv = BM_ELEM_CD_GET_VOID_P(l_tmp, data->cd_ofs); luv_next = BM_ELEM_CD_GET_VOID_P(l_next_tmp, data->cd_ofs); compute_normalize_edge_vectors(auv, @@ -4076,7 +3384,7 @@ static void extract_edituv_stretch_angle_iter_poly_bm(const MeshRenderData *mr, copy_v2_v2(last_auv, auv[1]); copy_v3_v3(last_av, av[1]); } - if (l_next == BM_FACE_FIRST_LOOP(efa)) { + if (l_next == BM_FACE_FIRST_LOOP(f)) { /* Move previous edge. */ copy_v2_v2(auv[0], auv[1]); copy_v3_v3(av[0], av[1]); @@ -4085,27 +3393,31 @@ static void extract_edituv_stretch_angle_iter_poly_bm(const MeshRenderData *mr, copy_v3_v3(av[1], last_av); } else { - luv = BM_ELEM_CD_GET_VOID_P(l, data->cd_ofs); + luv = BM_ELEM_CD_GET_VOID_P(l_iter, data->cd_ofs); luv_next = BM_ELEM_CD_GET_VOID_P(l_next, data->cd_ofs); - compute_normalize_edge_vectors( - auv, av, luv->uv, luv_next->uv, bm_vert_co_get(mr, l->v), bm_vert_co_get(mr, l_next->v)); + compute_normalize_edge_vectors(auv, + av, + luv->uv, + luv_next->uv, + bm_vert_co_get(mr, l_iter->v), + bm_vert_co_get(mr, l_next->v)); } edituv_get_edituv_stretch_angle(auv, av, &data->vbo_data[l_index]); - } - EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); + } while ((l_iter = l_iter->next) != l_first); } static void extract_edituv_stretch_angle_iter_poly_mesh(const MeshRenderData *mr, - const ExtractPolyMesh_Params *params, + const MPoly *mp, + const int UNUSED(mp_index), void *_data) { MeshExtract_StretchAngle_Data *data = _data; - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) - { + const int ml_index_end = mp->loopstart + mp->totloop; + for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { float(*auv)[2] = data->auv, *last_auv = data->last_auv; float(*av)[3] = data->av, *last_av = data->last_av; - int l_next = ml_index + 1, ml_index_end = mp->loopstart + mp->totloop; + int l_next = ml_index + 1; const MVert *v, *v_next; if (ml_index == mp->loopstart) { /* First loop in face. */ @@ -4136,7 +3448,6 @@ static void extract_edituv_stretch_angle_iter_poly_mesh(const MeshRenderData *mr } edituv_get_edituv_stretch_angle(auv, av, &data->vbo_data[ml_index]); } - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static void extract_edituv_stretch_angle_finish(const MeshRenderData *UNUSED(mr), @@ -4147,14 +3458,14 @@ static void extract_edituv_stretch_angle_finish(const MeshRenderData *UNUSED(mr) MEM_freeN(data); } -static const MeshExtract extract_edituv_stretch_angle = { +const MeshExtract extract_edituv_stretch_angle = { .init = extract_edituv_stretch_angle_init, .iter_poly_bm = extract_edituv_stretch_angle_iter_poly_bm, .iter_poly_mesh = extract_edituv_stretch_angle_iter_poly_mesh, .finish = extract_edituv_stretch_angle_finish, - .data_flag = 0, + .data_type = 0, .use_threading = false, -}; + .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edituv_stretch_angle)}; /** \} */ @@ -4166,12 +3477,12 @@ static void *extract_mesh_analysis_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf) { + GPUVertBuf *vbo = buf; static GPUVertFormat format = {0}; if (format.attr_len == 0) { GPU_vertformat_attr_add(&format, "weight", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); } - GPUVertBuf *vbo = buf; GPU_vertbuf_init_with_format(vbo, &format); GPU_vertbuf_data_alloc(vbo, mr->loop_len); @@ -4725,14 +4036,14 @@ static void statvis_calc_sharp(const MeshRenderData *mr, float *r_sharp) MEM_freeN(vert_angles); } -static void extract_mesh_analysis_finish(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), - void *buf, - void *UNUSED(data)) +static void extract_analysis_iter_finish_mesh(const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *UNUSED(data)) { + GPUVertBuf *vbo = buf; BLI_assert(mr->edit_bmesh); - GPUVertBuf *vbo = buf; float *l_weight = (float *)GPU_vertbuf_get_data(vbo); switch (mr->toolsettings->statvis.type) { @@ -4754,103 +4065,99 @@ static void extract_mesh_analysis_finish(const MeshRenderData *mr, } } -static const MeshExtract extract_mesh_analysis = { +const MeshExtract extract_mesh_analysis = { .init = extract_mesh_analysis_init, - .finish = extract_mesh_analysis_finish, + .finish = extract_analysis_iter_finish_mesh, /* This is not needed for all visualization types. * * Maybe split into different extract. */ - .data_flag = MR_DATA_POLY_NOR | MR_DATA_LOOPTRI, + .data_type = MR_DATA_POLY_NOR | MR_DATA_LOOPTRI, .use_threading = false, -}; + .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.mesh_analysis)}; /** \} */ /* ---------------------------------------------------------------------- */ -/** \name Extract Facedots positions +/** \name Extract Face-dots positions * \{ */ static void *extract_fdots_pos_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf) { + GPUVertBuf *vbo = buf; static GPUVertFormat format = {0}; if (format.attr_len == 0) { GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); } - GPUVertBuf *vbo = buf; + GPU_vertbuf_init_with_format(vbo, &format); GPU_vertbuf_data_alloc(vbo, mr->poly_len); return GPU_vertbuf_get_data(vbo); } static void extract_fdots_pos_iter_poly_bm(const MeshRenderData *mr, - const ExtractPolyBMesh_Params *params, + BMFace *f, + const int f_index, void *data) { float(*center)[3] = data; - EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr) - { - float *co = center[f_index]; - zero_v3(co); + float *co = center[f_index]; + zero_v3(co); - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - add_v3_v3(co, bm_vert_co_get(mr, l_iter->v)); - } while ((l_iter = l_iter->next) != l_first); - mul_v3_fl(co, 1.0f / (float)f->len); - } - EXTRACT_POLY_FOREACH_BM_END; + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + add_v3_v3(co, bm_vert_co_get(mr, l_iter->v)); + } while ((l_iter = l_iter->next) != l_first); + mul_v3_fl(co, 1.0f / (float)f->len); } static void extract_fdots_pos_iter_poly_mesh(const MeshRenderData *mr, - const ExtractPolyMesh_Params *params, + const MPoly *mp, + const int mp_index, void *data) { float(*center)[3] = (float(*)[3])data; + float *co = center[mp_index]; + zero_v3(co); + const MVert *mvert = mr->mvert; const MLoop *mloop = mr->mloop; - if (mr->use_subsurf_fdots) { - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) - { + const int ml_index_end = mp->loopstart + mp->totloop; + for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { + const MLoop *ml = &mloop[ml_index]; + if (mr->use_subsurf_fdots) { const MVert *mv = &mr->mvert[ml->v]; if (mv->flag & ME_VERT_FACEDOT) { copy_v3_v3(center[mp_index], mv->co); + break; } } - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; - } - else { - EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr) - { - float *co = center[mp_index]; - zero_v3(co); - - const MLoop *ml = &mloop[mp->loopstart]; - for (int i = 0; i < mp->totloop; i++, ml++) { - const MVert *mv = &mvert[ml->v]; - add_v3_v3(center[mp_index], mv->co); - } - mul_v3_fl(co, 1.0f / (float)mp->totloop); + else { + const MVert *mv = &mvert[ml->v]; + add_v3_v3(center[mp_index], mv->co); } - EXTRACT_POLY_FOREACH_MESH_END; + } + + if (!mr->use_subsurf_fdots) { + mul_v3_fl(co, 1.0f / (float)mp->totloop); } } -static const MeshExtract extract_fdots_pos = { +const MeshExtract extract_fdots_pos = { .init = extract_fdots_pos_init, .iter_poly_bm = extract_fdots_pos_iter_poly_bm, .iter_poly_mesh = extract_fdots_pos_iter_poly_mesh, - .data_flag = 0, + .data_type = 0, .use_threading = true, -}; + .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdots_pos)}; /** \} */ /* ---------------------------------------------------------------------- */ -/** \name Extract Facedots Normal and edit flag +/** \name Extract Face-dots Normal and edit flag * \{ */ #define NOR_AND_FLAG_DEFAULT 0 #define NOR_AND_FLAG_SELECT 1 @@ -4861,11 +4168,12 @@ static void *extract_fdots_nor_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf) { + GPUVertBuf *vbo = buf; static GPUVertFormat format = {0}; if (format.attr_len == 0) { GPU_vertformat_attr_add(&format, "norAndFlag", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); } - GPUVertBuf *vbo = buf; + GPU_vertbuf_init_with_format(vbo, &format); GPU_vertbuf_data_alloc(vbo, mr->poly_len); @@ -4877,8 +4185,8 @@ static void extract_fdots_nor_finish(const MeshRenderData *mr, void *buf, void *UNUSED(data)) { - static float invalid_normal[3] = {0.0f, 0.0f, 0.0f}; GPUVertBuf *vbo = buf; + static float invalid_normal[3] = {0.0f, 0.0f, 0.0f}; GPUPackedNormal *nor = (GPUPackedNormal *)GPU_vertbuf_get_data(vbo); BMFace *efa; @@ -4921,27 +4229,28 @@ static void extract_fdots_nor_finish(const MeshRenderData *mr, } } -static const MeshExtract extract_fdots_nor = { +const MeshExtract extract_fdots_nor = { .init = extract_fdots_nor_init, .finish = extract_fdots_nor_finish, - .data_flag = MR_DATA_POLY_NOR, + .data_type = MR_DATA_POLY_NOR, .use_threading = false, -}; + .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdots_nor)}; /** \} */ /* ---------------------------------------------------------------------- */ -/** \name Extract Facedots High Quality Normal and edit flag +/** \name Extract Face-dots High Quality Normal and edit flag * \{ */ static void *extract_fdots_nor_hq_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf) { + GPUVertBuf *vbo = buf; static GPUVertFormat format = {0}; if (format.attr_len == 0) { GPU_vertformat_attr_add(&format, "norAndFlag", GPU_COMP_I16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); } - GPUVertBuf *vbo = buf; + GPU_vertbuf_init_with_format(vbo, &format); GPU_vertbuf_data_alloc(vbo, mr->poly_len); @@ -4953,8 +4262,8 @@ static void extract_fdots_nor_hq_finish(const MeshRenderData *mr, void *buf, void *UNUSED(data)) { - static float invalid_normal[3] = {0.0f, 0.0f, 0.0f}; GPUVertBuf *vbo = buf; + static float invalid_normal[3] = {0.0f, 0.0f, 0.0f}; short *nor = (short *)GPU_vertbuf_get_data(vbo); BMFace *efa; @@ -4997,17 +4306,17 @@ static void extract_fdots_nor_hq_finish(const MeshRenderData *mr, } } -static const MeshExtract extract_fdots_nor_hq = { +const MeshExtract extract_fdots_nor_hq = { .init = extract_fdots_nor_hq_init, .finish = extract_fdots_nor_hq_finish, - .data_flag = MR_DATA_POLY_NOR, + .data_type = MR_DATA_POLY_NOR, .use_threading = false, -}; + .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdots_nor)}; /** \} */ /* ---------------------------------------------------------------------- */ -/** \name Extract Facedots UV +/** \name Extract Face-dots UV * \{ */ typedef struct MeshExtract_FdotUV_Data { @@ -5020,13 +4329,14 @@ static void *extract_fdots_uv_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf) { + GPUVertBuf *vbo = buf; static GPUVertFormat format = {0}; if (format.attr_len == 0) { GPU_vertformat_attr_add(&format, "u", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); GPU_vertformat_alias_add(&format, "au"); GPU_vertformat_alias_add(&format, "pos"); } - GPUVertBuf *vbo = buf; + GPU_vertbuf_init_with_format(vbo, &format); GPU_vertbuf_data_alloc(vbo, mr->poly_len); @@ -5047,42 +4357,41 @@ static void *extract_fdots_uv_init(const MeshRenderData *mr, return data; } -static void extract_fdots_uv_iter_poly_bm(const MeshRenderData *mr, - const ExtractPolyBMesh_Params *params, +static void extract_fdots_uv_iter_poly_bm(const MeshRenderData *UNUSED(mr), + BMFace *f, + const int UNUSED(f_index), void *_data) { MeshExtract_FdotUV_Data *data = _data; - EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) - { - float w = 1.0f / (float)l->f->len; - const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, data->cd_ofs); - madd_v2_v2fl(data->vbo_data[BM_elem_index_get(l->f)], luv->uv, w); - } - EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + float w = 1.0f / (float)f->len; + const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, data->cd_ofs); + madd_v2_v2fl(data->vbo_data[BM_elem_index_get(f)], luv->uv, w); + } while ((l_iter = l_iter->next) != l_first); } static void extract_fdots_uv_iter_poly_mesh(const MeshRenderData *mr, - const ExtractPolyMesh_Params *params, + const MPoly *mp, + const int mp_index, void *_data) { MeshExtract_FdotUV_Data *data = _data; - if (mr->use_subsurf_fdots) { - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) - { + const MLoop *mloop = mr->mloop; + const int ml_index_end = mp->loopstart + mp->totloop; + for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { + const MLoop *ml = &mloop[ml_index]; + if (mr->use_subsurf_fdots) { const MVert *mv = &mr->mvert[ml->v]; if (mv->flag & ME_VERT_FACEDOT) { copy_v2_v2(data->vbo_data[mp_index], data->uv_data[ml_index].uv); } } - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; - } - else { - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) - { + else { float w = 1.0f / (float)mp->totloop; madd_v2_v2fl(data->vbo_data[mp_index], data->uv_data[ml_index].uv, w); } - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } } @@ -5094,18 +4403,19 @@ static void extract_fdots_uv_finish(const MeshRenderData *UNUSED(mr), MEM_freeN(data); } -static const MeshExtract extract_fdots_uv = { +const MeshExtract extract_fdots_uv = { .init = extract_fdots_uv_init, .iter_poly_bm = extract_fdots_uv_iter_poly_bm, .iter_poly_mesh = extract_fdots_uv_iter_poly_mesh, .finish = extract_fdots_uv_finish, - .data_flag = 0, + .data_type = 0, .use_threading = true, -}; + .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdots_uv)}; + /** \} */ /* ---------------------------------------------------------------------- */ -/** \name Extract Facedots Edit UV flag +/** \name Extract Face-dots Edit UV flag * \{ */ typedef struct MeshExtract_EditUVFdotData_Data { @@ -5117,11 +4427,12 @@ static void *extract_fdots_edituv_data_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf) { + GPUVertBuf *vbo = buf; static GPUVertFormat format = {0}; if (format.attr_len == 0) { GPU_vertformat_attr_add(&format, "flag", GPU_COMP_U8, 4, GPU_FETCH_INT); } - GPUVertBuf *vbo = buf; + GPU_vertbuf_init_with_format(vbo, &format); GPU_vertbuf_data_alloc(vbo, mr->poly_len); @@ -5132,34 +4443,28 @@ static void *extract_fdots_edituv_data_init(const MeshRenderData *mr, } static void extract_fdots_edituv_data_iter_poly_bm(const MeshRenderData *mr, - const ExtractPolyBMesh_Params *params, + BMFace *f, + const int UNUSED(f_index), void *_data) { MeshExtract_EditUVFdotData_Data *data = _data; - EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr) - { - EditLoopData *eldata = &data->vbo_data[BM_elem_index_get(f)]; - memset(eldata, 0x0, sizeof(*eldata)); - mesh_render_data_face_flag(mr, f, data->cd_ofs, eldata); - } - EXTRACT_POLY_FOREACH_BM_END; + EditLoopData *eldata = &data->vbo_data[BM_elem_index_get(f)]; + memset(eldata, 0x0, sizeof(*eldata)); + mesh_render_data_face_flag(mr, f, data->cd_ofs, eldata); } static void extract_fdots_edituv_data_iter_poly_mesh(const MeshRenderData *mr, - const ExtractPolyMesh_Params *params, + const MPoly *UNUSED(mp), + const int mp_index, void *_data) { MeshExtract_EditUVFdotData_Data *data = _data; - EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr) - { - EditLoopData *eldata = &data->vbo_data[mp_index]; - memset(eldata, 0x0, sizeof(*eldata)); - BMFace *efa = bm_original_face_get(mr, mp_index); - if (efa) { - mesh_render_data_face_flag(mr, efa, data->cd_ofs, eldata); - } + EditLoopData *eldata = &data->vbo_data[mp_index]; + memset(eldata, 0x0, sizeof(*eldata)); + BMFace *efa = bm_original_face_get(mr, mp_index); + if (efa) { + mesh_render_data_face_flag(mr, efa, data->cd_ofs, eldata); } - EXTRACT_POLY_FOREACH_MESH_END; } static void extract_fdots_edituv_data_finish(const MeshRenderData *UNUSED(mr), @@ -5170,14 +4475,15 @@ static void extract_fdots_edituv_data_finish(const MeshRenderData *UNUSED(mr), MEM_freeN(data); } -static const MeshExtract extract_fdots_edituv_data = { +const MeshExtract extract_fdots_edituv_data = { .init = extract_fdots_edituv_data_init, .iter_poly_bm = extract_fdots_edituv_data_iter_poly_bm, .iter_poly_mesh = extract_fdots_edituv_data_iter_poly_mesh, .finish = extract_fdots_edituv_data_finish, - .data_flag = 0, + .data_type = 0, .use_threading = true, -}; + .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdots_edituv_data)}; + /** \} */ /* ---------------------------------------------------------------------- */ @@ -5193,6 +4499,7 @@ static void *extract_skin_roots_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf) { + GPUVertBuf *vbo = buf; /* Exclusively for edit mode. */ BLI_assert(mr->bm); @@ -5201,7 +4508,7 @@ static void *extract_skin_roots_init(const MeshRenderData *mr, GPU_vertformat_attr_add(&format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); GPU_vertformat_attr_add(&format, "local_pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); } - GPUVertBuf *vbo = buf; + GPU_vertbuf_init_with_format(vbo, &format); GPU_vertbuf_data_alloc(vbo, mr->bm->totvert); @@ -5228,11 +4535,11 @@ static void *extract_skin_roots_init(const MeshRenderData *mr, return NULL; } -static const MeshExtract extract_skin_roots = { +const MeshExtract extract_skin_roots = { .init = extract_skin_roots_init, - .data_flag = 0, + .data_type = 0, .use_threading = false, -}; + .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.skin_roots)}; /** \} */ @@ -5244,12 +4551,12 @@ static void *extract_select_idx_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf) { + GPUVertBuf *vbo = buf; static GPUVertFormat format = {0}; if (format.attr_len == 0) { /* TODO rename "color" to something more descriptive. */ GPU_vertformat_attr_add(&format, "color", GPU_COMP_U32, 1, GPU_FETCH_INT); } - GPUVertBuf *vbo = buf; GPU_vertbuf_init_with_format(vbo, &format); GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len); return GPU_vertbuf_get_data(vbo); @@ -5260,169 +4567,163 @@ static void *extract_select_idx_init(const MeshRenderData *mr, * index VBO's. We could upload the p/e/v_origindex as a buffer texture and sample it inside the * shader to output original index. */ -static void extract_poly_idx_iter_poly_bm(const MeshRenderData *mr, - const ExtractPolyBMesh_Params *params, +static void extract_poly_idx_iter_poly_bm(const MeshRenderData *UNUSED(mr), + BMFace *f, + const int f_index, void *data) { - EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) - { - ((uint32_t *)data)[l_index] = BM_elem_index_get(l->f); - } - EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + const int l_index = BM_elem_index_get(l_iter); + ((uint32_t *)data)[l_index] = f_index; + } while ((l_iter = l_iter->next) != l_first); } -static void extract_edge_idx_iter_poly_bm(const MeshRenderData *mr, - const ExtractPolyBMesh_Params *params, +static void extract_edge_idx_iter_poly_bm(const MeshRenderData *UNUSED(mr), + BMFace *f, + const int UNUSED(f_index), void *data) { - EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) - { - ((uint32_t *)data)[l_index] = BM_elem_index_get(l->e); - } - EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + const int l_index = BM_elem_index_get(l_iter); + ((uint32_t *)data)[l_index] = BM_elem_index_get(l_iter->e); + } while ((l_iter = l_iter->next) != l_first); } -static void extract_vert_idx_iter_poly_bm(const MeshRenderData *mr, - const ExtractPolyBMesh_Params *params, +static void extract_vert_idx_iter_poly_bm(const MeshRenderData *UNUSED(mr), + BMFace *f, + const int UNUSED(f_index), void *data) { - EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr) - { - ((uint32_t *)data)[l_index] = BM_elem_index_get(l->v); - } - EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l); + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + const int l_index = BM_elem_index_get(l_iter); + ((uint32_t *)data)[l_index] = BM_elem_index_get(l_iter->v); + } while ((l_iter = l_iter->next) != l_first); } static void extract_edge_idx_iter_ledge_bm(const MeshRenderData *mr, - const ExtractLEdgeBMesh_Params *params, + BMEdge *eed, + const int ledge_index, void *data) { - EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params) - { - ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 0] = BM_elem_index_get(eed); - ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 1] = BM_elem_index_get(eed); - } - EXTRACT_LEDGE_FOREACH_BM_END; + ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 0] = BM_elem_index_get(eed); + ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 1] = BM_elem_index_get(eed); } static void extract_vert_idx_iter_ledge_bm(const MeshRenderData *mr, - const ExtractLEdgeBMesh_Params *params, + BMEdge *eed, + const int ledge_index, void *data) { - EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params) - { - ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 0] = BM_elem_index_get(eed->v1); - ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 1] = BM_elem_index_get(eed->v2); - } - EXTRACT_LEDGE_FOREACH_BM_END; + ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 0] = BM_elem_index_get(eed->v1); + ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 1] = BM_elem_index_get(eed->v2); } static void extract_vert_idx_iter_lvert_bm(const MeshRenderData *mr, - const ExtractLVertBMesh_Params *params, + BMVert *eve, + const int lvert_index, void *data) { const int offset = mr->loop_len + (mr->edge_loose_len * 2); - EXTRACT_LVERT_FOREACH_BM_BEGIN(eve, lvert_index, params) - { - ((uint32_t *)data)[offset + lvert_index] = BM_elem_index_get(eve); - } - EXTRACT_LVERT_FOREACH_BM_END; + + ((uint32_t *)data)[offset + lvert_index] = BM_elem_index_get(eve); } static void extract_poly_idx_iter_poly_mesh(const MeshRenderData *mr, - const ExtractPolyMesh_Params *params, + const MPoly *mp, + const int mp_index, void *data) { - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) - { + const int ml_index_end = mp->loopstart + mp->totloop; + for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { ((uint32_t *)data)[ml_index] = (mr->p_origindex) ? mr->p_origindex[mp_index] : mp_index; } - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static void extract_edge_idx_iter_poly_mesh(const MeshRenderData *mr, - const ExtractPolyMesh_Params *params, + const MPoly *mp, + const int UNUSED(mp_index), void *data) { - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) - { + const MLoop *mloop = mr->mloop; + const int ml_index_end = mp->loopstart + mp->totloop; + for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { + const MLoop *ml = &mloop[ml_index]; ((uint32_t *)data)[ml_index] = (mr->e_origindex) ? mr->e_origindex[ml->e] : ml->e; } - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static void extract_vert_idx_iter_poly_mesh(const MeshRenderData *mr, - const ExtractPolyMesh_Params *params, + const MPoly *mp, + const int UNUSED(mp_index), void *data) { - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr) - { + const MLoop *mloop = mr->mloop; + const int ml_index_end = mp->loopstart + mp->totloop; + for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { + const MLoop *ml = &mloop[ml_index]; ((uint32_t *)data)[ml_index] = (mr->v_origindex) ? mr->v_origindex[ml->v] : ml->v; } - EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END; } static void extract_edge_idx_iter_ledge_mesh(const MeshRenderData *mr, - const ExtractLEdgeMesh_Params *params, + const MEdge *UNUSED(med), + const uint ledge_index, void *data) { - EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr) - { - const int e_index = mr->ledges[ledge_index]; - const int e_orig = (mr->e_origindex) ? mr->e_origindex[e_index] : e_index; - ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 0] = e_orig; - ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 1] = e_orig; - } - EXTRACT_LEDGE_FOREACH_MESH_END; + const int e_index = mr->ledges[ledge_index]; + const int e_orig = (mr->e_origindex) ? mr->e_origindex[e_index] : e_index; + ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 0] = e_orig; + ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 1] = e_orig; } static void extract_vert_idx_iter_ledge_mesh(const MeshRenderData *mr, - const ExtractLEdgeMesh_Params *params, + const MEdge *med, + const uint ledge_index, void *data) { - EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr) - { - int v1_orig = (mr->v_origindex) ? mr->v_origindex[med->v1] : med->v1; - int v2_orig = (mr->v_origindex) ? mr->v_origindex[med->v2] : med->v2; - ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 0] = v1_orig; - ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 1] = v2_orig; - } - EXTRACT_LEDGE_FOREACH_MESH_END; + int v1_orig = (mr->v_origindex) ? mr->v_origindex[med->v1] : med->v1; + int v2_orig = (mr->v_origindex) ? mr->v_origindex[med->v2] : med->v2; + ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 0] = v1_orig; + ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 1] = v2_orig; } static void extract_vert_idx_iter_lvert_mesh(const MeshRenderData *mr, - const ExtractLVertMesh_Params *params, + const MVert *UNUSED(mv), + const int lvert_index, void *data) { const int offset = mr->loop_len + (mr->edge_loose_len * 2); - EXTRACT_LVERT_FOREACH_MESH_BEGIN(med, lvert_index, params, mr) - { - const int v_index = mr->lverts[lvert_index]; - const int v_orig = (mr->v_origindex) ? mr->v_origindex[v_index] : v_index; - ((uint32_t *)data)[offset + lvert_index] = v_orig; - } - EXTRACT_LVERT_FOREACH_MESH_END; + + const int v_index = mr->lverts[lvert_index]; + const int v_orig = (mr->v_origindex) ? mr->v_origindex[v_index] : v_index; + ((uint32_t *)data)[offset + lvert_index] = v_orig; } -static const MeshExtract extract_poly_idx = { +const MeshExtract extract_poly_idx = { .init = extract_select_idx_init, .iter_poly_bm = extract_poly_idx_iter_poly_bm, .iter_poly_mesh = extract_poly_idx_iter_poly_mesh, - .data_flag = 0, + .data_type = 0, .use_threading = true, -}; + .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.poly_idx)}; -static const MeshExtract extract_edge_idx = { +const MeshExtract extract_edge_idx = { .init = extract_select_idx_init, .iter_poly_bm = extract_edge_idx_iter_poly_bm, .iter_poly_mesh = extract_edge_idx_iter_poly_mesh, .iter_ledge_bm = extract_edge_idx_iter_ledge_bm, .iter_ledge_mesh = extract_edge_idx_iter_ledge_mesh, - .data_flag = 0, + .data_type = 0, .use_threading = true, -}; + .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edge_idx)}; -static const MeshExtract extract_vert_idx = { +const MeshExtract extract_vert_idx = { .init = extract_select_idx_init, .iter_poly_bm = extract_vert_idx_iter_poly_bm, .iter_poly_mesh = extract_vert_idx_iter_poly_mesh, @@ -5430,736 +4731,51 @@ static const MeshExtract extract_vert_idx = { .iter_ledge_mesh = extract_vert_idx_iter_ledge_mesh, .iter_lvert_bm = extract_vert_idx_iter_lvert_bm, .iter_lvert_mesh = extract_vert_idx_iter_lvert_mesh, - .data_flag = 0, + .data_type = 0, .use_threading = true, -}; + .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.vert_idx)}; -static void *extract_select_fdot_idx_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), - void *buf) +static void *extract_fdot_idx_init(const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buf) { + GPUVertBuf *vbo = buf; static GPUVertFormat format = {0}; if (format.attr_len == 0) { /* TODO rename "color" to something more descriptive. */ GPU_vertformat_attr_add(&format, "color", GPU_COMP_U32, 1, GPU_FETCH_INT); } - GPUVertBuf *vbo = buf; + GPU_vertbuf_init_with_format(vbo, &format); GPU_vertbuf_data_alloc(vbo, mr->poly_len); return GPU_vertbuf_get_data(vbo); } -static void extract_fdot_idx_iter_poly_bm(const MeshRenderData *mr, - const ExtractPolyBMesh_Params *params, +static void extract_fdot_idx_iter_poly_bm(const MeshRenderData *UNUSED(mr), + BMFace *UNUSED(f), + const int f_index, void *data) { - EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr) - { - ((uint32_t *)data)[f_index] = f_index; - } - EXTRACT_POLY_FOREACH_BM_END; + ((uint32_t *)data)[f_index] = f_index; } static void extract_fdot_idx_iter_poly_mesh(const MeshRenderData *mr, - const ExtractPolyMesh_Params *params, + const MPoly *UNUSED(mp), + const int mp_index, void *data) { if (mr->p_origindex != NULL) { - EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr) - { - ((uint32_t *)data)[mp_index] = mr->p_origindex[mp_index]; - } - EXTRACT_POLY_FOREACH_MESH_END; + ((uint32_t *)data)[mp_index] = mr->p_origindex[mp_index]; } else { - EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr) - { - ((uint32_t *)data)[mp_index] = mp_index; - } - EXTRACT_POLY_FOREACH_MESH_END; + ((uint32_t *)data)[mp_index] = mp_index; } } -static const MeshExtract extract_fdot_idx = { - .init = extract_select_fdot_idx_init, +const MeshExtract extract_fdot_idx = { + .init = extract_fdot_idx_init, .iter_poly_bm = extract_fdot_idx_iter_poly_bm, .iter_poly_mesh = extract_fdot_idx_iter_poly_mesh, - .data_flag = 0, + .data_type = 0, .use_threading = true, -}; - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name ExtractTaskData - * \{ */ -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; - struct MeshBatchCache *cache; - const MeshExtract *extract; - ExtractTaskDataType tasktype; - eMRIterType iter_type; - int start, end; - /** Decremented each time a task is finished. */ - int32_t *task_counter; - void *buf; - ExtractUserData *user_data; -} ExtractTaskData; - -static ExtractTaskData *extract_task_data_create_mesh_extract(const MeshRenderData *mr, - struct MeshBatchCache *cache, - 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->cache = cache; - 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 user_data does not create a new - * instance of the counters we allocate the user_data 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, - struct MeshBatchCache *cache) -{ - ExtractTaskData *taskdata = MEM_callocN(sizeof(*taskdata), __func__); - taskdata->tasktype = EXTRACT_LINES_LOOSE; - taskdata->mr = mr; - taskdata->cache = cache; - return taskdata; -} - -static void extract_task_data_free(void *data) -{ - ExtractTaskData *task_data = data; - MEM_SAFE_FREE(task_data->user_data); - MEM_freeN(task_data); -} - -BLI_INLINE void mesh_extract_iter(const MeshRenderData *mr, - const eMRIterType iter_type, - int start, - int end, - const MeshExtract *extract, - void *user_data) -{ - switch (mr->extract_type) { - case MR_EXTRACT_BMESH: - if (iter_type & MR_ITER_LOOPTRI) { - extract->iter_looptri_bm(mr, - &(const ExtractTriBMesh_Params){ - .looptris = mr->edit_bmesh->looptris, - .tri_range = {start, min_ii(mr->tri_len, end)}, - }, - user_data); - } - if (iter_type & MR_ITER_POLY) { - extract->iter_poly_bm(mr, - &(const ExtractPolyBMesh_Params){ - .poly_range = {start, min_ii(mr->poly_len, end)}, - }, - user_data); - } - if (iter_type & MR_ITER_LEDGE) { - extract->iter_ledge_bm(mr, - &(const ExtractLEdgeBMesh_Params){ - .ledge = mr->ledges, - .ledge_range = {start, min_ii(mr->edge_loose_len, end)}, - }, - user_data); - } - if (iter_type & MR_ITER_LVERT) { - extract->iter_lvert_bm(mr, - &(const ExtractLVertBMesh_Params){ - .lvert = mr->lverts, - .lvert_range = {start, min_ii(mr->vert_loose_len, end)}, - }, - user_data); - } - break; - case MR_EXTRACT_MAPPED: - case MR_EXTRACT_MESH: - if (iter_type & MR_ITER_LOOPTRI) { - extract->iter_looptri_mesh(mr, - &(const ExtractTriMesh_Params){ - .mlooptri = mr->mlooptri, - .tri_range = {start, min_ii(mr->tri_len, end)}, - }, - user_data); - } - if (iter_type & MR_ITER_POLY) { - extract->iter_poly_mesh(mr, - &(const ExtractPolyMesh_Params){ - .poly_range = {start, min_ii(mr->poly_len, end)}, - }, - user_data); - } - if (iter_type & MR_ITER_LEDGE) { - extract->iter_ledge_mesh(mr, - &(const ExtractLEdgeMesh_Params){ - .ledge = mr->ledges, - .ledge_range = {start, min_ii(mr->edge_loose_len, end)}, - }, - user_data); - } - if (iter_type & MR_ITER_LVERT) { - extract->iter_lvert_mesh(mr, - &(const ExtractLVertMesh_Params){ - .lvert = mr->lverts, - .lvert_range = {start, min_ii(mr->vert_loose_len, end)}, - }, - user_data); - } - break; - } -} - -static void extract_init(ExtractTaskData *data) -{ - if (data->tasktype == EXTRACT_MESH_EXTRACT) { - data->user_data->user_data = data->extract->init(data->mr, data->cache, data->buf); - } -} - -static void extract_run(void *__restrict taskdata) -{ - ExtractTaskData *data = (ExtractTaskData *)taskdata; - 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->cache, data->buf, data->user_data->user_data); - } - } - else if (data->tasktype == EXTRACT_LINES_LOOSE) { - extract_lines_loose_subbuffer(data->mr, data->cache); - } -} - -static void extract_init_and_run(void *__restrict taskdata) -{ - extract_init((ExtractTaskData *)taskdata); - extract_run(taskdata); -} - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Task Node - Update Mesh Render Data - * \{ */ -typedef struct MeshRenderDataUpdateTaskData { - MeshRenderData *mr; - eMRIterType iter_type; - eMRDataType data_flag; -} MeshRenderDataUpdateTaskData; - -static void mesh_render_data_update_task_data_free(MeshRenderDataUpdateTaskData *taskdata) -{ - BLI_assert(taskdata); - MeshRenderData *mr = taskdata->mr; - mesh_render_data_free(mr); - MEM_freeN(taskdata); -} - -static void mesh_extract_render_data_node_exec(void *__restrict task_data) -{ - MeshRenderDataUpdateTaskData *update_task_data = task_data; - MeshRenderData *mr = update_task_data->mr; - const eMRIterType iter_type = update_task_data->iter_type; - const eMRDataType data_flag = update_task_data->data_flag; - - mesh_render_data_update_normals(mr, iter_type, data_flag); - mesh_render_data_update_looptris(mr, iter_type, data_flag); -} - -static struct TaskNode *mesh_extract_render_data_node_create(struct TaskGraph *task_graph, - MeshRenderData *mr, - const eMRIterType iter_type, - const eMRDataType data_flag) -{ - MeshRenderDataUpdateTaskData *task_data = MEM_mallocN(sizeof(MeshRenderDataUpdateTaskData), - __func__); - task_data->mr = mr; - task_data->iter_type = iter_type; - task_data->data_flag = data_flag; - - struct TaskNode *task_node = BLI_task_graph_node_create( - task_graph, - mesh_extract_render_data_node_exec, - task_data, - (TaskGraphNodeFreeFunction)mesh_render_data_update_task_data_free); - return task_node; -} - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Task Node - Extract Single Threaded - * \{ */ -typedef struct ExtractSingleThreadedTaskData { - ListBase task_datas; -} ExtractSingleThreadedTaskData; - -static void extract_single_threaded_task_data_free(ExtractSingleThreadedTaskData *taskdata) -{ - BLI_assert(taskdata); - LISTBASE_FOREACH_MUTABLE (ExtractTaskData *, td, &taskdata->task_datas) { - extract_task_data_free(td); - } - BLI_listbase_clear(&taskdata->task_datas); - MEM_freeN(taskdata); -} - -static void extract_single_threaded_task_node_exec(void *__restrict task_data) -{ - ExtractSingleThreadedTaskData *extract_task_data = task_data; - LISTBASE_FOREACH (ExtractTaskData *, td, &extract_task_data->task_datas) { - extract_init_and_run(td); - } -} - -static struct TaskNode *extract_single_threaded_task_node_create( - struct TaskGraph *task_graph, ExtractSingleThreadedTaskData *task_data) -{ - struct TaskNode *task_node = BLI_task_graph_node_create( - task_graph, - extract_single_threaded_task_node_exec, - task_data, - (TaskGraphNodeFreeFunction)extract_single_threaded_task_data_free); - return task_node; -} - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Task Node - UserData Initializer - * \{ */ -typedef struct UserDataInitTaskData { - ListBase task_datas; - int32_t *task_counters; - -} UserDataInitTaskData; - -static void user_data_init_task_data_free(UserDataInitTaskData *taskdata) -{ - BLI_assert(taskdata); - LISTBASE_FOREACH_MUTABLE (ExtractTaskData *, td, &taskdata->task_datas) { - extract_task_data_free(td); - } - BLI_listbase_clear(&taskdata->task_datas); - MEM_SAFE_FREE(taskdata->task_counters); - MEM_freeN(taskdata); -} - -static void user_data_init_task_data_exec(void *__restrict task_data) -{ - UserDataInitTaskData *extract_task_data = task_data; - LISTBASE_FOREACH (ExtractTaskData *, td, &extract_task_data->task_datas) { - extract_init(td); - } -} - -static struct TaskNode *user_data_init_task_node_create(struct TaskGraph *task_graph, - UserDataInitTaskData *task_data) -{ - struct TaskNode *task_node = BLI_task_graph_node_create( - task_graph, - user_data_init_task_data_exec, - task_data, - (TaskGraphNodeFreeFunction)user_data_init_task_data_free); - return task_node; -} - -/** \} */ -/* ---------------------------------------------------------------------- */ -/** \name Extract Loop - * \{ */ - -static void extract_range_task_create(struct TaskGraph *task_graph, - struct TaskNode *task_node_user_data_init, - ExtractTaskData *taskdata, - const eMRIterType type, - int start, - int length) -{ - taskdata = MEM_dupallocN(taskdata); - atomic_add_and_fetch_int32(taskdata->task_counter, 1); - taskdata->iter_type = type; - taskdata->start = start; - taskdata->end = start + length; - struct TaskNode *task_node = BLI_task_graph_node_create( - task_graph, extract_run, taskdata, MEM_freeN); - BLI_task_graph_edge_create(task_node_user_data_init, task_node); -} - -static void extract_task_create(struct TaskGraph *task_graph, - struct TaskNode *task_node_mesh_render_data, - struct TaskNode *task_node_user_data_init, - ListBase *single_threaded_task_datas, - ListBase *user_data_init_task_datas, - const Scene *scene, - const MeshRenderData *mr, - MeshBatchCache *cache, - const MeshExtract *extract, - void *buf, - int32_t *task_counter) -{ - BLI_assert(scene != NULL); - const bool do_hq_normals = (scene->r.perf_flag & SCE_PERF_HQ_NORMALS) != 0 || - GPU_use_hq_normals_workaround(); - if (do_hq_normals) { - if (extract == &extract_lnor) { - extract = &extract_lnor_hq; - } - else if (extract == &extract_pos_nor) { - extract = &extract_pos_nor_hq; - } - else if (extract == &extract_tan) { - extract = &extract_tan_hq; - } - else if (extract == &extract_fdots_nor) { - extract = &extract_fdots_nor_hq; - } - } - - /* Divide extraction of the VBO/IBO into sensible chunks of works. */ - ExtractTaskData *taskdata = extract_task_data_create_mesh_extract( - mr, cache, extract, buf, task_counter); - - /* Simple heuristic. */ - const int chunk_size = 8192; - const bool use_thread = (mr->loop_len + mr->loop_loose_len) > chunk_size; - if (use_thread && extract->use_threading) { - - /* Divide task into sensible chunks. */ - if (taskdata->iter_type & MR_ITER_LOOPTRI) { - for (int i = 0; i < mr->tri_len; i += chunk_size) { - extract_range_task_create( - task_graph, task_node_user_data_init, taskdata, MR_ITER_LOOPTRI, i, chunk_size); - } - } - if (taskdata->iter_type & MR_ITER_POLY) { - for (int i = 0; i < mr->poly_len; i += chunk_size) { - extract_range_task_create( - task_graph, task_node_user_data_init, taskdata, MR_ITER_POLY, i, chunk_size); - } - } - if (taskdata->iter_type & MR_ITER_LEDGE) { - for (int i = 0; i < mr->edge_loose_len; i += chunk_size) { - extract_range_task_create( - task_graph, task_node_user_data_init, taskdata, MR_ITER_LEDGE, i, chunk_size); - } - } - if (taskdata->iter_type & MR_ITER_LVERT) { - for (int i = 0; i < mr->vert_loose_len; i += chunk_size) { - extract_range_task_create( - task_graph, task_node_user_data_init, taskdata, MR_ITER_LVERT, i, chunk_size); - } - } - BLI_addtail(user_data_init_task_datas, taskdata); - } - else if (use_thread) { - /* One task for the whole VBO. */ - (*task_counter)++; - struct TaskNode *one_task = BLI_task_graph_node_create( - task_graph, extract_init_and_run, taskdata, extract_task_data_free); - BLI_task_graph_edge_create(task_node_mesh_render_data, one_task); - } - else { - /* Single threaded extraction. */ - (*task_counter)++; - BLI_addtail(single_threaded_task_datas, taskdata); - } -} - -void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, - MeshBatchCache *cache, - MeshBufferCache mbc, - Mesh *me, - - const bool is_editmode, - const bool is_paint_mode, - const bool is_mode_active, - const float obmat[4][4], - const bool do_final, - const bool do_uvedit, - const bool use_subsurf_fdots, - const DRW_MeshCDMask *cd_layer_used, - const Scene *scene, - const ToolSettings *ts, - const bool use_hide) -{ - /* For each mesh where batches needs to be updated a sub-graph will be added to the task_graph. - * This sub-graph starts with an extract_render_data_node. This fills/converts the required data - * from Mesh. - * - * Small extractions and extractions that can't be multi-threaded are grouped in a single - * `extract_single_threaded_task_node`. - * - * Other extractions will create a node for each loop exceeding 8192 items. these nodes are - * linked to the `user_data_init_task_node`. the `user_data_init_task_node` prepares the - * user_data needed for the extraction based on the data extracted from the mesh. - * counters are used to check if the finalize of a task has to be called. - * - * Mesh extraction sub graph - * - * +----------------------+ - * +-----> | extract_task1_loop_1 | - * | +----------------------+ - * +------------------+ +----------------------+ +----------------------+ - * | mesh_render_data | --> | | --> | extract_task1_loop_2 | - * +------------------+ | | +----------------------+ - * | | | +----------------------+ - * | | user_data_init | --> | extract_task2_loop_1 | - * v | | +----------------------+ - * +------------------+ | | +----------------------+ - * | single_threaded | | | --> | extract_task2_loop_2 | - * +------------------+ +----------------------+ +----------------------+ - * | +----------------------+ - * +-----> | extract_task2_loop_3 | - * +----------------------+ - */ - eMRIterType iter_flag = 0; - eMRDataType data_flag = 0; - - const bool do_lines_loose_subbuffer = mbc.ibo.lines_loose != NULL; - -#define TEST_ASSIGN(type, type_lowercase, name) \ - do { \ - if (DRW_TEST_ASSIGN_##type(mbc.type_lowercase.name)) { \ - iter_flag |= mesh_extract_iter_type(&extract_##name); \ - data_flag |= extract_##name.data_flag; \ - } \ - } while (0) - - TEST_ASSIGN(VBO, vbo, pos_nor); - TEST_ASSIGN(VBO, vbo, lnor); - TEST_ASSIGN(VBO, vbo, uv); - TEST_ASSIGN(VBO, vbo, tan); - TEST_ASSIGN(VBO, vbo, vcol); - TEST_ASSIGN(VBO, vbo, sculpt_data); - TEST_ASSIGN(VBO, vbo, orco); - TEST_ASSIGN(VBO, vbo, edge_fac); - TEST_ASSIGN(VBO, vbo, weights); - TEST_ASSIGN(VBO, vbo, edit_data); - TEST_ASSIGN(VBO, vbo, edituv_data); - TEST_ASSIGN(VBO, vbo, edituv_stretch_area); - TEST_ASSIGN(VBO, vbo, edituv_stretch_angle); - TEST_ASSIGN(VBO, vbo, mesh_analysis); - TEST_ASSIGN(VBO, vbo, fdots_pos); - TEST_ASSIGN(VBO, vbo, fdots_nor); - TEST_ASSIGN(VBO, vbo, fdots_uv); - TEST_ASSIGN(VBO, vbo, fdots_edituv_data); - TEST_ASSIGN(VBO, vbo, poly_idx); - TEST_ASSIGN(VBO, vbo, edge_idx); - TEST_ASSIGN(VBO, vbo, vert_idx); - TEST_ASSIGN(VBO, vbo, fdot_idx); - TEST_ASSIGN(VBO, vbo, skin_roots); - - TEST_ASSIGN(IBO, ibo, tris); - TEST_ASSIGN(IBO, ibo, lines); - TEST_ASSIGN(IBO, ibo, points); - TEST_ASSIGN(IBO, ibo, fdots); - TEST_ASSIGN(IBO, ibo, lines_paint_mask); - TEST_ASSIGN(IBO, ibo, lines_adjacency); - TEST_ASSIGN(IBO, ibo, edituv_tris); - TEST_ASSIGN(IBO, ibo, edituv_lines); - 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 - double rdata_start = PIL_check_seconds_timer(); -#endif - - MeshRenderData *mr = mesh_render_data_create(me, - is_editmode, - is_paint_mode, - is_mode_active, - obmat, - do_final, - do_uvedit, - cd_layer_used, - ts, - iter_flag, - data_flag); - mr->use_hide = use_hide; - mr->use_subsurf_fdots = use_subsurf_fdots; - mr->use_final_mesh = do_final; - -#ifdef DEBUG_TIME - double rdata_end = PIL_check_seconds_timer(); -#endif - - size_t counters_size = (sizeof(mbc) / sizeof(void *)) * sizeof(int32_t); - int32_t *task_counters = MEM_callocN(counters_size, __func__); - int counter_used = 0; - - struct TaskNode *task_node_mesh_render_data = mesh_extract_render_data_node_create( - task_graph, mr, iter_flag, data_flag); - ExtractSingleThreadedTaskData *single_threaded_task_data = MEM_callocN( - sizeof(ExtractSingleThreadedTaskData), __func__); - UserDataInitTaskData *user_data_init_task_data = MEM_callocN(sizeof(UserDataInitTaskData), - __func__); - user_data_init_task_data->task_counters = task_counters; - struct TaskNode *task_node_user_data_init = user_data_init_task_node_create( - task_graph, user_data_init_task_data); - -#define EXTRACT(buf, name) \ - if (mbc.buf.name) { \ - extract_task_create(task_graph, \ - task_node_mesh_render_data, \ - task_node_user_data_init, \ - &single_threaded_task_data->task_datas, \ - &user_data_init_task_data->task_datas, \ - scene, \ - mr, \ - cache, \ - &extract_##name, \ - mbc.buf.name, \ - &task_counters[counter_used++]); \ - } \ - ((void)0) - - EXTRACT(vbo, pos_nor); - EXTRACT(vbo, lnor); - EXTRACT(vbo, uv); - EXTRACT(vbo, tan); - EXTRACT(vbo, vcol); - EXTRACT(vbo, sculpt_data); - EXTRACT(vbo, orco); - EXTRACT(vbo, edge_fac); - EXTRACT(vbo, weights); - EXTRACT(vbo, edit_data); - EXTRACT(vbo, edituv_data); - EXTRACT(vbo, edituv_stretch_area); - EXTRACT(vbo, edituv_stretch_angle); - EXTRACT(vbo, mesh_analysis); - EXTRACT(vbo, fdots_pos); - EXTRACT(vbo, fdots_nor); - EXTRACT(vbo, fdots_uv); - EXTRACT(vbo, fdots_edituv_data); - EXTRACT(vbo, poly_idx); - EXTRACT(vbo, edge_idx); - EXTRACT(vbo, vert_idx); - EXTRACT(vbo, fdot_idx); - EXTRACT(vbo, skin_roots); - - EXTRACT(ibo, tris); - if (mbc.ibo.lines) { - /* When `lines` and `lines_loose` are requested, schedule lines extraction that also creates - * the `lines_loose` sub-buffer. */ - const MeshExtract *lines_extractor = do_lines_loose_subbuffer ? - &extract_lines_with_lines_loose : - &extract_lines; - extract_task_create(task_graph, - task_node_mesh_render_data, - task_node_user_data_init, - &single_threaded_task_data->task_datas, - &user_data_init_task_data->task_datas, - scene, - mr, - cache, - lines_extractor, - mbc.ibo.lines, - &task_counters[counter_used++]); - } - else { - if (do_lines_loose_subbuffer) { - ExtractTaskData *taskdata = extract_task_data_create_lines_loose(mr, cache); - BLI_addtail(&single_threaded_task_data->task_datas, taskdata); - } - } - EXTRACT(ibo, points); - EXTRACT(ibo, fdots); - EXTRACT(ibo, lines_paint_mask); - EXTRACT(ibo, lines_adjacency); - EXTRACT(ibo, edituv_tris); - EXTRACT(ibo, edituv_lines); - EXTRACT(ibo, edituv_points); - EXTRACT(ibo, edituv_fdots); - - /* Only create the edge when there is user data that needs to be initialized. - * The task is still part of the graph so the task_data will be freed when the graph is freed. - */ - if (!BLI_listbase_is_empty(&user_data_init_task_data->task_datas)) { - BLI_task_graph_edge_create(task_node_mesh_render_data, task_node_user_data_init); - } - - if (!BLI_listbase_is_empty(&single_threaded_task_data->task_datas)) { - struct TaskNode *task_node = extract_single_threaded_task_node_create( - task_graph, single_threaded_task_data); - BLI_task_graph_edge_create(task_node_mesh_render_data, task_node); - } - else { - extract_single_threaded_task_data_free(single_threaded_task_data); - } - - /* Trigger the sub-graph for this mesh. */ - BLI_task_graph_node_push_work(task_node_mesh_render_data); - -#undef EXTRACT - -#ifdef DEBUG_TIME - BLI_task_graph_work_and_wait(task_graph); - double end = PIL_check_seconds_timer(); - - static double avg = 0; - static double avg_fps = 0; - static double avg_rdata = 0; - static double end_prev = 0; - - if (end_prev == 0) { - end_prev = end; - } - - avg = avg * 0.95 + (end - rdata_end) * 0.05; - avg_fps = avg_fps * 0.95 + (end - end_prev) * 0.05; - avg_rdata = avg_rdata * 0.95 + (rdata_end - rdata_start) * 0.05; - - printf( - "rdata %.0fms iter %.0fms (frame %.0fms)\n", avg_rdata * 1000, avg * 1000, avg_fps * 1000); - - end_prev = end; -#endif -} - -/** \} */ + .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdot_idx)}; diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_private.h b/source/blender/draw/intern/draw_cache_extract_mesh_private.h new file mode 100644 index 00000000000..6761282fe79 --- /dev/null +++ b/source/blender/draw/intern/draw_cache_extract_mesh_private.h @@ -0,0 +1,514 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 by Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup draw + * + * \brief Extraction of Mesh data into VBO to feed to GPU. + */ + +#pragma once + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BKE_editmesh.h" + +#include "draw_cache_extract.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum eMRExtractType { + MR_EXTRACT_BMESH, + MR_EXTRACT_MAPPED, + MR_EXTRACT_MESH, +} eMRExtractType; + +typedef struct MeshRenderData { + eMRExtractType extract_type; + + int poly_len, edge_len, vert_len, loop_len; + int edge_loose_len; + int vert_loose_len; + int loop_loose_len; + int tri_len; + int mat_len; + + bool use_hide; + bool use_subsurf_fdots; + bool use_final_mesh; + + /** Use for #MeshStatVis calculation which use world-space coords. */ + float obmat[4][4]; + + const ToolSettings *toolsettings; + /** Edit Mesh */ + BMEditMesh *edit_bmesh; + BMesh *bm; + EditMeshData *edit_data; + + /* For deformed edit-mesh data. */ + /* Use for #ME_WRAPPER_TYPE_BMESH. */ + const float (*bm_vert_coords)[3]; + const float (*bm_vert_normals)[3]; + const float (*bm_poly_normals)[3]; + const float (*bm_poly_centers)[3]; + + int *v_origindex, *e_origindex, *p_origindex; + int crease_ofs; + int bweight_ofs; + int freestyle_edge_ofs; + int freestyle_face_ofs; + /** Mesh */ + Mesh *me; + const MVert *mvert; + const MEdge *medge; + const MLoop *mloop; + const MPoly *mpoly; + BMVert *eve_act; + BMEdge *eed_act; + BMFace *efa_act; + BMFace *efa_act_uv; + /* Data created on-demand (usually not for #BMesh based data). */ + MLoopTri *mlooptri; + float (*loop_normals)[3]; + float (*poly_normals)[3]; + int *lverts, *ledges; +} MeshRenderData; + +BLI_INLINE BMFace *bm_original_face_get(const MeshRenderData *mr, int idx) +{ + return ((mr->p_origindex != NULL) && (mr->p_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ? + BM_face_at_index(mr->bm, mr->p_origindex[idx]) : + NULL; +} + +BLI_INLINE BMEdge *bm_original_edge_get(const MeshRenderData *mr, int idx) +{ + return ((mr->e_origindex != NULL) && (mr->e_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ? + BM_edge_at_index(mr->bm, mr->e_origindex[idx]) : + NULL; +} + +BLI_INLINE BMVert *bm_original_vert_get(const MeshRenderData *mr, int idx) +{ + return ((mr->v_origindex != NULL) && (mr->v_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ? + BM_vert_at_index(mr->bm, mr->v_origindex[idx]) : + NULL; +} + +BLI_INLINE const float *bm_vert_co_get(const MeshRenderData *mr, const BMVert *eve) +{ + const float(*vert_coords)[3] = mr->bm_vert_coords; + if (vert_coords != NULL) { + return vert_coords[BM_elem_index_get(eve)]; + } + + UNUSED_VARS(mr); + return eve->co; +} + +BLI_INLINE const float *bm_vert_no_get(const MeshRenderData *mr, const BMVert *eve) +{ + const float(*vert_normals)[3] = mr->bm_vert_normals; + if (vert_normals != NULL) { + return vert_normals[BM_elem_index_get(eve)]; + } + + UNUSED_VARS(mr); + return eve->no; +} + +BLI_INLINE const float *bm_face_no_get(const MeshRenderData *mr, const BMFace *efa) +{ + const float(*poly_normals)[3] = mr->bm_poly_normals; + if (poly_normals != NULL) { + return poly_normals[BM_elem_index_get(efa)]; + } + + UNUSED_VARS(mr); + return efa->no; +} + +/* TODO(jbakker): phase out batch iteration macros as they are only used once. */ +/* ---------------------------------------------------------------------- */ +/** \name Mesh Elements Extract: Loop Triangles + * \{ */ + +typedef struct ExtractTriBMesh_Params { + BMLoop *(*looptris)[3]; + int tri_range[2]; +} ExtractTriBMesh_Params; +typedef void(ExtractTriBMeshFn)(const MeshRenderData *mr, + BMLoop **elt, + const int elt_index, + void *data); + +#define EXTRACT_TRIS_LOOPTRI_FOREACH_BM_BEGIN(elem_tri, index_tri, params) \ + CHECK_TYPE(params, const ExtractTriBMesh_Params *); \ + { \ + const int _tri_index_end = (params)->tri_range[1]; \ + BMLoop **elem_tri = (params)->looptris[(params)->tri_range[0]]; \ + for (int index_tri = (params)->tri_range[0]; index_tri < _tri_index_end; \ + index_tri += 1, elem_tri += 3) +#define EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END } + +typedef struct ExtractTriMesh_Params { + const MLoopTri *mlooptri; + int tri_range[2]; +} ExtractTriMesh_Params; +typedef void(ExtractTriMeshFn)(const MeshRenderData *mr, + const MLoopTri *mlt, + const int elt_index, + void *data); + +#define EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_BEGIN(elem_tri, index_tri, params) \ + CHECK_TYPE(params, const ExtractTriMesh_Params *); \ + { \ + const int _tri_index_end = (params)->tri_range[1]; \ + const MLoopTri *elem_tri = &(params)->mlooptri[(params)->tri_range[0]]; \ + for (int index_tri = (params)->tri_range[0]; index_tri < _tri_index_end; \ + index_tri += 1, elem_tri += 1) +#define EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END } + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Mesh Elements Extract: Polygons, Loops + * \{ */ + +typedef struct ExtractPolyBMesh_Params { + BMLoop *(*looptris)[3]; + int poly_range[2]; +} ExtractPolyBMesh_Params; +typedef void(ExtractPolyBMeshFn)(const MeshRenderData *mr, + BMFace *f, + const int f_index, + void *data); + +#define EXTRACT_POLY_FOREACH_BM_BEGIN(elem_poly, index_poly, params, mr) \ + CHECK_TYPE(params, const ExtractPolyBMesh_Params *); \ + { \ + BLI_assert((mr->bm->elem_table_dirty & BM_FACE) == 0); \ + BMFace **_ftable = mr->bm->ftable; \ + const int _poly_index_end = (params)->poly_range[1]; \ + for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \ + index_poly += 1) { \ + BMFace *elem_poly = _ftable[index_poly]; \ + (void)elem_poly; + +#define EXTRACT_POLY_FOREACH_BM_END \ + } \ + } + +/* Iterate over polygon and loop. */ +#define EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(elem_loop, index_loop, params, mr) \ + CHECK_TYPE(params, const ExtractPolyBMesh_Params *); \ + { \ + BLI_assert((mr->bm->elem_table_dirty & BM_FACE) == 0); \ + BMFace **_ftable = mr->bm->ftable; \ + const int _poly_index_end = (params)->poly_range[1]; \ + for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \ + index_poly += 1) { \ + BMFace *elem_face = _ftable[index_poly]; \ + BMLoop *elem_loop, *l_first; \ + elem_loop = l_first = BM_FACE_FIRST_LOOP(elem_face); \ + do { \ + const int index_loop = BM_elem_index_get(elem_loop); \ + (void)index_loop; /* Quiet warning when unused. */ + +#define EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(elem_loop) \ + } \ + while ((elem_loop = elem_loop->next) != l_first) \ + ; \ + } \ + } + +typedef struct ExtractPolyMesh_Params { + int poly_range[2]; +} ExtractPolyMesh_Params; +typedef void(ExtractPolyMeshFn)(const MeshRenderData *mr, + const MPoly *mp, + const int mp_index, + void *data); + +#define EXTRACT_POLY_FOREACH_MESH_BEGIN(elem_poly, index_poly, params, mr) \ + CHECK_TYPE(params, const ExtractPolyMesh_Params *); \ + { \ + const MPoly *_mpoly = mr->mpoly; \ + const int _poly_index_end = (params)->poly_range[1]; \ + for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \ + index_poly += 1) { \ + const MPoly *elem_poly = &_mpoly[index_poly]; \ + (void)elem_poly; + +#define EXTRACT_POLY_FOREACH_MESH_END \ + } \ + } + +/* Iterate over polygon and loop. */ +#define EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN( \ + elem_poly, index_poly, elem_loop, index_loop, params, mr) \ + CHECK_TYPE(params, const ExtractPolyMesh_Params *); \ + { \ + const MPoly *_mpoly = mr->mpoly; \ + const MLoop *_mloop = mr->mloop; \ + const int _poly_index_end = (params)->poly_range[1]; \ + for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \ + index_poly += 1) { \ + const MPoly *elem_poly = &_mpoly[index_poly]; \ + const int _index_end = elem_poly->loopstart + elem_poly->totloop; \ + for (int index_loop = elem_poly->loopstart; index_loop < _index_end; index_loop += 1) { \ + const MLoop *elem_loop = &_mloop[index_loop]; \ + (void)elem_loop; + +#define EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END \ + } \ + } \ + } + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Mesh Elements Extract: Loose Edges + * \{ */ + +typedef struct ExtractLEdgeBMesh_Params { + const int *ledge; + int ledge_range[2]; +} ExtractLEdgeBMesh_Params; +typedef void(ExtractLEdgeBMeshFn)(const MeshRenderData *mr, + BMEdge *eed, + const int ledge_index, + void *data); + +#define EXTRACT_LEDGE_FOREACH_BM_BEGIN(elem_edge, index_ledge, params) \ + CHECK_TYPE(params, const ExtractLEdgeBMesh_Params *); \ + { \ + BLI_assert((mr->bm->elem_table_dirty & BM_EDGE) == 0); \ + BMEdge **_etable = mr->bm->etable; \ + const int *_ledge = (params)->ledge; \ + const int _ledge_index_end = (params)->ledge_range[1]; \ + for (int index_ledge = (params)->ledge_range[0]; index_ledge < _ledge_index_end; \ + index_ledge += 1) { \ + BMEdge *elem_edge = _etable[_ledge[index_ledge]]; \ + (void)elem_edge; /* Quiet warning when unused. */ \ + { +#define EXTRACT_LEDGE_FOREACH_BM_END \ + } \ + } \ + } + +typedef struct ExtractLEdgeMesh_Params { + const int *ledge; + int ledge_range[2]; +} ExtractLEdgeMesh_Params; +typedef void(ExtractLEdgeMeshFn)(const MeshRenderData *mr, + const MEdge *med, + const uint ledge_index, + void *data); + +#define EXTRACT_LEDGE_FOREACH_MESH_BEGIN(elem_edge, index_ledge, params, mr) \ + CHECK_TYPE(params, const ExtractLEdgeMesh_Params *); \ + { \ + const MEdge *_medge = mr->medge; \ + const int *_ledge = (params)->ledge; \ + const int _ledge_index_end = (params)->ledge_range[1]; \ + for (int index_ledge = (params)->ledge_range[0]; index_ledge < _ledge_index_end; \ + index_ledge += 1) { \ + const MEdge *elem_edge = &_medge[_ledge[index_ledge]]; \ + (void)elem_edge; /* Quiet warning when unused. */ \ + { +#define EXTRACT_LEDGE_FOREACH_MESH_END \ + } \ + } \ + } + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Mesh Elements Extract: Loose Vertices + * \{ */ + +typedef struct ExtractLVertBMesh_Params { + const int *lvert; + int lvert_range[2]; +} ExtractLVertBMesh_Params; +typedef void(ExtractLVertBMeshFn)(const MeshRenderData *mr, + BMVert *eve, + const int lvert_index, + void *data); + +#define EXTRACT_LVERT_FOREACH_BM_BEGIN(elem_vert, index_lvert, params) \ + CHECK_TYPE(params, const ExtractLVertBMesh_Params *); \ + { \ + BLI_assert((mr->bm->elem_table_dirty & BM_FACE) == 0); \ + BMVert **vtable = mr->bm->vtable; \ + const int *lverts = (params)->lvert; \ + const int _lvert_index_end = (params)->lvert_range[1]; \ + for (int index_lvert = (params)->lvert_range[0]; index_lvert < _lvert_index_end; \ + index_lvert += 1) { \ + BMVert *elem_vert = vtable[lverts[index_lvert]]; \ + (void)elem_vert; /* Quiet warning when unused. */ \ + { +#define EXTRACT_LVERT_FOREACH_BM_END \ + } \ + } \ + } + +typedef struct ExtractLVertMesh_Params { + const int *lvert; + int lvert_range[2]; +} ExtractLVertMesh_Params; +typedef void(ExtractLVertMeshFn)(const MeshRenderData *mr, + const MVert *mv, + const int lvert_index, + void *data); + +#define EXTRACT_LVERT_FOREACH_MESH_BEGIN(elem, index_lvert, params, mr) \ + CHECK_TYPE(params, const ExtractLVertMesh_Params *); \ + { \ + const MVert *mvert = mr->mvert; \ + const int *lverts = (params)->lvert; \ + const int _lvert_index_end = (params)->lvert_range[1]; \ + for (int index_lvert = (params)->lvert_range[0]; index_lvert < _lvert_index_end; \ + index_lvert += 1) { \ + const MVert *elem = &mvert[lverts[index_lvert]]; \ + (void)elem; /* Quiet warning when unused. */ \ + { +#define EXTRACT_LVERT_FOREACH_MESH_END \ + } \ + } \ + } + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Mesh Elements Extract Struct + * \{ */ + +typedef void *(ExtractInitFn)(const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buffer); +typedef void(ExtractFinishFn)(const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buffer, + void *data); + +typedef struct MeshExtract { + /** Executed on main thread and return user data for iteration functions. */ + ExtractInitFn *init; + /** Executed on one (or more if use_threading) worker thread(s). */ + ExtractTriBMeshFn *iter_looptri_bm; + ExtractTriMeshFn *iter_looptri_mesh; + ExtractPolyBMeshFn *iter_poly_bm; + ExtractPolyMeshFn *iter_poly_mesh; + ExtractLEdgeBMeshFn *iter_ledge_bm; + ExtractLEdgeMeshFn *iter_ledge_mesh; + ExtractLVertBMeshFn *iter_lvert_bm; + ExtractLVertMeshFn *iter_lvert_mesh; + /** Executed on one worker thread after all elements iterations. */ + ExtractFinishFn *finish; + /** Used to request common data. */ + const eMRDataType data_type; + /** Used to know if the element callbacks are thread-safe and can be parallelized. */ + const bool use_threading; + /** + * Offset in bytes of the buffer inside a MeshBufferCache instance. Points to a vertex or index + * buffer. + */ + const size_t mesh_buffer_offset; +} MeshExtract; + +/** \} */ + +/* draw_cache_extract_mesh_render_data.c */ +MeshRenderData *mesh_render_data_create(Mesh *me, + MeshBufferExtractionCache *cache, + const bool is_editmode, + const bool is_paint_mode, + const bool is_mode_active, + const float obmat[4][4], + const bool do_final, + const bool do_uvedit, + const ToolSettings *ts, + const eMRIterType iter_type); +void mesh_render_data_free(MeshRenderData *mr); +void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_flag); +void mesh_render_data_update_looptris(MeshRenderData *mr, + const eMRIterType iter_type, + const eMRDataType data_flag); + +/* draw_cache_extract_mesh_extractors.c */ +void *mesh_extract_buffer_get(const MeshExtract *extractor, MeshBufferCache *mbc); +eMRIterType mesh_extract_iter_type(const MeshExtract *ext); +const MeshExtract *mesh_extract_override_get(const MeshExtract *extractor, + const bool do_hq_normals); +/* + * Total number of extractions types. + */ +#define M_EXTRACT_LEN 38 + +extern const MeshExtract extract_tris; +extern const MeshExtract extract_lines; +extern const MeshExtract extract_lines_with_lines_loose; +extern const MeshExtract extract_lines_loose_only; +extern const MeshExtract extract_points; +extern const MeshExtract extract_fdots; +extern const MeshExtract extract_lines_paint_mask; +extern const MeshExtract extract_lines_adjacency; +extern const MeshExtract extract_edituv_tris; +extern const MeshExtract extract_edituv_lines; +extern const MeshExtract extract_edituv_points; +extern const MeshExtract extract_edituv_fdots; +extern const MeshExtract extract_pos_nor; +extern const MeshExtract extract_pos_nor_hq; +extern const MeshExtract extract_lnor_hq; +extern const MeshExtract extract_lnor; +extern const MeshExtract extract_uv; +extern const MeshExtract extract_tan; +extern const MeshExtract extract_tan_hq; +extern const MeshExtract extract_sculpt_data; +extern const MeshExtract extract_vcol; +extern const MeshExtract extract_orco; +extern const MeshExtract extract_edge_fac; +extern const MeshExtract extract_weights; +extern const MeshExtract extract_edit_data; +extern const MeshExtract extract_edituv_data; +extern const MeshExtract extract_edituv_stretch_area; +extern const MeshExtract extract_edituv_stretch_angle; +extern const MeshExtract extract_mesh_analysis; +extern const MeshExtract extract_fdots_pos; +extern const MeshExtract extract_fdots_nor; +extern const MeshExtract extract_fdots_nor_hq; +extern const MeshExtract extract_fdots_uv; +extern const MeshExtract extract_fdots_edituv_data; +extern const MeshExtract extract_skin_roots; +extern const MeshExtract extract_poly_idx; +extern const MeshExtract extract_edge_idx; +extern const MeshExtract extract_vert_idx; +extern const MeshExtract extract_fdot_idx; + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c new file mode 100644 index 00000000000..4741bcb06c9 --- /dev/null +++ b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c @@ -0,0 +1,371 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 by Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup draw + * + * \brief Extraction of Mesh data into VBO to feed to GPU. + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_bitmap.h" +#include "BLI_math.h" + +#include "BKE_editmesh.h" +#include "BKE_editmesh_cache.h" +#include "BKE_mesh.h" + +#include "GPU_batch.h" + +#include "ED_mesh.h" + +#include "draw_cache_extract_mesh_private.h" + +/* ---------------------------------------------------------------------- */ +/** \name Mesh/BMesh Interface (indirect, partially cached access to complex data). + * \{ */ + +static void mesh_render_data_loose_geom_load(MeshRenderData *mr, MeshBufferExtractionCache *cache) +{ + mr->ledges = cache->ledges; + mr->lverts = cache->lverts; + mr->vert_loose_len = cache->vert_loose_len; + mr->edge_loose_len = cache->edge_loose_len; + + mr->loop_loose_len = mr->vert_loose_len + (mr->edge_loose_len * 2); +} + +static void mesh_render_data_loose_geom_ensure(const MeshRenderData *mr, + MeshBufferExtractionCache *cache) +{ + /* Early exit: Are loose geometry already available. Only checking for loose verts as loose edges + * and verts are calculated at the same time.*/ + if (cache->lverts) { + return; + } + + cache->vert_loose_len = 0; + cache->edge_loose_len = 0; + + if (mr->extract_type != MR_EXTRACT_BMESH) { + /* Mesh */ + + BLI_bitmap *lvert_map = BLI_BITMAP_NEW(mr->vert_len, __func__); + + cache->ledges = MEM_mallocN(mr->edge_len * sizeof(*cache->ledges), __func__); + const MEdge *med = mr->medge; + for (int med_index = 0; med_index < mr->edge_len; med_index++, med++) { + if (med->flag & ME_LOOSEEDGE) { + cache->ledges[cache->edge_loose_len++] = med_index; + } + /* Tag verts as not loose. */ + BLI_BITMAP_ENABLE(lvert_map, med->v1); + BLI_BITMAP_ENABLE(lvert_map, med->v2); + } + if (cache->edge_loose_len < mr->edge_len) { + cache->ledges = MEM_reallocN(cache->ledges, cache->edge_loose_len * sizeof(*cache->ledges)); + } + + cache->lverts = MEM_mallocN(mr->vert_len * sizeof(*mr->lverts), __func__); + for (int v = 0; v < mr->vert_len; v++) { + if (!BLI_BITMAP_TEST(lvert_map, v)) { + cache->lverts[cache->vert_loose_len++] = v; + } + } + if (cache->vert_loose_len < mr->vert_len) { + cache->lverts = MEM_reallocN(cache->lverts, cache->vert_loose_len * sizeof(*cache->lverts)); + } + + MEM_freeN(lvert_map); + } + else { + /* #BMesh */ + BMesh *bm = mr->bm; + int elem_id; + BMIter iter; + BMVert *eve; + BMEdge *ede; + + cache->lverts = MEM_mallocN(mr->vert_len * sizeof(*cache->lverts), __func__); + BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, elem_id) { + if (eve->e == NULL) { + cache->lverts[cache->vert_loose_len++] = elem_id; + } + } + if (cache->vert_loose_len < mr->vert_len) { + cache->lverts = MEM_reallocN(cache->lverts, cache->vert_loose_len * sizeof(*cache->lverts)); + } + + cache->ledges = MEM_mallocN(mr->edge_len * sizeof(*cache->ledges), __func__); + BM_ITER_MESH_INDEX (ede, &iter, bm, BM_EDGES_OF_MESH, elem_id) { + if (ede->l == NULL) { + cache->ledges[cache->edge_loose_len++] = elem_id; + } + } + if (cache->edge_loose_len < mr->edge_len) { + cache->ledges = MEM_reallocN(cache->ledges, cache->edge_loose_len * sizeof(*cache->ledges)); + } + } +} + +/** + * Part of the creation of the #MeshRenderData that happens in a thread. + */ +void mesh_render_data_update_looptris(MeshRenderData *mr, + const eMRIterType iter_type, + const eMRDataType data_flag) +{ + Mesh *me = mr->me; + if (mr->extract_type != MR_EXTRACT_BMESH) { + /* Mesh */ + if ((iter_type & MR_ITER_LOOPTRI) || (data_flag & MR_DATA_LOOPTRI)) { + mr->mlooptri = MEM_mallocN(sizeof(*mr->mlooptri) * mr->tri_len, "MR_DATATYPE_LOOPTRI"); + BKE_mesh_recalc_looptri( + me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, mr->mlooptri); + } + } + else { + /* #BMesh */ + if ((iter_type & MR_ITER_LOOPTRI) || (data_flag & MR_DATA_LOOPTRI)) { + /* Edit mode ensures this is valid, no need to calculate. */ + BLI_assert((mr->bm->totloop == 0) || (mr->edit_bmesh->looptris != NULL)); + } + } +} + +void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_flag) +{ + Mesh *me = mr->me; + const bool is_auto_smooth = (me->flag & ME_AUTOSMOOTH) != 0; + const float split_angle = is_auto_smooth ? me->smoothresh : (float)M_PI; + + if (mr->extract_type != MR_EXTRACT_BMESH) { + /* Mesh */ + if (data_flag & (MR_DATA_POLY_NOR | MR_DATA_LOOP_NOR | MR_DATA_TAN_LOOP_NOR)) { + mr->poly_normals = MEM_mallocN(sizeof(*mr->poly_normals) * mr->poly_len, __func__); + BKE_mesh_calc_normals_poly((MVert *)mr->mvert, + NULL, + mr->vert_len, + mr->mloop, + mr->mpoly, + mr->loop_len, + mr->poly_len, + mr->poly_normals, + true); + } + if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) { + mr->loop_normals = MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__); + short(*clnors)[2] = CustomData_get_layer(&mr->me->ldata, CD_CUSTOMLOOPNORMAL); + BKE_mesh_normals_loop_split(mr->me->mvert, + mr->vert_len, + mr->me->medge, + mr->edge_len, + mr->me->mloop, + mr->loop_normals, + mr->loop_len, + mr->me->mpoly, + mr->poly_normals, + mr->poly_len, + is_auto_smooth, + split_angle, + NULL, + clnors, + NULL); + } + } + else { + /* #BMesh */ + if (data_flag & MR_DATA_POLY_NOR) { + /* Use #BMFace.no instead. */ + } + if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) { + + const float(*vert_coords)[3] = NULL; + const float(*vert_normals)[3] = NULL; + const float(*poly_normals)[3] = NULL; + + if (mr->edit_data && mr->edit_data->vertexCos) { + vert_coords = mr->bm_vert_coords; + vert_normals = mr->bm_vert_normals; + poly_normals = mr->bm_poly_normals; + } + + mr->loop_normals = MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__); + const int clnors_offset = CustomData_get_offset(&mr->bm->ldata, CD_CUSTOMLOOPNORMAL); + BM_loops_calc_normal_vcos(mr->bm, + vert_coords, + vert_normals, + poly_normals, + is_auto_smooth, + split_angle, + mr->loop_normals, + NULL, + NULL, + clnors_offset, + false); + } + } +} + +/** + * \param is_mode_active: When true, use the modifiers from the edit-data, + * otherwise don't use modifiers as they are not from this object. + */ +MeshRenderData *mesh_render_data_create(Mesh *me, + MeshBufferExtractionCache *cache, + const bool is_editmode, + const bool is_paint_mode, + const bool is_mode_active, + const float obmat[4][4], + const bool do_final, + const bool do_uvedit, + const ToolSettings *ts, + const eMRIterType iter_type) +{ + MeshRenderData *mr = MEM_callocN(sizeof(*mr), __func__); + mr->toolsettings = ts; + mr->mat_len = mesh_render_mat_len_get(me); + + copy_m4_m4(mr->obmat, obmat); + + if (is_editmode) { + BLI_assert(me->edit_mesh->mesh_eval_cage && me->edit_mesh->mesh_eval_final); + mr->bm = me->edit_mesh->bm; + mr->edit_bmesh = me->edit_mesh; + mr->me = (do_final) ? me->edit_mesh->mesh_eval_final : me->edit_mesh->mesh_eval_cage; + mr->edit_data = is_mode_active ? mr->me->runtime.edit_data : NULL; + + if (mr->edit_data) { + EditMeshData *emd = mr->edit_data; + if (emd->vertexCos) { + BKE_editmesh_cache_ensure_vert_normals(mr->edit_bmesh, emd); + BKE_editmesh_cache_ensure_poly_normals(mr->edit_bmesh, emd); + } + + mr->bm_vert_coords = mr->edit_data->vertexCos; + mr->bm_vert_normals = mr->edit_data->vertexNos; + mr->bm_poly_normals = mr->edit_data->polyNos; + mr->bm_poly_centers = mr->edit_data->polyCos; + } + + bool has_mdata = is_mode_active && (mr->me->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA); + bool use_mapped = is_mode_active && + (has_mdata && !do_uvedit && mr->me && !mr->me->runtime.is_original); + + int bm_ensure_types = BM_VERT | BM_EDGE | BM_LOOP | BM_FACE; + + BM_mesh_elem_index_ensure(mr->bm, bm_ensure_types); + BM_mesh_elem_table_ensure(mr->bm, bm_ensure_types & ~BM_LOOP); + + mr->efa_act_uv = EDBM_uv_active_face_get(mr->edit_bmesh, false, false); + mr->efa_act = BM_mesh_active_face_get(mr->bm, false, true); + mr->eed_act = BM_mesh_active_edge_get(mr->bm); + mr->eve_act = BM_mesh_active_vert_get(mr->bm); + + mr->crease_ofs = CustomData_get_offset(&mr->bm->edata, CD_CREASE); + mr->bweight_ofs = CustomData_get_offset(&mr->bm->edata, CD_BWEIGHT); +#ifdef WITH_FREESTYLE + mr->freestyle_edge_ofs = CustomData_get_offset(&mr->bm->edata, CD_FREESTYLE_EDGE); + mr->freestyle_face_ofs = CustomData_get_offset(&mr->bm->pdata, CD_FREESTYLE_FACE); +#endif + + if (use_mapped) { + mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX); + mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX); + mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX); + + use_mapped = (mr->v_origindex || mr->e_origindex || mr->p_origindex); + } + + mr->extract_type = use_mapped ? MR_EXTRACT_MAPPED : MR_EXTRACT_BMESH; + + /* Seems like the mesh_eval_final do not have the right origin indices. + * Force not mapped in this case. */ + if (has_mdata && do_final && me->edit_mesh->mesh_eval_final != me->edit_mesh->mesh_eval_cage) { + // mr->edit_bmesh = NULL; + mr->extract_type = MR_EXTRACT_MESH; + } + } + else { + mr->me = me; + mr->edit_bmesh = NULL; + + bool use_mapped = is_paint_mode && mr->me && !mr->me->runtime.is_original; + if (use_mapped) { + mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX); + mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX); + mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX); + + use_mapped = (mr->v_origindex || mr->e_origindex || mr->p_origindex); + } + + mr->extract_type = use_mapped ? MR_EXTRACT_MAPPED : MR_EXTRACT_MESH; + } + + if (mr->extract_type != MR_EXTRACT_BMESH) { + /* Mesh */ + mr->vert_len = mr->me->totvert; + mr->edge_len = mr->me->totedge; + mr->loop_len = mr->me->totloop; + mr->poly_len = mr->me->totpoly; + mr->tri_len = poly_to_tri_count(mr->poly_len, mr->loop_len); + + mr->mvert = CustomData_get_layer(&mr->me->vdata, CD_MVERT); + mr->medge = CustomData_get_layer(&mr->me->edata, CD_MEDGE); + mr->mloop = CustomData_get_layer(&mr->me->ldata, CD_MLOOP); + mr->mpoly = CustomData_get_layer(&mr->me->pdata, CD_MPOLY); + + mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX); + mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX); + mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX); + } + else { + /* #BMesh */ + BMesh *bm = mr->bm; + + mr->vert_len = bm->totvert; + mr->edge_len = bm->totedge; + mr->loop_len = bm->totloop; + mr->poly_len = bm->totface; + mr->tri_len = poly_to_tri_count(mr->poly_len, mr->loop_len); + } + + if (iter_type & (MR_ITER_LEDGE | MR_ITER_LVERT)) { + mesh_render_data_loose_geom_ensure(mr, cache); + mesh_render_data_loose_geom_load(mr, cache); + } + + return mr; +} + +void mesh_render_data_free(MeshRenderData *mr) +{ + MEM_SAFE_FREE(mr->mlooptri); + MEM_SAFE_FREE(mr->poly_normals); + MEM_SAFE_FREE(mr->loop_normals); + + /* Loose geometry are owned by MeshBufferExtractionCache. */ + mr->ledges = NULL; + mr->lverts = NULL; + + MEM_freeN(mr); +} + +/** \} */
\ No newline at end of file diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h index 2c2ab9eaadd..5743f39f7da 100644 --- a/source/blender/draw/intern/draw_cache_impl.h +++ b/source/blender/draw/intern/draw_cache_impl.h @@ -266,7 +266,6 @@ struct GPUBatch *DRW_particles_batch_cache_get_edit_inner_points(struct Object * struct GPUBatch *DRW_particles_batch_cache_get_edit_tip_points(struct Object *object, struct ParticleSystem *psys, struct PTCacheEdit *edit); - #ifdef __cplusplus } #endif diff --git a/source/blender/draw/intern/draw_cache_impl_curve.cc b/source/blender/draw/intern/draw_cache_impl_curve.cc index 223b44724b6..ee6a47e3dc6 100644 --- a/source/blender/draw/intern/draw_cache_impl_curve.cc +++ b/source/blender/draw/intern/draw_cache_impl_curve.cc @@ -25,8 +25,11 @@ #include "MEM_guardedalloc.h" +#include "BLI_array.hh" +#include "BLI_float3.hh" #include "BLI_listbase.h" #include "BLI_math_vector.h" +#include "BLI_span.hh" #include "BLI_utildefines.h" #include "DNA_curve_types.h" @@ -34,6 +37,8 @@ #include "BKE_curve.h" #include "BKE_displist.h" #include "BKE_font.h" +#include "BKE_geometry_set.hh" +#include "BKE_spline.hh" #include "GPU_batch.h" #include "GPU_capabilities.h" @@ -48,6 +53,11 @@ #include "draw_cache_impl.h" /* own include */ +using blender::Array; +using blender::float3; +using blender::IndexRange; +using blender::Span; + /* See: edit_curve_point_vert.glsl for duplicate includes. */ #define SELECT 1 #define ACTIVE_NURB (1 << 2) @@ -139,6 +149,21 @@ static void curve_render_wire_verts_edges_len_get(const CurveCache *ob_curve_cac } } +static void curve_eval_render_wire_verts_edges_len_get(const CurveEval &curve_eval, + int *r_curve_len, + int *r_vert_len, + int *r_edge_len) +{ + Span<SplinePtr> splines = curve_eval.splines(); + *r_curve_len = splines.size(); + *r_vert_len = 0; + *r_edge_len = 0; + for (const SplinePtr &spline : splines) { + *r_vert_len += spline->evaluated_points_size(); + *r_edge_len += spline->evaluated_edges_size(); + } +} + static int curve_render_normal_len_get(const ListBase *lb, const CurveCache *ob_curve_cache) { int normal_len = 0; @@ -192,6 +217,9 @@ struct CurveRenderData { /* borrow from 'Object' */ CurveCache *ob_curve_cache; + /* Owned by the evaluated object's geometry set (#geometry_set_eval). */ + const CurveEval *curve_eval; + /* borrow from 'Curve' */ ListBase *nurbs; @@ -230,11 +258,21 @@ static CurveRenderData *curve_render_data_create(Curve *cu, rdata->ob_curve_cache = ob_curve_cache; + rdata->curve_eval = cu->curve_eval; + if (types & CU_DATATYPE_WIRE) { - curve_render_wire_verts_edges_len_get(rdata->ob_curve_cache, - &rdata->wire.curve_len, - &rdata->wire.vert_len, - &rdata->wire.edge_len); + if (rdata->curve_eval != nullptr) { + curve_eval_render_wire_verts_edges_len_get(*rdata->curve_eval, + &rdata->wire.curve_len, + &rdata->wire.vert_len, + &rdata->wire.edge_len); + } + else { + curve_render_wire_verts_edges_len_get(rdata->ob_curve_cache, + &rdata->wire.curve_len, + &rdata->wire.vert_len, + &rdata->wire.edge_len); + } } if (cu->editnurb) { @@ -556,8 +594,6 @@ void DRW_curve_batch_cache_free(Curve *cu) /* GPUBatch cache usage. */ static void curve_create_curves_pos(CurveRenderData *rdata, GPUVertBuf *vbo_curves_pos) { - BLI_assert(rdata->ob_curve_cache != nullptr); - static GPUVertFormat format = {0}; static struct { uint pos; @@ -570,30 +606,46 @@ static void curve_create_curves_pos(CurveRenderData *rdata, GPUVertBuf *vbo_curv GPU_vertbuf_init_with_format(vbo_curves_pos, &format); GPU_vertbuf_data_alloc(vbo_curves_pos, vert_len); - int v_idx = 0; - LISTBASE_FOREACH (const BevList *, bl, &rdata->ob_curve_cache->bev) { - if (bl->nr <= 0) { - continue; - } - const int i_end = v_idx + bl->nr; - for (const BevPoint *bevp = bl->bevpoints; v_idx < i_end; v_idx++, bevp++) { - GPU_vertbuf_attr_set(vbo_curves_pos, attr_id.pos, v_idx, bevp->vec); + if (rdata->curve_eval != nullptr) { + const CurveEval &curve_eval = *rdata->curve_eval; + Span<SplinePtr> splines = curve_eval.splines(); + Array<int> offsets = curve_eval.evaluated_point_offsets(); + BLI_assert(offsets.last() == vert_len); + + for (const int i_spline : splines.index_range()) { + Span<float3> positions = splines[i_spline]->evaluated_positions(); + for (const int i_point : positions.index_range()) { + GPU_vertbuf_attr_set( + vbo_curves_pos, attr_id.pos, offsets[i_spline] + i_point, positions[i_point]); + } } } - LISTBASE_FOREACH (const DispList *, dl, &rdata->ob_curve_cache->disp) { - if (ELEM(dl->type, DL_SEGM, DL_POLY)) { - for (int i = 0; i < dl->nr; v_idx++, i++) { - GPU_vertbuf_attr_set(vbo_curves_pos, attr_id.pos, v_idx, &((float(*)[3])dl->verts)[i]); + else { + BLI_assert(rdata->ob_curve_cache != nullptr); + + int v_idx = 0; + LISTBASE_FOREACH (const BevList *, bl, &rdata->ob_curve_cache->bev) { + if (bl->nr <= 0) { + continue; + } + const int i_end = v_idx + bl->nr; + for (const BevPoint *bevp = bl->bevpoints; v_idx < i_end; v_idx++, bevp++) { + GPU_vertbuf_attr_set(vbo_curves_pos, attr_id.pos, v_idx, bevp->vec); } } + LISTBASE_FOREACH (const DispList *, dl, &rdata->ob_curve_cache->disp) { + if (ELEM(dl->type, DL_SEGM, DL_POLY)) { + for (int i = 0; i < dl->nr; v_idx++, i++) { + GPU_vertbuf_attr_set(vbo_curves_pos, attr_id.pos, v_idx, &((float(*)[3])dl->verts)[i]); + } + } + } + BLI_assert(v_idx == vert_len); } - BLI_assert(v_idx == vert_len); } static void curve_create_curves_lines(CurveRenderData *rdata, GPUIndexBuf *ibo_curve_lines) { - BLI_assert(rdata->ob_curve_cache != nullptr); - const int vert_len = curve_render_data_wire_verts_len_get(rdata); const int edge_len = curve_render_data_wire_edges_len_get(rdata); const int curve_len = curve_render_data_wire_curve_len_get(rdata); @@ -603,34 +655,56 @@ static void curve_create_curves_lines(CurveRenderData *rdata, GPUIndexBuf *ibo_c GPUIndexBufBuilder elb; GPU_indexbuf_init_ex(&elb, GPU_PRIM_LINE_STRIP, index_len, vert_len); - int v_idx = 0; - LISTBASE_FOREACH (const BevList *, bl, &rdata->ob_curve_cache->bev) { - if (bl->nr <= 0) { - continue; - } - const bool is_cyclic = bl->poly != -1; - if (is_cyclic) { - GPU_indexbuf_add_generic_vert(&elb, v_idx + (bl->nr - 1)); - } - for (int i = 0; i < bl->nr; i++) { - GPU_indexbuf_add_generic_vert(&elb, v_idx + i); + if (rdata->curve_eval != nullptr) { + const CurveEval &curve_eval = *rdata->curve_eval; + Span<SplinePtr> splines = curve_eval.splines(); + Array<int> offsets = curve_eval.evaluated_point_offsets(); + BLI_assert(offsets.last() == vert_len); + + for (const int i_spline : splines.index_range()) { + const int eval_size = splines[i_spline]->evaluated_points_size(); + if (splines[i_spline]->is_cyclic()) { + GPU_indexbuf_add_generic_vert(&elb, offsets[i_spline] + eval_size - 1); + } + for (const int i_point : IndexRange(eval_size)) { + GPU_indexbuf_add_generic_vert(&elb, offsets[i_spline] + i_point); + } + GPU_indexbuf_add_primitive_restart(&elb); } - GPU_indexbuf_add_primitive_restart(&elb); - v_idx += bl->nr; } - LISTBASE_FOREACH (const DispList *, dl, &rdata->ob_curve_cache->disp) { - if (ELEM(dl->type, DL_SEGM, DL_POLY)) { - const bool is_cyclic = dl->type == DL_POLY; + else { + BLI_assert(rdata->ob_curve_cache != nullptr); + + int v_idx = 0; + LISTBASE_FOREACH (const BevList *, bl, &rdata->ob_curve_cache->bev) { + if (bl->nr <= 0) { + continue; + } + const bool is_cyclic = bl->poly != -1; if (is_cyclic) { - GPU_indexbuf_add_generic_vert(&elb, v_idx + (dl->nr - 1)); + GPU_indexbuf_add_generic_vert(&elb, v_idx + (bl->nr - 1)); } - for (int i = 0; i < dl->nr; i++) { + for (int i = 0; i < bl->nr; i++) { GPU_indexbuf_add_generic_vert(&elb, v_idx + i); } GPU_indexbuf_add_primitive_restart(&elb); - v_idx += dl->nr; + v_idx += bl->nr; + } + LISTBASE_FOREACH (const DispList *, dl, &rdata->ob_curve_cache->disp) { + if (ELEM(dl->type, DL_SEGM, DL_POLY)) { + const bool is_cyclic = dl->type == DL_POLY; + if (is_cyclic) { + GPU_indexbuf_add_generic_vert(&elb, v_idx + (dl->nr - 1)); + } + for (int i = 0; i < dl->nr; i++) { + GPU_indexbuf_add_generic_vert(&elb, v_idx + i); + } + GPU_indexbuf_add_primitive_restart(&elb); + v_idx += dl->nr; + } } } + GPU_indexbuf_build_in_place(&elb, ibo_curve_lines); } @@ -769,6 +843,9 @@ static void curve_create_edit_data_and_handles(CurveRenderData *rdata, int edges_len_capacity = curve_render_data_overlay_edges_len_get(rdata) * 2; int vbo_len_used = 0; +#define DRW_TEST_ASSIGN_VBO(v) (v = (DRW_vbo_requested(v) ? (v) : NULL)) +#define DRW_TEST_ASSIGN_IBO(v) (v = (DRW_ibo_requested(v) ? (v) : NULL)) + if (DRW_TEST_ASSIGN_VBO(vbo_pos)) { GPU_vertbuf_init_with_format(vbo_pos, &format_pos); GPU_vertbuf_data_alloc(vbo_pos, verts_len_capacity); @@ -789,6 +866,9 @@ static void curve_create_edit_data_and_handles(CurveRenderData *rdata, GPU_indexbuf_init(elbp_lines, GPU_PRIM_LINES, edges_len_capacity, verts_len_capacity); } +#undef DRW_TEST_ASSIGN_VBO +#undef DRW_TEST_ASSIGN_IBO + int nu_id = 0; for (Nurb *nu = (Nurb *)rdata->nurbs->first; nu; nu = nu->next, nu_id++) { const BezTriple *bezt = nu->bezt; @@ -796,7 +876,7 @@ static void curve_create_edit_data_and_handles(CurveRenderData *rdata, if (bezt) { for (int a = 0; a < nu->pntsu; a++, bezt++) { - if (bezt->hide == true) { + if (bezt->hide != 0) { continue; } const bool handle_selected = BEZT_ISSEL_ANY(bezt); @@ -831,7 +911,7 @@ static void curve_create_edit_data_and_handles(CurveRenderData *rdata, else if (bp) { int pt_len = nu->pntsu * nu->pntsv; for (int a = 0; a < pt_len; a++, bp++, vbo_len_used += 1) { - if (bp->hide == true) { + if (bp->hide != 0) { continue; } int u = (a % nu->pntsu); @@ -1070,8 +1150,11 @@ void DRW_curve_batch_cache_create_requested(Object *ob, const struct Scene *scen CurveRenderData *rdata = curve_render_data_create(cu, ob->runtime.curve_cache, mr_flag); - /* DispLists */ - ListBase *lb = &rdata->ob_curve_cache->disp; + /* The object's curve cache can be empty (in one case because we use #CurveEval's cache instead), + * If so, point to an empty DispList list to avoid the need to check for null in the following + * functions. */ + ListBase empty_lb = {nullptr, nullptr}; + ListBase *lb = rdata->ob_curve_cache == nullptr ? &empty_lb : &rdata->ob_curve_cache->disp; /* Generate VBOs */ if (DRW_vbo_requested(cache->ordered.pos_nor)) { diff --git a/source/blender/draw/intern/draw_cache_impl_displist.c b/source/blender/draw/intern/draw_cache_impl_displist.c index d606f70db9e..ee16cb1a022 100644 --- a/source/blender/draw/intern/draw_cache_impl_displist.c +++ b/source/blender/draw/intern/draw_cache_impl_displist.c @@ -532,6 +532,8 @@ void DRW_displist_vertbuf_create_loop_pos_and_nor_and_uv_and_tan(ListBase *lb, GPUVertBufRaw uv_step = {0}; GPUVertBufRaw tan_step = {0}; +#define DRW_TEST_ASSIGN_VBO(v) (v = (DRW_vbo_requested(v) ? (v) : NULL)) + if (DRW_TEST_ASSIGN_VBO(vbo_pos_nor)) { GPU_vertbuf_init_with_format(vbo_pos_nor, do_hq_normals ? &format_pos_nor_hq : &format_pos_nor); @@ -550,6 +552,8 @@ void DRW_displist_vertbuf_create_loop_pos_and_nor_and_uv_and_tan(ListBase *lb, GPU_vertbuf_attr_get_raw_data(vbo_tan, tan_id, &tan_step); } +#undef DRW_TEST_ASSIGN_VBO + BKE_displist_normals_add(lb); LISTBASE_FOREACH (const DispList *, dl, lb) { diff --git a/source/blender/draw/intern/draw_cache_impl_gpencil.c b/source/blender/draw/intern/draw_cache_impl_gpencil.c index 49b5e0fecd3..bea9ba1122b 100644 --- a/source/blender/draw/intern/draw_cache_impl_gpencil.c +++ b/source/blender/draw/intern/draw_cache_impl_gpencil.c @@ -405,7 +405,7 @@ static void gpencil_batches_ensure(Object *ob, GpencilBatchCache *cache, int cfr if (cache->vbo == NULL) { /* Should be discarded together. */ BLI_assert(cache->vbo == NULL && cache->ibo == NULL); - BLI_assert(cache->stroke_batch == NULL && cache->stroke_batch == NULL); + BLI_assert(cache->fill_batch == NULL && cache->stroke_batch == NULL); /* TODO/PERF: Could be changed to only do it if needed. * For now it's simpler to assume we always need it * since multiple viewport could or could not need it. diff --git a/source/blender/draw/intern/draw_cache_impl_hair.c b/source/blender/draw/intern/draw_cache_impl_hair.c index fd28ac00186..6424b21666d 100644 --- a/source/blender/draw/intern/draw_cache_impl_hair.c +++ b/source/blender/draw/intern/draw_cache_impl_hair.c @@ -243,7 +243,8 @@ static void hair_batch_cache_ensure_procedural_final_points(ParticleHairCache *c GPUVertFormat format = {0}; GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); - cache->final[subdiv].proc_buf = GPU_vertbuf_create_with_format(&format); + cache->final[subdiv].proc_buf = GPU_vertbuf_create_with_format_ex(&format, + GPU_USAGE_DEVICE_ONLY); /* Create a destination buffer for the transform feedback. Sized appropriately */ /* Those are points! not line segments. */ diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index af54b57b162..3cc71e47f28 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -707,6 +707,26 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, eMeshBatchDirtyMode mode) } } +static void mesh_buffer_cache_clear(MeshBufferCache *mbufcache) +{ + GPUVertBuf **vbos = (GPUVertBuf **)&mbufcache->vbo; + GPUIndexBuf **ibos = (GPUIndexBuf **)&mbufcache->ibo; + for (int i = 0; i < sizeof(mbufcache->vbo) / sizeof(void *); i++) { + GPU_VERTBUF_DISCARD_SAFE(vbos[i]); + } + for (int i = 0; i < sizeof(mbufcache->ibo) / sizeof(void *); i++) { + GPU_INDEXBUF_DISCARD_SAFE(ibos[i]); + } +} + +static void mesh_buffer_extraction_cache_clear(MeshBufferExtractionCache *extraction_cache) +{ + MEM_SAFE_FREE(extraction_cache->lverts); + MEM_SAFE_FREE(extraction_cache->ledges); + extraction_cache->edge_loose_len = 0; + extraction_cache->vert_loose_len = 0; +} + static void mesh_batch_cache_clear(Mesh *me) { MeshBatchCache *cache = me->runtime.batch_cache; @@ -714,16 +734,13 @@ static void mesh_batch_cache_clear(Mesh *me) return; } FOREACH_MESH_BUFFER_CACHE (cache, mbufcache) { - GPUVertBuf **vbos = (GPUVertBuf **)&mbufcache->vbo; - GPUIndexBuf **ibos = (GPUIndexBuf **)&mbufcache->ibo; - for (int i = 0; i < sizeof(mbufcache->vbo) / sizeof(void *); i++) { - GPU_VERTBUF_DISCARD_SAFE(vbos[i]); - } - for (int i = 0; i < sizeof(mbufcache->ibo) / sizeof(void *); i++) { - GPU_INDEXBUF_DISCARD_SAFE(ibos[i]); - } + mesh_buffer_cache_clear(mbufcache); } + mesh_buffer_extraction_cache_clear(&cache->final_extraction_cache); + mesh_buffer_extraction_cache_clear(&cache->cage_extraction_cache); + mesh_buffer_extraction_cache_clear(&cache->uv_cage_extraction_cache); + for (int i = 0; i < cache->mat_len; i++) { GPU_INDEXBUF_DISCARD_SAFE(cache->final.tris_per_mat[i]); } @@ -1160,25 +1177,25 @@ static void drw_mesh_batch_cache_check_available(struct TaskGraph *task_graph, M * some issues (See T77867 where we needed to disable this function in order to debug what was * happening in release builds). */ BLI_task_graph_work_and_wait(task_graph); - for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); i++) { + for (int i = 0; i < MBC_BATCH_LEN; i++) { BLI_assert(!DRW_batch_requested(((GPUBatch **)&cache->batch)[i], 0)); } - for (int i = 0; i < sizeof(cache->final.vbo) / sizeof(void *); i++) { + for (int i = 0; i < MBC_VBO_LEN; i++) { BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->final.vbo)[i])); } - for (int i = 0; i < sizeof(cache->final.ibo) / sizeof(void *); i++) { + for (int i = 0; i < MBC_IBO_LEN; i++) { BLI_assert(!DRW_ibo_requested(((GPUIndexBuf **)&cache->final.ibo)[i])); } - for (int i = 0; i < sizeof(cache->cage.vbo) / sizeof(void *); i++) { + for (int i = 0; i < MBC_VBO_LEN; i++) { BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->cage.vbo)[i])); } - for (int i = 0; i < sizeof(cache->cage.ibo) / sizeof(void *); i++) { + for (int i = 0; i < MBC_IBO_LEN; i++) { BLI_assert(!DRW_ibo_requested(((GPUIndexBuf **)&cache->cage.ibo)[i])); } - for (int i = 0; i < sizeof(cache->uv_cage.vbo) / sizeof(void *); i++) { + for (int i = 0; i < MBC_VBO_LEN; i++) { BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->uv_cage.vbo)[i])); } - for (int i = 0; i < sizeof(cache->uv_cage.ibo) / sizeof(void *); i++) { + for (int i = 0; i < MBC_IBO_LEN; i++) { BLI_assert(!DRW_ibo_requested(((GPUIndexBuf **)&cache->uv_cage.ibo)[i])); } } @@ -1542,7 +1559,8 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, if (do_uvcage) { mesh_buffer_cache_create_requested(task_graph, cache, - cache->uv_cage, + &cache->uv_cage, + &cache->uv_cage_extraction_cache, me, is_editmode, is_paint_mode, @@ -1551,7 +1569,6 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, false, true, false, - &cache->cd_used, scene, ts, true); @@ -1560,7 +1577,8 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, if (do_cage) { mesh_buffer_cache_create_requested(task_graph, cache, - cache->cage, + &cache->cage, + &cache->cage_extraction_cache, me, is_editmode, is_paint_mode, @@ -1569,7 +1587,6 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, false, false, use_subsurf_fdots, - &cache->cd_used, scene, ts, true); @@ -1577,7 +1594,8 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, mesh_buffer_cache_create_requested(task_graph, cache, - cache->final, + &cache->final, + &cache->final_extraction_cache, me, is_editmode, is_paint_mode, @@ -1586,7 +1604,6 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, true, false, use_subsurf_fdots, - &cache->cd_used, scene, ts, use_hide); diff --git a/source/blender/draw/intern/draw_cache_inline.h b/source/blender/draw/intern/draw_cache_inline.h index bfc714e5d6a..6e537a3bffa 100644 --- a/source/blender/draw/intern/draw_cache_inline.h +++ b/source/blender/draw/intern/draw_cache_inline.h @@ -40,10 +40,6 @@ (flag |= DRW_ibo_requested(ibo) ? (value) : 0) #endif -/* Test and assign NULL if test fails */ -#define DRW_TEST_ASSIGN_VBO(v) (v = (DRW_vbo_requested(v) ? (v) : NULL)) -#define DRW_TEST_ASSIGN_IBO(v) (v = (DRW_ibo_requested(v) ? (v) : NULL)) - BLI_INLINE GPUBatch *DRW_batch_request(GPUBatch **batch) { /* XXX TODO(fclem): We are writing to batch cache here. Need to make this thread safe. */ diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c index bca227a24e2..585e171adc5 100644 --- a/source/blender/draw/intern/draw_hair.c +++ b/source/blender/draw/intern/draw_hair.c @@ -36,15 +36,28 @@ #include "BKE_duplilist.h" #include "GPU_batch.h" +#include "GPU_capabilities.h" +#include "GPU_compute.h" #include "GPU_shader.h" +#include "GPU_texture.h" #include "GPU_vertex_buffer.h" #include "draw_hair_private.h" #ifndef __APPLE__ # define USE_TRANSFORM_FEEDBACK +# define USE_COMPUTE_SHADERS #endif +BLI_INLINE bool drw_hair_use_compute_shaders(void) +{ +#ifdef USE_COMPUTE_SHADERS + return GPU_compute_shader_support(); +#else + return false; +#endif +} + typedef enum ParticleRefineShader { PART_REFINE_CATMULL_ROM = 0, PART_REFINE_MAX_SHADER, @@ -71,38 +84,89 @@ static DRWPass *g_tf_pass; /* XXX can be a problem with multiple DRWManager in t extern char datatoc_common_hair_lib_glsl[]; extern char datatoc_common_hair_refine_vert_glsl[]; +extern char datatoc_common_hair_refine_comp_glsl[]; extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[]; -static GPUShader *hair_refine_shader_get(ParticleRefineShader sh) +/* TODO(jbakker): move shader creation to `draw_shaders` and add test cases. */ +/* TODO(jbakker): replace defines with `constexpr` to check compilation on all OS's. + * Currently the `__APPLE__` code-path does not compile on other platforms and vice versa. */ +#ifdef USE_COMPUTE_SHADERS +static GPUShader *hair_refine_shader_compute_create(ParticleRefineShader UNUSED(refinement)) { - if (g_refine_shaders[sh]) { - return g_refine_shaders[sh]; - } - - char *vert_with_lib = BLI_string_joinN(datatoc_common_hair_lib_glsl, - datatoc_common_hair_refine_vert_glsl); + GPUShader *sh = NULL; + sh = GPU_shader_create_compute(datatoc_common_hair_refine_comp_glsl, + datatoc_common_hair_lib_glsl, + "#define HAIR_PHASE_SUBDIV\n", + __func__); + return sh; +} +#endif #ifdef USE_TRANSFORM_FEEDBACK +static GPUShader *hair_refine_shader_transform_feedback_create( + ParticleRefineShader UNUSED(refinement)) +{ + GPUShader *sh = NULL; + + char *shader_src = BLI_string_joinN(datatoc_common_hair_lib_glsl, + datatoc_common_hair_refine_vert_glsl); const char *var_names[1] = {"finalColor"}; - g_refine_shaders[sh] = DRW_shader_create_with_transform_feedback( - vert_with_lib, NULL, "#define HAIR_PHASE_SUBDIV\n", GPU_SHADER_TFB_POINTS, var_names, 1); -#else - g_refine_shaders[sh] = DRW_shader_create(vert_with_lib, - NULL, - datatoc_gpu_shader_3D_smooth_color_frag_glsl, - "#define blender_srgb_to_framebuffer_space(a) a\n" - "#define HAIR_PHASE_SUBDIV\n" - "#define TF_WORKAROUND\n"); + sh = DRW_shader_create_with_transform_feedback( + shader_src, NULL, "#define HAIR_PHASE_SUBDIV\n", GPU_SHADER_TFB_POINTS, var_names, 1); + MEM_freeN(shader_src); + + return sh; +} #endif - MEM_freeN(vert_with_lib); +static GPUShader *hair_refine_shader_transform_feedback_workaround_create( + ParticleRefineShader UNUSED(refinement)) +{ + GPUShader *sh = NULL; + + char *shader_src = BLI_string_joinN(datatoc_common_hair_lib_glsl, + datatoc_common_hair_refine_vert_glsl); + sh = DRW_shader_create(shader_src, + NULL, + datatoc_gpu_shader_3D_smooth_color_frag_glsl, + "#define blender_srgb_to_framebuffer_space(a) a\n" + "#define HAIR_PHASE_SUBDIV\n" + "#define TF_WORKAROUND\n"); + MEM_freeN(shader_src); + + return sh; +} + +static GPUShader *hair_refine_shader_get(ParticleRefineShader refinement) +{ + if (g_refine_shaders[refinement]) { + return g_refine_shaders[refinement]; + } + +#ifdef USE_COMPUTE_SHADERS + if (drw_hair_use_compute_shaders()) { + g_refine_shaders[refinement] = hair_refine_shader_compute_create(refinement); + if (g_refine_shaders[refinement]) { + return g_refine_shaders[refinement]; + } + } +#endif + +#ifdef USE_TRANSFORM_FEEDBACK + g_refine_shaders[refinement] = hair_refine_shader_transform_feedback_create(refinement); + if (g_refine_shaders[refinement]) { + return g_refine_shaders[refinement]; + } +#endif - return g_refine_shaders[sh]; + g_refine_shaders[refinement] = hair_refine_shader_transform_feedback_workaround_create( + refinement); + return g_refine_shaders[refinement]; } void DRW_hair_init(void) { -#ifdef USE_TRANSFORM_FEEDBACK +#if defined(USE_TRANSFORM_FEEDBACK) || defined(USE_COMPUTE_SHADERS) g_tf_pass = DRW_pass_create("Update Hair Pass", 0); #else g_tf_pass = DRW_pass_create("Update Hair Pass", DRW_STATE_WRITE_COLOR); @@ -125,6 +189,67 @@ void DRW_hair_init(void) } } +static void drw_hair_particle_cache_shgrp_attach_resources(DRWShadingGroup *shgrp, + ParticleHairCache *cache, + const int subdiv) +{ + DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", cache->point_tex); + DRW_shgroup_uniform_texture(shgrp, "hairStrandBuffer", cache->strand_tex); + DRW_shgroup_uniform_texture(shgrp, "hairStrandSegBuffer", cache->strand_seg_tex); + DRW_shgroup_uniform_int(shgrp, "hairStrandsRes", &cache->final[subdiv].strands_res, 1); +} + +static void drw_hair_particle_cache_update_compute(ParticleHairCache *cache, const int subdiv) +{ + const int strands_len = cache->strands_len; + const int final_points_len = cache->final[subdiv].strands_res * strands_len; + if (final_points_len > 0) { + GPUShader *shader = hair_refine_shader_get(PART_REFINE_CATMULL_ROM); + DRWShadingGroup *shgrp = DRW_shgroup_create(shader, g_tf_pass); + drw_hair_particle_cache_shgrp_attach_resources(shgrp, cache, subdiv); + DRW_shgroup_vertex_buffer(shgrp, "hairPointOutputBuffer", cache->final[subdiv].proc_buf); + + const int max_strands_per_call = GPU_max_work_group_count(0); + int strands_start = 0; + while (strands_start < strands_len) { + int batch_strands_len = MIN2(strands_len - strands_start, max_strands_per_call); + DRWShadingGroup *subgroup = DRW_shgroup_create_sub(shgrp); + DRW_shgroup_uniform_int_copy(subgroup, "hairStrandOffset", strands_start); + DRW_shgroup_call_compute(subgroup, batch_strands_len, cache->final[subdiv].strands_res, 1); + strands_start += batch_strands_len; + } + } +} + +static void drw_hair_particle_cache_update_transform_feedback(ParticleHairCache *cache, + const int subdiv) +{ + const int final_points_len = cache->final[subdiv].strands_res * cache->strands_len; + if (final_points_len > 0) { + GPUShader *tf_shader = hair_refine_shader_get(PART_REFINE_CATMULL_ROM); + +#ifdef USE_TRANSFORM_FEEDBACK + DRWShadingGroup *tf_shgrp = DRW_shgroup_transform_feedback_create( + tf_shader, g_tf_pass, cache->final[subdiv].proc_buf); +#else + DRWShadingGroup *tf_shgrp = DRW_shgroup_create(tf_shader, g_tf_pass); + + ParticleRefineCall *pr_call = MEM_mallocN(sizeof(*pr_call), __func__); + pr_call->next = g_tf_calls; + pr_call->vbo = cache->final[subdiv].proc_buf; + pr_call->shgrp = tf_shgrp; + pr_call->vert_len = final_points_len; + g_tf_calls = pr_call; + DRW_shgroup_uniform_int(tf_shgrp, "targetHeight", &g_tf_target_height, 1); + DRW_shgroup_uniform_int(tf_shgrp, "targetWidth", &g_tf_target_width, 1); + DRW_shgroup_uniform_int(tf_shgrp, "idOffset", &g_tf_id_offset, 1); +#endif + + drw_hair_particle_cache_shgrp_attach_resources(tf_shgrp, cache, subdiv); + DRW_shgroup_call_procedural_points(tf_shgrp, NULL, final_points_len); + } +} + static ParticleHairCache *drw_hair_particle_cache_get( Object *object, ParticleSystem *psys, ModifierData *md, int subdiv, int thickness_res) { @@ -140,32 +265,11 @@ static ParticleHairCache *drw_hair_particle_cache_get( } if (update) { - int final_points_len = cache->final[subdiv].strands_res * cache->strands_len; - if (final_points_len > 0) { - GPUShader *tf_shader = hair_refine_shader_get(PART_REFINE_CATMULL_ROM); - -#ifdef USE_TRANSFORM_FEEDBACK - DRWShadingGroup *tf_shgrp = DRW_shgroup_transform_feedback_create( - tf_shader, g_tf_pass, cache->final[subdiv].proc_buf); -#else - DRWShadingGroup *tf_shgrp = DRW_shgroup_create(tf_shader, g_tf_pass); - - ParticleRefineCall *pr_call = MEM_mallocN(sizeof(*pr_call), __func__); - pr_call->next = g_tf_calls; - pr_call->vbo = cache->final[subdiv].proc_buf; - pr_call->shgrp = tf_shgrp; - pr_call->vert_len = final_points_len; - g_tf_calls = pr_call; - DRW_shgroup_uniform_int(tf_shgrp, "targetHeight", &g_tf_target_height, 1); - DRW_shgroup_uniform_int(tf_shgrp, "targetWidth", &g_tf_target_width, 1); - DRW_shgroup_uniform_int(tf_shgrp, "idOffset", &g_tf_id_offset, 1); -#endif - - DRW_shgroup_uniform_texture(tf_shgrp, "hairPointBuffer", cache->point_tex); - DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandBuffer", cache->strand_tex); - DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandSegBuffer", cache->strand_seg_tex); - DRW_shgroup_uniform_int(tf_shgrp, "hairStrandsRes", &cache->final[subdiv].strands_res, 1); - DRW_shgroup_call_procedural_points(tf_shgrp, NULL, final_points_len); + if (drw_hair_use_compute_shaders()) { + drw_hair_particle_cache_update_compute(cache, subdiv); + } + else { + drw_hair_particle_cache_update_transform_feedback(cache, subdiv); } } return cache; @@ -367,9 +471,11 @@ void DRW_hair_update(void) MEM_freeN(data); GPU_framebuffer_free(fb); #else - /* TODO(fclem): replace by compute shader. */ - /* Just render using transform feedback. */ + /* Just render the pass when using compute shaders or transform feedback. */ DRW_draw_pass(g_tf_pass); + if (drw_hair_use_compute_shaders()) { + GPU_memory_barrier(GPU_BARRIER_SHADER_STORAGE); + } #endif } diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h index 84bc0327aa2..d4e22c83798 100644 --- a/source/blender/draw/intern/draw_manager.h +++ b/source/blender/draw/intern/draw_manager.h @@ -187,6 +187,10 @@ typedef enum { DRW_CMD_DRAW_INSTANCE = 2, DRW_CMD_DRAW_INSTANCE_RANGE = 3, DRW_CMD_DRAW_PROCEDURAL = 4, + + /* Compute Commands. */ + DRW_CMD_COMPUTE = 8, + /* Other Commands */ DRW_CMD_CLEAR = 12, DRW_CMD_DRWSTATE = 13, @@ -224,6 +228,12 @@ typedef struct DRWCommandDrawInstanceRange { uint inst_count; } DRWCommandDrawInstanceRange; +typedef struct DRWCommandCompute { + int groups_x_len; + int groups_y_len; + int groups_z_len; +} DRWCommandCompute; + typedef struct DRWCommandDrawProcedural { GPUBatch *batch; DRWResourceHandle handle; @@ -260,6 +270,7 @@ typedef union DRWCommand { DRWCommandDrawInstance instance; DRWCommandDrawInstanceRange instance_range; DRWCommandDrawProcedural procedural; + DRWCommandCompute compute; DRWCommandSetMutableState state; DRWCommandSetStencil stencil; DRWCommandSetSelectID select_id; @@ -274,6 +285,7 @@ struct DRWCallBuffer { }; /** Used by #DRWUniform.type */ +/* TODO(jbakker): rename to DRW_RESOURCE/DRWResourceType. */ typedef enum { DRW_UNIFORM_INT = 0, DRW_UNIFORM_INT_COPY, @@ -286,6 +298,7 @@ typedef enum { DRW_UNIFORM_BLOCK, DRW_UNIFORM_BLOCK_REF, DRW_UNIFORM_TFEEDBACK_TARGET, + DRW_UNIFORM_VERTEX_BUFFER_AS_STORAGE, /** Per drawcall uniforms/UBO */ DRW_UNIFORM_BLOCK_OBMATS, DRW_UNIFORM_BLOCK_OBINFOS, diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c index 6bdc5305fed..3b852e7f8c8 100644 --- a/source/blender/draw/intern/draw_manager_data.c +++ b/source/blender/draw/intern/draw_manager_data.c @@ -47,6 +47,7 @@ #endif #include "GPU_buffers.h" +#include "GPU_capabilities.h" #include "GPU_material.h" #include "GPU_uniform_buffer.h" @@ -446,6 +447,19 @@ void DRW_shgroup_uniform_vec4_array_copy(DRWShadingGroup *shgroup, } } +void DRW_shgroup_vertex_buffer(DRWShadingGroup *shgroup, + const char *name, + GPUVertBuf *vertex_buffer) +{ + int location = GPU_shader_get_ssbo(shgroup->shader, name); + if (location == -1) { + BLI_assert(false && "Unable to locate binding of shader storage buffer objects."); + return; + } + drw_shgroup_uniform_create_ex( + shgroup, location, DRW_UNIFORM_VERTEX_BUFFER_AS_STORAGE, vertex_buffer, 0, 0, 1); +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -700,6 +714,17 @@ static void drw_command_draw_intance_range( cmd->inst_count = count; } +static void drw_command_compute(DRWShadingGroup *shgroup, + int groups_x_len, + int groups_y_len, + int groups_z_len) +{ + DRWCommandCompute *cmd = drw_command_create(shgroup, DRW_CMD_COMPUTE); + cmd->groups_x_len = groups_x_len; + cmd->groups_y_len = groups_y_len; + cmd->groups_z_len = groups_z_len; +} + static void drw_command_draw_procedural(DRWShadingGroup *shgroup, GPUBatch *batch, DRWResourceHandle handle, @@ -815,6 +840,17 @@ void DRW_shgroup_call_instance_range( drw_command_draw_intance_range(shgroup, geom, handle, i_sta, i_ct); } +void DRW_shgroup_call_compute(DRWShadingGroup *shgroup, + int groups_x_len, + int groups_y_len, + int groups_z_len) +{ + BLI_assert(groups_x_len > 0 && groups_y_len > 0 && groups_z_len > 0); + BLI_assert(GPU_compute_shader_support()); + + drw_command_compute(shgroup, groups_x_len, groups_y_len, groups_z_len); +} + static void drw_shgroup_call_procedural_add_ex(DRWShadingGroup *shgroup, GPUBatch *geom, Object *ob, diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c index 4c8fcb0e016..f29caebeb84 100644 --- a/source/blender/draw/intern/draw_manager_exec.c +++ b/source/blender/draw/intern/draw_manager_exec.c @@ -29,6 +29,7 @@ #include "BKE_global.h" +#include "GPU_compute.h" #include "GPU_platform.h" #include "GPU_shader.h" #include "GPU_state.h" @@ -672,6 +673,9 @@ static void draw_update_uniforms(DRWShadingGroup *shgroup, *use_tfeedback = GPU_shader_transform_feedback_enable(shgroup->shader, ((GPUVertBuf *)uni->pvalue)); break; + case DRW_UNIFORM_VERTEX_BUFFER_AS_STORAGE: + GPU_vertbuf_bind_as_ssbo((GPUVertBuf *)uni->pvalue, uni->location); + break; /* Legacy/Fallback support. */ case DRW_UNIFORM_BASE_INSTANCE: state->baseinst_loc = uni->location; @@ -1050,6 +1054,12 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) cmd->instance_range.inst_count, false); break; + case DRW_CMD_COMPUTE: + GPU_compute_dispatch(shgroup->shader, + cmd->compute.groups_x_len, + cmd->compute.groups_y_len, + cmd->compute.groups_z_len); + break; } } diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c index 2aad1f10154..83d0030f89b 100644 --- a/source/blender/draw/intern/draw_manager_shader.c +++ b/source/blender/draw/intern/draw_manager_shader.c @@ -396,6 +396,7 @@ GPUShader *DRW_shader_create_with_transform_feedback(const char *vert, datatoc_gpu_shader_depth_only_frag_glsl, geom, NULL, + NULL, defines, prim_type, varying_names, diff --git a/source/blender/draw/intern/shaders/common_hair_lib.glsl b/source/blender/draw/intern/shaders/common_hair_lib.glsl index 8684d82f228..02c335ddae2 100644 --- a/source/blender/draw/intern/shaders/common_hair_lib.glsl +++ b/source/blender/draw/intern/shaders/common_hair_lib.glsl @@ -28,6 +28,9 @@ uniform bool hairCloseTip = true; uniform vec4 hairDupliMatrix[4]; +/* Strand batch offset when used in compute shaders. */ +uniform int hairStrandOffset = 0; + /* -- Per control points -- */ uniform samplerBuffer hairPointBuffer; /* RGBA32F */ #define point_position xyz @@ -43,13 +46,37 @@ uniform usamplerBuffer hairStrandSegBuffer; /* R16UI */ /* -- Subdivision stage -- */ /** - * We use a transform feedback to preprocess the strands and add more subdivision to it. - * For the moment these are simple smooth interpolation but one could hope to see the full + * We use a transform feedback or compute shader to preprocess the strands and add more subdivision + * to it. For the moment these are simple smooth interpolation but one could hope to see the full * children particle modifiers being evaluated at this stage. * * If no more subdivision is needed, we can skip this step. */ +#ifdef GPU_VERTEX_SHADER +float hair_get_local_time() +{ + return float(gl_VertexID % hairStrandsRes) / float(hairStrandsRes - 1); +} + +int hair_get_id() +{ + return gl_VertexID / hairStrandsRes; +} +#endif + +#ifdef GPU_COMPUTE_SHADER +float hair_get_local_time() +{ + return float(gl_GlobalInvocationID.y) / float(hairStrandsRes - 1); +} + +int hair_get_id() +{ + return int(gl_GlobalInvocationID.x) + hairStrandOffset; +} +#endif + #ifdef HAIR_PHASE_SUBDIV int hair_get_base_id(float local_time, int strand_segments, out float interp_time) { @@ -64,9 +91,9 @@ int hair_get_base_id(float local_time, int strand_segments, out float interp_tim void hair_get_interp_attrs( out vec4 data0, out vec4 data1, out vec4 data2, out vec4 data3, out float interp_time) { - float local_time = float(gl_VertexID % hairStrandsRes) / float(hairStrandsRes - 1); + float local_time = hair_get_local_time(); - int hair_id = gl_VertexID / hairStrandsRes; + int hair_id = hair_get_id(); int strand_offset = int(texelFetch(hairStrandBuffer, hair_id).x); int strand_segments = int(texelFetch(hairStrandSegBuffer, hair_id).x); @@ -96,6 +123,7 @@ void hair_get_interp_attrs( */ #if !defined(HAIR_PHASE_SUBDIV) && defined(GPU_VERTEX_SHADER) + int hair_get_strand_id(void) { return gl_VertexID / (hairStrandsRes * hairThicknessRes); @@ -227,3 +255,45 @@ vec2 hair_resolve_barycentric(vec2 vert_barycentric) return vec2(1.0 - vert_barycentric.x, 0.0); } } + +/* Hair interpolation functions. */ +vec4 hair_get_weights_cardinal(float t) +{ + float t2 = t * t; + float t3 = t2 * t; +#if defined(CARDINAL) + float fc = 0.71; +#else /* defined(CATMULL_ROM) */ + float fc = 0.5; +#endif + + vec4 weights; + /* GLSL Optimized version of key_curve_position_weights() */ + float fct = t * fc; + float fct2 = t2 * fc; + float fct3 = t3 * fc; + weights.x = (fct2 * 2.0 - fct3) - fct; + weights.y = (t3 * 2.0 - fct3) + (-t2 * 3.0 + fct2) + 1.0; + weights.z = (-t3 * 2.0 + fct3) + (t2 * 3.0 - (2.0 * fct2)) + fct; + weights.w = fct3 - fct2; + return weights; +} + +/* TODO(fclem): This one is buggy, find why. (it's not the optimization!!) */ +vec4 hair_get_weights_bspline(float t) +{ + float t2 = t * t; + float t3 = t2 * t; + + vec4 weights; + /* GLSL Optimized version of key_curve_position_weights() */ + weights.xz = vec2(-0.16666666, -0.5) * t3 + (0.5 * t2 + 0.5 * vec2(-t, t) + 0.16666666); + weights.y = (0.5 * t3 - t2 + 0.66666666); + weights.w = (0.16666666 * t3); + return weights; +} + +vec4 hair_interp_data(vec4 v0, vec4 v1, vec4 v2, vec4 v3, vec4 w) +{ + return v0 * w.x + v1 * w.y + v2 * w.z + v3 * w.w; +} diff --git a/source/blender/draw/intern/shaders/common_hair_refine_comp.glsl b/source/blender/draw/intern/shaders/common_hair_refine_comp.glsl new file mode 100644 index 00000000000..4dcde4b0245 --- /dev/null +++ b/source/blender/draw/intern/shaders/common_hair_refine_comp.glsl @@ -0,0 +1,24 @@ + +/* + * To be compiled with common_hair_lib.glsl. + */ + +layout(local_size_x = 1, local_size_y = 1) in; +layout(std430, binding = 0) writeonly buffer hairPointOutputBuffer +{ + vec4 posTime[]; +} +out_vertbuf; + +void main(void) +{ + float interp_time; + vec4 data0, data1, data2, data3; + hair_get_interp_attrs(data0, data1, data2, data3, interp_time); + + vec4 weights = hair_get_weights_cardinal(interp_time); + vec4 result = hair_interp_data(data0, data1, data2, data3, weights); + + uint index = uint(hair_get_id() * hairStrandsRes) + gl_GlobalInvocationID.y; + out_vertbuf.posTime[index] = result; +} diff --git a/source/blender/draw/intern/shaders/common_hair_refine_vert.glsl b/source/blender/draw/intern/shaders/common_hair_refine_vert.glsl index 3f5e3f8226f..371d43827b9 100644 --- a/source/blender/draw/intern/shaders/common_hair_refine_vert.glsl +++ b/source/blender/draw/intern/shaders/common_hair_refine_vert.glsl @@ -3,47 +3,6 @@ out vec4 finalColor; -vec4 get_weights_cardinal(float t) -{ - float t2 = t * t; - float t3 = t2 * t; -#if defined(CARDINAL) - float fc = 0.71; -#else /* defined(CATMULL_ROM) */ - float fc = 0.5; -#endif - - vec4 weights; - /* GLSL Optimized version of key_curve_position_weights() */ - float fct = t * fc; - float fct2 = t2 * fc; - float fct3 = t3 * fc; - weights.x = (fct2 * 2.0 - fct3) - fct; - weights.y = (t3 * 2.0 - fct3) + (-t2 * 3.0 + fct2) + 1.0; - weights.z = (-t3 * 2.0 + fct3) + (t2 * 3.0 - (2.0 * fct2)) + fct; - weights.w = fct3 - fct2; - return weights; -} - -/* TODO(fclem): This one is buggy, find why. (it's not the optimization!!) */ -vec4 get_weights_bspline(float t) -{ - float t2 = t * t; - float t3 = t2 * t; - - vec4 weights; - /* GLSL Optimized version of key_curve_position_weights() */ - weights.xz = vec2(-0.16666666, -0.5) * t3 + (0.5 * t2 + 0.5 * vec2(-t, t) + 0.16666666); - weights.y = (0.5 * t3 - t2 + 0.66666666); - weights.w = (0.16666666 * t3); - return weights; -} - -vec4 interp_data(vec4 v0, vec4 v1, vec4 v2, vec4 v3, vec4 w) -{ - return v0 * w.x + v1 * w.y + v2 * w.z + v3 * w.w; -} - #ifdef TF_WORKAROUND uniform int targetWidth; uniform int targetHeight; @@ -56,8 +15,8 @@ void main(void) vec4 data0, data1, data2, data3; hair_get_interp_attrs(data0, data1, data2, data3, interp_time); - vec4 weights = get_weights_cardinal(interp_time); - finalColor = interp_data(data0, data1, data2, data3, weights); + vec4 weights = hair_get_weights_cardinal(interp_time); + finalColor = hair_interp_data(data0, data1, data2, data3, weights); #ifdef TF_WORKAROUND int id = gl_VertexID - idOffset; diff --git a/source/blender/draw/intern/shaders/common_math_lib.glsl b/source/blender/draw/intern/shaders/common_math_lib.glsl index 33deae0b0a1..479f9cd1827 100644 --- a/source/blender/draw/intern/shaders/common_math_lib.glsl +++ b/source/blender/draw/intern/shaders/common_math_lib.glsl @@ -86,6 +86,8 @@ float safe_rcp(float a) { return (a != 0.0) ? (1.0 / a) : 0.0; } vec2 safe_rcp(vec2 a) { return mix(vec2(0.0), (1.0 / a), notEqual(a, vec2(0.0))); } vec4 safe_rcp(vec4 a) { return mix(vec4(0.0), (1.0 / a), notEqual(a, vec4(0.0))); } +float safe_sqrt(float a) { return sqrt(max(a, 0.0)); } + float sqr(float a) { return a * a; } vec2 sqr(vec2 a) { return a * a; } vec3 sqr(vec3 a) { return a * a; } |