Refactor: Extract color attributes as generic attributes

Previously there was a special extraction process for "vertex colors"
that copied the color data to the GPU with a special format. Instead,
this patch replaces this with use of the generic attribute extraction.
This reduces the number of code paths, allowing easier optimization
in the future.

To make it possible to use the generic extraction system for attributes
but also assign aliases for use by shaders, some changes are necessary.
First, the GPU material attribute can now store whether it actually refers
to the default color attribute, rather than a specific name. This replaces
the hack to use `CD_MCOL` in the color attribute shader node. Second,
the extraction code checks the names against the default and active
names and assigns aliases if the request corresponds to a special active
attribute. Finally, support for byte color attributes was added to the
generic attribute extraction.

Differential Revision: https://developer.blender.org/D15205
This commit is contained in:
Hans Goudey 2022-07-26 08:37:08 -05:00
parent 5945a90df9
commit 1998269b10
Notes: blender-bot 2023-02-13 22:38:46 +01:00
Referenced by issue #104370, Regression: color attribute is emitted as black on Eevee
12 changed files with 252 additions and 664 deletions

View File

@ -67,7 +67,6 @@ set(SRC
intern/mesh_extractors/extract_mesh_vbo_skin_roots.cc
intern/mesh_extractors/extract_mesh_vbo_tan.cc
intern/mesh_extractors/extract_mesh_vbo_uv.cc
intern/mesh_extractors/extract_mesh_vbo_vcol.cc
intern/mesh_extractors/extract_mesh_vbo_weights.cc
intern/draw_attributes.cc
intern/draw_cache_impl_curve.cc

View File

@ -88,7 +88,7 @@ bool drw_custom_data_match_attribute(const CustomData *custom_data,
int *r_layer_index,
eCustomDataType *r_type)
{
const eCustomDataType possible_attribute_types[7] = {
const eCustomDataType possible_attribute_types[8] = {
CD_PROP_BOOL,
CD_PROP_INT8,
CD_PROP_INT32,
@ -96,6 +96,7 @@ bool drw_custom_data_match_attribute(const CustomData *custom_data,
CD_PROP_FLOAT2,
CD_PROP_FLOAT3,
CD_PROP_COLOR,
CD_PROP_BYTE_COLOR,
};
for (int i = 0; i < ARRAY_SIZE(possible_attribute_types); i++) {

View File

@ -55,7 +55,6 @@ enum {
struct DRW_MeshCDMask {
uint32_t uv : 8;
uint32_t tan : 8;
uint32_t vcol : 8;
uint32_t orco : 1;
uint32_t tan_orco : 1;
uint32_t sculpt_overlays : 1;
@ -111,7 +110,6 @@ struct MeshBufferList {
GPUVertBuf *weights; /* extend */
GPUVertBuf *uv;
GPUVertBuf *tan;
GPUVertBuf *vcol;
GPUVertBuf *sculpt_data;
GPUVertBuf *orco;
/* Only for edit mode. */

View File

@ -619,7 +619,6 @@ void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
EXTRACT_ADD_REQUESTED(vbo, lnor);
EXTRACT_ADD_REQUESTED(vbo, uv);
EXTRACT_ADD_REQUESTED(vbo, tan);
EXTRACT_ADD_REQUESTED(vbo, vcol);
EXTRACT_ADD_REQUESTED(vbo, sculpt_data);
EXTRACT_ADD_REQUESTED(vbo, orco);
EXTRACT_ADD_REQUESTED(vbo, edge_fac);
@ -848,7 +847,6 @@ void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
EXTRACT_ADD_REQUESTED(vbo, edituv_stretch_angle);
EXTRACT_ADD_REQUESTED(ibo, lines_paint_mask);
EXTRACT_ADD_REQUESTED(ibo, lines_adjacency);
EXTRACT_ADD_REQUESTED(vbo, vcol);
EXTRACT_ADD_REQUESTED(vbo, weights);
EXTRACT_ADD_REQUESTED(vbo, sculpt_data);

View File

@ -431,6 +431,30 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_
}
}
static void retrieve_active_attribute_names(MeshRenderData &mr,
const Object &object,
const Mesh &mesh)
{
const Mesh *mesh_final = editmesh_final_or_this(&object, &mesh);
const CustomData *cd_vdata = mesh_cd_vdata_get_from_mesh(mesh_final);
const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(mesh_final);
/* Necessary because which attributes are active/default is stored in #CustomData. */
Mesh me_query = blender::dna::shallow_zero_initialize();
BKE_id_attribute_copy_domains_temp(
ID_ME, cd_vdata, nullptr, cd_ldata, nullptr, nullptr, &me_query.id);
mr.active_color_name = nullptr;
mr.default_color_name = nullptr;
if (const CustomDataLayer *active = BKE_id_attributes_active_color_get(&me_query.id)) {
mr.active_color_name = active->name;
}
if (const CustomDataLayer *render = BKE_id_attributes_render_color_get(&me_query.id)) {
mr.default_color_name = render->name;
}
}
MeshRenderData *mesh_render_data_create(Object *object,
Mesh *me,
const bool is_editmode,
@ -566,6 +590,8 @@ MeshRenderData *mesh_render_data_create(Object *object,
mr->tri_len = poly_to_tri_count(mr->poly_len, mr->loop_len);
}
retrieve_active_attribute_names(*mr, *object, *me);
return mr;
}

View File

@ -21,6 +21,7 @@
#include "BLI_math_vector.h"
#include "BLI_span.hh"
#include "BLI_string.h"
#include "BLI_string_ref.hh"
#include "BLI_task.h"
#include "BLI_utildefines.h"
@ -67,6 +68,7 @@
using blender::IndexRange;
using blender::Map;
using blender::Span;
using blender::StringRefNull;
/* ---------------------------------------------------------------------- */
/** \name Dependencies between buffer and batch
@ -115,8 +117,6 @@ static constexpr DRWBatchFlag batches_that_use_buffer(const int buffer_index)
MBC_SURFACE_PER_MAT;
case BUFFER_INDEX(vbo.tan):
return MBC_SURFACE_PER_MAT;
case BUFFER_INDEX(vbo.vcol):
return MBC_SURFACE | MBC_SURFACE_PER_MAT;
case BUFFER_INDEX(vbo.sculpt_data):
return MBC_SCULPT_OVERLAYS;
case BUFFER_INDEX(vbo.orco):
@ -236,87 +236,11 @@ BLI_INLINE void mesh_cd_layers_type_clear(DRW_MeshCDMask *a)
*((uint32_t *)a) = 0;
}
BLI_INLINE const Mesh *editmesh_final_or_this(const Object *object, const Mesh *me)
{
if (me->edit_mesh != nullptr) {
Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object);
if (editmesh_eval_final != nullptr) {
return editmesh_eval_final;
}
}
return me;
}
static void mesh_cd_calc_edit_uv_layer(const Mesh *UNUSED(me), DRW_MeshCDMask *cd_used)
{
cd_used->edit_uv = 1;
}
BLI_INLINE const CustomData *mesh_cd_ldata_get_from_mesh(const Mesh *me)
{
switch ((eMeshWrapperType)me->runtime.wrapper_type) {
case ME_WRAPPER_TYPE_SUBD:
case ME_WRAPPER_TYPE_MDATA:
return &me->ldata;
break;
case ME_WRAPPER_TYPE_BMESH:
return &me->edit_mesh->bm->ldata;
break;
}
BLI_assert(0);
return &me->ldata;
}
BLI_INLINE const CustomData *mesh_cd_pdata_get_from_mesh(const Mesh *me)
{
switch ((eMeshWrapperType)me->runtime.wrapper_type) {
case ME_WRAPPER_TYPE_SUBD:
case ME_WRAPPER_TYPE_MDATA:
return &me->pdata;
break;
case ME_WRAPPER_TYPE_BMESH:
return &me->edit_mesh->bm->pdata;
break;
}
BLI_assert(0);
return &me->pdata;
}
BLI_INLINE const CustomData *mesh_cd_edata_get_from_mesh(const Mesh *me)
{
switch ((eMeshWrapperType)me->runtime.wrapper_type) {
case ME_WRAPPER_TYPE_SUBD:
case ME_WRAPPER_TYPE_MDATA:
return &me->edata;
break;
case ME_WRAPPER_TYPE_BMESH:
return &me->edit_mesh->bm->edata;
break;
}
BLI_assert(0);
return &me->edata;
}
BLI_INLINE const CustomData *mesh_cd_vdata_get_from_mesh(const Mesh *me)
{
switch ((eMeshWrapperType)me->runtime.wrapper_type) {
case ME_WRAPPER_TYPE_SUBD:
case ME_WRAPPER_TYPE_MDATA:
return &me->vdata;
break;
case ME_WRAPPER_TYPE_BMESH:
return &me->edit_mesh->bm->vdata;
break;
}
BLI_assert(0);
return &me->vdata;
}
static void mesh_cd_calc_active_uv_layer(const Object *object,
const Mesh *me,
DRW_MeshCDMask *cd_used)
@ -341,75 +265,6 @@ static void mesh_cd_calc_active_mask_uv_layer(const Object *object,
}
}
static void mesh_cd_calc_active_mloopcol_layer(const Object *object,
const Mesh *me,
DRW_MeshCDMask *cd_used)
{
const Mesh *me_final = editmesh_final_or_this(object, me);
Mesh me_query = blender::dna::shallow_zero_initialize();
const CustomData *cd_vdata = mesh_cd_vdata_get_from_mesh(me_final);
const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final);
BKE_id_attribute_copy_domains_temp(
ID_ME, cd_vdata, nullptr, cd_ldata, nullptr, nullptr, &me_query.id);
const CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me_query.id);
int layer_i = BKE_id_attribute_to_index(
&me_query.id, layer, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
if (layer_i != -1) {
cd_used->vcol |= (1UL << (uint)layer_i);
}
}
static uint mesh_cd_calc_gpu_layers_vcol_used(const Mesh *me_query,
const CustomData *cd_vdata,
const CustomData *cd_ldata,
const char name[])
{
const CustomDataLayer *layer = nullptr;
eAttrDomain domain;
if (name[0]) {
int layer_i = 0;
domain = ATTR_DOMAIN_POINT;
layer_i = CustomData_get_named_layer_index(cd_vdata, CD_PROP_COLOR, name);
layer_i = layer_i == -1 ?
CustomData_get_named_layer_index(cd_vdata, CD_PROP_BYTE_COLOR, name) :
layer_i;
if (layer_i == -1) {
domain = ATTR_DOMAIN_CORNER;
layer_i = layer_i == -1 ? CustomData_get_named_layer_index(cd_ldata, CD_PROP_COLOR, name) :
layer_i;
layer_i = layer_i == -1 ?
CustomData_get_named_layer_index(cd_ldata, CD_PROP_BYTE_COLOR, name) :
layer_i;
}
/* NOTE: this is not the same as the layer_i below. */
if (layer_i != -1) {
layer = (domain == ATTR_DOMAIN_POINT ? cd_vdata : cd_ldata)->layers + layer_i;
}
}
else {
layer = BKE_id_attributes_render_color_get(&me_query->id);
}
if (!layer) {
return -1;
}
/* NOTE: this is the logical index into the color attribute list,
* not the customdata index. */
int vcol_i = BKE_id_attribute_to_index(
(ID *)me_query, layer, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
return vcol_i;
}
static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
const Mesh *me,
struct GPUMaterial **gpumat_array,
@ -433,6 +288,9 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
DRW_MeshCDMask cd_used;
mesh_cd_layers_type_clear(&cd_used);
const CustomDataLayer *default_color = BKE_id_attributes_render_color_get(&me_query.id);
const StringRefNull default_color_name = default_color ? default_color->name : "";
for (int i = 0; i < gpumat_array_len; i++) {
GPUMaterial *gpumat = gpumat_array[i];
if (gpumat) {
@ -443,6 +301,10 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
int layer = -1;
std::optional<eAttrDomain> domain;
if (gpu_attr->is_default_color) {
name = default_color_name.c_str();
}
if (type == CD_AUTO_FROM_NAME) {
/* We need to deduce what exact layer is used.
*
@ -452,38 +314,6 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
layer = CustomData_get_named_layer(cd_ldata, CD_MLOOPUV, name);
type = CD_MTFACE;
if (layer == -1) {
layer = CustomData_get_named_layer(cd_vdata, CD_PROP_COLOR, name);
if (layer != -1) {
type = CD_PROP_COLOR;
domain = ATTR_DOMAIN_POINT;
}
}
if (layer == -1) {
layer = CustomData_get_named_layer(cd_ldata, CD_PROP_COLOR, name);
if (layer != -1) {
type = CD_PROP_COLOR;
domain = ATTR_DOMAIN_CORNER;
}
}
if (layer == -1) {
layer = CustomData_get_named_layer(cd_vdata, CD_PROP_BYTE_COLOR, name);
if (layer != -1) {
type = CD_PROP_BYTE_COLOR;
domain = ATTR_DOMAIN_POINT;
}
}
if (layer == -1) {
layer = CustomData_get_named_layer(cd_ldata, CD_PROP_BYTE_COLOR, name);
if (layer != -1) {
type = CD_PROP_BYTE_COLOR;
domain = ATTR_DOMAIN_CORNER;
}
}
#if 0 /* Tangents are always from UV's - this will never happen. */
if (layer == -1) {
layer = CustomData_get_named_layer(cd_ldata, CD_TANGENT, name);
@ -556,28 +386,8 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
cd_used.orco = 1;
break;
}
/* NOTE: attr->type will always be CD_PROP_COLOR even for
* CD_PROP_BYTE_COLOR layers, see node_shader_gpu_vertex_color in
* node_shader_vertex_color.cc.
*/
case CD_MCOL:
case CD_PROP_BYTE_COLOR:
case CD_PROP_COLOR: {
/* First check Color attributes, when not found check mesh attributes. Geometry nodes
* can generate those layers. */
int vcol_bit = mesh_cd_calc_gpu_layers_vcol_used(&me_query, cd_vdata, cd_ldata, name);
if (vcol_bit != -1) {
cd_used.vcol |= 1UL << (uint)vcol_bit;
break;
}
if (layer != -1 && domain.has_value()) {
drw_attributes_add_request(attributes, name, type, layer, *domain);
}
break;
}
case CD_PROP_COLOR:
case CD_PROP_FLOAT3:
case CD_PROP_BOOL:
case CD_PROP_INT8:
@ -863,10 +673,9 @@ static void mesh_batch_cache_discard_shaded_tri(MeshBatchCache *cache)
FOREACH_MESH_BUFFER_CACHE (cache, mbc) {
GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.uv);
GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.tan);
GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.vcol);
GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.orco);
}
DRWBatchFlag batch_map = BATCH_MAP(vbo.uv, vbo.tan, vbo.vcol, vbo.orco);
DRWBatchFlag batch_map = BATCH_MAP(vbo.uv, vbo.tan, vbo.orco);
mesh_batch_cache_discard_batch(cache, batch_map);
mesh_cd_layers_type_clear(&cache->cd_used);
}
@ -1070,42 +879,35 @@ static void texpaint_request_active_uv(MeshBatchCache *cache, Object *object, Me
mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed);
}
static void texpaint_request_active_vcol(MeshBatchCache *cache, Object *object, Mesh *me)
static void request_active_and_default_color_attributes(const Object &object,
const Mesh &mesh,
DRW_Attributes &attributes)
{
DRW_MeshCDMask cd_needed;
mesh_cd_layers_type_clear(&cd_needed);
mesh_cd_calc_active_mloopcol_layer(object, me, &cd_needed);
BLI_assert(cd_needed.vcol != 0 &&
"No MLOOPCOL layer available in vertpaint, but batches requested anyway!");
mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed);
}
static void sculpt_request_active_vcol(MeshBatchCache *cache, Object *object, Mesh *me)
{
const Mesh *me_final = editmesh_final_or_this(object, me);
const Mesh *me_final = editmesh_final_or_this(&object, &mesh);
const CustomData *cd_vdata = mesh_cd_vdata_get_from_mesh(me_final);
const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final);
/* Necessary because which attributes are active/default is stored in #CustomData. */
Mesh me_query = blender::dna::shallow_zero_initialize();
BKE_id_attribute_copy_domains_temp(
ID_ME, cd_vdata, nullptr, cd_ldata, nullptr, nullptr, &me_query.id);
const CustomDataLayer *active = BKE_id_attributes_active_color_get(&me_query.id);
const CustomDataLayer *render = BKE_id_attributes_render_color_get(&me_query.id);
auto request_color_attribute = [&](const char *name) {
int layer_index;
eCustomDataType type;
if (drw_custom_data_match_attribute(cd_vdata, name, &layer_index, &type)) {
drw_attributes_add_request(&attributes, name, type, layer_index, ATTR_DOMAIN_POINT);
}
else if (drw_custom_data_match_attribute(cd_ldata, name, &layer_index, &type)) {
drw_attributes_add_request(&attributes, name, type, layer_index, ATTR_DOMAIN_CORNER);
}
};
int active_i = BKE_id_attribute_to_index(
&me_query.id, active, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
int render_i = BKE_id_attribute_to_index(
&me_query.id, render, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
if (active_i >= 0) {
cache->cd_needed.vcol |= 1UL << (uint)active_i;
if (const CustomDataLayer *active = BKE_id_attributes_active_color_get(&me_query.id)) {
request_color_attribute(active->name);
}
if (render_i >= 0) {
cache->cd_needed.vcol |= 1UL << (uint)render_i;
if (const CustomDataLayer *render = BKE_id_attributes_render_color_get(&me_query.id)) {
request_color_attribute(render->name);
}
}
@ -1214,7 +1016,13 @@ GPUBatch *DRW_mesh_batch_cache_get_surface_texpaint_single(Object *object, Mesh
GPUBatch *DRW_mesh_batch_cache_get_surface_vertpaint(Object *object, Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
texpaint_request_active_vcol(cache, object, me);
DRW_Attributes attrs_needed{};
request_active_and_default_color_attributes(*object, *me, attrs_needed);
ThreadMutex *mesh_render_mutex = (ThreadMutex *)me->runtime.render_mutex;
drw_attributes_merge(&cache->attr_needed, &attrs_needed, mesh_render_mutex);
mesh_batch_cache_request_surface_batches(cache);
return cache->batch.surface;
}
@ -1222,7 +1030,13 @@ GPUBatch *DRW_mesh_batch_cache_get_surface_vertpaint(Object *object, Mesh *me)
GPUBatch *DRW_mesh_batch_cache_get_surface_sculpt(Object *object, Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
sculpt_request_active_vcol(cache, object, me);
DRW_Attributes attrs_needed{};
request_active_and_default_color_attributes(*object, *me, attrs_needed);
ThreadMutex *mesh_render_mutex = (ThreadMutex *)me->runtime.render_mutex;
drw_attributes_merge(&cache->attr_needed, &attrs_needed, mesh_render_mutex);
mesh_batch_cache_request_surface_batches(cache);
return cache->batch.surface;
}
@ -1621,9 +1435,6 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
if (cache->cd_used.sculpt_overlays != cache->cd_needed.sculpt_overlays) {
GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.sculpt_data);
}
if ((cache->cd_used.vcol & cache->cd_needed.vcol) != cache->cd_needed.vcol) {
GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.vcol);
}
if (!drw_attributes_overlap(&cache->attr_used, &cache->attr_needed)) {
for (int i = 0; i < GPU_MAX_ATTR; i++) {
GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.attr[i]);
@ -1710,15 +1521,26 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
MeshBufferList *mbuflist = &cache->final.buff;
/* Initialize batches and request VBO's & IBO's. */
assert_deps_valid(
MBC_SURFACE,
{BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.lnor), BUFFER_INDEX(vbo.pos_nor),
BUFFER_INDEX(vbo.uv), BUFFER_INDEX(vbo.vcol), BUFFER_INDEX(vbo.attr[0]),
BUFFER_INDEX(vbo.attr[1]), BUFFER_INDEX(vbo.attr[2]), BUFFER_INDEX(vbo.attr[3]),
BUFFER_INDEX(vbo.attr[4]), BUFFER_INDEX(vbo.attr[5]), BUFFER_INDEX(vbo.attr[6]),
BUFFER_INDEX(vbo.attr[7]), BUFFER_INDEX(vbo.attr[8]), BUFFER_INDEX(vbo.attr[9]),
BUFFER_INDEX(vbo.attr[10]), BUFFER_INDEX(vbo.attr[11]), BUFFER_INDEX(vbo.attr[12]),
BUFFER_INDEX(vbo.attr[13]), BUFFER_INDEX(vbo.attr[14])});
assert_deps_valid(MBC_SURFACE,
{BUFFER_INDEX(ibo.tris),
BUFFER_INDEX(vbo.lnor),
BUFFER_INDEX(vbo.pos_nor),
BUFFER_INDEX(vbo.uv),
BUFFER_INDEX(vbo.attr[0]),
BUFFER_INDEX(vbo.attr[1]),
BUFFER_INDEX(vbo.attr[2]),
BUFFER_INDEX(vbo.attr[3]),
BUFFER_INDEX(vbo.attr[4]),
BUFFER_INDEX(vbo.attr[5]),
BUFFER_INDEX(vbo.attr[6]),
BUFFER_INDEX(vbo.attr[7]),
BUFFER_INDEX(vbo.attr[8]),
BUFFER_INDEX(vbo.attr[9]),
BUFFER_INDEX(vbo.attr[10]),
BUFFER_INDEX(vbo.attr[11]),
BUFFER_INDEX(vbo.attr[12]),
BUFFER_INDEX(vbo.attr[13]),
BUFFER_INDEX(vbo.attr[14])});
if (DRW_batch_requested(cache->batch.surface, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.surface, &mbuflist->ibo.tris);
/* Order matters. First ones override latest VBO's attributes. */
@ -1727,9 +1549,6 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
if (cache->cd_used.uv != 0) {
DRW_vbo_request(cache->batch.surface, &mbuflist->vbo.uv);
}
if (cache->cd_used.vcol != 0) {
DRW_vbo_request(cache->batch.surface, &mbuflist->vbo.vcol);
}
drw_add_attributes_vbo(cache->batch.surface, mbuflist, &cache->attr_used);
}
assert_deps_valid(MBC_ALL_VERTS, {BUFFER_INDEX(vbo.pos_nor)});
@ -1807,12 +1626,12 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
assert_deps_valid(
MBC_SURFACE_PER_MAT,
{BUFFER_INDEX(vbo.lnor), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.uv),
BUFFER_INDEX(vbo.tan), BUFFER_INDEX(vbo.vcol), BUFFER_INDEX(vbo.orco),
BUFFER_INDEX(vbo.attr[0]), BUFFER_INDEX(vbo.attr[1]), BUFFER_INDEX(vbo.attr[2]),
BUFFER_INDEX(vbo.attr[3]), BUFFER_INDEX(vbo.attr[4]), BUFFER_INDEX(vbo.attr[5]),
BUFFER_INDEX(vbo.attr[6]), BUFFER_INDEX(vbo.attr[7]), BUFFER_INDEX(vbo.attr[8]),
BUFFER_INDEX(vbo.attr[9]), BUFFER_INDEX(vbo.attr[10]), BUFFER_INDEX(vbo.attr[11]),
BUFFER_INDEX(vbo.attr[12]), BUFFER_INDEX(vbo.attr[13]), BUFFER_INDEX(vbo.attr[14])});
BUFFER_INDEX(vbo.tan), BUFFER_INDEX(vbo.orco), BUFFER_INDEX(vbo.attr[0]),
BUFFER_INDEX(vbo.attr[1]), BUFFER_INDEX(vbo.attr[2]), BUFFER_INDEX(vbo.attr[3]),
BUFFER_INDEX(vbo.attr[4]), BUFFER_INDEX(vbo.attr[5]), BUFFER_INDEX(vbo.attr[6]),
BUFFER_INDEX(vbo.attr[7]), BUFFER_INDEX(vbo.attr[8]), BUFFER_INDEX(vbo.attr[9]),
BUFFER_INDEX(vbo.attr[10]), BUFFER_INDEX(vbo.attr[11]), BUFFER_INDEX(vbo.attr[12]),
BUFFER_INDEX(vbo.attr[13]), BUFFER_INDEX(vbo.attr[14])});
assert_deps_valid(MBC_SURFACE_PER_MAT, {TRIS_PER_MAT_INDEX});
for (int i = 0; i < cache->mat_len; i++) {
if (DRW_batch_requested(cache->surface_per_mat[i], GPU_PRIM_TRIS)) {
@ -1826,9 +1645,6 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
if ((cache->cd_used.tan != 0) || (cache->cd_used.tan_orco != 0)) {
DRW_vbo_request(cache->surface_per_mat[i], &mbuflist->vbo.tan);
}
if (cache->cd_used.vcol != 0) {
DRW_vbo_request(cache->surface_per_mat[i], &mbuflist->vbo.vcol);
}
if (cache->cd_used.orco != 0) {
DRW_vbo_request(cache->surface_per_mat[i], &mbuflist->vbo.orco);
}
@ -1994,7 +1810,6 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
assert_final_deps_valid(BUFFER_INDEX(vbo.lnor));
assert_final_deps_valid(BUFFER_INDEX(vbo.pos_nor));
assert_final_deps_valid(BUFFER_INDEX(vbo.uv));
assert_final_deps_valid(BUFFER_INDEX(vbo.vcol));
assert_final_deps_valid(BUFFER_INDEX(vbo.sculpt_data));
assert_final_deps_valid(BUFFER_INDEX(vbo.weights));
assert_final_deps_valid(BUFFER_INDEX(vbo.edge_fac));

View File

@ -86,6 +86,9 @@ struct MeshRenderData {
float (*loop_normals)[3];
int *lverts, *ledges;
const char *active_color_name;
const char *default_color_name;
struct {
int *tri_first_index;
int *mat_tri_len;
@ -93,6 +96,82 @@ struct MeshRenderData {
} poly_sorted;
};
BLI_INLINE const Mesh *editmesh_final_or_this(const Object *object, const Mesh *me)
{
if (me->edit_mesh != nullptr) {
Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object);
if (editmesh_eval_final != nullptr) {
return editmesh_eval_final;
}
}
return me;
}
BLI_INLINE const CustomData *mesh_cd_ldata_get_from_mesh(const Mesh *me)
{
switch ((eMeshWrapperType)me->runtime.wrapper_type) {
case ME_WRAPPER_TYPE_SUBD:
case ME_WRAPPER_TYPE_MDATA:
return &me->ldata;
break;
case ME_WRAPPER_TYPE_BMESH:
return &me->edit_mesh->bm->ldata;
break;
}
BLI_assert(0);
return &me->ldata;
}
BLI_INLINE const CustomData *mesh_cd_pdata_get_from_mesh(const Mesh *me)
{
switch ((eMeshWrapperType)me->runtime.wrapper_type) {
case ME_WRAPPER_TYPE_SUBD:
case ME_WRAPPER_TYPE_MDATA:
return &me->pdata;
break;
case ME_WRAPPER_TYPE_BMESH:
return &me->edit_mesh->bm->pdata;
break;
}
BLI_assert(0);
return &me->pdata;
}
BLI_INLINE const CustomData *mesh_cd_edata_get_from_mesh(const Mesh *me)
{
switch ((eMeshWrapperType)me->runtime.wrapper_type) {
case ME_WRAPPER_TYPE_SUBD:
case ME_WRAPPER_TYPE_MDATA:
return &me->edata;
break;
case ME_WRAPPER_TYPE_BMESH:
return &me->edit_mesh->bm->edata;
break;
}
BLI_assert(0);
return &me->edata;
}
BLI_INLINE const CustomData *mesh_cd_vdata_get_from_mesh(const Mesh *me)
{
switch ((eMeshWrapperType)me->runtime.wrapper_type) {
case ME_WRAPPER_TYPE_SUBD:
case ME_WRAPPER_TYPE_MDATA:
return &me->vdata;
break;
case ME_WRAPPER_TYPE_BMESH:
return &me->edit_mesh->bm->vdata;
break;
}
BLI_assert(0);
return &me->vdata;
}
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) ?

View File

@ -9,6 +9,7 @@
#include <functional>
#include "BLI_color.hh"
#include "BLI_math_vec_types.hh"
#include "BLI_string.h"
@ -74,6 +75,18 @@ template<> struct AttributeTypeConverter<MPropCol, gpuMeshCol> {
}
};
template<> struct AttributeTypeConverter<ColorGeometry4b, gpuMeshCol> {
static gpuMeshCol convert_value(ColorGeometry4b value)
{
gpuMeshCol result;
result.r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[value.r]);
result.g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[value.g]);
result.b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[value.b]);
result.a = unit_float_to_ushort_clamp(value.a * (1.0f / 255.0f));
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(eCustomDataType type)
{
@ -90,6 +103,7 @@ static uint gpu_component_size_for_attribute_type(eCustomDataType type)
case CD_PROP_FLOAT3:
return 3;
case CD_PROP_COLOR:
case CD_PROP_BYTE_COLOR:
return 4;
default:
return 0;
@ -102,6 +116,7 @@ static GPUVertFetchMode get_fetch_mode_for_type(eCustomDataType type)
case CD_PROP_INT32:
return GPU_FETCH_INT_TO_FLOAT;
case CD_PROP_COLOR:
case CD_PROP_BYTE_COLOR:
return GPU_FETCH_INT_TO_FLOAT_UNIT;
default:
return GPU_FETCH_FLOAT;
@ -114,13 +129,15 @@ static GPUVertCompType get_comp_type_for_type(eCustomDataType type)
case CD_PROP_INT32:
return GPU_COMP_I32;
case CD_PROP_COLOR:
case CD_PROP_BYTE_COLOR:
return GPU_COMP_U16;
default:
return GPU_COMP_F32;
}
}
static void init_vbo_for_attribute(GPUVertBuf *vbo,
static void init_vbo_for_attribute(const MeshRenderData &mr,
GPUVertBuf *vbo,
const DRW_AttributeRequest &request,
bool build_on_device,
uint32_t len)
@ -140,6 +157,13 @@ static void init_vbo_for_attribute(GPUVertBuf *vbo,
GPU_vertformat_deinterleave(&format);
GPU_vertformat_attr_add(&format, attr_name, comp_type, comp_size, fetch_mode);
if (mr.active_color_name && STREQ(request.attribute_name, mr.active_color_name)) {
GPU_vertformat_alias_add(&format, "ac");
}
if (mr.default_color_name && STREQ(request.attribute_name, mr.default_color_name)) {
GPU_vertformat_alias_add(&format, "c");
}
if (build_on_device) {
GPU_vertbuf_init_build_on_device(vbo, &format, len);
}
@ -262,7 +286,7 @@ static void extract_attr_init(
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
init_vbo_for_attribute(vbo, request, false, static_cast<uint32_t>(mr->loop_len));
init_vbo_for_attribute(*mr, vbo, request, false, static_cast<uint32_t>(mr->loop_len));
/* 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
@ -290,6 +314,9 @@ static void extract_attr_init(
case CD_PROP_COLOR:
extract_attr_generic<MPropCol, gpuMeshCol>(mr, vbo, request);
break;
case CD_PROP_BYTE_COLOR:
extract_attr_generic<ColorGeometry4b, gpuMeshCol>(mr, vbo, request);
break;
default:
BLI_assert_unreachable();
}
@ -338,12 +365,15 @@ static void extract_attr_init_subdiv(const DRWSubdivCache *subdiv_cache,
case CD_PROP_COLOR:
extract_attr_generic<MPropCol, gpuMeshCol>(mr, src_data, request);
break;
case CD_PROP_BYTE_COLOR:
extract_attr_generic<ColorGeometry4b, gpuMeshCol>(mr, src_data, request);
break;
default:
BLI_assert_unreachable();
}
GPUVertBuf *dst_buffer = static_cast<GPUVertBuf *>(buffer);
init_vbo_for_attribute(dst_buffer, request, true, subdiv_cache->num_subdiv_loops);
init_vbo_for_attribute(*mr, dst_buffer, request, true, subdiv_cache->num_subdiv_loops);
/* Ensure data is uploaded properly. */
GPU_vertbuf_tag_dirty(src_data);
@ -352,7 +382,7 @@ static void extract_attr_init_subdiv(const DRWSubdivCache *subdiv_cache,
dst_buffer,
static_cast<int>(dimensions),
0,
request.cd_type == CD_PROP_COLOR);
ELEM(request.cd_type, CD_PROP_COLOR, CD_PROP_BYTE_COLOR));
GPU_vertbuf_discard(src_data);
}

View File

@ -1,387 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2021 Blender Foundation. All rights reserved. */
/** \file
* \ingroup draw
*/
#include "MEM_guardedalloc.h"
#include "BKE_attribute.h"
#include "BLI_string.h"
#include "BLI_vector.hh"
#include "draw_subdivision.h"
#include "extract_mesh.hh"
namespace blender::draw {
struct VColRef {
const CustomDataLayer *layer;
eAttrDomain domain;
};
/** Get all vcol layers as AttributeRefs.
*
* \param vcol_layers: bitmask to filter vcol layers by, each bit
* corresponds to the integer position of the attribute
* within the global color attribute list.
*/
static Vector<VColRef> get_vcol_refs(const CustomData *cd_vdata,
const CustomData *cd_ldata,
const uint vcol_layers)
{
Vector<VColRef> refs;
uint layeri = 0;
auto buildList = [&](const CustomData *cdata, eAttrDomain domain) {
for (int i = 0; i < cdata->totlayer; i++) {
const CustomDataLayer *layer = cdata->layers + i;
if (!(CD_TYPE_AS_MASK(layer->type) & CD_MASK_COLOR_ALL)) {
continue;
}
if (layer->flag & CD_FLAG_TEMPORARY) {
continue;
}
if (!(vcol_layers & (1UL << layeri))) {
layeri++;
continue;
}
VColRef ref = {};
ref.domain = domain;
ref.layer = layer;
refs.append(ref);
layeri++;
}
};
buildList(cd_vdata, ATTR_DOMAIN_POINT);
buildList(cd_ldata, ATTR_DOMAIN_CORNER);
return refs;
}
/* ---------------------------------------------------------------------- */
/** \name Extract VCol
* \{ */
/* Initialize the common vertex format for vcol for coarse and subdivided meshes. */
static void init_vcol_format(GPUVertFormat *format,
const MeshBatchCache *cache,
const CustomData *cd_vdata,
const CustomData *cd_ldata,
const CustomDataLayer *active,
const CustomDataLayer *render)
{
GPU_vertformat_deinterleave(format);
const uint32_t vcol_layers = cache->cd_used.vcol;
Vector<VColRef> refs = get_vcol_refs(cd_vdata, cd_ldata, vcol_layers);
for (const VColRef &ref : refs) {
char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
GPU_vertformat_safe_attr_name(ref.layer->name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
/* VCol layer name. */
BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name);
GPU_vertformat_attr_add(format, attr_name, GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
/* Active layer name. */
if (ref.layer == active) {
GPU_vertformat_alias_add(format, "ac");
}
/* Active render layer name. */
if (ref.layer == render) {
GPU_vertformat_alias_add(format, "c");
}
}
}
/* Vertex format for vertex colors, only used during the coarse data upload for the subdivision
* case. */
static GPUVertFormat *get_coarse_vcol_format()
{
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
GPU_vertformat_attr_add(&format, "cCol", GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
GPU_vertformat_alias_add(&format, "c");
GPU_vertformat_alias_add(&format, "ac");
}
return &format;
}
struct gpuMeshVcol {
ushort r, g, b, a;
};
static void extract_vcol_init(const MeshRenderData *mr,
MeshBatchCache *cache,
void *buf,
void *UNUSED(tls_data))
{
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
GPUVertFormat format = {0};
const CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata :
&mr->me->vdata;
const CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata :
&mr->me->ldata;
Mesh me_query = blender::dna::shallow_zero_initialize();
BKE_id_attribute_copy_domains_temp(
ID_ME, cd_vdata, nullptr, cd_ldata, nullptr, nullptr, &me_query.id);
const CustomDataLayer *active_color = BKE_id_attributes_active_color_get(&me_query.id);
const CustomDataLayer *render_color = BKE_id_attributes_render_color_get(&me_query.id);
const uint32_t vcol_layers = cache->cd_used.vcol;
init_vcol_format(&format, cache, cd_vdata, cd_ldata, active_color, render_color);
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len);
gpuMeshVcol *vcol_data = (gpuMeshVcol *)GPU_vertbuf_get_data(vbo);
Vector<VColRef> refs = get_vcol_refs(cd_vdata, cd_ldata, vcol_layers);
for (const VColRef &ref : refs) {
const CustomData *cdata = ref.domain == ATTR_DOMAIN_POINT ? cd_vdata : cd_ldata;
if (mr->extract_type == MR_EXTRACT_BMESH) {
int cd_ofs = ref.layer->offset;
if (cd_ofs == -1) {
vcol_data += ref.domain == ATTR_DOMAIN_POINT ? mr->bm->totvert : mr->bm->totloop;
continue;
}
BMIter iter;
const bool is_byte = ref.layer->type == CD_PROP_BYTE_COLOR;
const bool is_point = ref.domain == ATTR_DOMAIN_POINT;
BMFace *f;
BM_ITER_MESH (f, &iter, mr->bm, BM_FACES_OF_MESH) {
const BMLoop *l_iter = f->l_first;
do {
const BMElem *elem = is_point ? reinterpret_cast<const BMElem *>(l_iter->v) :
reinterpret_cast<const BMElem *>(l_iter);
if (is_byte) {
const MLoopCol *mloopcol = (const MLoopCol *)BM_ELEM_CD_GET_VOID_P(elem, cd_ofs);
vcol_data->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->r]);
vcol_data->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->g]);
vcol_data->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->b]);
vcol_data->a = unit_float_to_ushort_clamp(mloopcol->a * (1.0f / 255.0f));
vcol_data++;
}
else {
const MPropCol *mpcol = (const MPropCol *)BM_ELEM_CD_GET_VOID_P(elem, cd_ofs);
vcol_data->r = unit_float_to_ushort_clamp(mpcol->color[0]);
vcol_data->g = unit_float_to_ushort_clamp(mpcol->color[1]);
vcol_data->b = unit_float_to_ushort_clamp(mpcol->color[2]);
vcol_data->a = unit_float_to_ushort_clamp(mpcol->color[3]);
vcol_data++;
}
} while ((l_iter = l_iter->next) != f->l_first);
}
}
else {
int totloop = mr->loop_len;
const int idx = CustomData_get_named_layer_index(cdata, ref.layer->type, ref.layer->name);
const MLoopCol *mcol = nullptr;
const MPropCol *pcol = nullptr;
const MLoop *mloop = mr->mloop;
if (ref.layer->type == CD_PROP_COLOR) {
pcol = static_cast<const MPropCol *>(cdata->layers[idx].data);
}
else {
mcol = static_cast<const MLoopCol *>(cdata->layers[idx].data);
}
const bool is_corner = ref.domain == ATTR_DOMAIN_CORNER;
for (int i = 0; i < totloop; i++, mloop++) {
const int v_i = is_corner ? i : mloop->v;
if (mcol) {
vcol_data->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol[v_i].r]);
vcol_data->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol[v_i].g]);
vcol_data->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol[v_i].b]);
vcol_data->a = unit_float_to_ushort_clamp(mcol[v_i].a * (1.0f / 255.0f));
vcol_data++;
}
else if (pcol) {
vcol_data->r = unit_float_to_ushort_clamp(pcol[v_i].color[0]);
vcol_data->g = unit_float_to_ushort_clamp(pcol[v_i].color[1]);
vcol_data->b = unit_float_to_ushort_clamp(pcol[v_i].color[2]);
vcol_data->a = unit_float_to_ushort_clamp(pcol[v_i].color[3]);
vcol_data++;
}
}
}
}
}
static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *mr,
MeshBatchCache *cache,
void *buffer,
void *UNUSED(data))
{
GPUVertBuf *dst_buffer = static_cast<GPUVertBuf *>(buffer);
const Mesh *coarse_mesh = subdiv_cache->mesh;
bool extract_bmesh = mr->extract_type == MR_EXTRACT_BMESH;
const CustomData *cd_vdata = extract_bmesh ? &coarse_mesh->edit_mesh->bm->vdata :
&coarse_mesh->vdata;
const CustomData *cd_ldata = extract_bmesh ? &coarse_mesh->edit_mesh->bm->ldata :
&coarse_mesh->ldata;
const int totloop = extract_bmesh ? coarse_mesh->edit_mesh->bm->totloop : coarse_mesh->totloop;
Mesh me_query = blender::dna::shallow_copy(*coarse_mesh);
BKE_id_attribute_copy_domains_temp(
ID_ME, cd_vdata, nullptr, cd_ldata, nullptr, nullptr, &me_query.id);
const CustomDataLayer *active_color = BKE_id_attributes_active_color_get(&me_query.id);
const CustomDataLayer *render_color = BKE_id_attributes_render_color_get(&me_query.id);
GPUVertFormat format = {0};
init_vcol_format(
&format, cache, &coarse_mesh->vdata, &coarse_mesh->ldata, active_color, render_color);
GPU_vertbuf_init_build_on_device(dst_buffer, &format, subdiv_cache->num_subdiv_loops);
GPUVertBuf *src_data = GPU_vertbuf_calloc();
/* Dynamic as we upload and interpolate layers one at a time. */
GPU_vertbuf_init_with_format_ex(src_data, get_coarse_vcol_format(), GPU_USAGE_DYNAMIC);
GPU_vertbuf_data_alloc(src_data, totloop);
gpuMeshVcol *mesh_vcol = (gpuMeshVcol *)GPU_vertbuf_get_data(src_data);
const uint vcol_layers = cache->cd_used.vcol;
Vector<VColRef> refs = get_vcol_refs(cd_vdata, cd_ldata, vcol_layers);
/* Index of the vertex color layer in the compact buffer. Used vertex color layers are stored in
* a single buffer. */
int pack_layer_index = 0;
for (const VColRef &ref : refs) {
/* Include stride in offset, we use a stride of 2 since colors are packed into 2 uints. */
const int dst_offset = (int)subdiv_cache->num_subdiv_loops * 2 * pack_layer_index++;
const CustomData *cdata = ref.domain == ATTR_DOMAIN_POINT ? cd_vdata : cd_ldata;
int layer_i = CustomData_get_named_layer_index(cdata, ref.layer->type, ref.layer->name);
if (layer_i == -1) {
printf("%s: missing color layer %s\n", __func__, ref.layer->name);
continue;
}
gpuMeshVcol *vcol = mesh_vcol;
const bool is_vert = ref.domain == ATTR_DOMAIN_POINT;
if (extract_bmesh) {
BMesh *bm = coarse_mesh->edit_mesh->bm;
BMIter iter;
BMFace *f;
int cd_ofs = cdata->layers[layer_i].offset;
const bool is_byte = ref.layer->type == CD_PROP_BYTE_COLOR;
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
const BMLoop *l_iter = f->l_first;
do {
const BMElem *elem = is_vert ? reinterpret_cast<const BMElem *>(l_iter->v) :
reinterpret_cast<const BMElem *>(l_iter);
if (is_byte) {
const MLoopCol *mcol2 = static_cast<const MLoopCol *>(
BM_ELEM_CD_GET_VOID_P(elem, cd_ofs));
vcol->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol2->r]);
vcol->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol2->g]);
vcol->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol2->b]);
vcol->a = unit_float_to_ushort_clamp(mcol2->a * (1.0f / 255.0f));
}
else {
const MPropCol *pcol2 = static_cast<const MPropCol *>(
BM_ELEM_CD_GET_VOID_P(elem, cd_ofs));
vcol->r = unit_float_to_ushort_clamp(pcol2->color[0]);
vcol->g = unit_float_to_ushort_clamp(pcol2->color[1]);
vcol->b = unit_float_to_ushort_clamp(pcol2->color[2]);
vcol->a = unit_float_to_ushort_clamp(pcol2->color[3]);
}
vcol++;
} while ((l_iter = l_iter->next) != f->l_first);
}
}
else {
const MLoop *ml = coarse_mesh->mloop;
const MLoopCol *mcol = nullptr;
const MPropCol *pcol = nullptr;
if (ref.layer->type == CD_PROP_COLOR) {
pcol = static_cast<const MPropCol *>(cdata->layers[layer_i].data);
}
else {
mcol = static_cast<const MLoopCol *>(cdata->layers[layer_i].data);
}
for (int ml_index = 0; ml_index < coarse_mesh->totloop; ml_index++, vcol++, ml++) {
int idx = is_vert ? ml->v : ml_index;
if (mcol) {
vcol->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol[idx].r]);
vcol->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol[idx].g]);
vcol->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol[idx].b]);
vcol->a = unit_float_to_ushort_clamp(mcol[idx].a * (1.0f / 255.0f));
}
else if (pcol) {
vcol->r = unit_float_to_ushort_clamp(pcol[idx].color[0]);
vcol->g = unit_float_to_ushort_clamp(pcol[idx].color[1]);
vcol->b = unit_float_to_ushort_clamp(pcol[idx].color[2]);
vcol->a = unit_float_to_ushort_clamp(pcol[idx].color[3]);
}
}
}
/* Ensure data is uploaded properly. */
GPU_vertbuf_tag_dirty(src_data);
draw_subdiv_interp_custom_data(subdiv_cache, src_data, dst_buffer, 4, dst_offset, true);
}
GPU_vertbuf_discard(src_data);
}
constexpr MeshExtract create_extractor_vcol()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_vcol_init;
extractor.init_subdiv = extract_vcol_init_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = 0;
extractor.use_threading = false;
extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.vcol);
return extractor;
}
/** \} */
} // namespace blender::draw
const MeshExtract extract_vcol = blender::draw::create_extractor_vcol();

