DRW-Next: Add uniform attributes (object attributes) support
This replaces the direct shader uniform layout declaration by a linear search through a global buffer. Each instance has an attribute offset inside the global buffer and an attribute count. This removes any padding and tighly pack all uniform attributes inside a single buffer. This would also remove the limit of 8 attribute but it is kept because of compatibility with the old system that is still used by the old draw manager.
This commit is contained in:
@@ -227,6 +227,8 @@ set(SRC
|
||||
intern/draw_manager.h
|
||||
intern/draw_manager.hh
|
||||
intern/draw_pass.hh
|
||||
intern/draw_resource.cc
|
||||
intern/draw_resource.hh
|
||||
intern/draw_shader_shared.h
|
||||
intern/draw_shader.h
|
||||
intern/draw_subdivision.h
|
||||
|
||||
@@ -152,3 +152,7 @@ vec4 attr_load_color_post(vec4 attr)
|
||||
{
|
||||
return attr;
|
||||
}
|
||||
vec4 attr_load_uniform(vec4 attr, const uint attr_hash)
|
||||
{
|
||||
return attr;
|
||||
}
|
||||
|
||||
@@ -182,3 +182,7 @@ vec4 attr_load_color_post(vec4 attr)
|
||||
{
|
||||
return attr;
|
||||
}
|
||||
vec4 attr_load_uniform(vec4 attr, const uint attr_hash)
|
||||
{
|
||||
return attr;
|
||||
}
|
||||
|
||||
@@ -165,3 +165,7 @@ vec4 attr_load_color_post(vec4 attr)
|
||||
{
|
||||
return attr;
|
||||
}
|
||||
vec4 attr_load_uniform(vec4 attr, const uint attr_hash)
|
||||
{
|
||||
return attr;
|
||||
}
|
||||
|
||||
@@ -178,3 +178,7 @@ vec4 attr_load_color_post(vec4 attr)
|
||||
#endif
|
||||
return attr;
|
||||
}
|
||||
vec4 attr_load_uniform(vec4 attr, const uint attr_hash)
|
||||
{
|
||||
return attr;
|
||||
}
|
||||
|
||||
@@ -87,3 +87,8 @@ vec4 attr_load_color_post(vec4 attr)
|
||||
{
|
||||
return attr;
|
||||
}
|
||||
|
||||
vec4 attr_load_uniform(vec4 attr, const uint attr_hash)
|
||||
{
|
||||
return attr;
|
||||
}
|
||||
|
||||
@@ -409,3 +409,26 @@ vec4 attr_load_color_post(vec4 attr)
|
||||
#endif
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Volume Attribute post
|
||||
*
|
||||
* TODO(@fclem): These implementation details should concern the DRWManager and not be a fix on
|
||||
* the engine side. But as of now, the engines are responsible for loading the attributes.
|
||||
*
|
||||
* \{ */
|
||||
|
||||
vec4 attr_load_uniform(vec4 attr, const uint attr_hash)
|
||||
{
|
||||
#if defined(OBINFO_LIB) && defined(OBATTR_LIB)
|
||||
for (int i = ObjectAttributeStart; i < ObjectAttributeLen; i++) {
|
||||
if (drw_attrs[i].hash_code == attr_hash) {
|
||||
return vec4(
|
||||
drw_attrs[i].data_x, drw_attrs[i].data_y, drw_attrs[i].data_z, drw_attrs[i].data_w);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return attr;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -43,6 +43,7 @@ void Manager::begin_sync()
|
||||
memset(infos_buf.data(), 0xF0, resource_len_ * sizeof(*infos_buf.data()));
|
||||
#endif
|
||||
resource_len_ = 0;
|
||||
attribute_len_ = 0;
|
||||
/* TODO(fclem): Resize buffers if too big, but with an hysteresis threshold. */
|
||||
|
||||
object_active = DST.draw_ctx.obact;
|
||||
@@ -58,6 +59,8 @@ void Manager::end_sync()
|
||||
matrix_buf.push_update();
|
||||
bounds_buf.push_update();
|
||||
infos_buf.push_update();
|
||||
attributes_buf.push_update();
|
||||
attributes_buf_legacy.push_update();
|
||||
|
||||
debug_bind();
|
||||
|
||||
@@ -90,6 +93,16 @@ void Manager::debug_bind()
|
||||
#endif
|
||||
}
|
||||
|
||||
void Manager::resource_bind()
|
||||
{
|
||||
GPU_storagebuf_bind(matrix_buf, DRW_OBJ_MAT_SLOT);
|
||||
GPU_storagebuf_bind(infos_buf, DRW_OBJ_INFOS_SLOT);
|
||||
GPU_storagebuf_bind(attributes_buf, DRW_OBJ_ATTR_SLOT);
|
||||
/* 2 is the hardcoded location of the uniform attr UBO. */
|
||||
/* TODO(@fclem): Remove this workaround. */
|
||||
GPU_uniformbuf_bind(attributes_buf_legacy, 2);
|
||||
}
|
||||
|
||||
void Manager::submit(PassSimple &pass, View &view)
|
||||
{
|
||||
view.bind();
|
||||
@@ -101,9 +114,7 @@ void Manager::submit(PassSimple &pass, View &view)
|
||||
|
||||
pass.draw_commands_buf_.bind(state, pass.headers_, pass.commands_);
|
||||
|
||||
GPU_storagebuf_bind(matrix_buf, DRW_OBJ_MAT_SLOT);
|
||||
GPU_storagebuf_bind(infos_buf, DRW_OBJ_INFOS_SLOT);
|
||||
// GPU_storagebuf_bind(attribute_buf, DRW_OBJ_ATTR_SLOT); /* TODO */
|
||||
resource_bind();
|
||||
|
||||
pass.submit(state);
|
||||
|
||||
@@ -126,9 +137,7 @@ void Manager::submit(PassMain &pass, View &view)
|
||||
|
||||
pass.draw_commands_buf_.bind(state, pass.headers_, pass.commands_, view.visibility_buf_);
|
||||
|
||||
GPU_storagebuf_bind(matrix_buf, DRW_OBJ_MAT_SLOT);
|
||||
GPU_storagebuf_bind(infos_buf, DRW_OBJ_INFOS_SLOT);
|
||||
// GPU_storagebuf_bind(attribute_buf, DRW_OBJ_ATTR_SLOT); /* TODO */
|
||||
resource_bind();
|
||||
|
||||
pass.submit(state);
|
||||
|
||||
@@ -150,9 +159,7 @@ void Manager::submit(PassSimple &pass)
|
||||
|
||||
pass.draw_commands_buf_.bind(state, pass.headers_, pass.commands_);
|
||||
|
||||
GPU_storagebuf_bind(matrix_buf, DRW_OBJ_MAT_SLOT);
|
||||
GPU_storagebuf_bind(infos_buf, DRW_OBJ_INFOS_SLOT);
|
||||
// GPU_storagebuf_bind(attribute_buf, DRW_OBJ_ATTR_SLOT); /* TODO */
|
||||
resource_bind();
|
||||
|
||||
pass.submit(state);
|
||||
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
* \note It is currently work in progress and should replace the old global draw manager.
|
||||
*/
|
||||
|
||||
#include "BLI_listbase_wrapper.hh"
|
||||
#include "BLI_sys_types.h"
|
||||
#include "GPU_material.h"
|
||||
|
||||
#include "draw_resource.hh"
|
||||
#include "draw_view.hh"
|
||||
@@ -41,6 +43,9 @@ class Manager {
|
||||
using ObjectMatricesBuf = StorageArrayBuffer<ObjectMatrices, 128>;
|
||||
using ObjectBoundsBuf = StorageArrayBuffer<ObjectBounds, 128>;
|
||||
using ObjectInfosBuf = StorageArrayBuffer<ObjectInfos, 128>;
|
||||
using ObjectAttributeBuf = StorageArrayBuffer<ObjectAttribute, 128>;
|
||||
/** TODO(fclem): Remove once we get rid of old EEVEE codebase. DRW_RESOURCE_CHUNK_LEN = 512 */
|
||||
using ObjectAttributeLegacyBuf = UniformArrayBuffer<float4, 8 * 512>;
|
||||
|
||||
public:
|
||||
struct SubmitDebugOutput {
|
||||
@@ -67,14 +72,25 @@ class Manager {
|
||||
ObjectBoundsBuf bounds_buf;
|
||||
ObjectInfosBuf infos_buf;
|
||||
|
||||
/**
|
||||
* Object Attributes are reference by indirection data inside ObjectInfos.
|
||||
* This is because attribute list is arbitrary.
|
||||
*/
|
||||
ObjectAttributeBuf attributes_buf;
|
||||
/** TODO(fclem): Remove once we get rid of old EEVEE codebase. Only here to satisfy bindings. */
|
||||
ObjectAttributeLegacyBuf attributes_buf_legacy;
|
||||
|
||||
/** List of textures coming from Image data-blocks. They need to be refcounted in order to avoid
|
||||
* beeing freed in another thread. */
|
||||
Vector<GPUTexture *> acquired_textures;
|
||||
|
||||
private:
|
||||
/** Number of resource handle recorded. */
|
||||
uint resource_len_ = 0;
|
||||
Object *object = nullptr;
|
||||
/** Number of object attribute recorded. */
|
||||
uint attribute_len_ = 0;
|
||||
|
||||
Object *object = nullptr;
|
||||
Object *object_active = nullptr;
|
||||
|
||||
public:
|
||||
@@ -104,7 +120,7 @@ class Manager {
|
||||
* Populate additional per resource data on demand.
|
||||
*/
|
||||
void extract_object_attributes(ResourceHandle handle,
|
||||
Object &object,
|
||||
const ObjectRef &ref,
|
||||
Span<GPUMaterial *> materials);
|
||||
|
||||
/**
|
||||
@@ -145,6 +161,7 @@ class Manager {
|
||||
void end_sync();
|
||||
|
||||
void debug_bind();
|
||||
void resource_bind();
|
||||
};
|
||||
|
||||
inline ResourceHandle Manager::resource_handle(const ObjectRef ref)
|
||||
@@ -175,13 +192,34 @@ inline ResourceHandle Manager::resource_handle(const float4x4 &model_matrix,
|
||||
}
|
||||
|
||||
inline void Manager::extract_object_attributes(ResourceHandle handle,
|
||||
Object &object,
|
||||
const ObjectRef &ref,
|
||||
Span<GPUMaterial *> materials)
|
||||
{
|
||||
/* TODO */
|
||||
(void)handle;
|
||||
(void)object;
|
||||
(void)materials;
|
||||
ObjectInfos &infos = infos_buf.get_or_resize(handle.resource_index());
|
||||
infos.object_attrs_offset = attribute_len_;
|
||||
|
||||
/* Simple cache solution to avoid duplicates. */
|
||||
Vector<uint32_t, 4> hash_cache;
|
||||
|
||||
for (const GPUMaterial *mat : materials) {
|
||||
const GPUUniformAttrList *attr_list = GPU_material_uniform_attributes(mat);
|
||||
if (attr_list == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (const GPUUniformAttr *, attr, &attr_list->list) {
|
||||
/** WATCH: Linear Search. Avoid duplicate attributes across materials. */
|
||||
if ((mat != materials.first()) && (hash_cache.first_index_of_try(attr->hash_code) != -1)) {
|
||||
/* Attribute has already been added to the attribute buffer by another material. */
|
||||
continue;
|
||||
}
|
||||
hash_cache.append(attr->hash_code);
|
||||
if (attributes_buf.get_or_resize(attribute_len_).sync(ref, *attr)) {
|
||||
infos.object_attrs_len++;
|
||||
attribute_len_++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::draw
|
||||
|
||||
109
source/blender/draw/intern/draw_resource.cc
Normal file
109
source/blender/draw/intern/draw_resource.cc
Normal file
@@ -0,0 +1,109 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2022 Blender Foundation. */
|
||||
|
||||
/** \file
|
||||
* \ingroup draw
|
||||
*/
|
||||
|
||||
#include "DNA_particle_types.h"
|
||||
#include "RNA_access.h"
|
||||
#include "RNA_path.h"
|
||||
#include "RNA_types.h"
|
||||
|
||||
#include "draw_handle.hh"
|
||||
#include "draw_manager.hh"
|
||||
#include "draw_shader_shared.h"
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name ObjectAttributes
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* Extract object attribute from RNA property.
|
||||
* Returns true if the attribute was correctly extracted.
|
||||
* This function mirrors lookup_property in cycles/blender/blender_object.cpp
|
||||
*/
|
||||
bool ObjectAttribute::id_property_lookup(ID *id, const char *name)
|
||||
{
|
||||
PointerRNA ptr, id_ptr;
|
||||
PropertyRNA *prop;
|
||||
|
||||
if (id == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RNA_id_pointer_create(id, &id_ptr);
|
||||
|
||||
if (!RNA_path_resolve(&id_ptr, name, &ptr, &prop)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (prop == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PropertyType type = RNA_property_type(prop);
|
||||
int array_len = RNA_property_array_length(&ptr, prop);
|
||||
|
||||
if (array_len == 0) {
|
||||
float value;
|
||||
|
||||
if (type == PROP_FLOAT) {
|
||||
value = RNA_property_float_get(&ptr, prop);
|
||||
}
|
||||
else if (type == PROP_INT) {
|
||||
value = RNA_property_int_get(&ptr, prop);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
*reinterpret_cast<float4 *>(&data_x) = float4(value, value, value, 1.0f);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (type == PROP_FLOAT && array_len <= 4) {
|
||||
*reinterpret_cast<float4 *>(&data_x) = float4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
RNA_property_float_get_array(&ptr, prop, &data_x);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Go through all possible source of the given object uniform attribute.
|
||||
* Returns true if the attribute was correctly filled.
|
||||
* This function mirrors lookup_instance_property in cycles/blender/blender_object.cpp
|
||||
*/
|
||||
bool ObjectAttribute::sync(const blender::draw::ObjectRef &ref, const GPUUniformAttr &attr)
|
||||
{
|
||||
hash_code = attr.hash_code;
|
||||
|
||||
/* If requesting instance data, check the parent particle system and object. */
|
||||
if (attr.use_dupli) {
|
||||
if ((ref.dupli_object != nullptr) && (ref.dupli_object->particle_system != nullptr)) {
|
||||
ParticleSettings *settings = ref.dupli_object->particle_system->part;
|
||||
if (this->id_property_lookup((ID *)settings, attr.name_id_prop) ||
|
||||
this->id_property_lookup((ID *)settings, attr.name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (this->id_property_lookup((ID *)ref.dupli_parent, attr.name_id_prop) ||
|
||||
this->id_property_lookup((ID *)ref.dupli_parent, attr.name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check the object and mesh. */
|
||||
if (ref.object != nullptr) {
|
||||
if (this->id_property_lookup((ID *)ref.object, attr.name_id_prop) ||
|
||||
this->id_property_lookup((ID *)ref.object, attr.name) ||
|
||||
this->id_property_lookup((ID *)ref.object->data, attr.name_id_prop) ||
|
||||
this->id_property_lookup((ID *)ref.object->data, attr.name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
@@ -59,11 +59,17 @@ ENUM_OPERATORS(eObjectInfoFlag, OBJECT_NEGATIVE_SCALE)
|
||||
|
||||
inline void ObjectInfos::sync()
|
||||
{
|
||||
object_attrs_len = 0;
|
||||
object_attrs_offset = 0;
|
||||
|
||||
flag = eObjectInfoFlag::OBJECT_NO_INFO;
|
||||
}
|
||||
|
||||
inline void ObjectInfos::sync(const blender::draw::ObjectRef ref, bool is_active_object)
|
||||
{
|
||||
object_attrs_len = 0;
|
||||
object_attrs_offset = 0;
|
||||
|
||||
color = ref.object->color;
|
||||
index = ref.object->index;
|
||||
SET_FLAG_FROM_TEST(flag, is_active_object, eObjectInfoFlag::OBJECT_ACTIVE);
|
||||
|
||||
@@ -13,6 +13,7 @@ typedef struct ObjectInfos ObjectInfos;
|
||||
typedef struct ObjectBounds ObjectBounds;
|
||||
typedef struct VolumeInfos VolumeInfos;
|
||||
typedef struct CurvesInfos CurvesInfos;
|
||||
typedef struct ObjectAttribute ObjectAttribute;
|
||||
typedef struct DrawCommand DrawCommand;
|
||||
typedef struct DispatchCommand DispatchCommand;
|
||||
typedef struct DRWDebugPrintBuffer DRWDebugPrintBuffer;
|
||||
@@ -22,6 +23,8 @@ typedef struct DRWDebugDrawBuffer DRWDebugDrawBuffer;
|
||||
# ifdef __cplusplus
|
||||
/* C++ only forward declarations. */
|
||||
struct Object;
|
||||
struct ID;
|
||||
struct GPUUniformAttr;
|
||||
|
||||
namespace blender::draw {
|
||||
|
||||
@@ -130,9 +133,9 @@ struct ObjectInfos {
|
||||
#else
|
||||
/** Uploaded as center + size. Converted to mul+bias to local coord. */
|
||||
float3 orco_add;
|
||||
float _pad0;
|
||||
uint object_attrs_offset;
|
||||
float3 orco_mul;
|
||||
float _pad1;
|
||||
uint object_attrs_len;
|
||||
|
||||
float4 color;
|
||||
uint index;
|
||||
@@ -193,6 +196,23 @@ struct CurvesInfos {
|
||||
};
|
||||
BLI_STATIC_ASSERT_ALIGN(CurvesInfos, 16)
|
||||
|
||||
#pragma pack(push, 4)
|
||||
struct ObjectAttribute {
|
||||
/* Workaround the padding cost from alignment requirements.
|
||||
* (see GL spec : 7.6.2.2 Standard Uniform Block Layout) */
|
||||
float data_x, data_y, data_z, data_w;
|
||||
uint hash_code;
|
||||
|
||||
#if !defined(GPU_SHADER) && defined(__cplusplus)
|
||||
bool sync(const blender::draw::ObjectRef &ref, const GPUUniformAttr &attr);
|
||||
bool id_property_lookup(ID *id, const char *name);
|
||||
#endif
|
||||
};
|
||||
#pragma pack(pop)
|
||||
/** \note we only align to 4 bytes and fetch data manually so make sure
|
||||
* C++ compiler gives us the same size. */
|
||||
BLI_STATIC_ASSERT_ALIGN(ObjectAttribute, 20)
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
@@ -25,3 +25,4 @@ float attr_load_float(sampler3D tex);
|
||||
|
||||
float attr_load_temperature_post(float attr);
|
||||
vec4 attr_load_color_post(vec4 attr);
|
||||
vec4 attr_load_uniform(vec4 attr, const uint attr_hash);
|
||||
|
||||
@@ -25,4 +25,12 @@ GPU_SHADER_CREATE_INFO(draw_object_infos_new)
|
||||
.define("OrcoTexCoFactors", "(drw_infos[resource_id].orco_mul_bias)")
|
||||
.define("ObjectInfo", "(drw_infos[resource_id].infos)")
|
||||
.define("ObjectColor", "(drw_infos[resource_id].color)")
|
||||
.storage_buf(DRW_OBJ_INFOS_SLOT, Qualifier::READ, "ObjectInfos", "drw_infos[]");
|
||||
.storage_buf(DRW_OBJ_INFOS_SLOT, Qualifier::READ, "ObjectInfos", "drw_infos[]");
|
||||
|
||||
/** \note Requires draw_object_infos_new. */
|
||||
GPU_SHADER_CREATE_INFO(draw_object_attribute_new)
|
||||
.define("OBATTR_LIB")
|
||||
.define("ObjectAttributeStart", "(drw_infos[resource_id].orco_mul_bias[0].w)")
|
||||
.define("ObjectAttributeLen", "(drw_infos[resource_id].orco_mul_bias[1].w)")
|
||||
.storage_buf(DRW_OBJ_ATTR_SLOT, Qualifier::READ, "ObjectAttribute", "drw_attrs[]")
|
||||
.additional_info("draw_object_infos_new");
|
||||
|
||||
@@ -149,7 +149,10 @@ GPUNodeLink *GPU_attribute_with_default(GPUMaterial *mat,
|
||||
eCustomDataType type,
|
||||
const char *name,
|
||||
eGPUDefaultValue default_value);
|
||||
GPUNodeLink *GPU_uniform_attribute(GPUMaterial *mat, const char *name, bool use_dupli);
|
||||
GPUNodeLink *GPU_uniform_attribute(GPUMaterial *mat,
|
||||
const char *name,
|
||||
bool use_dupli,
|
||||
uint32_t *r_hash);
|
||||
GPUNodeLink *GPU_image(GPUMaterial *mat,
|
||||
struct Image *ima,
|
||||
struct ImageUser *iuser,
|
||||
|
||||
@@ -199,8 +199,7 @@ static std::ostream &operator<<(std::ostream &stream, const GPUOutput *output)
|
||||
}
|
||||
|
||||
/* Trick type to change overload and keep a somewhat nice syntax. */
|
||||
struct GPUConstant : public GPUInput {
|
||||
};
|
||||
struct GPUConstant : public GPUInput {};
|
||||
|
||||
/* Print data constructor (i.e: vec2(1.0f, 1.0f)). */
|
||||
static std::ostream &operator<<(std::ostream &stream, const GPUConstant *input)
|
||||
@@ -208,9 +207,10 @@ static std::ostream &operator<<(std::ostream &stream, const GPUConstant *input)
|
||||
stream << input->type << "(";
|
||||
for (int i = 0; i < input->type; i++) {
|
||||
char formated_float[32];
|
||||
/* Print with the maximum precision for single precision float using scientific notation.
|
||||
* See https://stackoverflow.com/questions/16839658/#answer-21162120 */
|
||||
SNPRINTF(formated_float, "%.9g", input->vec[i]);
|
||||
/* Use uint representation to allow exact same bit pattern even if NaN. This is because we can
|
||||
* pass UINTs as floats for constants. */
|
||||
const uint32_t *uint_vec = reinterpret_cast<const uint32_t *>(input->vec);
|
||||
SNPRINTF(formated_float, "uintBitsToFloat(%uu)", uint_vec[i]);
|
||||
stream << formated_float;
|
||||
if (i < input->type - 1) {
|
||||
stream << ", ";
|
||||
|
||||
@@ -320,20 +320,7 @@ void gpu_node_graph_finalize_uniform_attrs(GPUNodeGraph *graph)
|
||||
|
||||
LISTBASE_FOREACH (GPUUniformAttr *, attr, &attrs->list) {
|
||||
attr->id = next_id++;
|
||||
|
||||
attr->hash_code = BLI_ghashutil_strhash_p(attr->name);
|
||||
|
||||
if (attr->use_dupli) {
|
||||
attr->hash_code ^= BLI_ghashutil_uinthash(attr->id);
|
||||
}
|
||||
|
||||
attrs->hash_code ^= attr->hash_code;
|
||||
|
||||
{
|
||||
char attr_name_esc[sizeof(attr->name) * 2];
|
||||
BLI_str_escape(attr_name_esc, attr->name, sizeof(attr_name_esc));
|
||||
SNPRINTF(attr->name_id_prop, "[\"%s\"]", attr_name_esc);
|
||||
}
|
||||
attrs->hash_code ^= BLI_ghashutil_uinthash(attr->hash_code + (1 << (attr->id + 1)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -428,7 +415,13 @@ static GPUUniformAttr *gpu_node_graph_add_uniform_attribute(GPUNodeGraph *graph,
|
||||
if (attr == NULL && attrs->count < GPU_MAX_UNIFORM_ATTR) {
|
||||
attr = MEM_callocN(sizeof(*attr), __func__);
|
||||
STRNCPY(attr->name, name);
|
||||
{
|
||||
char attr_name_esc[sizeof(attr->name) * 2];
|
||||
BLI_str_escape(attr_name_esc, attr->name, sizeof(attr_name_esc));
|
||||
SNPRINTF(attr->name_id_prop, "[\"%s\"]", attr_name_esc);
|
||||
}
|
||||
attr->use_dupli = use_dupli;
|
||||
attr->hash_code = BLI_ghashutil_strhash_p(attr->name) << 1 | (attr->use_dupli ? 0 : 1);
|
||||
attr->id = -1;
|
||||
BLI_addtail(&attrs->list, attr);
|
||||
attrs->count++;
|
||||
@@ -532,16 +525,21 @@ GPUNodeLink *GPU_attribute_with_default(GPUMaterial *mat,
|
||||
return link;
|
||||
}
|
||||
|
||||
GPUNodeLink *GPU_uniform_attribute(GPUMaterial *mat, const char *name, bool use_dupli)
|
||||
GPUNodeLink *GPU_uniform_attribute(GPUMaterial *mat,
|
||||
const char *name,
|
||||
bool use_dupli,
|
||||
uint32_t *r_hash)
|
||||
{
|
||||
GPUNodeGraph *graph = gpu_material_node_graph(mat);
|
||||
GPUUniformAttr *attr = gpu_node_graph_add_uniform_attribute(graph, name, use_dupli);
|
||||
|
||||
/* Dummy fallback if out of slots. */
|
||||
if (attr == NULL) {
|
||||
*r_hash = 0;
|
||||
static const float zero_data[GPU_MAX_CONSTANT_DATA] = {0.0f};
|
||||
return GPU_constant(zero_data);
|
||||
}
|
||||
*r_hash = attr->hash_code;
|
||||
|
||||
GPUNodeLink *link = gpu_node_link_create();
|
||||
link->link_type = GPU_NODE_LINK_UNIFORM_ATTR;
|
||||
|
||||
@@ -22,6 +22,13 @@ void node_attribute_flame(vec4 attr, out float out_attr)
|
||||
out_attr = attr.x;
|
||||
}
|
||||
|
||||
void node_attribute_uniform(vec4 attr, const float attr_hash, out vec4 out_attr)
|
||||
{
|
||||
/* Temporary solution to support both old UBO attribs and new SSBO loading.
|
||||
* Old UBO load is already done through `attr` and will just be passed through. */
|
||||
out_attr = attr_load_uniform(attr, floatBitsToUint(attr_hash));
|
||||
}
|
||||
|
||||
void node_attribute(
|
||||
vec4 attr, out vec4 outcol, out vec3 outvec, out float outf, out float outalpha)
|
||||
{
|
||||
|
||||
@@ -36,6 +36,7 @@ static int node_shader_gpu_attribute(GPUMaterial *mat,
|
||||
{
|
||||
NodeShaderAttribute *attr = static_cast<NodeShaderAttribute *>(node->storage);
|
||||
bool is_varying = attr->type == SHD_ATTRIBUTE_GEOMETRY;
|
||||
float attr_hash = 0.0f;
|
||||
|
||||
GPUNodeLink *cd_attr;
|
||||
|
||||
@@ -43,7 +44,12 @@ static int node_shader_gpu_attribute(GPUMaterial *mat,
|
||||
cd_attr = GPU_attribute(mat, CD_AUTO_FROM_NAME, attr->name);
|
||||
}
|
||||
else {
|
||||
cd_attr = GPU_uniform_attribute(mat, attr->name, attr->type == SHD_ATTRIBUTE_INSTANCER);
|
||||
cd_attr = GPU_uniform_attribute(mat,
|
||||
attr->name,
|
||||
attr->type == SHD_ATTRIBUTE_INSTANCER,
|
||||
reinterpret_cast<uint32_t *>(&attr_hash));
|
||||
|
||||
GPU_link(mat, "node_attribute_uniform", cd_attr, GPU_constant(&attr_hash), &cd_attr);
|
||||
}
|
||||
|
||||
if (STREQ(attr->name, "color")) {
|
||||
@@ -55,9 +61,11 @@ static int node_shader_gpu_attribute(GPUMaterial *mat,
|
||||
|
||||
GPU_stack_link(mat, node, "node_attribute", in, out, cd_attr);
|
||||
|
||||
int i;
|
||||
LISTBASE_FOREACH_INDEX (bNodeSocket *, sock, &node->outputs, i) {
|
||||
node_shader_gpu_bump_tex_coord(mat, node, &out[i].link);
|
||||
if (is_varying) {
|
||||
int i;
|
||||
LISTBASE_FOREACH_INDEX (bNodeSocket *, sock, &node->outputs, i) {
|
||||
node_shader_gpu_bump_tex_coord(mat, node, &out[i].link);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
Reference in New Issue
Block a user