Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHoward Trickey <howard.trickey@gmail.com>2021-10-30 22:37:05 +0300
committerHoward Trickey <howard.trickey@gmail.com>2021-10-30 22:37:05 +0300
commite9bbfd0c8c7a508d220bf355722ff03f91e93183 (patch)
tree1230f26bc82f24547aeccbaa7fcd6d3db2655fd3 /source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc
parent1aa953bd1913c81b22c80a00edbf4ad88a32c52f (diff)
parent03a962d8cab44221650f59eb223cb0a767e05b2b (diff)
Merge branch 'master' into soc-2020-io-performancesoc-2020-io-performance
Diffstat (limited to 'source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc')
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc398
1 files changed, 398 insertions, 0 deletions
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc
new file mode 100644
index 00000000000..9edefe32fbc
--- /dev/null
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc
@@ -0,0 +1,398 @@
+/*
+ * 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
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include <functional>
+
+#include "BLI_float2.hh"
+#include "BLI_float3.hh"
+#include "BLI_float4.hh"
+#include "BLI_string.h"
+
+#include "BKE_attribute.h"
+
+#include "extract_mesh.h"
+
+namespace blender::draw {
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Attributes
+ * \{ */
+
+static CustomData *get_custom_data_for_domain(const MeshRenderData *mr, AttributeDomain domain)
+{
+ switch (domain) {
+ default: {
+ return nullptr;
+ }
+ case ATTR_DOMAIN_POINT: {
+ return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata;
+ }
+ case ATTR_DOMAIN_CORNER: {
+ return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
+ }
+ case ATTR_DOMAIN_FACE: {
+ return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->pdata : &mr->me->pdata;
+ }
+ case ATTR_DOMAIN_EDGE: {
+ return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->edata : &mr->me->edata;
+ }
+ }
+}
+
+/* Utility to convert from the type used in the attributes to the types for the VBO.
+ * This is mostly used to promote integers and booleans to floats, as other types (float, float2,
+ * etc.) directly map to available GPU types. Booleans are still converted as attributes are vec4
+ * in the shader.
+ */
+template<typename AttributeType, typename VBOType> struct attribute_type_converter {
+ static VBOType convert_value(AttributeType value)
+ {
+ if constexpr (std::is_same_v<AttributeType, VBOType>) {
+ return value;
+ }
+
+ /* This should only concern bools which are converted to floats. */
+ return static_cast<VBOType>(value);
+ }
+};
+
+/* Similar to the one in #extract_mesh_vcol_vbo.cc */
+struct gpuMeshCol {
+ ushort r, g, b, a;
+};
+
+template<> struct attribute_type_converter<MPropCol, gpuMeshCol> {
+ static gpuMeshCol convert_value(MPropCol value)
+ {
+ gpuMeshCol result;
+ result.r = unit_float_to_ushort_clamp(value.color[0]);
+ result.g = unit_float_to_ushort_clamp(value.color[1]);
+ result.b = unit_float_to_ushort_clamp(value.color[2]);
+ result.a = unit_float_to_ushort_clamp(value.color[3]);
+ return result;
+ }
+};
+
+/* Return the number of component for the attribute's value type, or 0 if is it unsupported. */
+static uint gpu_component_size_for_attribute_type(CustomDataType type)
+{
+ switch (type) {
+ case CD_PROP_BOOL:
+ case CD_PROP_INT32:
+ case CD_PROP_FLOAT: {
+ /* TODO(kevindietrich) : should be 1 when scalar attributes conversion is handled by us. See
+ * comment #extract_attr_init. */
+ return 3;
+ }
+ case CD_PROP_FLOAT2: {
+ return 2;
+ }
+ case CD_PROP_FLOAT3: {
+ return 3;
+ }
+ case CD_PROP_COLOR: {
+ return 4;
+ }
+ default: {
+ return 0;
+ }
+ }
+}
+
+static GPUVertFetchMode get_fetch_mode_for_type(CustomDataType type)
+{
+ switch (type) {
+ case CD_PROP_INT32: {
+ return GPU_FETCH_INT_TO_FLOAT;
+ }
+ case CD_PROP_COLOR: {
+ return GPU_FETCH_INT_TO_FLOAT_UNIT;
+ }
+ default: {
+ return GPU_FETCH_FLOAT;
+ }
+ }
+}
+
+static GPUVertCompType get_comp_type_for_type(CustomDataType type)
+{
+ switch (type) {
+ case CD_PROP_INT32: {
+ return GPU_COMP_I32;
+ }
+ case CD_PROP_COLOR: {
+ return GPU_COMP_U16;
+ }
+ default: {
+ return GPU_COMP_F32;
+ }
+ }
+}
+
+static void init_vbo_for_attribute(const MeshRenderData *mr,
+ GPUVertBuf *vbo,
+ const DRW_AttributeRequest &request)
+{
+ GPUVertCompType comp_type = get_comp_type_for_type(request.cd_type);
+ GPUVertFetchMode fetch_mode = get_fetch_mode_for_type(request.cd_type);
+ const uint comp_size = gpu_component_size_for_attribute_type(request.cd_type);
+ /* We should not be here if the attribute type is not supported. */
+ BLI_assert(comp_size != 0);
+
+ const CustomData *custom_data = get_custom_data_for_domain(mr, request.domain);
+ char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
+ const char *layer_name = CustomData_get_layer_name(
+ custom_data, request.cd_type, request.layer_index);
+ GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
+ /* Attributes use auto-name. */
+ BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name);
+
+ GPUVertFormat format = {0};
+ GPU_vertformat_deinterleave(&format);
+ GPU_vertformat_attr_add(&format, attr_name, comp_type, comp_size, fetch_mode);
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, static_cast<uint32_t>(mr->loop_len));
+}
+
+template<typename AttributeType, typename VBOType>
+static void fill_vertbuf_with_attribute(const MeshRenderData *mr,
+ VBOType *vbo_data,
+ const DRW_AttributeRequest &request)
+{
+ const CustomData *custom_data = get_custom_data_for_domain(mr, request.domain);
+ BLI_assert(custom_data);
+ const int layer_index = request.layer_index;
+
+ const MPoly *mpoly = mr->mpoly;
+ const MLoop *mloop = mr->mloop;
+
+ const AttributeType *attr_data = static_cast<AttributeType *>(
+ CustomData_get_layer_n(custom_data, request.cd_type, layer_index));
+
+ using converter = attribute_type_converter<AttributeType, VBOType>;
+
+ switch (request.domain) {
+ default: {
+ BLI_assert(false);
+ break;
+ }
+ case ATTR_DOMAIN_POINT: {
+ for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vbo_data++, mloop++) {
+ *vbo_data = converter::convert_value(attr_data[mloop->v]);
+ }
+ break;
+ }
+ case ATTR_DOMAIN_CORNER: {
+ for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vbo_data++) {
+ *vbo_data = converter::convert_value(attr_data[ml_index]);
+ }
+ break;
+ }
+ case ATTR_DOMAIN_EDGE: {
+ for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vbo_data++, mloop++) {
+ *vbo_data = converter::convert_value(attr_data[mloop->e]);
+ }
+ break;
+ }
+ case ATTR_DOMAIN_FACE: {
+ for (int mp_index = 0; mp_index < mr->poly_len; mp_index++) {
+ const MPoly &poly = mpoly[mp_index];
+ const VBOType value = converter::convert_value(attr_data[mp_index]);
+ for (int l = 0; l < poly.totloop; l++) {
+ *vbo_data++ = value;
+ }
+ }
+ break;
+ }
+ }
+}
+
+template<typename AttributeType, typename VBOType>
+static void fill_vertbuf_with_attribute_bm(const MeshRenderData *mr,
+ VBOType *&vbo_data,
+ const DRW_AttributeRequest &request)
+{
+ const CustomData *custom_data = get_custom_data_for_domain(mr, request.domain);
+ BLI_assert(custom_data);
+ const int layer_index = request.layer_index;
+
+ int cd_ofs = CustomData_get_n_offset(custom_data, request.cd_type, layer_index);
+
+ using converter = attribute_type_converter<AttributeType, VBOType>;
+
+ BMIter f_iter;
+ BMFace *efa;
+ BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
+ do {
+ const AttributeType *attr_data = nullptr;
+ if (request.domain == ATTR_DOMAIN_POINT) {
+ attr_data = static_cast<const AttributeType *>(BM_ELEM_CD_GET_VOID_P(l_iter->v, cd_ofs));
+ }
+ else if (request.domain == ATTR_DOMAIN_CORNER) {
+ attr_data = static_cast<const AttributeType *>(BM_ELEM_CD_GET_VOID_P(l_iter, cd_ofs));
+ }
+ else if (request.domain == ATTR_DOMAIN_FACE) {
+ attr_data = static_cast<const AttributeType *>(BM_ELEM_CD_GET_VOID_P(efa, cd_ofs));
+ }
+ else if (request.domain == ATTR_DOMAIN_EDGE) {
+ attr_data = static_cast<const AttributeType *>(BM_ELEM_CD_GET_VOID_P(l_iter->e, cd_ofs));
+ }
+ else {
+ BLI_assert(false);
+ continue;
+ }
+ *vbo_data = converter::convert_value(*attr_data);
+ vbo_data++;
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+}
+
+template<typename AttributeType, typename VBOType = AttributeType>
+static void extract_attr_generic(const MeshRenderData *mr,
+ GPUVertBuf *vbo,
+ const DRW_AttributeRequest &request)
+{
+ VBOType *vbo_data = static_cast<VBOType *>(GPU_vertbuf_get_data(vbo));
+
+ if (mr->extract_type == MR_EXTRACT_BMESH) {
+ fill_vertbuf_with_attribute_bm<AttributeType>(mr, vbo_data, request);
+ }
+ else {
+ fill_vertbuf_with_attribute<AttributeType>(mr, vbo_data, request);
+ }
+}
+
+static void extract_attr_init(const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buf,
+ void *UNUSED(tls_data),
+ int index)
+{
+ const DRW_MeshAttributes *attrs_used = &cache->attr_used;
+ const DRW_AttributeRequest &request = attrs_used->requests[index];
+
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+
+ init_vbo_for_attribute(mr, vbo, request);
+
+ /* TODO(kevindietrich) : float3 is used for scalar attributes as the implicit conversion done by
+ * OpenGL to vec4 for a scalar `s` will produce a `vec4(s, 0, 0, 1)`. However, following the
+ * Blender convention, it should be `vec4(s, s, s, 1)`. This could be resolved using a similar
+ * texture as for volume attribute, so we can control the conversion ourselves. */
+ switch (request.cd_type) {
+ case CD_PROP_BOOL: {
+ extract_attr_generic<bool, float3>(mr, vbo, request);
+ break;
+ }
+ case CD_PROP_INT32: {
+ extract_attr_generic<int32_t, float3>(mr, vbo, request);
+ break;
+ }
+ case CD_PROP_FLOAT: {
+ extract_attr_generic<float, float3>(mr, vbo, request);
+ break;
+ }
+ case CD_PROP_FLOAT2: {
+ extract_attr_generic<float2>(mr, vbo, request);
+ break;
+ }
+ case CD_PROP_FLOAT3: {
+ extract_attr_generic<float3>(mr, vbo, request);
+ break;
+ }
+ case CD_PROP_COLOR: {
+ extract_attr_generic<MPropCol, gpuMeshCol>(mr, vbo, request);
+ break;
+ }
+ default: {
+ BLI_assert(false);
+ }
+ }
+}
+
+/* Wrappers around extract_attr_init so we can pass the index of the attribute that we want to
+ * extract. The overall API does not allow us to pass this in a convenient way. */
+#define EXTRACT_INIT_WRAPPER(index) \
+ static void extract_attr_init##index( \
+ const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf, void *tls_data) \
+ { \
+ extract_attr_init(mr, cache, buf, tls_data, index); \
+ }
+
+EXTRACT_INIT_WRAPPER(0)
+EXTRACT_INIT_WRAPPER(1)
+EXTRACT_INIT_WRAPPER(2)
+EXTRACT_INIT_WRAPPER(3)
+EXTRACT_INIT_WRAPPER(4)
+EXTRACT_INIT_WRAPPER(5)
+EXTRACT_INIT_WRAPPER(6)
+EXTRACT_INIT_WRAPPER(7)
+EXTRACT_INIT_WRAPPER(8)
+EXTRACT_INIT_WRAPPER(9)
+EXTRACT_INIT_WRAPPER(10)
+EXTRACT_INIT_WRAPPER(11)
+EXTRACT_INIT_WRAPPER(12)
+EXTRACT_INIT_WRAPPER(13)
+EXTRACT_INIT_WRAPPER(14)
+
+template<int index> constexpr MeshExtract create_extractor_attr(ExtractInitFn fn)
+{
+ MeshExtract extractor = {nullptr};
+ extractor.init = fn;
+ extractor.data_type = MR_DATA_NONE;
+ extractor.data_size = 0;
+ extractor.use_threading = false;
+ extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.attr[index]);
+ return extractor;
+}
+
+/** \} */
+
+} // namespace blender::draw
+
+extern "C" {
+#define CREATE_EXTRACTOR_ATTR(index) \
+ blender::draw::create_extractor_attr<index>(blender::draw::extract_attr_init##index)
+
+const MeshExtract extract_attr[GPU_MAX_ATTR] = {
+ CREATE_EXTRACTOR_ATTR(0),
+ CREATE_EXTRACTOR_ATTR(1),
+ CREATE_EXTRACTOR_ATTR(2),
+ CREATE_EXTRACTOR_ATTR(3),
+ CREATE_EXTRACTOR_ATTR(4),
+ CREATE_EXTRACTOR_ATTR(5),
+ CREATE_EXTRACTOR_ATTR(6),
+ CREATE_EXTRACTOR_ATTR(7),
+ CREATE_EXTRACTOR_ATTR(8),
+ CREATE_EXTRACTOR_ATTR(9),
+ CREATE_EXTRACTOR_ATTR(10),
+ CREATE_EXTRACTOR_ATTR(11),
+ CREATE_EXTRACTOR_ATTR(12),
+ CREATE_EXTRACTOR_ATTR(13),
+ CREATE_EXTRACTOR_ATTR(14),
+};
+}