From e05c36f56d2b6f2eb50b795aa723c568320a9d21 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Tue, 31 Oct 2023 17:33:15 +0100 Subject: [PATCH] Fix #113496: PBVH draw crashes and unsupported attribute types Use more modern approaches for supporting all generic attribute types, rather than hardcoding all of the types and mistakenly correlating types and domains. A "Converter" template class handles conversion to GPU data and describing the GPU format. The class is based on recent work in Cycles attribute upload and is meant to replace the `AttributeTypeConverter` class in `extract_vbo_attributes.cc`. I will do that as a separate step. This structure will give build errors if new attribute types are added but not supported here, preventing the situation described in the report. All generic attribute types are supported now, consistently with non sculpt mode drawing. The edge domain isn't supported though. Typically edges are more costly and complex to access, and interpolation is less well defined anyway. Pull Request: https://projects.blender.org/blender/blender/pulls/114334 --- source/blender/draw/intern/draw_pbvh.cc | 683 +++++++++++++----------- 1 file changed, 382 insertions(+), 301 deletions(-) diff --git a/source/blender/draw/intern/draw_pbvh.cc b/source/blender/draw/intern/draw_pbvh.cc index 6223c4f7abc..ebbc3b1e765 100644 --- a/source/blender/draw/intern/draw_pbvh.cc +++ b/source/blender/draw/intern/draw_pbvh.cc @@ -36,7 +36,8 @@ #include "DNA_meshdata_types.h" #include "BKE_DerivedMesh.h" -#include "BKE_attribute.h" +#include "BKE_attribute.hh" +#include "BKE_attribute_math.hh" #include "BKE_ccg.h" #include "BKE_customdata.h" #include "BKE_mesh.hh" @@ -75,20 +76,147 @@ using blender::ushort3; using blender::ushort4; using blender::Vector; -static bool valid_pbvh_attr(int type) -{ - switch (type) { - case CD_PBVH_CO_TYPE: - case CD_PBVH_NO_TYPE: - case CD_PBVH_FSET_TYPE: - case CD_PBVH_MASK_TYPE: - case CD_PROP_COLOR: - case CD_PROP_BYTE_COLOR: - case CD_PROP_FLOAT2: - return true; - } +/** + * Component length of 3 is used for scalars because implicit conversion is done by OpenGL from a + * scalar `s` will produce `vec4(s, 0, 0, 1)`. However, following the Blender convention, it should + * be `vec4(s, s, s, 1)`. + */ +constexpr int COMPONENT_LEN_SCALAR = 3; - return false; +namespace blender::draw { + +/** Similar to #AttributeTypeConverter. */ +template struct AttributeConverter { + using VBOT = void; +}; + +template<> struct AttributeConverter { + using VBOT = VecBase; + static constexpr GPUVertCompType gpu_component_type = GPU_COMP_I32; + static constexpr int gpu_component_len = COMPONENT_LEN_SCALAR; + static constexpr GPUVertFetchMode gpu_fetch_mode = GPU_FETCH_INT_TO_FLOAT; + static VBOT convert(const bool &value) + { + return VBOT(value); + } +}; +template<> struct AttributeConverter { + using VBOT = VecBase; + static constexpr GPUVertCompType gpu_component_type = GPU_COMP_I32; + static constexpr int gpu_component_len = COMPONENT_LEN_SCALAR; + static constexpr GPUVertFetchMode gpu_fetch_mode = GPU_FETCH_INT_TO_FLOAT; + static VBOT convert(const int8_t &value) + { + return VecBase(value); + } +}; +template<> struct AttributeConverter { + using VBOT = VecBase; + static constexpr GPUVertCompType gpu_component_type = GPU_COMP_I32; + static constexpr int gpu_component_len = COMPONENT_LEN_SCALAR; + static constexpr GPUVertFetchMode gpu_fetch_mode = GPU_FETCH_INT_TO_FLOAT; + static VBOT convert(const int &value) + { + return int3(value); + } +}; +template<> struct AttributeConverter { + using VBOT = int2; + static constexpr GPUVertCompType gpu_component_type = GPU_COMP_I32; + static constexpr int gpu_component_len = 2; + static constexpr GPUVertFetchMode gpu_fetch_mode = GPU_FETCH_INT_TO_FLOAT; + static VBOT convert(const int2 &value) + { + return int2(value.x, value.y); + } +}; +template<> struct AttributeConverter { + using VBOT = VecBase; + static constexpr GPUVertCompType gpu_component_type = GPU_COMP_F32; + static constexpr int gpu_component_len = COMPONENT_LEN_SCALAR; + static constexpr GPUVertFetchMode gpu_fetch_mode = GPU_FETCH_FLOAT; + static VBOT convert(const float &value) + { + return VBOT(value); + } +}; +template<> struct AttributeConverter { + using VBOT = float2; + static constexpr GPUVertCompType gpu_component_type = GPU_COMP_F32; + static constexpr int gpu_component_len = 2; + static constexpr GPUVertFetchMode gpu_fetch_mode = GPU_FETCH_FLOAT; + static VBOT convert(const float2 &value) + { + return value; + } +}; +template<> struct AttributeConverter { + using VBOT = float3; + static constexpr GPUVertCompType gpu_component_type = GPU_COMP_F32; + static constexpr int gpu_component_len = 3; + static constexpr GPUVertFetchMode gpu_fetch_mode = GPU_FETCH_FLOAT; + static VBOT convert(const float3 &value) + { + return value; + } +}; +template<> struct AttributeConverter { + /* 16 bits are required to store the color in linear space without precision loss. */ + using VBOT = ushort4; + static constexpr GPUVertCompType gpu_component_type = GPU_COMP_U16; + static constexpr int gpu_component_len = 4; + static constexpr GPUVertFetchMode gpu_fetch_mode = GPU_FETCH_INT_TO_FLOAT_UNIT; + static VBOT convert(const ColorGeometry4b &value) + { + return {unit_float_to_ushort_clamp(BLI_color_from_srgb_table[value.r]), + unit_float_to_ushort_clamp(BLI_color_from_srgb_table[value.g]), + unit_float_to_ushort_clamp(BLI_color_from_srgb_table[value.b]), + ushort(value.a * 257)}; + } +}; +template<> struct AttributeConverter { + using VBOT = ColorGeometry4f; + static constexpr GPUVertCompType gpu_component_type = GPU_COMP_F32; + static constexpr int gpu_component_len = 4; + static constexpr GPUVertFetchMode gpu_fetch_mode = GPU_FETCH_FLOAT; + static VBOT convert(const ColorGeometry4f &value) + { + return value; + } +}; +template<> struct AttributeConverter { + using VBOT = float4; + static constexpr GPUVertCompType gpu_component_type = GPU_COMP_F32; + static constexpr int gpu_component_len = 4; + static constexpr GPUVertFetchMode gpu_fetch_mode = GPU_FETCH_FLOAT; + static VBOT convert(const blender::math::Quaternion &value) + { + return float4(value.w, value.x, value.y, value.z); + } +}; + +} // namespace blender::draw + +static bool pbvh_attr_supported(int type, const eAttrDomain domain) +{ + using namespace blender; + if (!ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_FACE, ATTR_DOMAIN_CORNER)) { + /* PBVH drawing does not support edge domain attributes. */ + return false; + } + if (ELEM(type, CD_PBVH_CO_TYPE, CD_PBVH_NO_TYPE, CD_PBVH_FSET_TYPE, CD_PBVH_MASK_TYPE)) { + return true; + } + bool type_supported = false; + bke::attribute_math::convert_to_static_type(eCustomDataType(type), [&](auto dummy) { + using T = decltype(dummy); + using Converter = draw::AttributeConverter; + using VBOT = typename Converter::VBOT; + if constexpr (!std::is_void_v) { + type_supported = true; + } + }); + return type_supported; } struct PBVHVbo { @@ -118,46 +246,18 @@ struct PBVHVbo { } }; -template VBOT convert_value(const AttributeT &value) -{ - if constexpr (std::is_same_v) { - return value; - } -} - -template<> inline uchar convert_value(const float &value) -{ - return uchar(value * 255.0f); -} - -template<> inline ushort4 convert_value(const MPropCol &value) -{ - return {unit_float_to_ushort_clamp(value.color[0]), - unit_float_to_ushort_clamp(value.color[1]), - unit_float_to_ushort_clamp(value.color[2]), - unit_float_to_ushort_clamp(value.color[3])}; -} - -template<> inline ushort4 convert_value(const MLoopCol &value) -{ - return {unit_float_to_ushort_clamp(BLI_color_from_srgb_table[value.r]), - unit_float_to_ushort_clamp(BLI_color_from_srgb_table[value.g]), - unit_float_to_ushort_clamp(BLI_color_from_srgb_table[value.b]), - ushort(value.a * 257)}; -} - -template<> inline short4 convert_value(const float3 &value) +inline short4 normal_float_to_short(const float3 &value) { short3 result; normal_float_to_short_v3(result, value); return short4(result.x, result.y, result.z, 0); } -template -void extract_data_vert_faces(const PBVH_GPU_Args &args, - const Span attribute, - GPUVertBuf &vbo) +template +void extract_data_vert_faces(const PBVH_GPU_Args &args, const Span attribute, GPUVertBuf &vbo) { + using Converter = blender::draw::AttributeConverter; + using VBOT = typename Converter::VBOT; const Span corner_verts = args.corner_verts; const Span looptris = args.mlooptri; const Span looptri_faces = args.looptri_faces; @@ -170,17 +270,38 @@ void extract_data_vert_faces(const PBVH_GPU_Args &args, } for (int i : IndexRange(3)) { const int vert = corner_verts[looptris[looptri_i].tri[i]]; - *data = convert_value(attribute[vert]); + *data = Converter::convert(attribute[vert]); data++; } } } -template -void extract_data_corner_faces(const PBVH_GPU_Args &args, - const Span attribute, - GPUVertBuf &vbo) +template +void extract_data_face_faces(const PBVH_GPU_Args &args, const Span attribute, GPUVertBuf &vbo) { + using Converter = blender::draw::AttributeConverter; + using VBOT = typename Converter::VBOT; + + const Span looptri_faces = args.looptri_faces; + const bool *hide_poly = args.hide_poly; + + VBOT *data = static_cast(GPU_vertbuf_get_data(&vbo)); + for (const int looptri_i : args.prim_indices) { + const int face = looptri_faces[looptri_i]; + if (hide_poly && hide_poly[face]) { + continue; + } + std::fill_n(data, 3, Converter::convert(attribute[face])); + data += 3; + } +} + +template +void extract_data_corner_faces(const PBVH_GPU_Args &args, const Span attribute, GPUVertBuf &vbo) +{ + using Converter = blender::draw::AttributeConverter; + using VBOT = typename Converter::VBOT; + const Span looptris = args.mlooptri; const Span looptri_faces = args.looptri_faces; const bool *hide_poly = args.hide_poly; @@ -192,7 +313,7 @@ void extract_data_corner_faces(const PBVH_GPU_Args &args, } for (int i : IndexRange(3)) { const int corner = looptris[looptri_i].tri[i]; - *data = convert_value(attribute[corner]); + *data = Converter::convert(attribute[corner]); data++; } } @@ -344,7 +465,7 @@ struct PBVHBatches { for (int i : IndexRange(attrs_num)) { PBVHAttrReq *attr = attrs + i; - if (!valid_pbvh_attr(attr->type)) { + if (!pbvh_attr_supported(attr->type, attr->domain)) { continue; } @@ -424,17 +545,17 @@ struct PBVHBatches { } if (sharp_faces && sharp_faces[face_i]) { if (face_i != last_face) { - face_no = convert_value(args.face_normals[face_i]); + face_no = normal_float_to_short(args.face_normals[face_i]); last_face = face_i; } - *data = *(data + 1) = *(data + 2) = face_no; + std::fill_n(data, 3, face_no); data += 3; } else { for (const int i : IndexRange(3)) { const int vert = args.corner_verts[args.mlooptri[looptri_i].tri[i]]; - *data = convert_value(args.vert_normals[vert]); + *data = normal_float_to_short(args.vert_normals[vert]); data++; } } @@ -447,6 +568,7 @@ struct PBVHBatches { FunctionRef func)> foreach_grids) { + using namespace blender; uint vert_per_grid = square_i(args.ccg_key.grid_size - 1) * 4; uint vert_count = args.grid_indices.size() * vert_per_grid; @@ -461,103 +583,94 @@ struct PBVHBatches { GPUVertBufRaw access; GPU_vertbuf_attr_get_raw_data(vbo.vert_buf, 0, &access); - switch (vbo.type) { - case CD_PROP_COLOR: - case CD_PROP_BYTE_COLOR: { - /* TODO: Implement color support for multires similar to the mesh cache - * extractor code. For now just upload white. - */ - const ushort4 white(USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX); + if (vbo.type == CD_PBVH_CO_TYPE) { + foreach_grids([&](int /*x*/, int /*y*/, int /*grid_index*/, CCGElem *elems[4], int i) { + float *co = CCG_elem_co(&args.ccg_key, elems[i]); + + *static_cast(GPU_vertbuf_raw_step(&access)) = co; + }); + } + else if (vbo.type == CD_PBVH_NO_TYPE) { + foreach_grids([&](int /*x*/, int /*y*/, int grid_index, CCGElem *elems[4], int /*i*/) { + float3 no(0.0f, 0.0f, 0.0f); + + const bool smooth = !args.grid_flag_mats[grid_index].sharp; + + if (smooth) { + no = CCG_elem_no(&args.ccg_key, elems[0]); + } + else { + normal_quad_v3(no, + CCG_elem_co(&args.ccg_key, elems[3]), + CCG_elem_co(&args.ccg_key, elems[2]), + CCG_elem_co(&args.ccg_key, elems[1]), + CCG_elem_co(&args.ccg_key, elems[0])); + } + + short sno[3]; + + normal_float_to_short_v3(sno, no); + + *static_cast(GPU_vertbuf_raw_step(&access)) = sno; + }); + } + else if (vbo.type == CD_PBVH_MASK_TYPE) { + if (args.ccg_key.has_mask) { + foreach_grids([&](int /*x*/, int /*y*/, int /*grid_index*/, CCGElem *elems[4], int i) { + float *mask = CCG_elem_mask(&args.ccg_key, elems[i]); + + *static_cast(GPU_vertbuf_raw_step(&access)) = *mask; + }); + } + else { + foreach_grids( + [&](int /*x*/, int /*y*/, int /*grid_index*/, CCGElem * /*elems*/[4], int /*i*/) { + *static_cast(GPU_vertbuf_raw_step(&access)) = 0; + }); + } + } + else if (vbo.type == CD_PBVH_FSET_TYPE) { + const int *face_sets = args.face_sets; + + if (!face_sets) { + uchar white[3] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX}; foreach_grids( [&](int /*x*/, int /*y*/, int /*grid_index*/, CCGElem * /*elems*/[4], int /*i*/) { - *static_cast(GPU_vertbuf_raw_step(&access)) = white; + *static_cast(GPU_vertbuf_raw_step(&access)) = white; }); - break; } - case CD_PBVH_CO_TYPE: - foreach_grids([&](int /*x*/, int /*y*/, int /*grid_index*/, CCGElem *elems[4], int i) { - float *co = CCG_elem_co(&args.ccg_key, elems[i]); + else { + foreach_grids( + [&](int /*x*/, int /*y*/, int grid_index, CCGElem * /*elems*/[4], int /*i*/) { + uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX}; - *static_cast(GPU_vertbuf_raw_step(&access)) = co; - }); - break; + if (face_sets) { + const int face_index = BKE_subdiv_ccg_grid_to_face_index(args.subdiv_ccg, + grid_index); + const int fset = face_sets[face_index]; - case CD_PBVH_NO_TYPE: - foreach_grids([&](int /*x*/, int /*y*/, int grid_index, CCGElem *elems[4], int /*i*/) { - float3 no(0.0f, 0.0f, 0.0f); - - const bool smooth = !args.grid_flag_mats[grid_index].sharp; - - if (smooth) { - no = CCG_elem_no(&args.ccg_key, elems[0]); - } - else { - normal_quad_v3(no, - CCG_elem_co(&args.ccg_key, elems[3]), - CCG_elem_co(&args.ccg_key, elems[2]), - CCG_elem_co(&args.ccg_key, elems[1]), - CCG_elem_co(&args.ccg_key, elems[0])); - } - - short sno[3]; - - normal_float_to_short_v3(sno, no); - - *static_cast(GPU_vertbuf_raw_step(&access)) = sno; - }); - break; - - case CD_PBVH_MASK_TYPE: - if (args.ccg_key.has_mask) { - foreach_grids([&](int /*x*/, int /*y*/, int /*grid_index*/, CCGElem *elems[4], int i) { - float *mask = CCG_elem_mask(&args.ccg_key, elems[i]); - - *static_cast(GPU_vertbuf_raw_step(&access)) = *mask; - }); - } - else { - foreach_grids( - [&](int /*x*/, int /*y*/, int /*grid_index*/, CCGElem * /*elems*/[4], int /*i*/) { - *static_cast(GPU_vertbuf_raw_step(&access)) = 0; - }); - } - break; - - case CD_PBVH_FSET_TYPE: { - const int *face_sets = args.face_sets; - - if (!face_sets) { - uchar white[3] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX}; - - foreach_grids( - [&](int /*x*/, int /*y*/, int /*grid_index*/, CCGElem * /*elems*/[4], int /*i*/) { - *static_cast(GPU_vertbuf_raw_step(&access)) = white; - }); - } - else { - foreach_grids( - [&](int /*x*/, int /*y*/, int grid_index, CCGElem * /*elems*/[4], int /*i*/) { - uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX}; - - if (face_sets) { - const int face_index = BKE_subdiv_ccg_grid_to_face_index(args.subdiv_ccg, - grid_index); - const int fset = face_sets[face_index]; - - /* Skip for the default color Face Set to render it white. */ - if (fset != args.face_sets_color_default) { - BKE_paint_face_set_overlay_color_get( - fset, args.face_sets_color_seed, face_set_color); - } + /* Skip for the default color Face Set to render it white. */ + if (fset != args.face_sets_color_default) { + BKE_paint_face_set_overlay_color_get( + fset, args.face_sets_color_seed, face_set_color); } + } - *static_cast(GPU_vertbuf_raw_step(&access)) = face_set_color; - }); - } - break; + *static_cast(GPU_vertbuf_raw_step(&access)) = face_set_color; + }); } } + else { + bke::attribute_math::convert_to_static_type(eCustomDataType(vbo.type), [&](auto dummy) { + using T = decltype(dummy); + using Converter = draw::AttributeConverter; + using VBOT = typename Converter::VBOT; + std::fill_n(static_cast(GPU_vertbuf_get_data(vbo.vert_buf)), + GPU_vertbuf_get_vertex_len(vbo.vert_buf), + VBOT()); + }); + } } void fill_vbo_grids(PBVHVbo &vbo, const PBVH_GPU_Args &args) @@ -626,6 +739,7 @@ struct PBVHBatches { void fill_vbo_faces(PBVHVbo &vbo, const PBVH_GPU_Args &args) { + using namespace blender; const int totvert = this->count_faces(args) * 3; int existing_num = GPU_vertbuf_get_vertex_len(vbo.vert_buf); @@ -638,92 +752,76 @@ struct PBVHBatches { GPUVertBuf &vert_buf = *vbo.vert_buf; - switch (vbo.type) { - case CD_PBVH_CO_TYPE: - extract_data_vert_faces(args, args.vert_positions, vert_buf); - break; - case CD_PBVH_NO_TYPE: - fill_vbo_normal_faces(args, vert_buf); - break; - case CD_PBVH_MASK_TYPE: { - if (const float *mask = static_cast( - CustomData_get_layer(args.vert_data, CD_PAINT_MASK))) - { - extract_data_vert_faces(args, {mask, args.me->totvert}, vert_buf); - } - else { - MutableSpan(static_cast(GPU_vertbuf_get_data(vbo.vert_buf)), totvert).fill(0); - } - break; + if (vbo.type == CD_PBVH_CO_TYPE) { + extract_data_vert_faces(args, args.vert_positions, vert_buf); + } + else if (vbo.type == CD_PBVH_NO_TYPE) { + fill_vbo_normal_faces(args, vert_buf); + } + else if (vbo.type == CD_PBVH_MASK_TYPE) { + if (const float *mask = static_cast( + CustomData_get_layer(args.vert_data, CD_PAINT_MASK))) + { + extract_data_vert_faces(args, {mask, args.me->totvert}, vert_buf); } - case CD_PBVH_FSET_TYPE: { - const int *face_sets = static_cast( - CustomData_get_layer_named(args.face_data, CD_PROP_INT32, ".sculpt_face_set")); - uchar4 *data = static_cast(GPU_vertbuf_get_data(vbo.vert_buf)); - if (face_sets) { - int last_face = -1; - uchar4 fset_color(UCHAR_MAX); + else { + MutableSpan(static_cast(GPU_vertbuf_get_data(vbo.vert_buf)), totvert).fill(0); + } + } + else if (vbo.type == CD_PBVH_FSET_TYPE) { + const int *face_sets = static_cast( + CustomData_get_layer_named(args.face_data, CD_PROP_INT32, ".sculpt_face_set")); + uchar4 *data = static_cast(GPU_vertbuf_get_data(vbo.vert_buf)); + if (face_sets) { + int last_face = -1; + uchar4 fset_color(UCHAR_MAX); - for (const int looptri_i : args.prim_indices) { - if (args.hide_poly && args.hide_poly[args.looptri_faces[looptri_i]]) { - continue; - } - const int face_i = args.looptri_faces[looptri_i]; - if (last_face != face_i) { - last_face = face_i; - - const int fset = face_sets[face_i]; - - if (fset != args.face_sets_color_default) { - BKE_paint_face_set_overlay_color_get(fset, args.face_sets_color_seed, fset_color); - } - else { - /* Skip for the default color face set to render it white. */ - fset_color[0] = fset_color[1] = fset_color[2] = UCHAR_MAX; - } - } - *data = *(data + 1) = *(data + 2) = fset_color; - data += 3; + for (const int looptri_i : args.prim_indices) { + if (args.hide_poly && args.hide_poly[args.looptri_faces[looptri_i]]) { + continue; } + const int face_i = args.looptri_faces[looptri_i]; + if (last_face != face_i) { + last_face = face_i; + + const int fset = face_sets[face_i]; + + if (fset != args.face_sets_color_default) { + BKE_paint_face_set_overlay_color_get(fset, args.face_sets_color_seed, fset_color); + } + else { + /* Skip for the default color face set to render it white. */ + fset_color[0] = fset_color[1] = fset_color[2] = UCHAR_MAX; + } + } + std::fill_n(data, 3, fset_color); + data += 3; } - else { - MutableSpan(data, totvert).fill(uchar4(255)); - } - break; } - case CD_PROP_COLOR: { - const MPropCol *data = static_cast(CustomData_get_layer_named( - get_cdata(vbo.domain, args), CD_PROP_COLOR, vbo.name.c_str())); - if (vbo.domain == ATTR_DOMAIN_POINT) { - extract_data_vert_faces(args, {data, args.me->totvert}, vert_buf); - } - else if (vbo.domain == ATTR_DOMAIN_CORNER) { - extract_data_corner_faces(args, {data, args.me->totloop}, vert_buf); - } - break; + else { + MutableSpan(data, totvert).fill(uchar4(255)); } - case CD_PROP_BYTE_COLOR: { - const MLoopCol *data = static_cast(CustomData_get_layer_named( - get_cdata(vbo.domain, args), CD_PROP_BYTE_COLOR, vbo.name.c_str())); - if (vbo.domain == ATTR_DOMAIN_POINT) { - extract_data_vert_faces(args, {data, args.me->totvert}, vert_buf); + } + else { + const bke::AttributeAccessor attributes = args.me->attributes(); + const eCustomDataType data_type = eCustomDataType(vbo.type); + const GVArraySpan attribute = *attributes.lookup_or_default(vbo.name, vbo.domain, data_type); + bke::attribute_math::convert_to_static_type(data_type, [&](auto dummy) { + using T = decltype(dummy); + switch (vbo.domain) { + case ATTR_DOMAIN_POINT: + extract_data_vert_faces(args, attribute.typed(), vert_buf); + break; + case ATTR_DOMAIN_FACE: + extract_data_face_faces(args, attribute.typed(), vert_buf); + break; + case ATTR_DOMAIN_CORNER: + extract_data_corner_faces(args, attribute.typed(), vert_buf); + break; + default: + BLI_assert_unreachable(); } - else if (vbo.domain == ATTR_DOMAIN_CORNER) { - extract_data_corner_faces(args, {data, args.me->totloop}, vert_buf); - } - break; - } - case CD_PROP_FLOAT2: { - const float2 *data = static_cast(CustomData_get_layer_named( - get_cdata(vbo.domain, args), CD_PROP_FLOAT2, vbo.name.c_str())); - if (vbo.domain == ATTR_DOMAIN_POINT) { - extract_data_vert_faces(args, {data, args.me->totvert}, vert_buf); - } - else if (vbo.domain == ATTR_DOMAIN_CORNER) { - extract_data_corner_faces(args, {data, args.me->totloop}, vert_buf); - } - break; - } + }); } } @@ -747,6 +845,7 @@ struct PBVHBatches { void fill_vbo_bmesh(PBVHVbo &vbo, const PBVH_GPU_Args &args) { + using namespace blender; auto foreach_bmesh = [&](FunctionRef callback) { GSET_FOREACH_BEGIN (BMFace *, f, args.bm_faces) { if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { @@ -784,55 +883,49 @@ struct PBVHBatches { } #endif - switch (vbo.type) { - case CD_PROP_COLOR: - case CD_PROP_BYTE_COLOR: { - ushort4 white = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX}; + if (vbo.type == CD_PBVH_CO_TYPE) { + foreach_bmesh( + [&](BMLoop *l) { *static_cast(GPU_vertbuf_raw_step(&access)) = l->v->co; }); + } + else if (vbo.type == CD_PBVH_NO_TYPE) { + foreach_bmesh([&](BMLoop *l) { + short no[3]; + bool smooth = BM_elem_flag_test(l->f, BM_ELEM_SMOOTH); - foreach_bmesh([&](BMLoop * /*l*/) { - *static_cast(GPU_vertbuf_raw_step(&access)) = white; - }); - break; - } - case CD_PBVH_CO_TYPE: + normal_float_to_short_v3(no, smooth ? l->v->no : l->f->no); + *static_cast(GPU_vertbuf_raw_step(&access)) = no; + }); + } + else if (vbo.type == CD_PBVH_FSET_TYPE) { + uchar3 white(UCHAR_MAX, UCHAR_MAX, UCHAR_MAX); + foreach_bmesh( + [&](BMLoop * /*l*/) { *static_cast(GPU_vertbuf_raw_step(&access)) = white; }); + } + else if (vbo.type == CD_PBVH_MASK_TYPE) { + int cd_mask = args.cd_mask_layer; + + if (cd_mask == -1) { foreach_bmesh( - [&](BMLoop *l) { *static_cast(GPU_vertbuf_raw_step(&access)) = l->v->co; }); - break; - - case CD_PBVH_NO_TYPE: + [&](BMLoop * /*l*/) { *static_cast(GPU_vertbuf_raw_step(&access)) = 0; }); + } + else { foreach_bmesh([&](BMLoop *l) { - short no[3]; - bool smooth = BM_elem_flag_test(l->f, BM_ELEM_SMOOTH); + float mask = BM_ELEM_CD_GET_FLOAT(l->v, cd_mask); - normal_float_to_short_v3(no, smooth ? l->v->no : l->f->no); - *static_cast(GPU_vertbuf_raw_step(&access)) = no; - }); - break; - - case CD_PBVH_MASK_TYPE: { - int cd_mask = args.cd_mask_layer; - - if (cd_mask == -1) { - foreach_bmesh( - [&](BMLoop * /*l*/) { *static_cast(GPU_vertbuf_raw_step(&access)) = 0; }); - } - else { - foreach_bmesh([&](BMLoop *l) { - float mask = BM_ELEM_CD_GET_FLOAT(l->v, cd_mask); - - *static_cast(GPU_vertbuf_raw_step(&access)) = mask; - }); - } - break; - } - case CD_PBVH_FSET_TYPE: { - uchar3 white(UCHAR_MAX, UCHAR_MAX, UCHAR_MAX); - - foreach_bmesh([&](BMLoop * /*l*/) { - *static_cast(GPU_vertbuf_raw_step(&access)) = white; + *static_cast(GPU_vertbuf_raw_step(&access)) = mask; }); } } + else { + bke::attribute_math::convert_to_static_type(eCustomDataType(vbo.type), [&](auto dummy) { + using T = decltype(dummy); + using Converter = draw::AttributeConverter; + using VBOT = typename Converter::VBOT; + std::fill_n(static_cast(GPU_vertbuf_get_data(vbo.vert_buf)), + GPU_vertbuf_get_vertex_len(vbo.vert_buf), + VBOT()); + }); + } } void fill_vbo(PBVHVbo &vbo, const PBVH_GPU_Args &args) @@ -855,6 +948,7 @@ struct PBVHBatches { const StringRefNull name, const PBVH_GPU_Args &args) { + using namespace blender; PBVHVbo vbo(domain, type, name); GPUVertFormat format; @@ -863,42 +957,29 @@ struct PBVHBatches { GPU_vertformat_clear(&format); - switch (type) { - case CD_PBVH_CO_TYPE: - GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - break; - case CD_PROP_FLOAT3: - GPU_vertformat_attr_add(&format, "a", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - need_aliases = true; - break; - case CD_PBVH_NO_TYPE: - GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); - break; - case CD_PROP_FLOAT2: - GPU_vertformat_attr_add(&format, "a", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - need_aliases = true; - break; - case CD_PBVH_FSET_TYPE: - GPU_vertformat_attr_add(&format, "fset", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); - break; - case CD_PBVH_MASK_TYPE: - GPU_vertformat_attr_add(&format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); - break; - case CD_PROP_FLOAT: - GPU_vertformat_attr_add(&format, "f", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); - need_aliases = true; - break; - case CD_PROP_COLOR: - case CD_PROP_BYTE_COLOR: { - GPU_vertformat_attr_add(&format, "c", GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); - need_aliases = true; - break; - } - default: - printf("%s: Unsupported attribute type %u\n", __func__, type); - BLI_assert_unreachable(); - - return; + if (type == CD_PBVH_CO_TYPE) { + GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + } + else if (type == CD_PBVH_NO_TYPE) { + GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); + } + else if (type == CD_PBVH_FSET_TYPE) { + GPU_vertformat_attr_add(&format, "fset", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); + } + else if (type == CD_PBVH_MASK_TYPE) { + GPU_vertformat_attr_add(&format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + } + else { + bke::attribute_math::convert_to_static_type(eCustomDataType(type), [&](auto dummy) { + using T = decltype(dummy); + using Converter = draw::AttributeConverter; + GPU_vertformat_attr_add(&format, + "data", + Converter::gpu_component_type, + Converter::gpu_component_len, + Converter::gpu_fetch_mode); + }); + need_aliases = true; } if (need_aliases) { @@ -1294,7 +1375,7 @@ struct PBVHBatches { for (int i : IndexRange(attrs_num)) { PBVHAttrReq *attr = attrs + i; - if (!valid_pbvh_attr(attr->type)) { + if (!pbvh_attr_supported(attr->type, attr->domain)) { continue; }