View File

@ -131,6 +131,11 @@ typedef void (*GPUCodegenCallbackFn)(void *thunk, GPUMaterial *mat, GPUCodegenOu
GPUNodeLink *GPU_constant(const float *num);
GPUNodeLink *GPU_uniform(const float *num);
GPUNodeLink *GPU_attribute(GPUMaterial *mat, eCustomDataType type, const char *name);
/**
* Add a GPU attribute that refers to the default color attribute on a geometry.
* The name, type, and domain are unknown and do not depend on the material.
*/
GPUNodeLink *GPU_attribute_default_color(GPUMaterial *mat);
GPUNodeLink *GPU_attribute_with_default(GPUMaterial *mat,
eCustomDataType type,
const char *name,
@ -266,6 +271,12 @@ typedef struct GPUMaterialAttribute {
eGPUDefaultValue default_value; /* Only for volumes attributes. */
int id;
int users;
/**
* If true, the corresponding attribute is the specified default color attribute on the mesh,
* if it exists. In that case the type and name data can vary per geometry, so it will not be
* valid here.
*/
bool is_default_color;
} GPUMaterialAttribute;
typedef struct GPUMaterialTexture {

View File

@ -328,13 +328,14 @@ void gpu_node_graph_finalize_uniform_attrs(GPUNodeGraph *graph)
/* Attributes and Textures */
static char attr_prefix_get(eCustomDataType type)
static char attr_prefix_get(GPUMaterialAttribute *attr)
{
switch (type) {
if (attr->is_default_color) {
return 'c';
}
switch (attr->type) {
case CD_TANGENT:
return 't';
case CD_MCOL:
return 'c';
case CD_AUTO_FROM_NAME:
return 'a';
case CD_HAIRLENGTH:
@ -353,7 +354,7 @@ static void attr_input_name(GPUMaterialAttribute *attr)
STRNCPY(attr->input_name, "orco");
}
else {
attr->input_name[0] = attr_prefix_get(attr->type);
attr->input_name[0] = attr_prefix_get(attr);
attr->input_name[1] = '\0';
if (attr->name[0] != '\0') {
/* XXX FIXME: see notes in mesh_render_data_create() */
@ -365,13 +366,15 @@ static void attr_input_name(GPUMaterialAttribute *attr)
/** Add a new varying attribute of given type and name. Returns NULL if out of slots. */
static GPUMaterialAttribute *gpu_node_graph_add_attribute(GPUNodeGraph *graph,
eCustomDataType type,
const char *name)
const char *name,
const bool is_default_color)
{
/* Find existing attribute. */
int num_attributes = 0;
GPUMaterialAttribute *attr = graph->attributes.first;
for (; attr; attr = attr->next) {
if (attr->type == type && STREQ(attr->name, name)) {
if (attr->type == type && STREQ(attr->name, name) &&
attr->is_default_color == is_default_color) {
break;
}
num_attributes++;
@ -380,6 +383,7 @@ static GPUMaterialAttribute *gpu_node_graph_add_attribute(GPUNodeGraph *graph,
/* Add new requested attribute if it's within GPU limits. */
if (attr == NULL) {
attr = MEM_callocN(sizeof(*attr), __func__);
attr->is_default_color = is_default_color;
attr->type = type;
STRNCPY(attr->name, name);
attr_input_name(attr);
@ -471,7 +475,7 @@ static GPUMaterialTexture *gpu_node_graph_add_texture(GPUNodeGraph *graph,
GPUNodeLink *GPU_attribute(GPUMaterial *mat, const eCustomDataType type, const char *name)
{
GPUNodeGraph *graph = gpu_material_node_graph(mat);
GPUMaterialAttribute *attr = gpu_node_graph_add_attribute(graph, type, name);
GPUMaterialAttribute *attr = gpu_node_graph_add_attribute(graph, type, name, false);
if (type == CD_ORCO) {
/* OPTI: orco might be computed from local positions and needs object infos. */
@ -490,6 +494,21 @@ GPUNodeLink *GPU_attribute(GPUMaterial *mat, const eCustomDataType type, const c
return link;
}
GPUNodeLink *GPU_attribute_default_color(GPUMaterial *mat)
{
GPUNodeGraph *graph = gpu_material_node_graph(mat);
GPUMaterialAttribute *attr = gpu_node_graph_add_attribute(graph, CD_AUTO_FROM_NAME, "", true);
if (attr == NULL) {
static const float zero_data[GPU_MAX_CONSTANT_DATA] = {0.0f};
return GPU_constant(zero_data);
}
attr->is_default_color = true;
GPUNodeLink *link = gpu_node_link_create();
link->link_type = GPU_NODE_LINK_ATTR;
link->attr = attr;
return link;
}
GPUNodeLink *GPU_attribute_with_default(GPUMaterial *mat,
const eCustomDataType type,
const char *name,

View File

@ -42,9 +42,8 @@ static int node_shader_gpu_vertex_color(GPUMaterial *mat,
GPUNodeStack *out)
{
NodeShaderVertexColor *vertexColor = (NodeShaderVertexColor *)node->storage;
/* NOTE: using CD_AUTO_FROM_NAME instead of CD_MCOL or CD_PROP_COLOR for named attributes
* as geometry nodes may overwrite data which will also change the eCustomDataType.
* This will also make EEVEE and Cycles
/* NOTE: Using #CD_AUTO_FROM_NAME is necessary because there are multiple color attribute types,
* and the type may change during evaluation anyway. This will also make EEVEE and Cycles
* consistent. See T93179. */
GPUNodeLink *vertexColorLink;
@ -53,7 +52,7 @@ static int node_shader_gpu_vertex_color(GPUMaterial *mat,
vertexColorLink = GPU_attribute(mat, CD_AUTO_FROM_NAME, vertexColor->layer_name);
}
else { /* Fall back on active render color attribute. */
vertexColorLink = GPU_attribute(mat, CD_MCOL, vertexColor->layer_name);
vertexColorLink = GPU_attribute_default_color(mat);
}
return GPU_stack_link(mat, node, "node_vertex_color", in, out, vertexColorLink);