Merge branch 'master' into sculpt-dev
This commit is contained in:
commit
46582b3743
|
@ -855,10 +855,7 @@ void BlenderSync::sync_hair(BL::Depsgraph b_depsgraph, BL::Object b_ob, Hair *ha
|
|||
hair->set_value(socket, new_hair, socket);
|
||||
}
|
||||
|
||||
hair->attributes.clear();
|
||||
foreach (Attribute &attr, new_hair.attributes.attributes) {
|
||||
hair->attributes.attributes.push_back(std::move(attr));
|
||||
}
|
||||
hair->attributes.update(std::move(new_hair.attributes));
|
||||
|
||||
/* tag update */
|
||||
|
||||
|
|
|
@ -124,7 +124,7 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
|
|||
|
||||
foreach (Node *node, geom->get_used_shaders()) {
|
||||
Shader *shader = static_cast<Shader *>(node);
|
||||
if (shader->need_update_geometry) {
|
||||
if (shader->need_update_geometry()) {
|
||||
attribute_recalc = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1075,15 +1075,8 @@ void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *me
|
|||
mesh->set_value(socket, new_mesh, socket);
|
||||
}
|
||||
|
||||
mesh->attributes.clear();
|
||||
foreach (Attribute &attr, new_mesh.attributes.attributes) {
|
||||
mesh->attributes.attributes.push_back(std::move(attr));
|
||||
}
|
||||
|
||||
mesh->subd_attributes.clear();
|
||||
foreach (Attribute &attr, new_mesh.subd_attributes.attributes) {
|
||||
mesh->subd_attributes.attributes.push_back(std::move(attr));
|
||||
}
|
||||
mesh->attributes.update(std::move(new_mesh.attributes));
|
||||
mesh->subd_attributes.update(std::move(new_mesh.subd_attributes));
|
||||
|
||||
mesh->set_num_subd_faces(new_mesh.get_num_subd_faces());
|
||||
|
||||
|
|
|
@ -243,9 +243,6 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
|
|||
|
||||
/* holdout */
|
||||
object->set_use_holdout(use_holdout);
|
||||
if (object->use_holdout_is_modified()) {
|
||||
scene->object_manager->tag_update(scene);
|
||||
}
|
||||
|
||||
object->set_visibility(visibility);
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ bool BlenderSync::sync_dupli_particle(BL::Object &b_ob,
|
|||
|
||||
/* no update needed? */
|
||||
if (!need_update && !object->get_geometry()->is_modified() &&
|
||||
!scene->object_manager->need_update)
|
||||
!scene->object_manager->need_update())
|
||||
return true;
|
||||
|
||||
/* first time used in this sync loop? clear and tag update */
|
||||
|
@ -85,7 +85,7 @@ bool BlenderSync::sync_dupli_particle(BL::Object &b_ob,
|
|||
object->set_particle_index(psys->particles.size() - 1);
|
||||
|
||||
if (object->particle_index_is_modified())
|
||||
scene->object_manager->tag_update(scene);
|
||||
scene->object_manager->tag_update(scene, ObjectManager::PARTICLE_MODIFIED);
|
||||
|
||||
/* return that this object has particle data */
|
||||
return true;
|
||||
|
|
|
@ -552,7 +552,6 @@ void BlenderSession::render(BL::Depsgraph &b_depsgraph_)
|
|||
int seed = scene->integrator->get_seed();
|
||||
seed += hash_uint2(seed, hash_uint2(view_index * 0xdeadbeef, 0));
|
||||
scene->integrator->set_seed(seed);
|
||||
scene->integrator->tag_update(scene);
|
||||
}
|
||||
|
||||
/* Update number of samples per layer. */
|
||||
|
@ -1116,10 +1115,6 @@ void BlenderSession::update_resumable_tile_manager(int num_samples)
|
|||
|
||||
scene->integrator->set_start_sample(rounded_range_start_sample);
|
||||
|
||||
if (scene->integrator->is_modified()) {
|
||||
scene->integrator->tag_update(scene);
|
||||
}
|
||||
|
||||
session->tile_manager.range_start_sample = rounded_range_start_sample;
|
||||
session->tile_manager.range_num_samples = rounded_range_num_samples;
|
||||
}
|
||||
|
|
|
@ -1497,7 +1497,6 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d,
|
|||
|
||||
shader->set_graph(graph);
|
||||
shader->tag_update(scene);
|
||||
background->tag_update(scene);
|
||||
}
|
||||
|
||||
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
|
||||
|
@ -1517,8 +1516,7 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d,
|
|||
viewport_parameters.custom_viewport_parameters());
|
||||
background->set_use_ao(background->get_use_ao() && view_layer.use_background_ao);
|
||||
|
||||
if (background->is_modified())
|
||||
background->tag_update(scene);
|
||||
background->tag_update(scene);
|
||||
}
|
||||
|
||||
/* Sync Lights */
|
||||
|
|
|
@ -302,11 +302,6 @@ void BlenderSync::sync_integrator()
|
|||
integrator->set_sample_clamp_direct(get_float(cscene, "sample_clamp_direct"));
|
||||
integrator->set_sample_clamp_indirect(get_float(cscene, "sample_clamp_indirect"));
|
||||
if (!preview) {
|
||||
if (integrator->get_motion_blur() != r.use_motion_blur()) {
|
||||
scene->object_manager->tag_update(scene);
|
||||
scene->camera->tag_modified();
|
||||
}
|
||||
|
||||
integrator->set_motion_blur(r.use_motion_blur());
|
||||
}
|
||||
|
||||
|
@ -375,8 +370,8 @@ void BlenderSync::sync_integrator()
|
|||
integrator->set_ao_bounces(0);
|
||||
}
|
||||
|
||||
if (integrator->is_modified())
|
||||
integrator->tag_update(scene);
|
||||
/* UPDATE_NONE as we don't want to tag the integrator as modified, just tag dependent things */
|
||||
integrator->tag_update(scene, Integrator::UPDATE_NONE);
|
||||
}
|
||||
|
||||
/* Film */
|
||||
|
@ -729,7 +724,7 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay,
|
|||
|
||||
scene->film->set_pass_alpha_threshold(b_view_layer.pass_alpha_threshold());
|
||||
scene->film->tag_passes_update(scene, passes);
|
||||
scene->integrator->tag_update(scene);
|
||||
scene->integrator->tag_update(scene, Integrator::UPDATE_ALL);
|
||||
|
||||
return passes;
|
||||
}
|
||||
|
|
|
@ -259,6 +259,8 @@ class device_memory {
|
|||
device_ptr original_device_ptr;
|
||||
size_t original_device_size;
|
||||
Device *original_device;
|
||||
bool need_realloc_;
|
||||
bool modified;
|
||||
};
|
||||
|
||||
/* Device Only Memory
|
||||
|
@ -329,6 +331,8 @@ template<typename T> class device_vector : public device_memory {
|
|||
{
|
||||
data_type = device_type_traits<T>::data_type;
|
||||
data_elements = device_type_traits<T>::num_elements;
|
||||
modified = true;
|
||||
need_realloc_ = true;
|
||||
|
||||
assert(data_elements > 0);
|
||||
}
|
||||
|
@ -347,6 +351,7 @@ template<typename T> class device_vector : public device_memory {
|
|||
device_free();
|
||||
host_free();
|
||||
host_pointer = host_alloc(sizeof(T) * new_size);
|
||||
modified = true;
|
||||
assert(device_pointer == 0);
|
||||
}
|
||||
|
||||
|
@ -400,6 +405,19 @@ template<typename T> class device_vector : public device_memory {
|
|||
assert(device_pointer == 0);
|
||||
}
|
||||
|
||||
void give_data(array<T> &to)
|
||||
{
|
||||
device_free();
|
||||
|
||||
to.set_data((T *)host_pointer, data_size);
|
||||
data_size = 0;
|
||||
data_width = 0;
|
||||
data_height = 0;
|
||||
data_depth = 0;
|
||||
host_pointer = 0;
|
||||
assert(device_pointer == 0);
|
||||
}
|
||||
|
||||
/* Free device and host memory. */
|
||||
void free()
|
||||
{
|
||||
|
@ -411,10 +429,40 @@ template<typename T> class device_vector : public device_memory {
|
|||
data_height = 0;
|
||||
data_depth = 0;
|
||||
host_pointer = 0;
|
||||
modified = true;
|
||||
need_realloc_ = true;
|
||||
assert(device_pointer == 0);
|
||||
}
|
||||
|
||||
size_t size()
|
||||
void free_if_need_realloc(bool force_free)
|
||||
{
|
||||
if (need_realloc_ || force_free) {
|
||||
free();
|
||||
}
|
||||
}
|
||||
|
||||
bool is_modified() const
|
||||
{
|
||||
return modified;
|
||||
}
|
||||
|
||||
bool need_realloc()
|
||||
{
|
||||
return need_realloc_;
|
||||
}
|
||||
|
||||
void tag_modified()
|
||||
{
|
||||
modified = true;
|
||||
}
|
||||
|
||||
void tag_realloc()
|
||||
{
|
||||
need_realloc_ = true;
|
||||
tag_modified();
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
return data_size;
|
||||
}
|
||||
|
@ -432,7 +480,24 @@ template<typename T> class device_vector : public device_memory {
|
|||
|
||||
void copy_to_device()
|
||||
{
|
||||
device_copy_to();
|
||||
if (data_size != 0) {
|
||||
device_copy_to();
|
||||
}
|
||||
}
|
||||
|
||||
void copy_to_device_if_modified()
|
||||
{
|
||||
if (!modified) {
|
||||
return;
|
||||
}
|
||||
|
||||
copy_to_device();
|
||||
}
|
||||
|
||||
void clear_modified()
|
||||
{
|
||||
modified = false;
|
||||
need_realloc_ = false;
|
||||
}
|
||||
|
||||
void copy_from_device()
|
||||
|
|
|
@ -454,7 +454,7 @@ ccl_device_inline bool cylinder_culling_test(const float2 p1, const float2 p2, c
|
|||
/* Performs culling against a cylinder. */
|
||||
const float2 dp = p2 - p1;
|
||||
const float num = dp.x * p1.y - dp.y * p1.x;
|
||||
const float den2 = dot(p2 - p1, p2 - p1);
|
||||
const float den2 = dot(dp, dp);
|
||||
return num * num <= r * r * den2;
|
||||
}
|
||||
|
||||
|
@ -571,46 +571,46 @@ ccl_device_inline bool ribbon_intersect(const float3 ray_org,
|
|||
for (int i = 0; i < N; i++) {
|
||||
const float u = i * step_size;
|
||||
const float4 p1 = catmull_rom_basis_eval(curve, u + step_size);
|
||||
bool valid = cylinder_culling_test(
|
||||
const bool valid = cylinder_culling_test(
|
||||
make_float2(p0.x, p0.y), make_float2(p1.x, p1.y), max(p0.w, p1.w));
|
||||
if (!valid) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Evaluate next point. */
|
||||
float3 dp1dt = float4_to_float3(catmull_rom_basis_derivative(curve, u + step_size));
|
||||
dp1dt = (max3(fabs(dp1dt)) < eps) ? float4_to_float3(p1 - p0) : dp1dt;
|
||||
const float3 wn1 = normalize(make_float3(dp1dt.y, -dp1dt.x, 0.0f)) * p1.w;
|
||||
|
||||
/* Construct quad coordinates. */
|
||||
const float3 lp0 = float4_to_float3(p0) + wn0;
|
||||
const float3 lp1 = float4_to_float3(p1) + wn1;
|
||||
const float3 up0 = float4_to_float3(p0) - wn0;
|
||||
const float3 up1 = float4_to_float3(p1) - wn1;
|
||||
if (valid) {
|
||||
/* Construct quad coordinates. */
|
||||
const float3 lp0 = float4_to_float3(p0) + wn0;
|
||||
const float3 lp1 = float4_to_float3(p1) + wn1;
|
||||
const float3 up0 = float4_to_float3(p0) - wn0;
|
||||
const float3 up1 = float4_to_float3(p1) - wn1;
|
||||
|
||||
/* Intersect quad. */
|
||||
float vu, vv, vt;
|
||||
bool valid0 = ribbon_intersect_quad(isect->t, lp0, lp1, up1, up0, &vu, &vv, &vt);
|
||||
|
||||
if (valid0) {
|
||||
/* ignore self intersections */
|
||||
const float avoidance_factor = 2.0f;
|
||||
if (avoidance_factor != 0.0f) {
|
||||
float r = mix(p0.w, p1.w, vu);
|
||||
valid0 = vt > avoidance_factor * r;
|
||||
}
|
||||
/* Intersect quad. */
|
||||
float vu, vv, vt;
|
||||
bool valid0 = ribbon_intersect_quad(isect->t, lp0, lp1, up1, up0, &vu, &vv, &vt);
|
||||
|
||||
if (valid0) {
|
||||
vv = 2.0f * vv - 1.0f;
|
||||
/* ignore self intersections */
|
||||
const float avoidance_factor = 2.0f;
|
||||
if (avoidance_factor != 0.0f) {
|
||||
float r = mix(p0.w, p1.w, vu);
|
||||
valid0 = vt > avoidance_factor * r;
|
||||
}
|
||||
|
||||
/* Record intersection. */
|
||||
isect->t = vt;
|
||||
isect->u = u + vu * step_size;
|
||||
isect->v = vv;
|
||||
return true;
|
||||
if (valid0) {
|
||||
vv = 2.0f * vv - 1.0f;
|
||||
|
||||
/* Record intersection. */
|
||||
isect->t = vt;
|
||||
isect->u = u + vu * step_size;
|
||||
isect->v = vv;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Store point for next step. */
|
||||
p0 = p1;
|
||||
wn0 = wn1;
|
||||
}
|
||||
|
|
|
@ -15,7 +15,20 @@
|
|||
*/
|
||||
|
||||
#ifdef WITH_NANOVDB
|
||||
/* Data type to replace `double` used in the NanoVDB headers. Cycles don't need doubles, and is
|
||||
* safer and more portable to never use double datatype on GPU.
|
||||
* Use a special structure, so that the following is true:
|
||||
* - No unnoticed implicit cast or mathermatical operations used on scalar 64bit type
|
||||
* (which rules out trick like using `uint64_t` as a drop-in replacement for double).
|
||||
* - Padding rules are matching exactly `double`
|
||||
* (which rules out array of `uint8_t`). */
|
||||
typedef struct ccl_vdb_double_t {
|
||||
uint64_t i;
|
||||
} ccl_vdb_double_t;
|
||||
|
||||
# define double ccl_vdb_double_t
|
||||
# include "nanovdb/CNanoVDB.h"
|
||||
# undef double
|
||||
#endif
|
||||
|
||||
/* For OpenCL we do manual lookup and interpolation. */
|
||||
|
|
|
@ -28,7 +28,7 @@ CCL_NAMESPACE_BEGIN
|
|||
|
||||
Attribute::Attribute(
|
||||
ustring name, TypeDesc type, AttributeElement element, Geometry *geom, AttributePrimitive prim)
|
||||
: name(name), std(ATTR_STD_NONE), type(type), element(element), flags(0)
|
||||
: name(name), std(ATTR_STD_NONE), type(type), element(element), flags(0), modified(true)
|
||||
{
|
||||
/* string and matrix not supported! */
|
||||
assert(type == TypeDesc::TypeFloat || type == TypeDesc::TypeColor ||
|
||||
|
@ -82,6 +82,8 @@ void Attribute::add(const float &f)
|
|||
|
||||
for (size_t i = 0; i < size; i++)
|
||||
buffer.push_back(data[i]);
|
||||
|
||||
modified = true;
|
||||
}
|
||||
|
||||
void Attribute::add(const uchar4 &f)
|
||||
|
@ -93,6 +95,8 @@ void Attribute::add(const uchar4 &f)
|
|||
|
||||
for (size_t i = 0; i < size; i++)
|
||||
buffer.push_back(data[i]);
|
||||
|
||||
modified = true;
|
||||
}
|
||||
|
||||
void Attribute::add(const float2 &f)
|
||||
|
@ -104,6 +108,8 @@ void Attribute::add(const float2 &f)
|
|||
|
||||
for (size_t i = 0; i < size; i++)
|
||||
buffer.push_back(data[i]);
|
||||
|
||||
modified = true;
|
||||
}
|
||||
|
||||
void Attribute::add(const float3 &f)
|
||||
|
@ -115,6 +121,8 @@ void Attribute::add(const float3 &f)
|
|||
|
||||
for (size_t i = 0; i < size; i++)
|
||||
buffer.push_back(data[i]);
|
||||
|
||||
modified = true;
|
||||
}
|
||||
|
||||
void Attribute::add(const Transform &f)
|
||||
|
@ -126,6 +134,8 @@ void Attribute::add(const Transform &f)
|
|||
|
||||
for (size_t i = 0; i < size; i++)
|
||||
buffer.push_back(data[i]);
|
||||
|
||||
modified = true;
|
||||
}
|
||||
|
||||
void Attribute::add(const char *data)
|
||||
|
@ -134,6 +144,26 @@ void Attribute::add(const char *data)
|
|||
|
||||
for (size_t i = 0; i < size; i++)
|
||||
buffer.push_back(data[i]);
|
||||
|
||||
modified = true;
|
||||
}
|
||||
|
||||
void Attribute::set_data_from(Attribute &&other)
|
||||
{
|
||||
assert(other.std == std);
|
||||
assert(other.type == type);
|
||||
assert(other.element == element);
|
||||
|
||||
this->flags = other.flags;
|
||||
|
||||
if (this->buffer.size() != other.buffer.size()) {
|
||||
this->buffer = std::move(other.buffer);
|
||||
modified = true;
|
||||
}
|
||||
else if (memcmp(this->data(), other.data(), other.buffer.size()) != 0) {
|
||||
this->buffer = std::move(other.buffer);
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
size_t Attribute::data_sizeof() const
|
||||
|
@ -627,6 +657,49 @@ void AttributeSet::clear(bool preserve_voxel_data)
|
|||
}
|
||||
}
|
||||
|
||||
void AttributeSet::update(AttributeSet &&new_attributes)
|
||||
{
|
||||
/* add or update old_attributes based on the new_attributes */
|
||||
foreach (Attribute &attr, new_attributes.attributes) {
|
||||
Attribute *nattr = nullptr;
|
||||
|
||||
if (attr.std != ATTR_STD_NONE) {
|
||||
nattr = add(attr.std, attr.name);
|
||||
}
|
||||
else {
|
||||
nattr = add(attr.name, attr.type, attr.element);
|
||||
}
|
||||
|
||||
nattr->set_data_from(std::move(attr));
|
||||
}
|
||||
|
||||
/* remove any attributes not on new_attributes */
|
||||
list<Attribute>::iterator it;
|
||||
for (it = attributes.begin(); it != attributes.end();) {
|
||||
if (it->std != ATTR_STD_NONE) {
|
||||
if (new_attributes.find(it->std) == nullptr) {
|
||||
attributes.erase(it++);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (it->name != "") {
|
||||
if (new_attributes.find(it->name) == nullptr) {
|
||||
attributes.erase(it++);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
void AttributeSet::clear_modified()
|
||||
{
|
||||
foreach (Attribute &attr, attributes) {
|
||||
attr.modified = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* AttributeRequest */
|
||||
|
||||
AttributeRequest::AttributeRequest(ustring name_)
|
||||
|
|
|
@ -54,6 +54,8 @@ class Attribute {
|
|||
AttributeElement element;
|
||||
uint flags; /* enum AttributeFlag */
|
||||
|
||||
bool modified;
|
||||
|
||||
Attribute(ustring name,
|
||||
TypeDesc type,
|
||||
AttributeElement element,
|
||||
|
@ -159,6 +161,8 @@ class Attribute {
|
|||
void add(const Transform &tfm);
|
||||
void add(const char *data);
|
||||
|
||||
void set_data_from(Attribute &&other);
|
||||
|
||||
static bool same_storage(TypeDesc a, TypeDesc b);
|
||||
static const char *standard_name(AttributeStandard std);
|
||||
static AttributeStandard name_standard(const char *name);
|
||||
|
@ -194,6 +198,12 @@ class AttributeSet {
|
|||
|
||||
void resize(bool reserve_only = false);
|
||||
void clear(bool preserve_voxel_data = false);
|
||||
|
||||
/* Update the attributes in this AttributeSet with the ones from the new set,
|
||||
* and remove any attribute not found on the new set from this. */
|
||||
void update(AttributeSet &&new_attributes);
|
||||
|
||||
void clear_modified();
|
||||
};
|
||||
|
||||
/* AttributeRequest
|
||||
|
|
|
@ -130,8 +130,9 @@ void Background::device_free(Device * /*device*/, DeviceScene * /*dscene*/)
|
|||
|
||||
void Background::tag_update(Scene *scene)
|
||||
{
|
||||
scene->integrator->tag_update(scene);
|
||||
tag_modified();
|
||||
if (ao_factor_is_modified() || use_ao_is_modified()) {
|
||||
scene->integrator->tag_update(scene, Integrator::BACKGROUND_AO_MODIFIED);
|
||||
}
|
||||
}
|
||||
|
||||
Shader *Background::get_shader(const Scene *scene)
|
||||
|
|
|
@ -78,7 +78,7 @@ BakeManager::BakeManager()
|
|||
type = SHADER_EVAL_BAKE;
|
||||
pass_filter = 0;
|
||||
|
||||
need_update = true;
|
||||
need_update_ = true;
|
||||
}
|
||||
|
||||
BakeManager::~BakeManager()
|
||||
|
@ -114,9 +114,9 @@ void BakeManager::set(Scene *scene,
|
|||
|
||||
/* create device and update scene */
|
||||
scene->film->tag_modified();
|
||||
scene->integrator->tag_update(scene);
|
||||
scene->integrator->tag_update(scene, Integrator::UPDATE_ALL);
|
||||
|
||||
need_update = true;
|
||||
need_update_ = true;
|
||||
}
|
||||
|
||||
void BakeManager::device_update(Device * /*device*/,
|
||||
|
@ -124,7 +124,7 @@ void BakeManager::device_update(Device * /*device*/,
|
|||
Scene *scene,
|
||||
Progress & /* progress */)
|
||||
{
|
||||
if (!need_update)
|
||||
if (!need_update())
|
||||
return;
|
||||
|
||||
scoped_callback_timer timer([scene](double time) {
|
||||
|
@ -152,11 +152,21 @@ void BakeManager::device_update(Device * /*device*/,
|
|||
object_index++;
|
||||
}
|
||||
|
||||
need_update = false;
|
||||
need_update_ = false;
|
||||
}
|
||||
|
||||
void BakeManager::device_free(Device * /*device*/, DeviceScene * /*dscene*/)
|
||||
{
|
||||
}
|
||||
|
||||
void BakeManager::tag_update()
|
||||
{
|
||||
need_update_ = true;
|
||||
}
|
||||
|
||||
bool BakeManager::need_update() const
|
||||
{
|
||||
return need_update_;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
|
|
@ -36,9 +36,12 @@ class BakeManager {
|
|||
void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);
|
||||
void device_free(Device *device, DeviceScene *dscene);
|
||||
|
||||
bool need_update;
|
||||
void tag_update();
|
||||
|
||||
bool need_update() const;
|
||||
|
||||
private:
|
||||
bool need_update_;
|
||||
ShaderEvalType type;
|
||||
int pass_filter;
|
||||
std::string object_name;
|
||||
|
|
|
@ -688,16 +688,16 @@ void Film::device_free(Device * /*device*/, DeviceScene * /*dscene*/, Scene *sce
|
|||
void Film::tag_passes_update(Scene *scene, const vector<Pass> &passes_, bool update_passes)
|
||||
{
|
||||
if (Pass::contains(scene->passes, PASS_UV) != Pass::contains(passes_, PASS_UV)) {
|
||||
scene->geometry_manager->tag_update(scene);
|
||||
scene->geometry_manager->tag_update(scene, GeometryManager::UV_PASS_NEEDED);
|
||||
|
||||
foreach (Shader *shader, scene->shaders)
|
||||
shader->need_update_geometry = true;
|
||||
shader->need_update_uvs = true;
|
||||
}
|
||||
else if (Pass::contains(scene->passes, PASS_MOTION) != Pass::contains(passes_, PASS_MOTION)) {
|
||||
scene->geometry_manager->tag_update(scene);
|
||||
scene->geometry_manager->tag_update(scene, GeometryManager::MOTION_PASS_NEEDED);
|
||||
}
|
||||
else if (Pass::contains(scene->passes, PASS_AO) != Pass::contains(passes_, PASS_AO)) {
|
||||
scene->integrator->tag_update(scene);
|
||||
scene->integrator->tag_update(scene, Integrator::AO_PASS_MODIFIED);
|
||||
}
|
||||
|
||||
if (update_passes) {
|
||||
|
|
|
@ -240,7 +240,6 @@ void Geometry::compute_bvh(
|
|||
}
|
||||
}
|
||||
|
||||
clear_modified();
|
||||
need_update_rebuild = false;
|
||||
}
|
||||
|
||||
|
@ -262,22 +261,21 @@ bool Geometry::has_voxel_attributes() const
|
|||
|
||||
void Geometry::tag_update(Scene *scene, bool rebuild)
|
||||
{
|
||||
tag_modified();
|
||||
|
||||
if (rebuild) {
|
||||
need_update_rebuild = true;
|
||||
scene->light_manager->need_update = true;
|
||||
scene->light_manager->tag_update(scene, LightManager::MESH_NEED_REBUILD);
|
||||
}
|
||||
else {
|
||||
foreach (Node *node, used_shaders) {
|
||||
Shader *shader = static_cast<Shader *>(node);
|
||||
if (shader->has_surface_emission)
|
||||
scene->light_manager->need_update = true;
|
||||
if (shader->has_surface_emission) {
|
||||
scene->light_manager->tag_update(scene, LightManager::EMISSIVE_MESH_MODIFIED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scene->geometry_manager->need_update = true;
|
||||
scene->object_manager->need_update = true;
|
||||
scene->geometry_manager->tag_update(scene, GeometryManager::GEOMETRY_MODIFIED);
|
||||
}
|
||||
|
||||
void Geometry::tag_bvh_update(bool rebuild)
|
||||
|
@ -293,7 +291,7 @@ void Geometry::tag_bvh_update(bool rebuild)
|
|||
|
||||
GeometryManager::GeometryManager()
|
||||
{
|
||||
need_update = true;
|
||||
update_flags = UPDATE_ALL;
|
||||
need_flags_update = true;
|
||||
}
|
||||
|
||||
|
@ -494,6 +492,10 @@ void GeometryManager::update_svm_attributes(Device *,
|
|||
if (attr_map_size == 0)
|
||||
return;
|
||||
|
||||
if (!dscene->attributes_map.need_realloc()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* create attribute map */
|
||||
uint4 *attr_map = dscene->attributes_map.alloc(attr_map_size);
|
||||
memset(attr_map, 0, dscene->attributes_map.size() * sizeof(uint));
|
||||
|
@ -602,8 +604,10 @@ void GeometryManager::update_attribute_element_offset(Geometry *geom,
|
|||
offset = attr_uchar4_offset;
|
||||
|
||||
assert(attr_uchar4.size() >= offset + size);
|
||||
for (size_t k = 0; k < size; k++) {
|
||||
attr_uchar4[offset + k] = data[k];
|
||||
if (mattr->modified) {
|
||||
for (size_t k = 0; k < size; k++) {
|
||||
attr_uchar4[offset + k] = data[k];
|
||||
}
|
||||
}
|
||||
attr_uchar4_offset += size;
|
||||
}
|
||||
|
@ -612,8 +616,10 @@ void GeometryManager::update_attribute_element_offset(Geometry *geom,
|
|||
offset = attr_float_offset;
|
||||
|
||||
assert(attr_float.size() >= offset + size);
|
||||
for (size_t k = 0; k < size; k++) {
|
||||
attr_float[offset + k] = data[k];
|
||||
if (mattr->modified) {
|
||||
for (size_t k = 0; k < size; k++) {
|
||||
attr_float[offset + k] = data[k];
|
||||
}
|
||||
}
|
||||
attr_float_offset += size;
|
||||
}
|
||||
|
@ -622,8 +628,10 @@ void GeometryManager::update_attribute_element_offset(Geometry *geom,
|
|||
offset = attr_float2_offset;
|
||||
|
||||
assert(attr_float2.size() >= offset + size);
|
||||
for (size_t k = 0; k < size; k++) {
|
||||
attr_float2[offset + k] = data[k];
|
||||
if (mattr->modified) {
|
||||
for (size_t k = 0; k < size; k++) {
|
||||
attr_float2[offset + k] = data[k];
|
||||
}
|
||||
}
|
||||
attr_float2_offset += size;
|
||||
}
|
||||
|
@ -632,8 +640,10 @@ void GeometryManager::update_attribute_element_offset(Geometry *geom,
|
|||
offset = attr_float3_offset;
|
||||
|
||||
assert(attr_float3.size() >= offset + size * 3);
|
||||
for (size_t k = 0; k < size * 3; k++) {
|
||||
attr_float3[offset + k] = (&tfm->x)[k];
|
||||
if (mattr->modified) {
|
||||
for (size_t k = 0; k < size * 3; k++) {
|
||||
attr_float3[offset + k] = (&tfm->x)[k];
|
||||
}
|
||||
}
|
||||
attr_float3_offset += size * 3;
|
||||
}
|
||||
|
@ -642,8 +652,10 @@ void GeometryManager::update_attribute_element_offset(Geometry *geom,
|
|||
offset = attr_float3_offset;
|
||||
|
||||
assert(attr_float3.size() >= offset + size);
|
||||
for (size_t k = 0; k < size; k++) {
|
||||
attr_float3[offset + k] = data[k];
|
||||
if (mattr->modified) {
|
||||
for (size_t k = 0; k < size; k++) {
|
||||
attr_float3[offset + k] = data[k];
|
||||
}
|
||||
}
|
||||
attr_float3_offset += size;
|
||||
}
|
||||
|
@ -808,6 +820,11 @@ void GeometryManager::device_update_attributes(Device *device,
|
|||
dscene->attributes_float3.alloc(attr_float3_size);
|
||||
dscene->attributes_uchar4.alloc(attr_uchar4_size);
|
||||
|
||||
const bool copy_all_data = dscene->attributes_float.need_realloc() ||
|
||||
dscene->attributes_float2.need_realloc() ||
|
||||
dscene->attributes_float3.need_realloc() ||
|
||||
dscene->attributes_uchar4.need_realloc();
|
||||
|
||||
size_t attr_float_offset = 0;
|
||||
size_t attr_float2_offset = 0;
|
||||
size_t attr_float3_offset = 0;
|
||||
|
@ -822,6 +839,12 @@ void GeometryManager::device_update_attributes(Device *device,
|
|||
* they actually refer to the same mesh attributes, optimize */
|
||||
foreach (AttributeRequest &req, attributes.requests) {
|
||||
Attribute *attr = geom->attributes.find(req);
|
||||
|
||||
if (attr) {
|
||||
/* force a copy if we need to reallocate all the data */
|
||||
attr->modified |= copy_all_data;
|
||||
}
|
||||
|
||||
update_attribute_element_offset(geom,
|
||||
dscene->attributes_float,
|
||||
attr_float_offset,
|
||||
|
@ -840,6 +863,11 @@ void GeometryManager::device_update_attributes(Device *device,
|
|||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
Attribute *subd_attr = mesh->subd_attributes.find(req);
|
||||
|
||||
if (subd_attr) {
|
||||
/* force a copy if we need to reallocate all the data */
|
||||
subd_attr->modified |= copy_all_data;
|
||||
}
|
||||
|
||||
update_attribute_element_offset(mesh,
|
||||
dscene->attributes_float,
|
||||
attr_float_offset,
|
||||
|
@ -903,18 +931,10 @@ void GeometryManager::device_update_attributes(Device *device,
|
|||
/* copy to device */
|
||||
progress.set_status("Updating Mesh", "Copying Attributes to device");
|
||||
|
||||
if (dscene->attributes_float.size()) {
|
||||
dscene->attributes_float.copy_to_device();
|
||||
}
|
||||
if (dscene->attributes_float2.size()) {
|
||||
dscene->attributes_float2.copy_to_device();
|
||||
}
|
||||
if (dscene->attributes_float3.size()) {
|
||||
dscene->attributes_float3.copy_to_device();
|
||||
}
|
||||
if (dscene->attributes_uchar4.size()) {
|
||||
dscene->attributes_uchar4.copy_to_device();
|
||||
}
|
||||
dscene->attributes_float.copy_to_device();
|
||||
dscene->attributes_float2.copy_to_device();
|
||||
dscene->attributes_float3.copy_to_device();
|
||||
dscene->attributes_uchar4.copy_to_device();
|
||||
|
||||
if (progress.get_cancel())
|
||||
return;
|
||||
|
@ -1066,17 +1086,34 @@ void GeometryManager::device_update_mesh(
|
|||
uint *tri_patch = dscene->tri_patch.alloc(tri_size);
|
||||
float2 *tri_patch_uv = dscene->tri_patch_uv.alloc(vert_size);
|
||||
|
||||
const bool copy_all_data = dscene->tri_shader.need_realloc() ||
|
||||
dscene->tri_vindex.need_realloc() ||
|
||||
dscene->tri_vnormal.need_realloc() ||
|
||||
dscene->tri_patch.need_realloc() ||
|
||||
dscene->tri_patch_uv.need_realloc();
|
||||
|
||||
foreach (Geometry *geom, scene->geometry) {
|
||||
if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
mesh->pack_shaders(scene, &tri_shader[mesh->prim_offset]);
|
||||
mesh->pack_normals(&vnormal[mesh->vert_offset]);
|
||||
mesh->pack_verts(tri_prim_index,
|
||||
&tri_vindex[mesh->prim_offset],
|
||||
&tri_patch[mesh->prim_offset],
|
||||
&tri_patch_uv[mesh->vert_offset],
|
||||
mesh->vert_offset,
|
||||
mesh->prim_offset);
|
||||
|
||||
if (mesh->shader_is_modified() || mesh->smooth_is_modified() ||
|
||||
mesh->triangles_is_modified() || copy_all_data) {
|
||||
mesh->pack_shaders(scene, &tri_shader[mesh->prim_offset]);
|
||||
}
|
||||
|
||||
if (mesh->verts_is_modified() || copy_all_data) {
|
||||
mesh->pack_normals(&vnormal[mesh->vert_offset]);
|
||||
}
|
||||
|
||||
if (mesh->triangles_is_modified() || mesh->vert_patch_uv_is_modified() || copy_all_data) {
|
||||
mesh->pack_verts(tri_prim_index,
|
||||
&tri_vindex[mesh->prim_offset],
|
||||
&tri_patch[mesh->prim_offset],
|
||||
&tri_patch_uv[mesh->vert_offset],
|
||||
mesh->vert_offset,
|
||||
mesh->prim_offset);
|
||||
}
|
||||
|
||||
if (progress.get_cancel())
|
||||
return;
|
||||
}
|
||||
|
@ -1085,11 +1122,11 @@ void GeometryManager::device_update_mesh(
|
|||
/* vertex coordinates */
|
||||
progress.set_status("Updating Mesh", "Copying Mesh to device");
|
||||
|
||||
dscene->tri_shader.copy_to_device();
|
||||
dscene->tri_vnormal.copy_to_device();
|
||||
dscene->tri_vindex.copy_to_device();
|
||||
dscene->tri_patch.copy_to_device();
|
||||
dscene->tri_patch_uv.copy_to_device();
|
||||
dscene->tri_shader.copy_to_device_if_modified();
|
||||
dscene->tri_vnormal.copy_to_device_if_modified();
|
||||
dscene->tri_vindex.copy_to_device_if_modified();
|
||||
dscene->tri_patch.copy_to_device_if_modified();
|
||||
dscene->tri_patch_uv.copy_to_device_if_modified();
|
||||
}
|
||||
|
||||
if (curve_size != 0) {
|
||||
|
@ -1098,9 +1135,21 @@ void GeometryManager::device_update_mesh(
|
|||
float4 *curve_keys = dscene->curve_keys.alloc(curve_key_size);
|
||||
float4 *curves = dscene->curves.alloc(curve_size);
|
||||
|
||||
const bool copy_all_data = dscene->curve_keys.need_realloc() || dscene->curves.need_realloc();
|
||||
|
||||
foreach (Geometry *geom, scene->geometry) {
|
||||
if (geom->is_hair()) {
|
||||
Hair *hair = static_cast<Hair *>(geom);
|
||||
|
||||
bool curve_keys_co_modified = hair->curve_radius_is_modified() ||
|
||||
hair->curve_keys_is_modified();
|
||||
bool curve_data_modified = hair->curve_shader_is_modified() ||
|
||||
hair->curve_first_key_is_modified();
|
||||
|
||||
if (!curve_keys_co_modified && !curve_data_modified && !copy_all_data) {
|
||||
continue;
|
||||
}
|
||||
|
||||
hair->pack_curves(scene,
|
||||
&curve_keys[hair->curvekey_offset],
|
||||
&curves[hair->prim_offset],
|
||||
|
@ -1110,11 +1159,11 @@ void GeometryManager::device_update_mesh(
|
|||
}
|
||||
}
|
||||
|
||||
dscene->curve_keys.copy_to_device();
|
||||
dscene->curves.copy_to_device();
|
||||
dscene->curve_keys.copy_to_device_if_modified();
|
||||
dscene->curves.copy_to_device_if_modified();
|
||||
}
|
||||
|
||||
if (patch_size != 0) {
|
||||
if (patch_size != 0 && dscene->patches.need_realloc()) {
|
||||
progress.set_status("Updating Mesh", "Copying Patches to device");
|
||||
|
||||
uint *patch_data = dscene->patches.alloc(patch_size);
|
||||
|
@ -1180,16 +1229,25 @@ void GeometryManager::device_update_bvh(Device *device,
|
|||
|
||||
VLOG(1) << "Using " << bvh_layout_name(bparams.bvh_layout) << " layout.";
|
||||
|
||||
delete scene->bvh;
|
||||
BVH *bvh = scene->bvh = BVH::create(bparams, scene->geometry, scene->objects, device);
|
||||
device->build_bvh(bvh, progress, false);
|
||||
const bool can_refit = scene->bvh != nullptr &&
|
||||
(bparams.bvh_layout == BVHLayout::BVH_LAYOUT_OPTIX);
|
||||
const bool pack_all = scene->bvh == nullptr;
|
||||
|
||||
BVH *bvh = scene->bvh;
|
||||
if (!scene->bvh) {
|
||||
bvh = scene->bvh = BVH::create(bparams, scene->geometry, scene->objects, device);
|
||||
}
|
||||
|
||||
device->build_bvh(bvh, progress, can_refit);
|
||||
|
||||
if (progress.get_cancel()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool has_bvh2_layout = (bparams.bvh_layout == BVH_LAYOUT_BVH2);
|
||||
|
||||
PackedBVH pack;
|
||||
if (bparams.bvh_layout == BVH_LAYOUT_BVH2) {
|
||||
if (has_bvh2_layout) {
|
||||
pack = std::move(static_cast<BVH2 *>(bvh)->pack);
|
||||
}
|
||||
else {
|
||||
|
@ -1210,12 +1268,22 @@ void GeometryManager::device_update_bvh(Device *device,
|
|||
}
|
||||
|
||||
pack.root_index = -1;
|
||||
pack.prim_tri_index.reserve(num_prims);
|
||||
pack.prim_tri_verts.reserve(num_tri_verts);
|
||||
pack.prim_type.reserve(num_prims);
|
||||
pack.prim_index.reserve(num_prims);
|
||||
pack.prim_object.reserve(num_prims);
|
||||
pack.prim_visibility.reserve(num_prims);
|
||||
|
||||
if (!pack_all) {
|
||||
/* if we do not need to recreate the BVH, then only the vertices are updated, so we can
|
||||
* safely retake the memory */
|
||||
dscene->prim_tri_verts.give_data(pack.prim_tri_verts);
|
||||
}
|
||||
else {
|
||||
/* it is not stricly necessary to skip those resizes we if do not have to repack, as the OS
|
||||
* will not allocate pages if we do not touch them, however it does help catching bugs */
|
||||
pack.prim_tri_index.resize(num_prims);
|
||||
pack.prim_tri_verts.resize(num_tri_verts);
|
||||
pack.prim_type.resize(num_prims);
|
||||
pack.prim_index.resize(num_prims);
|
||||
pack.prim_object.resize(num_prims);
|
||||
pack.prim_visibility.resize(num_prims);
|
||||
}
|
||||
|
||||
// Merge visibility flags of all objects and find object index for non-instanced geometry
|
||||
unordered_map<const Geometry *, pair<int, uint>> geometry_to_object_info;
|
||||
|
@ -1229,17 +1297,27 @@ void GeometryManager::device_update_bvh(Device *device,
|
|||
}
|
||||
}
|
||||
|
||||
TaskPool pool;
|
||||
// Iterate over scene mesh list instead of objects, since 'optix_prim_offset' was calculated
|
||||
// based on that list, which may be ordered differently from the object list.
|
||||
foreach (Geometry *geom, scene->geometry) {
|
||||
if (!pack_all && !geom->is_modified()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const pair<int, uint> &info = geometry_to_object_info[geom];
|
||||
geom->pack_primitives(pack, info.first, info.second);
|
||||
pool.push(function_bind(
|
||||
&Geometry::pack_primitives, geom, &pack, info.first, info.second, pack_all));
|
||||
}
|
||||
pool.wait_work();
|
||||
}
|
||||
|
||||
/* copy to device */
|
||||
progress.set_status("Updating Scene BVH", "Copying BVH to device");
|
||||
|
||||
/* When using BVH2, we always have to copy/update the data as its layout is dependent on the
|
||||
* BVH's leaf nodes which may be different when the objects or vertices move. */
|
||||
|
||||
if (pack.nodes.size()) {
|
||||
dscene->bvh_nodes.steal_data(pack.nodes);
|
||||
dscene->bvh_nodes.copy_to_device();
|
||||
|
@ -1252,7 +1330,7 @@ void GeometryManager::device_update_bvh(Device *device,
|
|||
dscene->object_node.steal_data(pack.object_node);
|
||||
dscene->object_node.copy_to_device();
|
||||
}
|
||||
if (pack.prim_tri_index.size()) {
|
||||
if (pack.prim_tri_index.size() && (dscene->prim_tri_index.need_realloc() || has_bvh2_layout)) {
|
||||
dscene->prim_tri_index.steal_data(pack.prim_tri_index);
|
||||
dscene->prim_tri_index.copy_to_device();
|
||||
}
|
||||
|
@ -1260,23 +1338,23 @@ void GeometryManager::device_update_bvh(Device *device,
|
|||
dscene->prim_tri_verts.steal_data(pack.prim_tri_verts);
|
||||
dscene->prim_tri_verts.copy_to_device();
|
||||
}
|
||||
if (pack.prim_type.size()) {
|
||||
if (pack.prim_type.size() && (dscene->prim_type.need_realloc() || has_bvh2_layout)) {
|
||||
dscene->prim_type.steal_data(pack.prim_type);
|
||||
dscene->prim_type.copy_to_device();
|
||||
}
|
||||
if (pack.prim_visibility.size()) {
|
||||
if (pack.prim_visibility.size() && (dscene->prim_visibility.need_realloc() || has_bvh2_layout)) {
|
||||
dscene->prim_visibility.steal_data(pack.prim_visibility);
|
||||
dscene->prim_visibility.copy_to_device();
|
||||
}
|
||||
if (pack.prim_index.size()) {
|
||||
if (pack.prim_index.size() && (dscene->prim_index.need_realloc() || has_bvh2_layout)) {
|
||||
dscene->prim_index.steal_data(pack.prim_index);
|
||||
dscene->prim_index.copy_to_device();
|
||||
}
|
||||
if (pack.prim_object.size()) {
|
||||
if (pack.prim_object.size() && (dscene->prim_object.need_realloc() || has_bvh2_layout)) {
|
||||
dscene->prim_object.steal_data(pack.prim_object);
|
||||
dscene->prim_object.copy_to_device();
|
||||
}
|
||||
if (pack.prim_time.size()) {
|
||||
if (pack.prim_time.size() && (dscene->prim_time.need_realloc() || has_bvh2_layout)) {
|
||||
dscene->prim_time.steal_data(pack.prim_time);
|
||||
dscene->prim_time.copy_to_device();
|
||||
}
|
||||
|
@ -1289,12 +1367,65 @@ void GeometryManager::device_update_bvh(Device *device,
|
|||
dscene->data.bvh.scene = NULL;
|
||||
}
|
||||
|
||||
/* Set of flags used to help determining what data has been modified or needs reallocation, so we
|
||||
* can decide which device data to free or update. */
|
||||
enum {
|
||||
DEVICE_CURVE_DATA_MODIFIED = (1 << 0),
|
||||
DEVICE_MESH_DATA_MODIFIED = (1 << 1),
|
||||
|
||||
ATTR_FLOAT_MODIFIED = (1 << 2),
|
||||
ATTR_FLOAT2_MODIFIED = (1 << 3),
|
||||
ATTR_FLOAT3_MODIFIED = (1 << 4),
|
||||
ATTR_UCHAR4_MODIFIED = (1 << 5),
|
||||
|
||||
CURVE_DATA_NEED_REALLOC = (1 << 6),
|
||||
MESH_DATA_NEED_REALLOC = (1 << 7),
|
||||
|
||||
ATTR_FLOAT_NEEDS_REALLOC = (1 << 8),
|
||||
ATTR_FLOAT2_NEEDS_REALLOC = (1 << 9),
|
||||
ATTR_FLOAT3_NEEDS_REALLOC = (1 << 10),
|
||||
ATTR_UCHAR4_NEEDS_REALLOC = (1 << 11),
|
||||
|
||||
ATTRS_NEED_REALLOC = (ATTR_FLOAT_NEEDS_REALLOC | ATTR_FLOAT2_NEEDS_REALLOC |
|
||||
ATTR_FLOAT3_NEEDS_REALLOC | ATTR_UCHAR4_NEEDS_REALLOC),
|
||||
DEVICE_MESH_DATA_NEEDS_REALLOC = (CURVE_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC),
|
||||
DEVICE_CURVE_DATA_NEEDS_REALLOC = (MESH_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC),
|
||||
};
|
||||
|
||||
static void update_device_flags_attribute(uint32_t &device_update_flags,
|
||||
const AttributeSet &attributes)
|
||||
{
|
||||
foreach (const Attribute &attr, attributes.attributes) {
|
||||
if (!attr.modified) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (attr.element == ATTR_ELEMENT_CORNER) {
|
||||
device_update_flags |= ATTR_UCHAR4_MODIFIED;
|
||||
}
|
||||
else if (attr.type == TypeDesc::TypeFloat) {
|
||||
device_update_flags |= ATTR_FLOAT_MODIFIED;
|
||||
}
|
||||
else if (attr.type == TypeFloat2) {
|
||||
device_update_flags |= ATTR_FLOAT2_MODIFIED;
|
||||
}
|
||||
else if (attr.type == TypeDesc::TypeMatrix) {
|
||||
device_update_flags |= ATTR_FLOAT3_MODIFIED;
|
||||
}
|
||||
else if (attr.element != ATTR_ELEMENT_VOXEL) {
|
||||
device_update_flags |= ATTR_FLOAT3_MODIFIED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Progress &progress)
|
||||
{
|
||||
if (!need_update && !need_flags_update) {
|
||||
if (!need_update() && !need_flags_update) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t device_update_flags = 0;
|
||||
|
||||
scoped_callback_timer timer([scene](double time) {
|
||||
if (scene->update_stats) {
|
||||
scene->update_stats->geometry.times.add_entry({"device_update_preprocess", time});
|
||||
|
@ -1314,9 +1445,54 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro
|
|||
if (shader->has_volume) {
|
||||
geom->has_volume = true;
|
||||
}
|
||||
|
||||
if (shader->has_surface_bssrdf) {
|
||||
geom->has_surface_bssrdf = true;
|
||||
}
|
||||
|
||||
if (shader->need_update_uvs) {
|
||||
device_update_flags |= ATTR_FLOAT2_NEEDS_REALLOC;
|
||||
|
||||
/* Attributes might need to be tesselated if added. */
|
||||
if (geom->is_mesh()) {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
if (mesh->need_tesselation()) {
|
||||
mesh->tag_modified();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shader->need_update_attribute) {
|
||||
device_update_flags |= ATTRS_NEED_REALLOC;
|
||||
|
||||
/* Attributes might need to be tesselated if added. */
|
||||
if (geom->is_mesh()) {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
if (mesh->need_tesselation()) {
|
||||
mesh->tag_modified();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shader->need_update_displacement) {
|
||||
/* tag displacement related sockets as modified */
|
||||
if (geom->is_mesh()) {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
mesh->tag_verts_modified();
|
||||
mesh->tag_subd_dicing_rate_modified();
|
||||
mesh->tag_subd_max_level_modified();
|
||||
mesh->tag_subd_objecttoworld_modified();
|
||||
|
||||
device_update_flags |= ATTRS_NEED_REALLOC;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* only check for modified attributes if we do not need to reallocate them already */
|
||||
if ((device_update_flags & ATTRS_NEED_REALLOC) == 0) {
|
||||
update_device_flags_attribute(device_update_flags, geom->attributes);
|
||||
/* don't check for subd_attributes, as if they were modified, we would need to reallocate
|
||||
* anyway */
|
||||
}
|
||||
|
||||
/* Re-create volume mesh if we will rebuild or refit the BVH. Note we
|
||||
|
@ -1332,13 +1508,118 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro
|
|||
|
||||
Volume *volume = static_cast<Volume *>(geom);
|
||||
create_volume_mesh(volume, progress);
|
||||
|
||||
/* always reallocate when we have a volume, as we need to rebuild the BVH */
|
||||
device_update_flags |= DEVICE_MESH_DATA_NEEDS_REALLOC;
|
||||
}
|
||||
|
||||
if (geom->is_hair()) {
|
||||
/* Set curve shape, still a global scene setting for now. */
|
||||
Hair *hair = static_cast<Hair *>(geom);
|
||||
hair->curve_shape = scene->params.hair_shape;
|
||||
|
||||
if (hair->need_update_rebuild) {
|
||||
device_update_flags |= DEVICE_CURVE_DATA_NEEDS_REALLOC;
|
||||
}
|
||||
else if (hair->is_modified()) {
|
||||
device_update_flags |= DEVICE_CURVE_DATA_MODIFIED;
|
||||
}
|
||||
}
|
||||
|
||||
if (geom->is_mesh()) {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
|
||||
if (mesh->need_update_rebuild) {
|
||||
device_update_flags |= DEVICE_MESH_DATA_NEEDS_REALLOC;
|
||||
}
|
||||
else if (mesh->verts_is_modified()) {
|
||||
device_update_flags |= DEVICE_MESH_DATA_MODIFIED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (update_flags & (MESH_ADDED | MESH_REMOVED)) {
|
||||
device_update_flags |= DEVICE_MESH_DATA_NEEDS_REALLOC;
|
||||
}
|
||||
|
||||
if (update_flags & (HAIR_ADDED | HAIR_REMOVED)) {
|
||||
device_update_flags |= DEVICE_CURVE_DATA_NEEDS_REALLOC;
|
||||
}
|
||||
|
||||
/* tag the device arrays for reallocation or modification */
|
||||
DeviceScene *dscene = &scene->dscene;
|
||||
|
||||
if (device_update_flags & (DEVICE_MESH_DATA_NEEDS_REALLOC | DEVICE_CURVE_DATA_NEEDS_REALLOC)) {
|
||||
delete scene->bvh;
|
||||
scene->bvh = nullptr;
|
||||
|
||||
dscene->bvh_nodes.tag_realloc();
|
||||
dscene->bvh_leaf_nodes.tag_realloc();
|
||||
dscene->object_node.tag_realloc();
|
||||
dscene->prim_tri_verts.tag_realloc();
|
||||
dscene->prim_tri_index.tag_realloc();
|
||||
dscene->prim_type.tag_realloc();
|
||||
dscene->prim_visibility.tag_realloc();
|
||||
dscene->prim_index.tag_realloc();
|
||||
dscene->prim_object.tag_realloc();
|
||||
dscene->prim_time.tag_realloc();
|
||||
|
||||
if (device_update_flags & DEVICE_MESH_DATA_NEEDS_REALLOC) {
|
||||
dscene->tri_vnormal.tag_realloc();
|
||||
dscene->tri_vindex.tag_realloc();
|
||||
dscene->tri_patch.tag_realloc();
|
||||
dscene->tri_vnormal.tag_realloc();
|
||||
dscene->tri_patch_uv.tag_realloc();
|
||||
dscene->patches.tag_realloc();
|
||||
}
|
||||
|
||||
if (device_update_flags & DEVICE_CURVE_DATA_NEEDS_REALLOC) {
|
||||
dscene->curves.tag_realloc();
|
||||
dscene->curve_keys.tag_realloc();
|
||||
}
|
||||
}
|
||||
|
||||
if (device_update_flags & ATTR_FLOAT_NEEDS_REALLOC) {
|
||||
dscene->attributes_map.tag_realloc();
|
||||
dscene->attributes_float.tag_realloc();
|
||||
}
|
||||
else if (device_update_flags & ATTR_FLOAT_MODIFIED) {
|
||||
dscene->attributes_float.tag_modified();
|
||||
}
|
||||
|
||||
if (device_update_flags & ATTR_FLOAT2_NEEDS_REALLOC) {
|
||||
dscene->attributes_map.tag_realloc();
|
||||
dscene->attributes_float2.tag_realloc();
|
||||
}
|
||||
else if (device_update_flags & ATTR_FLOAT_MODIFIED) {
|
||||
dscene->attributes_float.tag_modified();
|
||||
}
|
||||
|
||||
if (device_update_flags & ATTR_FLOAT3_NEEDS_REALLOC) {
|
||||
dscene->attributes_map.tag_realloc();
|
||||
dscene->attributes_float3.tag_realloc();
|
||||
}
|
||||
else if (device_update_flags & ATTR_FLOAT_MODIFIED) {
|
||||
dscene->attributes_float.tag_modified();
|
||||
}
|
||||
|
||||
if (device_update_flags & ATTR_UCHAR4_NEEDS_REALLOC) {
|
||||
dscene->attributes_map.tag_realloc();
|
||||
dscene->attributes_uchar4.tag_realloc();
|
||||
}
|
||||
else if (device_update_flags & ATTR_UCHAR4_MODIFIED) {
|
||||
dscene->attributes_uchar4.tag_modified();
|
||||
}
|
||||
|
||||
if (device_update_flags & DEVICE_MESH_DATA_MODIFIED) {
|
||||
/* if anything else than vertices are modified, we would need to reallocate, so this is the
|
||||
* only array that can be updated */
|
||||
dscene->tri_vnormal.tag_modified();
|
||||
}
|
||||
|
||||
if (device_update_flags & DEVICE_CURVE_DATA_MODIFIED) {
|
||||
dscene->curve_keys.tag_modified();
|
||||
dscene->curves.tag_modified();
|
||||
}
|
||||
|
||||
need_flags_update = false;
|
||||
|
@ -1423,7 +1704,7 @@ void GeometryManager::device_update(Device *device,
|
|||
Scene *scene,
|
||||
Progress &progress)
|
||||
{
|
||||
if (!need_update)
|
||||
if (!need_update())
|
||||
return;
|
||||
|
||||
VLOG(1) << "Total " << scene->geometry.size() << " meshes.";
|
||||
|
@ -1439,12 +1720,6 @@ void GeometryManager::device_update(Device *device,
|
|||
});
|
||||
|
||||
foreach (Geometry *geom, scene->geometry) {
|
||||
foreach (Node *node, geom->get_used_shaders()) {
|
||||
Shader *shader = static_cast<Shader *>(node);
|
||||
if (shader->need_update_geometry)
|
||||
geom->tag_modified();
|
||||
}
|
||||
|
||||
if (geom->is_modified() &&
|
||||
(geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME)) {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
|
@ -1541,7 +1816,7 @@ void GeometryManager::device_update(Device *device,
|
|||
}
|
||||
|
||||
/* Device update. */
|
||||
device_free(device, dscene);
|
||||
device_free(device, dscene, false);
|
||||
|
||||
const BVHLayout bvh_layout = BVHParams::best_bvh_layout(scene->params.bvh_layout,
|
||||
device->get_bvh_layout_mask());
|
||||
|
@ -1614,7 +1889,7 @@ void GeometryManager::device_update(Device *device,
|
|||
{"device_update (displacement: attributes)", time});
|
||||
}
|
||||
});
|
||||
device_free(device, dscene);
|
||||
device_free(device, dscene, false);
|
||||
|
||||
device_update_attributes(device, dscene, scene, progress);
|
||||
if (progress.get_cancel()) {
|
||||
|
@ -1622,6 +1897,9 @@ void GeometryManager::device_update(Device *device,
|
|||
}
|
||||
}
|
||||
|
||||
/* update the bvh even when there is no geometry so the kernel bvh data is still valid,
|
||||
* especially when removing all of the objects during interactive renders */
|
||||
bool need_update_scene_bvh = (scene->bvh == nullptr);
|
||||
{
|
||||
scoped_callback_timer timer([scene](double time) {
|
||||
if (scene->update_stats) {
|
||||
|
@ -1633,6 +1911,7 @@ void GeometryManager::device_update(Device *device,
|
|||
size_t i = 0;
|
||||
foreach (Geometry *geom, scene->geometry) {
|
||||
if (geom->is_modified()) {
|
||||
need_update_scene_bvh = true;
|
||||
pool.push(function_bind(
|
||||
&Geometry::compute_bvh, geom, device, dscene, &scene->params, &progress, i, num_bvh));
|
||||
if (geom->need_build_bvh(bvh_layout)) {
|
||||
|
@ -1647,7 +1926,9 @@ void GeometryManager::device_update(Device *device,
|
|||
}
|
||||
|
||||
foreach (Shader *shader, scene->shaders) {
|
||||
shader->need_update_geometry = false;
|
||||
shader->need_update_uvs = false;
|
||||
shader->need_update_attribute = false;
|
||||
shader->need_update_displacement = false;
|
||||
}
|
||||
|
||||
Scene::MotionType need_motion = scene->need_motion();
|
||||
|
@ -1670,7 +1951,7 @@ void GeometryManager::device_update(Device *device,
|
|||
return;
|
||||
}
|
||||
|
||||
{
|
||||
if (need_update_scene_bvh) {
|
||||
scoped_callback_timer timer([scene](double time) {
|
||||
if (scene->update_stats) {
|
||||
scene->update_stats->geometry.times.add_entry({"device_update (build scene BVH)", time});
|
||||
|
@ -1695,8 +1976,6 @@ void GeometryManager::device_update(Device *device,
|
|||
}
|
||||
}
|
||||
|
||||
need_update = false;
|
||||
|
||||
if (true_displacement_used) {
|
||||
/* Re-tag flags for update, so they're re-evaluated
|
||||
* for meshes with correct bounding boxes.
|
||||
|
@ -1706,33 +1985,71 @@ void GeometryManager::device_update(Device *device,
|
|||
*/
|
||||
scene->object_manager->need_flags_update = old_need_object_flags_update;
|
||||
}
|
||||
|
||||
/* unset flags */
|
||||
|
||||
foreach (Geometry *geom, scene->geometry) {
|
||||
geom->clear_modified();
|
||||
geom->attributes.clear_modified();
|
||||
|
||||
if (geom->is_mesh()) {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
mesh->subd_attributes.clear_modified();
|
||||
}
|
||||
}
|
||||
|
||||
update_flags = UPDATE_NONE;
|
||||
|
||||
dscene->bvh_nodes.clear_modified();
|
||||
dscene->bvh_leaf_nodes.clear_modified();
|
||||
dscene->object_node.clear_modified();
|
||||
dscene->prim_tri_verts.clear_modified();
|
||||
dscene->prim_tri_index.clear_modified();
|
||||
dscene->prim_type.clear_modified();
|
||||
dscene->prim_visibility.clear_modified();
|
||||
dscene->prim_index.clear_modified();
|
||||
dscene->prim_object.clear_modified();
|
||||
dscene->prim_time.clear_modified();
|
||||
dscene->tri_shader.clear_modified();
|
||||
dscene->tri_vindex.clear_modified();
|
||||
dscene->tri_patch.clear_modified();
|
||||
dscene->tri_vnormal.clear_modified();
|
||||
dscene->tri_patch_uv.clear_modified();
|
||||
dscene->curves.clear_modified();
|
||||
dscene->curve_keys.clear_modified();
|
||||
dscene->patches.clear_modified();
|
||||
dscene->attributes_map.clear_modified();
|
||||
dscene->attributes_float.clear_modified();
|
||||
dscene->attributes_float2.clear_modified();
|
||||
dscene->attributes_float3.clear_modified();
|
||||
dscene->attributes_uchar4.clear_modified();
|
||||
}
|
||||
|
||||
void GeometryManager::device_free(Device *device, DeviceScene *dscene)
|
||||
void GeometryManager::device_free(Device *device, DeviceScene *dscene, bool force_free)
|
||||
{
|
||||
dscene->bvh_nodes.free();
|
||||
dscene->bvh_leaf_nodes.free();
|
||||
dscene->object_node.free();
|
||||
dscene->prim_tri_verts.free();
|
||||
dscene->prim_tri_index.free();
|
||||
dscene->prim_type.free();
|
||||
dscene->prim_visibility.free();
|
||||
dscene->prim_index.free();
|
||||
dscene->prim_object.free();
|
||||
dscene->prim_time.free();
|
||||
dscene->tri_shader.free();
|
||||
dscene->tri_vnormal.free();
|
||||
dscene->tri_vindex.free();
|
||||
dscene->tri_patch.free();
|
||||
dscene->tri_patch_uv.free();
|
||||
dscene->curves.free();
|
||||
dscene->curve_keys.free();
|
||||
dscene->patches.free();
|
||||
dscene->attributes_map.free();
|
||||
dscene->attributes_float.free();
|
||||
dscene->attributes_float2.free();
|
||||
dscene->attributes_float3.free();
|
||||
dscene->attributes_uchar4.free();
|
||||
dscene->bvh_nodes.free_if_need_realloc(force_free);
|
||||
dscene->bvh_leaf_nodes.free_if_need_realloc(force_free);
|
||||
dscene->object_node.free_if_need_realloc(force_free);
|
||||
dscene->prim_tri_verts.free_if_need_realloc(force_free);
|
||||
dscene->prim_tri_index.free_if_need_realloc(force_free);
|
||||
dscene->prim_type.free_if_need_realloc(force_free);
|
||||
dscene->prim_visibility.free_if_need_realloc(force_free);
|
||||
dscene->prim_index.free_if_need_realloc(force_free);
|
||||
dscene->prim_object.free_if_need_realloc(force_free);
|
||||
dscene->prim_time.free_if_need_realloc(force_free);
|
||||
dscene->tri_shader.free_if_need_realloc(force_free);
|
||||
dscene->tri_vnormal.free_if_need_realloc(force_free);
|
||||
dscene->tri_vindex.free_if_need_realloc(force_free);
|
||||
dscene->tri_patch.free_if_need_realloc(force_free);
|
||||
dscene->tri_patch_uv.free_if_need_realloc(force_free);
|
||||
dscene->curves.free_if_need_realloc(force_free);
|
||||
dscene->curve_keys.free_if_need_realloc(force_free);
|
||||
dscene->patches.free_if_need_realloc(force_free);
|
||||
dscene->attributes_map.free_if_need_realloc(force_free);
|
||||
dscene->attributes_float.free_if_need_realloc(force_free);
|
||||
dscene->attributes_float2.free_if_need_realloc(force_free);
|
||||
dscene->attributes_float3.free_if_need_realloc(force_free);
|
||||
dscene->attributes_uchar4.free_if_need_realloc(force_free);
|
||||
|
||||
/* Signal for shaders like displacement not to do ray tracing. */
|
||||
dscene->data.bvh.bvh_layout = BVH_LAYOUT_NONE;
|
||||
|
@ -1750,10 +2067,19 @@ void GeometryManager::device_free(Device *device, DeviceScene *dscene)
|
|||
#endif
|
||||
}
|
||||
|
||||
void GeometryManager::tag_update(Scene *scene)
|
||||
void GeometryManager::tag_update(Scene *scene, uint32_t flag)
|
||||
{
|
||||
need_update = true;
|
||||
scene->object_manager->need_update = true;
|
||||
update_flags |= flag;
|
||||
|
||||
/* do not tag the object manager for an update if it is the one who tagged us */
|
||||
if ((flag & OBJECT_MANAGER) == 0) {
|
||||
scene->object_manager->tag_update(scene, ObjectManager::GEOMETRY_MANAGER);
|
||||
}
|
||||
}
|
||||
|
||||
bool GeometryManager::need_update() const
|
||||
{
|
||||
return update_flags != UPDATE_NONE;
|
||||
}
|
||||
|
||||
void GeometryManager::collect_statistics(const Scene *scene, RenderStats *stats)
|
||||
|
|
|
@ -125,7 +125,7 @@ class Geometry : public Node {
|
|||
int n,
|
||||
int total);
|
||||
|
||||
virtual void pack_primitives(PackedBVH &pack, int object, uint visibility) = 0;
|
||||
virtual void pack_primitives(PackedBVH *pack, int object, uint visibility, bool pack_all) = 0;
|
||||
|
||||
/* Check whether the geometry should have own BVH built separately. Briefly,
|
||||
* own BVH is needed for geometry, if:
|
||||
|
@ -155,6 +155,11 @@ class Geometry : public Node {
|
|||
return geometry_type == HAIR;
|
||||
}
|
||||
|
||||
bool is_volume() const
|
||||
{
|
||||
return geometry_type == VOLUME;
|
||||
}
|
||||
|
||||
/* Updates */
|
||||
void tag_update(Scene *scene, bool rebuild);
|
||||
|
||||
|
@ -164,9 +169,32 @@ class Geometry : public Node {
|
|||
/* Geometry Manager */
|
||||
|
||||
class GeometryManager {
|
||||
uint32_t update_flags;
|
||||
|
||||
public:
|
||||
enum : uint32_t {
|
||||
UV_PASS_NEEDED = (1 << 0),
|
||||
MOTION_PASS_NEEDED = (1 << 1),
|
||||
GEOMETRY_MODIFIED = (1 << 2),
|
||||
OBJECT_MANAGER = (1 << 3),
|
||||
MESH_ADDED = (1 << 4),
|
||||
MESH_REMOVED = (1 << 5),
|
||||
HAIR_ADDED = (1 << 6),
|
||||
HAIR_REMOVED = (1 << 7),
|
||||
|
||||
SHADER_ATTRIBUTE_MODIFIED = (1 << 8),
|
||||
SHADER_DISPLACEMENT_MODIFIED = (1 << 9),
|
||||
|
||||
GEOMETRY_ADDED = MESH_ADDED | HAIR_ADDED,
|
||||
GEOMETRY_REMOVED = MESH_REMOVED | HAIR_REMOVED,
|
||||
|
||||
/* tag everything in the manager for an update */
|
||||
UPDATE_ALL = ~0u,
|
||||
|
||||
UPDATE_NONE = 0u,
|
||||
};
|
||||
|
||||
/* Update Flags */
|
||||
bool need_update;
|
||||
bool need_flags_update;
|
||||
|
||||
/* Constructor/Destructor */
|
||||
|
@ -176,10 +204,12 @@ class GeometryManager {
|
|||
/* Device Updates */
|
||||
void device_update_preprocess(Device *device, Scene *scene, Progress &progress);
|
||||
void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);
|
||||
void device_free(Device *device, DeviceScene *dscene);
|
||||
void device_free(Device *device, DeviceScene *dscene, bool force_free);
|
||||
|
||||
/* Updates */
|
||||
void tag_update(Scene *scene);
|
||||
void tag_update(Scene *scene, uint32_t flag);
|
||||
|
||||
bool need_update() const;
|
||||
|
||||
/* Statistics */
|
||||
void collect_statistics(const Scene *scene, RenderStats *stats);
|
||||
|
|
|
@ -494,33 +494,38 @@ void Hair::pack_curves(Scene *scene,
|
|||
}
|
||||
}
|
||||
|
||||
void Hair::pack_primitives(PackedBVH &pack, int object, uint visibility)
|
||||
void Hair::pack_primitives(PackedBVH *pack, int object, uint visibility, bool pack_all)
|
||||
{
|
||||
if (curve_first_key.empty())
|
||||
return;
|
||||
|
||||
const size_t num_prims = num_segments();
|
||||
pack.prim_tri_index.reserve(pack.prim_tri_index.size() + num_prims);
|
||||
pack.prim_type.reserve(pack.prim_type.size() + num_prims);
|
||||
pack.prim_visibility.reserve(pack.prim_visibility.size() + num_prims);
|
||||
pack.prim_index.reserve(pack.prim_index.size() + num_prims);
|
||||
pack.prim_object.reserve(pack.prim_object.size() + num_prims);
|
||||
// 'pack.prim_time' is unused by Embree and OptiX
|
||||
/* If the BVH does not have to be recreated, we can bail out. */
|
||||
if (!pack_all) {
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int *prim_tri_index = &pack->prim_tri_index[optix_prim_offset];
|
||||
int *prim_type = &pack->prim_type[optix_prim_offset];
|
||||
unsigned int *prim_visibility = &pack->prim_visibility[optix_prim_offset];
|
||||
int *prim_index = &pack->prim_index[optix_prim_offset];
|
||||
int *prim_object = &pack->prim_object[optix_prim_offset];
|
||||
// 'pack->prim_time' is unused by Embree and OptiX
|
||||
|
||||
uint type = has_motion_blur() ?
|
||||
((curve_shape == CURVE_RIBBON) ? PRIMITIVE_MOTION_CURVE_RIBBON :
|
||||
PRIMITIVE_MOTION_CURVE_THICK) :
|
||||
((curve_shape == CURVE_RIBBON) ? PRIMITIVE_CURVE_RIBBON : PRIMITIVE_CURVE_THICK);
|
||||
|
||||
size_t index = 0;
|
||||
for (size_t j = 0; j < num_curves(); ++j) {
|
||||
Curve curve = get_curve(j);
|
||||
for (size_t k = 0; k < curve.num_segments(); ++k) {
|
||||
pack.prim_tri_index.push_back_reserved(-1);
|
||||
pack.prim_type.push_back_reserved(PRIMITIVE_PACK_SEGMENT(type, k));
|
||||
pack.prim_visibility.push_back_reserved(visibility);
|
||||
for (size_t k = 0; k < curve.num_segments(); ++k, ++index) {
|
||||
prim_tri_index[index] = -1;
|
||||
prim_type[index] = PRIMITIVE_PACK_SEGMENT(type, k);
|
||||
prim_visibility[index] = visibility;
|
||||
// Each curve segment points back to its curve index
|
||||
pack.prim_index.push_back_reserved(j + prim_offset);
|
||||
pack.prim_object.push_back_reserved(object);
|
||||
prim_index[index] = j + prim_offset;
|
||||
prim_object[index] = object;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -146,7 +146,7 @@ class Hair : public Geometry {
|
|||
/* BVH */
|
||||
void pack_curves(Scene *scene, float4 *curve_key_co, float4 *curve_data, size_t curvekey_offset);
|
||||
|
||||
void pack_primitives(PackedBVH &pack, int object, uint visibility) override;
|
||||
void pack_primitives(PackedBVH *pack, int object, uint visibility, bool pack_all) override;
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
|
|
@ -298,7 +298,7 @@ bool ImageLoader::is_vdb_loader() const
|
|||
|
||||
ImageManager::ImageManager(const DeviceInfo &info)
|
||||
{
|
||||
need_update = true;
|
||||
need_update_ = true;
|
||||
osl_texture_system = NULL;
|
||||
animation_frame = 0;
|
||||
|
||||
|
@ -451,7 +451,7 @@ int ImageManager::add_image_slot(ImageLoader *loader,
|
|||
|
||||
images[slot] = img;
|
||||
|
||||
need_update = true;
|
||||
need_update_ = true;
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
@ -478,7 +478,7 @@ void ImageManager::remove_image_user(int slot)
|
|||
* the reasons for this is that on shader changes we add and remove nodes
|
||||
* that use them, but we do not want to reload the image all the time. */
|
||||
if (image->users == 0)
|
||||
need_update = true;
|
||||
need_update_ = true;
|
||||
}
|
||||
|
||||
static bool image_associate_alpha(ImageManager::Image *img)
|
||||
|
@ -810,7 +810,7 @@ void ImageManager::device_free_image(Device *, int slot)
|
|||
|
||||
void ImageManager::device_update(Device *device, Scene *scene, Progress &progress)
|
||||
{
|
||||
if (!need_update) {
|
||||
if (!need_update()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -834,7 +834,7 @@ void ImageManager::device_update(Device *device, Scene *scene, Progress &progres
|
|||
|
||||
pool.wait_work();
|
||||
|
||||
need_update = false;
|
||||
need_update_ = false;
|
||||
}
|
||||
|
||||
void ImageManager::device_update_slot(Device *device, Scene *scene, int slot, Progress *progress)
|
||||
|
@ -854,7 +854,7 @@ void ImageManager::device_load_builtin(Device *device, Scene *scene, Progress &p
|
|||
{
|
||||
/* Load only builtin images, Blender needs this to load evaluated
|
||||
* scene data from depsgraph before it is freed. */
|
||||
if (!need_update) {
|
||||
if (!need_update()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -896,4 +896,14 @@ void ImageManager::collect_statistics(RenderStats *stats)
|
|||
}
|
||||
}
|
||||
|
||||
void ImageManager::tag_update()
|
||||
{
|
||||
need_update_ = true;
|
||||
}
|
||||
|
||||
bool ImageManager::need_update() const
|
||||
{
|
||||
return need_update_;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
|
|
@ -189,7 +189,9 @@ class ImageManager {
|
|||
|
||||
void collect_statistics(RenderStats *stats);
|
||||
|
||||
bool need_update;
|
||||
void tag_update();
|
||||
|
||||
bool need_update() const;
|
||||
|
||||
struct Image {
|
||||
ImageParams params;
|
||||
|
@ -209,6 +211,7 @@ class ImageManager {
|
|||
};
|
||||
|
||||
private:
|
||||
bool need_update_;
|
||||
bool has_half_images;
|
||||
|
||||
thread_mutex device_mutex;
|
||||
|
|
|
@ -17,9 +17,11 @@
|
|||
#include "render/integrator.h"
|
||||
#include "device/device.h"
|
||||
#include "render/background.h"
|
||||
#include "render/camera.h"
|
||||
#include "render/film.h"
|
||||
#include "render/jitter.h"
|
||||
#include "render/light.h"
|
||||
#include "render/object.h"
|
||||
#include "render/scene.h"
|
||||
#include "render/shader.h"
|
||||
#include "render/sobol.h"
|
||||
|
@ -113,6 +115,10 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene
|
|||
}
|
||||
});
|
||||
|
||||
if (sampling_pattern_is_modified()) {
|
||||
dscene->sample_pattern_lut.tag_realloc();
|
||||
}
|
||||
|
||||
device_free(device, dscene);
|
||||
|
||||
KernelIntegrator *kintegrator = &dscene->data.integrator;
|
||||
|
@ -242,45 +248,63 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene
|
|||
int dimensions = PRNG_BASE_NUM + max_samples * PRNG_BOUNCE_NUM;
|
||||
dimensions = min(dimensions, SOBOL_MAX_DIMENSIONS);
|
||||
|
||||
if (sampling_pattern == SAMPLING_PATTERN_SOBOL) {
|
||||
uint *directions = dscene->sample_pattern_lut.alloc(SOBOL_BITS * dimensions);
|
||||
if (sampling_pattern_is_modified()) {
|
||||
if (sampling_pattern == SAMPLING_PATTERN_SOBOL) {
|
||||
uint *directions = dscene->sample_pattern_lut.alloc(SOBOL_BITS * dimensions);
|
||||
|
||||
sobol_generate_direction_vectors((uint(*)[SOBOL_BITS])directions, dimensions);
|
||||
sobol_generate_direction_vectors((uint(*)[SOBOL_BITS])directions, dimensions);
|
||||
|
||||
dscene->sample_pattern_lut.copy_to_device();
|
||||
}
|
||||
else {
|
||||
constexpr int sequence_size = NUM_PMJ_SAMPLES;
|
||||
constexpr int num_sequences = NUM_PMJ_PATTERNS;
|
||||
float2 *directions = (float2 *)dscene->sample_pattern_lut.alloc(sequence_size * num_sequences *
|
||||
2);
|
||||
TaskPool pool;
|
||||
for (int j = 0; j < num_sequences; ++j) {
|
||||
float2 *sequence = directions + j * sequence_size;
|
||||
pool.push(
|
||||
function_bind(&progressive_multi_jitter_02_generate_2D, sequence, sequence_size, j));
|
||||
dscene->sample_pattern_lut.copy_to_device();
|
||||
}
|
||||
else {
|
||||
constexpr int sequence_size = NUM_PMJ_SAMPLES;
|
||||
constexpr int num_sequences = NUM_PMJ_PATTERNS;
|
||||
float2 *directions = (float2 *)dscene->sample_pattern_lut.alloc(sequence_size *
|
||||
num_sequences * 2);
|
||||
TaskPool pool;
|
||||
for (int j = 0; j < num_sequences; ++j) {
|
||||
float2 *sequence = directions + j * sequence_size;
|
||||
pool.push(
|
||||
function_bind(&progressive_multi_jitter_02_generate_2D, sequence, sequence_size, j));
|
||||
}
|
||||
pool.wait_work();
|
||||
dscene->sample_pattern_lut.copy_to_device();
|
||||
}
|
||||
pool.wait_work();
|
||||
dscene->sample_pattern_lut.copy_to_device();
|
||||
}
|
||||
|
||||
clear_modified();
|
||||
}
|
||||
|
||||
void Integrator::device_free(Device *, DeviceScene *dscene)
|
||||
void Integrator::device_free(Device *, DeviceScene *dscene, bool force_free)
|
||||
{
|
||||
dscene->sample_pattern_lut.free();
|
||||
dscene->sample_pattern_lut.free_if_need_realloc(force_free);
|
||||
}
|
||||
|
||||
void Integrator::tag_update(Scene *scene)
|
||||
void Integrator::tag_update(Scene *scene, uint32_t flag)
|
||||
{
|
||||
foreach (Shader *shader, scene->shaders) {
|
||||
if (shader->has_integrator_dependency) {
|
||||
scene->shader_manager->need_update = true;
|
||||
break;
|
||||
if (flag & UPDATE_ALL) {
|
||||
tag_modified();
|
||||
}
|
||||
|
||||
if (flag & (AO_PASS_MODIFIED | BACKGROUND_AO_MODIFIED)) {
|
||||
/* tag only the ao_bounces socket as modified so we avoid updating sample_pattern_lut
|
||||
* unnecessarily */
|
||||
tag_ao_bounces_modified();
|
||||
}
|
||||
|
||||
if (filter_glossy_is_modified()) {
|
||||
foreach (Shader *shader, scene->shaders) {
|
||||
if (shader->has_integrator_dependency) {
|
||||
scene->shader_manager->tag_update(scene, ShaderManager::INTEGRATOR_MODIFIED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
tag_modified();
|
||||
|
||||
if (motion_blur_is_modified()) {
|
||||
scene->object_manager->tag_update(scene, ObjectManager::MOTION_BLUR_MODIFIED);
|
||||
scene->camera->tag_modified();
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
|
|
@ -89,13 +89,23 @@ class Integrator : public Node {
|
|||
|
||||
NODE_SOCKET_API(SamplingPattern, sampling_pattern)
|
||||
|
||||
enum : uint32_t {
|
||||
AO_PASS_MODIFIED = (1 << 0),
|
||||
BACKGROUND_AO_MODIFIED = (1 << 1),
|
||||
|
||||
/* tag everything in the manager for an update */
|
||||
UPDATE_ALL = ~0u,
|
||||
|
||||
UPDATE_NONE = 0u,
|
||||
};
|
||||
|
||||
Integrator();
|
||||
~Integrator();
|
||||
|
||||
void device_update(Device *device, DeviceScene *dscene, Scene *scene);
|
||||
void device_free(Device *device, DeviceScene *dscene);
|
||||
void device_free(Device *device, DeviceScene *dscene, bool force_free = false);
|
||||
|
||||
void tag_update(Scene *scene);
|
||||
void tag_update(Scene *scene, uint32_t flag);
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
|
|
@ -162,7 +162,9 @@ Light::Light() : Node(node_type)
|
|||
|
||||
void Light::tag_update(Scene *scene)
|
||||
{
|
||||
scene->light_manager->need_update = is_modified();
|
||||
if (is_modified()) {
|
||||
scene->light_manager->tag_update(scene, LightManager::LIGHT_MODIFIED);
|
||||
}
|
||||
}
|
||||
|
||||
bool Light::has_contribution(Scene *scene)
|
||||
|
@ -183,7 +185,7 @@ bool Light::has_contribution(Scene *scene)
|
|||
|
||||
LightManager::LightManager()
|
||||
{
|
||||
need_update = true;
|
||||
update_flags = UPDATE_ALL;
|
||||
need_update_background = true;
|
||||
use_light_visibility = false;
|
||||
last_background_enabled = false;
|
||||
|
@ -962,7 +964,7 @@ void LightManager::device_update(Device *device,
|
|||
Scene *scene,
|
||||
Progress &progress)
|
||||
{
|
||||
if (!need_update)
|
||||
if (!need_update())
|
||||
return;
|
||||
|
||||
scoped_callback_timer timer([scene](double time) {
|
||||
|
@ -1000,7 +1002,7 @@ void LightManager::device_update(Device *device,
|
|||
|
||||
scene->film->set_use_light_visibility(use_light_visibility);
|
||||
|
||||
need_update = false;
|
||||
update_flags = UPDATE_NONE;
|
||||
need_update_background = false;
|
||||
}
|
||||
|
||||
|
@ -1015,9 +1017,14 @@ void LightManager::device_free(Device *, DeviceScene *dscene, const bool free_ba
|
|||
dscene->ies_lights.free();
|
||||
}
|
||||
|
||||
void LightManager::tag_update(Scene * /*scene*/)
|
||||
void LightManager::tag_update(Scene * /*scene*/, uint32_t flag)
|
||||
{
|
||||
need_update = true;
|
||||
update_flags |= flag;
|
||||
}
|
||||
|
||||
bool LightManager::need_update() const
|
||||
{
|
||||
return update_flags != UPDATE_NONE;
|
||||
}
|
||||
|
||||
int LightManager::add_ies_from_file(const string &filename)
|
||||
|
@ -1063,7 +1070,7 @@ int LightManager::add_ies(const string &content)
|
|||
ies_slots[slot]->users = 1;
|
||||
ies_slots[slot]->hash = hash;
|
||||
|
||||
need_update = true;
|
||||
update_flags = UPDATE_ALL;
|
||||
need_update_background = true;
|
||||
|
||||
return slot;
|
||||
|
@ -1082,8 +1089,10 @@ void LightManager::remove_ies(int slot)
|
|||
ies_slots[slot]->users--;
|
||||
|
||||
/* If the slot has no more users, update the device to remove it. */
|
||||
need_update |= (ies_slots[slot]->users == 0);
|
||||
need_update_background |= need_update;
|
||||
if (ies_slots[slot]->users == 0) {
|
||||
update_flags |= UPDATE_ALL;
|
||||
need_update_background = true;
|
||||
}
|
||||
}
|
||||
|
||||
void LightManager::device_update_ies(DeviceScene *dscene)
|
||||
|
|
|
@ -91,8 +91,23 @@ class Light : public Node {
|
|||
|
||||
class LightManager {
|
||||
public:
|
||||
enum : uint32_t {
|
||||
MESH_NEED_REBUILD = (1 << 0),
|
||||
EMISSIVE_MESH_MODIFIED = (1 << 1),
|
||||
LIGHT_MODIFIED = (1 << 2),
|
||||
LIGHT_ADDED = (1 << 3),
|
||||
LIGHT_REMOVED = (1 << 4),
|
||||
OBJECT_MANAGER = (1 << 5),
|
||||
SHADER_COMPILED = (1 << 6),
|
||||
SHADER_MODIFIED = (1 << 7),
|
||||
|
||||
/* tag everything in the manager for an update */
|
||||
UPDATE_ALL = ~0u,
|
||||
|
||||
UPDATE_NONE = 0u,
|
||||
};
|
||||
|
||||
bool use_light_visibility;
|
||||
bool need_update;
|
||||
|
||||
/* Need to update background (including multiple importance map) */
|
||||
bool need_update_background;
|
||||
|
@ -108,7 +123,9 @@ class LightManager {
|
|||
void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);
|
||||
void device_free(Device *device, DeviceScene *dscene, const bool free_background = true);
|
||||
|
||||
void tag_update(Scene *scene);
|
||||
void tag_update(Scene *scene, uint32_t flag);
|
||||
|
||||
bool need_update() const;
|
||||
|
||||
/* Check whether there is a background light. */
|
||||
bool has_background_light(Scene *scene);
|
||||
|
@ -145,6 +162,8 @@ class LightManager {
|
|||
|
||||
bool last_background_enabled;
|
||||
int last_background_resolution;
|
||||
|
||||
uint32_t update_flags;
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
|
|
@ -805,34 +805,42 @@ void Mesh::pack_patches(uint *patch_data, uint vert_offset, uint face_offset, ui
|
|||
}
|
||||
}
|
||||
|
||||
void Mesh::pack_primitives(PackedBVH &pack, int object, uint visibility)
|
||||
void Mesh::pack_primitives(ccl::PackedBVH *pack, int object, uint visibility, bool pack_all)
|
||||
{
|
||||
if (triangles.empty())
|
||||
return;
|
||||
|
||||
const size_t num_prims = num_triangles();
|
||||
pack.prim_tri_index.reserve(pack.prim_tri_index.size() + num_prims);
|
||||
pack.prim_tri_verts.reserve(pack.prim_tri_verts.size() + num_prims * 3);
|
||||
pack.prim_type.reserve(pack.prim_type.size() + num_prims);
|
||||
pack.prim_visibility.reserve(pack.prim_visibility.size() + num_prims);
|
||||
pack.prim_index.reserve(pack.prim_index.size() + num_prims);
|
||||
pack.prim_object.reserve(pack.prim_object.size() + num_prims);
|
||||
// 'pack.prim_time' is unused by Embree and OptiX
|
||||
|
||||
/* Use prim_offset for indexing as it is computed per geometry type, and prim_tri_verts does not
|
||||
* contain data for Hair geometries. */
|
||||
float4 *prim_tri_verts = &pack->prim_tri_verts[prim_offset * 3];
|
||||
// 'pack->prim_time' is unused by Embree and OptiX
|
||||
|
||||
uint type = has_motion_blur() ? PRIMITIVE_MOTION_TRIANGLE : PRIMITIVE_TRIANGLE;
|
||||
|
||||
if (pack_all) {
|
||||
/* Use optix_prim_offset for indexing as those arrays also contain data for Hair geometries. */
|
||||
unsigned int *prim_tri_index = &pack->prim_tri_index[optix_prim_offset];
|
||||
int *prim_type = &pack->prim_type[optix_prim_offset];
|
||||
unsigned int *prim_visibility = &pack->prim_visibility[optix_prim_offset];
|
||||
int *prim_index = &pack->prim_index[optix_prim_offset];
|
||||
int *prim_object = &pack->prim_object[optix_prim_offset];
|
||||
|
||||
for (size_t k = 0; k < num_prims; ++k) {
|
||||
prim_tri_index[k] = (prim_offset + k) * 3;
|
||||
prim_type[k] = type;
|
||||
prim_index[k] = prim_offset + k;
|
||||
prim_object[k] = object;
|
||||
prim_visibility[k] = visibility;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t k = 0; k < num_prims; ++k) {
|
||||
pack.prim_tri_index.push_back_reserved(pack.prim_tri_verts.size());
|
||||
|
||||
const Mesh::Triangle t = get_triangle(k);
|
||||
pack.prim_tri_verts.push_back_reserved(float3_to_float4(verts[t.v[0]]));
|
||||
pack.prim_tri_verts.push_back_reserved(float3_to_float4(verts[t.v[1]]));
|
||||
pack.prim_tri_verts.push_back_reserved(float3_to_float4(verts[t.v[2]]));
|
||||
|
||||
pack.prim_type.push_back_reserved(type);
|
||||
pack.prim_visibility.push_back_reserved(visibility);
|
||||
pack.prim_index.push_back_reserved(k + prim_offset);
|
||||
pack.prim_object.push_back_reserved(object);
|
||||
prim_tri_verts[k * 3] = float3_to_float4(verts[t.v[0]]);
|
||||
prim_tri_verts[k * 3 + 1] = float3_to_float4(verts[t.v[1]]);
|
||||
prim_tri_verts[k * 3 + 2] = float3_to_float4(verts[t.v[2]]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -232,7 +232,7 @@ class Mesh : public Geometry {
|
|||
size_t tri_offset);
|
||||
void pack_patches(uint *patch_data, uint vert_offset, uint face_offset, uint corner_offset);
|
||||
|
||||
void pack_primitives(PackedBVH &pack, int object, uint visibility) override;
|
||||
void pack_primitives(PackedBVH *pack, int object, uint visibility, bool pack_all) override;
|
||||
|
||||
void tessellate(DiagSplit *split);
|
||||
|
||||
|
|
|
@ -153,6 +153,10 @@ void Object::update_motion()
|
|||
|
||||
void Object::compute_bounds(bool motion_blur)
|
||||
{
|
||||
if (!is_modified() && !geometry->is_modified()) {
|
||||
return;
|
||||
}
|
||||
|
||||
BoundBox mbounds = geometry->bounds;
|
||||
|
||||
if (motion_blur && use_motion()) {
|
||||
|
@ -205,20 +209,39 @@ void Object::apply_transform(bool apply_to_motion)
|
|||
|
||||
void Object::tag_update(Scene *scene)
|
||||
{
|
||||
uint32_t flag = ObjectManager::UPDATE_NONE;
|
||||
|
||||
if (is_modified()) {
|
||||
flag |= ObjectManager::OBJECT_MODIFIED;
|
||||
|
||||
if (use_holdout_is_modified()) {
|
||||
flag |= ObjectManager::HOLDOUT_MODIFIED;
|
||||
}
|
||||
}
|
||||
|
||||
if (geometry) {
|
||||
if (geometry->transform_applied)
|
||||
geometry->tag_modified();
|
||||
if (tfm_is_modified()) {
|
||||
/* tag the geometry as modified so the BVH is updated, but do not tag everything as modified
|
||||
*/
|
||||
if (geometry->is_mesh() || geometry->is_volume()) {
|
||||
Mesh *mesh = static_cast<Mesh *>(geometry);
|
||||
mesh->tag_verts_modified();
|
||||
}
|
||||
else if (geometry->is_hair()) {
|
||||
Hair *hair = static_cast<Hair *>(geometry);
|
||||
hair->tag_curve_keys_modified();
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Node *node, geometry->get_used_shaders()) {
|
||||
Shader *shader = static_cast<Shader *>(node);
|
||||
if (shader->get_use_mis() && shader->has_surface_emission)
|
||||
scene->light_manager->need_update = true;
|
||||
scene->light_manager->tag_update(scene, LightManager::EMISSIVE_MESH_MODIFIED);
|
||||
}
|
||||
}
|
||||
|
||||
scene->camera->need_flags_update = true;
|
||||
scene->geometry_manager->need_update = true;
|
||||
scene->object_manager->need_update = true;
|
||||
scene->object_manager->tag_update(scene, flag);
|
||||
}
|
||||
|
||||
bool Object::use_motion() const
|
||||
|
@ -361,7 +384,7 @@ int Object::get_device_index() const
|
|||
|
||||
ObjectManager::ObjectManager()
|
||||
{
|
||||
need_update = true;
|
||||
update_flags = UPDATE_ALL;
|
||||
need_flags_update = true;
|
||||
}
|
||||
|
||||
|
@ -382,7 +405,9 @@ static float object_volume_density(const Transform &tfm, Geometry *geom)
|
|||
return 1.0f;
|
||||
}
|
||||
|
||||
void ObjectManager::device_update_object_transform(UpdateObjectTransformState *state, Object *ob)
|
||||
void ObjectManager::device_update_object_transform(UpdateObjectTransformState *state,
|
||||
Object *ob,
|
||||
bool update_all)
|
||||
{
|
||||
KernelObject &kobject = state->objects[ob->index];
|
||||
Transform *object_motion_pass = state->object_motion_pass;
|
||||
|
@ -456,8 +481,11 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
|
|||
kobject.motion_offset = state->motion_offset[ob->index];
|
||||
|
||||
/* Decompose transforms for interpolation. */
|
||||
DecomposedTransform *decomp = state->object_motion + kobject.motion_offset;
|
||||
transform_motion_decompose(decomp, ob->motion.data(), ob->motion.size());
|
||||
if (ob->tfm_is_modified() || update_all) {
|
||||
DecomposedTransform *decomp = state->object_motion + kobject.motion_offset;
|
||||
transform_motion_decompose(decomp, ob->motion.data(), ob->motion.size());
|
||||
}
|
||||
|
||||
flag |= SD_OBJECT_MOTION;
|
||||
state->have_motion = true;
|
||||
}
|
||||
|
@ -480,10 +508,14 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
|
|||
0;
|
||||
kobject.patch_map_offset = 0;
|
||||
kobject.attribute_map_offset = 0;
|
||||
uint32_t hash_name = util_murmur_hash3(ob->name.c_str(), ob->name.length(), 0);
|
||||
uint32_t hash_asset = util_murmur_hash3(ob->asset_name.c_str(), ob->asset_name.length(), 0);
|
||||
kobject.cryptomatte_object = util_hash_to_float(hash_name);
|
||||
kobject.cryptomatte_asset = util_hash_to_float(hash_asset);
|
||||
|
||||
if (ob->asset_name_is_modified() || update_all) {
|
||||
uint32_t hash_name = util_murmur_hash3(ob->name.c_str(), ob->name.length(), 0);
|
||||
uint32_t hash_asset = util_murmur_hash3(ob->asset_name.c_str(), ob->asset_name.length(), 0);
|
||||
kobject.cryptomatte_object = util_hash_to_float(hash_name);
|
||||
kobject.cryptomatte_asset = util_hash_to_float(hash_asset);
|
||||
}
|
||||
|
||||
kobject.shadow_terminator_offset = 1.0f / (1.0f - 0.5f * ob->shadow_terminator_offset);
|
||||
|
||||
/* Object flag. */
|
||||
|
@ -544,6 +576,9 @@ void ObjectManager::device_update_transforms(DeviceScene *dscene, Scene *scene,
|
|||
numparticles += psys->particles.size();
|
||||
}
|
||||
|
||||
/* as all the arrays are the same size, checking only dscene.objects is sufficient */
|
||||
const bool update_all = dscene->objects.need_realloc();
|
||||
|
||||
/* Parallel object update, with grain size to avoid too much threading overhead
|
||||
* for individual objects. */
|
||||
static const int OBJECTS_PER_TASK = 32;
|
||||
|
@ -551,7 +586,7 @@ void ObjectManager::device_update_transforms(DeviceScene *dscene, Scene *scene,
|
|||
[&](const blocked_range<size_t> &r) {
|
||||
for (size_t i = r.begin(); i != r.end(); i++) {
|
||||
Object *ob = state.scene->objects[i];
|
||||
device_update_object_transform(&state, ob);
|
||||
device_update_object_transform(&state, ob, update_all);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -559,7 +594,7 @@ void ObjectManager::device_update_transforms(DeviceScene *dscene, Scene *scene,
|
|||
return;
|
||||
}
|
||||
|
||||
dscene->objects.copy_to_device();
|
||||
dscene->objects.copy_to_device_if_modified();
|
||||
if (state.need_motion == Scene::MOTION_PASS) {
|
||||
dscene->object_motion_pass.copy_to_device();
|
||||
}
|
||||
|
@ -569,6 +604,10 @@ void ObjectManager::device_update_transforms(DeviceScene *dscene, Scene *scene,
|
|||
|
||||
dscene->data.bvh.have_motion = state.have_motion;
|
||||
dscene->data.bvh.have_curves = state.have_curves;
|
||||
|
||||
dscene->objects.clear_modified();
|
||||
dscene->object_motion_pass.clear_modified();
|
||||
dscene->object_motion.clear_modified();
|
||||
}
|
||||
|
||||
void ObjectManager::device_update(Device *device,
|
||||
|
@ -576,12 +615,28 @@ void ObjectManager::device_update(Device *device,
|
|||
Scene *scene,
|
||||
Progress &progress)
|
||||
{
|
||||
if (!need_update)
|
||||
if (!need_update())
|
||||
return;
|
||||
|
||||
if (update_flags & (OBJECT_ADDED | OBJECT_REMOVED)) {
|
||||
dscene->objects.tag_realloc();
|
||||
dscene->object_motion_pass.tag_realloc();
|
||||
dscene->object_motion.tag_realloc();
|
||||
dscene->object_flag.tag_realloc();
|
||||
dscene->object_volume_step.tag_realloc();
|
||||
}
|
||||
|
||||
if (update_flags & HOLDOUT_MODIFIED) {
|
||||
dscene->object_flag.tag_modified();
|
||||
}
|
||||
|
||||
if (update_flags & PARTICLE_MODIFIED) {
|
||||
dscene->objects.tag_modified();
|
||||
}
|
||||
|
||||
VLOG(1) << "Total " << scene->objects.size() << " objects.";
|
||||
|
||||
device_free(device, dscene);
|
||||
device_free(device, dscene, false);
|
||||
|
||||
if (scene->objects.size() == 0)
|
||||
return;
|
||||
|
@ -597,6 +652,16 @@ void ObjectManager::device_update(Device *device,
|
|||
int index = 0;
|
||||
foreach (Object *object, scene->objects) {
|
||||
object->index = index++;
|
||||
|
||||
/* this is a bit too broad, however a bigger refactor might be needed to properly separate
|
||||
* update each type of data (transform, flags, etc.) */
|
||||
if (object->is_modified()) {
|
||||
dscene->objects.tag_modified();
|
||||
dscene->object_motion_pass.tag_modified();
|
||||
dscene->object_motion.tag_modified();
|
||||
dscene->object_flag.tag_modified();
|
||||
dscene->object_volume_step.tag_modified();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -638,7 +703,7 @@ void ObjectManager::device_update(Device *device,
|
|||
void ObjectManager::device_update_flags(
|
||||
Device *, DeviceScene *dscene, Scene *scene, Progress & /*progress*/, bool bounds_valid)
|
||||
{
|
||||
if (!need_update && !need_flags_update)
|
||||
if (!need_update() && !need_flags_update)
|
||||
return;
|
||||
|
||||
scoped_callback_timer timer([scene](double time) {
|
||||
|
@ -647,7 +712,7 @@ void ObjectManager::device_update_flags(
|
|||
}
|
||||
});
|
||||
|
||||
need_update = false;
|
||||
update_flags = UPDATE_NONE;
|
||||
need_flags_update = false;
|
||||
|
||||
if (scene->objects.size() == 0)
|
||||
|
@ -717,6 +782,9 @@ void ObjectManager::device_update_flags(
|
|||
/* Copy object flag. */
|
||||
dscene->object_flag.copy_to_device();
|
||||
dscene->object_volume_step.copy_to_device();
|
||||
|
||||
dscene->object_flag.clear_modified();
|
||||
dscene->object_volume_step.clear_modified();
|
||||
}
|
||||
|
||||
void ObjectManager::device_update_mesh_offsets(Device *, DeviceScene *dscene, Scene *scene)
|
||||
|
@ -764,13 +832,13 @@ void ObjectManager::device_update_mesh_offsets(Device *, DeviceScene *dscene, Sc
|
|||
}
|
||||
}
|
||||
|
||||
void ObjectManager::device_free(Device *, DeviceScene *dscene)
|
||||
void ObjectManager::device_free(Device *, DeviceScene *dscene, bool force_free)
|
||||
{
|
||||
dscene->objects.free();
|
||||
dscene->object_motion_pass.free();
|
||||
dscene->object_motion.free();
|
||||
dscene->object_flag.free();
|
||||
dscene->object_volume_step.free();
|
||||
dscene->objects.free_if_need_realloc(force_free);
|
||||
dscene->object_motion_pass.free_if_need_realloc(force_free);
|
||||
dscene->object_motion.free_if_need_realloc(force_free);
|
||||
dscene->object_flag.free_if_need_realloc(force_free);
|
||||
dscene->object_volume_step.free_if_need_realloc(force_free);
|
||||
}
|
||||
|
||||
void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, Progress &progress)
|
||||
|
@ -841,11 +909,21 @@ void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, P
|
|||
}
|
||||
}
|
||||
|
||||
void ObjectManager::tag_update(Scene *scene)
|
||||
void ObjectManager::tag_update(Scene *scene, uint32_t flag)
|
||||
{
|
||||
need_update = true;
|
||||
scene->geometry_manager->need_update = true;
|
||||
scene->light_manager->need_update = true;
|
||||
update_flags |= flag;
|
||||
|
||||
/* avoid infinite loops if the geometry manager tagged us for an update */
|
||||
if ((flag & GEOMETRY_MANAGER) == 0) {
|
||||
scene->geometry_manager->tag_update(scene, GeometryManager::OBJECT_MANAGER);
|
||||
}
|
||||
|
||||
scene->light_manager->tag_update(scene, LightManager::OBJECT_MANAGER);
|
||||
}
|
||||
|
||||
bool ObjectManager::need_update() const
|
||||
{
|
||||
return update_flags != UPDATE_NONE;
|
||||
}
|
||||
|
||||
string ObjectManager::get_cryptomatte_objects(Scene *scene)
|
||||
|
|
|
@ -122,8 +122,24 @@ class Object : public Node {
|
|||
/* Object Manager */
|
||||
|
||||
class ObjectManager {
|
||||
uint32_t update_flags;
|
||||
|
||||
public:
|
||||
bool need_update;
|
||||
enum : uint32_t {
|
||||
PARTICLE_MODIFIED = (1 << 0),
|
||||
GEOMETRY_MANAGER = (1 << 1),
|
||||
MOTION_BLUR_MODIFIED = (1 << 2),
|
||||
OBJECT_ADDED = (1 << 3),
|
||||
OBJECT_REMOVED = (1 << 4),
|
||||
OBJECT_MODIFIED = (1 << 5),
|
||||
HOLDOUT_MODIFIED = (1 << 6),
|
||||
|
||||
/* tag everything in the manager for an update */
|
||||
UPDATE_ALL = ~0u,
|
||||
|
||||
UPDATE_NONE = 0u,
|
||||
};
|
||||
|
||||
bool need_flags_update;
|
||||
|
||||
ObjectManager();
|
||||
|
@ -139,9 +155,11 @@ class ObjectManager {
|
|||
bool bounds_valid = true);
|
||||
void device_update_mesh_offsets(Device *device, DeviceScene *dscene, Scene *scene);
|
||||
|
||||
void device_free(Device *device, DeviceScene *dscene);
|
||||
void device_free(Device *device, DeviceScene *dscene, bool force_free);
|
||||
|
||||
void tag_update(Scene *scene);
|
||||
void tag_update(Scene *scene, uint32_t flag);
|
||||
|
||||
bool need_update() const;
|
||||
|
||||
void apply_static_transforms(DeviceScene *dscene, Scene *scene, Progress &progress);
|
||||
|
||||
|
@ -149,7 +167,9 @@ class ObjectManager {
|
|||
string get_cryptomatte_assets(Scene *scene);
|
||||
|
||||
protected:
|
||||
void device_update_object_transform(UpdateObjectTransformState *state, Object *ob);
|
||||
void device_update_object_transform(UpdateObjectTransformState *state,
|
||||
Object *ob,
|
||||
bool update_all);
|
||||
void device_update_object_transform_task(UpdateObjectTransformState *state);
|
||||
bool device_update_object_transform_pop_work(UpdateObjectTransformState *state,
|
||||
int *start_index,
|
||||
|
|
|
@ -96,7 +96,7 @@ void OSLShaderManager::device_update(Device *device,
|
|||
Scene *scene,
|
||||
Progress &progress)
|
||||
{
|
||||
if (!need_update)
|
||||
if (!need_update())
|
||||
return;
|
||||
|
||||
scoped_callback_timer timer([scene](double time) {
|
||||
|
@ -132,7 +132,7 @@ void OSLShaderManager::device_update(Device *device,
|
|||
compiler.compile(og, shader);
|
||||
|
||||
if (shader->get_use_mis() && shader->has_surface_emission)
|
||||
scene->light_manager->need_update = true;
|
||||
scene->light_manager->tag_update(scene, LightManager::SHADER_COMPILED);
|
||||
}
|
||||
|
||||
/* setup shader engine */
|
||||
|
@ -147,7 +147,7 @@ void OSLShaderManager::device_update(Device *device,
|
|||
foreach (Shader *shader, scene->shaders)
|
||||
shader->clear_modified();
|
||||
|
||||
need_update = false;
|
||||
update_flags = UPDATE_NONE;
|
||||
|
||||
/* add special builtin texture types */
|
||||
services->textures.insert(ustring("@ao"), new OSLTextureHandle(OSLTextureHandle::AO));
|
||||
|
|
|
@ -46,14 +46,14 @@ ParticleSystem::~ParticleSystem()
|
|||
|
||||
void ParticleSystem::tag_update(Scene *scene)
|
||||
{
|
||||
scene->particle_system_manager->need_update = true;
|
||||
scene->particle_system_manager->tag_update(scene);
|
||||
}
|
||||
|
||||
/* Particle System Manager */
|
||||
|
||||
ParticleSystemManager::ParticleSystemManager()
|
||||
{
|
||||
need_update = true;
|
||||
need_update_ = true;
|
||||
}
|
||||
|
||||
ParticleSystemManager::~ParticleSystemManager()
|
||||
|
@ -109,7 +109,7 @@ void ParticleSystemManager::device_update(Device *device,
|
|||
Scene *scene,
|
||||
Progress &progress)
|
||||
{
|
||||
if (!need_update)
|
||||
if (!need_update())
|
||||
return;
|
||||
|
||||
scoped_callback_timer timer([scene](double time) {
|
||||
|
@ -128,7 +128,7 @@ void ParticleSystemManager::device_update(Device *device,
|
|||
if (progress.get_cancel())
|
||||
return;
|
||||
|
||||
need_update = false;
|
||||
need_update_ = false;
|
||||
}
|
||||
|
||||
void ParticleSystemManager::device_free(Device *, DeviceScene *dscene)
|
||||
|
@ -138,7 +138,12 @@ void ParticleSystemManager::device_free(Device *, DeviceScene *dscene)
|
|||
|
||||
void ParticleSystemManager::tag_update(Scene * /*scene*/)
|
||||
{
|
||||
need_update = true;
|
||||
need_update_ = true;
|
||||
}
|
||||
|
||||
bool ParticleSystemManager::need_update() const
|
||||
{
|
||||
return need_update_;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
|
|
@ -57,9 +57,9 @@ class ParticleSystem : public Node {
|
|||
/* ParticleSystem Manager */
|
||||
|
||||
class ParticleSystemManager {
|
||||
public:
|
||||
bool need_update;
|
||||
bool need_update_;
|
||||
|
||||
public:
|
||||
ParticleSystemManager();
|
||||
~ParticleSystemManager();
|
||||
|
||||
|
@ -71,6 +71,8 @@ class ParticleSystemManager {
|
|||
void device_free(Device *device, DeviceScene *dscene);
|
||||
|
||||
void tag_update(Scene *scene);
|
||||
|
||||
bool need_update() const;
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
|
|
@ -161,10 +161,10 @@ void Scene::free_memory(bool final)
|
|||
camera->device_free(device, &dscene, this);
|
||||
film->device_free(device, &dscene, this);
|
||||
background->device_free(device, &dscene);
|
||||
integrator->device_free(device, &dscene);
|
||||
integrator->device_free(device, &dscene, true);
|
||||
|
||||
object_manager->device_free(device, &dscene);
|
||||
geometry_manager->device_free(device, &dscene);
|
||||
object_manager->device_free(device, &dscene, true);
|
||||
geometry_manager->device_free(device, &dscene, true);
|
||||
shader_manager->device_free(device, &dscene, this);
|
||||
light_manager->device_free(device, &dscene);
|
||||
|
||||
|
@ -386,10 +386,11 @@ bool Scene::need_update()
|
|||
|
||||
bool Scene::need_data_update()
|
||||
{
|
||||
return (background->is_modified() || image_manager->need_update || object_manager->need_update ||
|
||||
geometry_manager->need_update || light_manager->need_update ||
|
||||
lookup_tables->need_update || integrator->is_modified() || shader_manager->need_update ||
|
||||
particle_system_manager->need_update || bake_manager->need_update ||
|
||||
return (background->is_modified() || image_manager->need_update() ||
|
||||
object_manager->need_update() || geometry_manager->need_update() ||
|
||||
light_manager->need_update() || lookup_tables->need_update() ||
|
||||
integrator->is_modified() || shader_manager->need_update() ||
|
||||
particle_system_manager->need_update() || bake_manager->need_update() ||
|
||||
film->is_modified());
|
||||
}
|
||||
|
||||
|
@ -407,11 +408,13 @@ void Scene::reset()
|
|||
camera->tag_modified();
|
||||
dicing_camera->tag_modified();
|
||||
film->tag_modified();
|
||||
background->tag_modified();
|
||||
|
||||
background->tag_update(this);
|
||||
integrator->tag_update(this);
|
||||
object_manager->tag_update(this);
|
||||
geometry_manager->tag_update(this);
|
||||
light_manager->tag_update(this);
|
||||
integrator->tag_update(this, Integrator::UPDATE_ALL);
|
||||
object_manager->tag_update(this, ObjectManager::UPDATE_ALL);
|
||||
geometry_manager->tag_update(this, GeometryManager::UPDATE_ALL);
|
||||
light_manager->tag_update(this, LightManager::UPDATE_ALL);
|
||||
particle_system_manager->tag_update(this);
|
||||
}
|
||||
|
||||
|
@ -596,7 +599,7 @@ template<> Light *Scene::create_node<Light>()
|
|||
Light *node = new Light();
|
||||
node->set_owner(this);
|
||||
lights.push_back(node);
|
||||
light_manager->tag_update(this);
|
||||
light_manager->tag_update(this, LightManager::LIGHT_ADDED);
|
||||
return node;
|
||||
}
|
||||
|
||||
|
@ -605,7 +608,7 @@ template<> Mesh *Scene::create_node<Mesh>()
|
|||
Mesh *node = new Mesh();
|
||||
node->set_owner(this);
|
||||
geometry.push_back(node);
|
||||
geometry_manager->tag_update(this);
|
||||
geometry_manager->tag_update(this, GeometryManager::MESH_ADDED);
|
||||
return node;
|
||||
}
|
||||
|
||||
|
@ -614,7 +617,7 @@ template<> Hair *Scene::create_node<Hair>()
|
|||
Hair *node = new Hair();
|
||||
node->set_owner(this);
|
||||
geometry.push_back(node);
|
||||
geometry_manager->tag_update(this);
|
||||
geometry_manager->tag_update(this, GeometryManager::HAIR_ADDED);
|
||||
return node;
|
||||
}
|
||||
|
||||
|
@ -623,7 +626,7 @@ template<> Volume *Scene::create_node<Volume>()
|
|||
Volume *node = new Volume();
|
||||
node->set_owner(this);
|
||||
geometry.push_back(node);
|
||||
geometry_manager->tag_update(this);
|
||||
geometry_manager->tag_update(this, GeometryManager::MESH_ADDED);
|
||||
return node;
|
||||
}
|
||||
|
||||
|
@ -632,7 +635,7 @@ template<> Object *Scene::create_node<Object>()
|
|||
Object *node = new Object();
|
||||
node->set_owner(this);
|
||||
objects.push_back(node);
|
||||
object_manager->tag_update(this);
|
||||
object_manager->tag_update(this, ObjectManager::OBJECT_ADDED);
|
||||
return node;
|
||||
}
|
||||
|
||||
|
@ -650,7 +653,7 @@ template<> Shader *Scene::create_node<Shader>()
|
|||
Shader *node = new Shader();
|
||||
node->set_owner(this);
|
||||
shaders.push_back(node);
|
||||
shader_manager->need_update = true;
|
||||
shader_manager->tag_update(this, ShaderManager::SHADER_ADDED);
|
||||
return node;
|
||||
}
|
||||
|
||||
|
@ -664,43 +667,52 @@ template<typename T> void delete_node_from_array(vector<T> &nodes, T node)
|
|||
}
|
||||
|
||||
nodes.resize(nodes.size() - 1);
|
||||
|
||||
delete node;
|
||||
}
|
||||
|
||||
template<> void Scene::delete_node_impl(Light *node)
|
||||
{
|
||||
delete_node_from_array(lights, node);
|
||||
light_manager->tag_update(this);
|
||||
light_manager->tag_update(this, LightManager::LIGHT_REMOVED);
|
||||
}
|
||||
|
||||
template<> void Scene::delete_node_impl(Mesh *node)
|
||||
{
|
||||
delete_node_from_array(geometry, static_cast<Geometry *>(node));
|
||||
geometry_manager->tag_update(this);
|
||||
geometry_manager->tag_update(this, GeometryManager::MESH_REMOVED);
|
||||
}
|
||||
|
||||
template<> void Scene::delete_node_impl(Hair *node)
|
||||
{
|
||||
delete_node_from_array(geometry, static_cast<Geometry *>(node));
|
||||
geometry_manager->tag_update(this);
|
||||
geometry_manager->tag_update(this, GeometryManager::HAIR_REMOVED);
|
||||
}
|
||||
|
||||
template<> void Scene::delete_node_impl(Volume *node)
|
||||
{
|
||||
delete_node_from_array(geometry, static_cast<Geometry *>(node));
|
||||
geometry_manager->tag_update(this);
|
||||
geometry_manager->tag_update(this, GeometryManager::MESH_REMOVED);
|
||||
}
|
||||
|
||||
template<> void Scene::delete_node_impl(Geometry *node)
|
||||
{
|
||||
uint flag;
|
||||
if (node->is_hair()) {
|
||||
flag = GeometryManager::HAIR_REMOVED;
|
||||
}
|
||||
else {
|
||||
flag = GeometryManager::MESH_REMOVED;
|
||||
}
|
||||
|
||||
delete_node_from_array(geometry, node);
|
||||
geometry_manager->tag_update(this);
|
||||
geometry_manager->tag_update(this, flag);
|
||||
}
|
||||
|
||||
template<> void Scene::delete_node_impl(Object *node)
|
||||
{
|
||||
delete_node_from_array(objects, node);
|
||||
object_manager->tag_update(this);
|
||||
object_manager->tag_update(this, ObjectManager::OBJECT_REMOVED);
|
||||
}
|
||||
|
||||
template<> void Scene::delete_node_impl(ParticleSystem *node)
|
||||
|
@ -742,19 +754,19 @@ static void remove_nodes_in_set(const set<T *> &nodes_set,
|
|||
template<> void Scene::delete_nodes(const set<Light *> &nodes, const NodeOwner *owner)
|
||||
{
|
||||
remove_nodes_in_set(nodes, lights, owner);
|
||||
light_manager->tag_update(this);
|
||||
light_manager->tag_update(this, LightManager::LIGHT_REMOVED);
|
||||
}
|
||||
|
||||
template<> void Scene::delete_nodes(const set<Geometry *> &nodes, const NodeOwner *owner)
|
||||
{
|
||||
remove_nodes_in_set(nodes, geometry, owner);
|
||||
geometry_manager->tag_update(this);
|
||||
geometry_manager->tag_update(this, GeometryManager::GEOMETRY_REMOVED);
|
||||
}
|
||||
|
||||
template<> void Scene::delete_nodes(const set<Object *> &nodes, const NodeOwner *owner)
|
||||
{
|
||||
remove_nodes_in_set(nodes, objects, owner);
|
||||
object_manager->tag_update(this);
|
||||
object_manager->tag_update(this, ObjectManager::OBJECT_REMOVED);
|
||||
}
|
||||
|
||||
template<> void Scene::delete_nodes(const set<ParticleSystem *> &nodes, const NodeOwner *owner)
|
||||
|
|
|
@ -541,8 +541,12 @@ bool Session::acquire_tile(RenderTile &rtile, Device *tile_device, uint tile_typ
|
|||
tile->buffers->reset(buffer_params);
|
||||
}
|
||||
else if (tile->buffers->buffer.device != tile_device) {
|
||||
/* Move buffer to current tile device again in case it was stolen before. */
|
||||
tile->buffers->buffer.move_device(tile_device);
|
||||
/* Move buffer to current tile device again in case it was stolen before.
|
||||
* Not needed for denoising since that already handles mapping of tiles and
|
||||
* neighbors to its own device. */
|
||||
if (rtile.task != RenderTile::DENOISE) {
|
||||
tile->buffers->buffer.move_device(tile_device);
|
||||
}
|
||||
}
|
||||
|
||||
tile->buffers->map_neighbor_copied = false;
|
||||
|
@ -555,7 +559,7 @@ bool Session::acquire_tile(RenderTile &rtile, Device *tile_device, uint tile_typ
|
|||
|
||||
if (read_bake_tile_cb) {
|
||||
/* This will read any passes needed as input for baking. */
|
||||
{
|
||||
if (tile_manager.state.sample == tile_manager.range_start_sample) {
|
||||
thread_scoped_lock tile_lock(tile_mutex);
|
||||
read_bake_tile_cb(rtile);
|
||||
}
|
||||
|
@ -1034,13 +1038,7 @@ bool Session::update_scene()
|
|||
BakeManager *bake_manager = scene->bake_manager;
|
||||
|
||||
if (integrator->get_sampling_pattern() != SAMPLING_PATTERN_SOBOL || bake_manager->get_baking()) {
|
||||
int aa_samples = tile_manager.num_samples;
|
||||
|
||||
integrator->set_aa_samples(aa_samples);
|
||||
|
||||
if (integrator->is_modified()) {
|
||||
integrator->tag_update(scene);
|
||||
}
|
||||
integrator->set_aa_samples(tile_manager.num_samples);
|
||||
}
|
||||
|
||||
bool kernel_switch_needed = false;
|
||||
|
|
|
@ -218,7 +218,9 @@ Shader::Shader() : Node(node_type)
|
|||
id = -1;
|
||||
used = false;
|
||||
|
||||
need_update_geometry = true;
|
||||
need_update_uvs = true;
|
||||
need_update_attribute = true;
|
||||
need_update_displacement = true;
|
||||
}
|
||||
|
||||
Shader::~Shader()
|
||||
|
@ -291,7 +293,7 @@ void Shader::set_graph(ShaderGraph *graph_)
|
|||
const char *new_hash = (graph_) ? graph_->displacement_hash.c_str() : "";
|
||||
|
||||
if (strcmp(old_hash, new_hash) != 0) {
|
||||
need_update_geometry = true;
|
||||
need_update_displacement = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -308,13 +310,14 @@ void Shader::tag_update(Scene *scene)
|
|||
{
|
||||
/* update tag */
|
||||
tag_modified();
|
||||
scene->shader_manager->need_update = true;
|
||||
|
||||
scene->shader_manager->tag_update(scene, ShaderManager::SHADER_MODIFIED);
|
||||
|
||||
/* if the shader previously was emissive, update light distribution,
|
||||
* if the new shader is emissive, a light manager update tag will be
|
||||
* done in the shader manager device update. */
|
||||
if (use_mis && has_surface_emission)
|
||||
scene->light_manager->need_update = true;
|
||||
scene->light_manager->tag_update(scene, LightManager::SHADER_MODIFIED);
|
||||
|
||||
/* Special handle of background MIS light for now: for some reason it
|
||||
* has use_mis set to false. We are quite close to release now, so
|
||||
|
@ -323,7 +326,7 @@ void Shader::tag_update(Scene *scene)
|
|||
if (this == scene->background->get_shader(scene)) {
|
||||
scene->light_manager->need_update_background = true;
|
||||
if (scene->light_manager->has_background_light(scene)) {
|
||||
scene->light_manager->need_update = true;
|
||||
scene->light_manager->tag_update(scene, LightManager::SHADER_MODIFIED);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -352,17 +355,17 @@ void Shader::tag_update(Scene *scene)
|
|||
attributes.add(ATTR_STD_POSITION_UNDISPLACED);
|
||||
}
|
||||
if (displacement_method_is_modified()) {
|
||||
need_update_geometry = true;
|
||||
scene->geometry_manager->need_update = true;
|
||||
need_update_displacement = true;
|
||||
scene->geometry_manager->tag_update(scene, GeometryManager::SHADER_DISPLACEMENT_MODIFIED);
|
||||
scene->object_manager->need_flags_update = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* compare if the attributes changed, mesh manager will check
|
||||
* need_update_geometry, update the relevant meshes and clear it. */
|
||||
* need_update_attribute, update the relevant meshes and clear it. */
|
||||
if (attributes.modified(prev_attributes)) {
|
||||
need_update_geometry = true;
|
||||
scene->geometry_manager->need_update = true;
|
||||
need_update_attribute = true;
|
||||
scene->geometry_manager->tag_update(scene, GeometryManager::SHADER_ATTRIBUTE_MODIFIED);
|
||||
}
|
||||
|
||||
if (has_volume != prev_has_volume || volume_step_rate != prev_volume_step_rate) {
|
||||
|
@ -378,15 +381,20 @@ void Shader::tag_used(Scene *scene)
|
|||
* recompiled because it was skipped for compilation before */
|
||||
if (!used) {
|
||||
tag_modified();
|
||||
scene->shader_manager->need_update = true;
|
||||
scene->shader_manager->tag_update(scene, ShaderManager::SHADER_MODIFIED);
|
||||
}
|
||||
}
|
||||
|
||||
bool Shader::need_update_geometry() const
|
||||
{
|
||||
return need_update_uvs || need_update_attribute || need_update_displacement;
|
||||
}
|
||||
|
||||
/* Shader Manager */
|
||||
|
||||
ShaderManager::ShaderManager()
|
||||
{
|
||||
need_update = true;
|
||||
update_flags = UPDATE_ALL;
|
||||
beckmann_table_offset = TABLE_OFFSET_INVALID;
|
||||
|
||||
xyz_to_r = make_float3(3.2404542f, -1.5371385f, -0.4985314f);
|
||||
|
@ -484,7 +492,7 @@ int ShaderManager::get_shader_id(Shader *shader, bool smooth)
|
|||
|
||||
void ShaderManager::update_shaders_used(Scene *scene)
|
||||
{
|
||||
if (!need_update) {
|
||||
if (!need_update()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -793,4 +801,15 @@ string ShaderManager::get_cryptomatte_materials(Scene *scene)
|
|||
return manifest;
|
||||
}
|
||||
|
||||
void ShaderManager::tag_update(Scene * /*scene*/, uint32_t /*flag*/)
|
||||
{
|
||||
/* update everything for now */
|
||||
update_flags = ShaderManager::UPDATE_ALL;
|
||||
}
|
||||
|
||||
bool ShaderManager::need_update() const
|
||||
{
|
||||
return update_flags != UPDATE_NONE;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
|
|
@ -100,7 +100,9 @@ class Shader : public Node {
|
|||
float prev_volume_step_rate;
|
||||
|
||||
/* synchronization */
|
||||
bool need_update_geometry;
|
||||
bool need_update_uvs;
|
||||
bool need_update_attribute;
|
||||
bool need_update_displacement;
|
||||
|
||||
/* If the shader has only volume components, the surface is assumed to
|
||||
* be transparent.
|
||||
|
@ -152,6 +154,8 @@ class Shader : public Node {
|
|||
void set_graph(ShaderGraph *graph);
|
||||
void tag_update(Scene *scene);
|
||||
void tag_used(Scene *scene);
|
||||
|
||||
bool need_update_geometry() const;
|
||||
};
|
||||
|
||||
/* Shader Manager virtual base class
|
||||
|
@ -161,7 +165,16 @@ class Shader : public Node {
|
|||
|
||||
class ShaderManager {
|
||||
public:
|
||||
bool need_update;
|
||||
enum : uint32_t {
|
||||
SHADER_ADDED = (1 << 0),
|
||||
SHADER_MODIFIED = (1 << 2),
|
||||
INTEGRATOR_MODIFIED = (1 << 3),
|
||||
|
||||
/* tag everything in the manager for an update */
|
||||
UPDATE_ALL = ~0u,
|
||||
|
||||
UPDATE_NONE = 0u,
|
||||
};
|
||||
|
||||
static ShaderManager *create(int shadingsystem);
|
||||
virtual ~ShaderManager();
|
||||
|
@ -204,9 +217,15 @@ class ShaderManager {
|
|||
|
||||
string get_cryptomatte_materials(Scene *scene);
|
||||
|
||||
void tag_update(Scene *scene, uint32_t flag);
|
||||
|
||||
bool need_update() const;
|
||||
|
||||
protected:
|
||||
ShaderManager();
|
||||
|
||||
uint32_t update_flags;
|
||||
|
||||
typedef unordered_map<ustring, uint, ustringHash> AttributeIDMap;
|
||||
AttributeIDMap unique_attribute_id;
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ void SVMShaderManager::device_update(Device *device,
|
|||
Scene *scene,
|
||||
Progress &progress)
|
||||
{
|
||||
if (!need_update)
|
||||
if (!need_update())
|
||||
return;
|
||||
|
||||
scoped_callback_timer timer([scene](double time) {
|
||||
|
@ -125,7 +125,7 @@ void SVMShaderManager::device_update(Device *device,
|
|||
|
||||
shader->clear_modified();
|
||||
if (shader->get_use_mis() && shader->has_surface_emission) {
|
||||
scene->light_manager->need_update = true;
|
||||
scene->light_manager->tag_update(scene, LightManager::SHADER_COMPILED);
|
||||
}
|
||||
|
||||
/* Update the global jump table.
|
||||
|
@ -159,7 +159,7 @@ void SVMShaderManager::device_update(Device *device,
|
|||
|
||||
device_update_common(device, dscene, scene, progress);
|
||||
|
||||
need_update = false;
|
||||
update_flags = UPDATE_NONE;
|
||||
|
||||
VLOG(1) << "Shader manager updated " << num_shaders << " shaders in " << time_dt() - start_time
|
||||
<< " seconds.";
|
||||
|
|
|
@ -28,7 +28,7 @@ CCL_NAMESPACE_BEGIN
|
|||
|
||||
LookupTables::LookupTables()
|
||||
{
|
||||
need_update = true;
|
||||
need_update_ = true;
|
||||
}
|
||||
|
||||
LookupTables::~LookupTables()
|
||||
|
@ -38,7 +38,7 @@ LookupTables::~LookupTables()
|
|||
|
||||
void LookupTables::device_update(Device *, DeviceScene *dscene, Scene *scene)
|
||||
{
|
||||
if (!need_update)
|
||||
if (!need_update())
|
||||
return;
|
||||
|
||||
scoped_callback_timer timer([scene](double time) {
|
||||
|
@ -52,7 +52,7 @@ void LookupTables::device_update(Device *, DeviceScene *dscene, Scene *scene)
|
|||
if (lookup_tables.size() > 0)
|
||||
dscene->lookup_table.copy_to_device();
|
||||
|
||||
need_update = false;
|
||||
need_update_ = false;
|
||||
}
|
||||
|
||||
void LookupTables::device_free(Device *, DeviceScene *dscene)
|
||||
|
@ -60,6 +60,11 @@ void LookupTables::device_free(Device *, DeviceScene *dscene)
|
|||
dscene->lookup_table.free();
|
||||
}
|
||||
|
||||
bool LookupTables::need_update() const
|
||||
{
|
||||
return need_update_;
|
||||
}
|
||||
|
||||
static size_t round_up_to_multiple(size_t size, size_t chunk)
|
||||
{
|
||||
return ((size + chunk - 1) / chunk) * chunk;
|
||||
|
@ -69,7 +74,7 @@ size_t LookupTables::add_table(DeviceScene *dscene, vector<float> &data)
|
|||
{
|
||||
assert(data.size() > 0);
|
||||
|
||||
need_update = true;
|
||||
need_update_ = true;
|
||||
|
||||
Table new_table;
|
||||
new_table.offset = 0;
|
||||
|
@ -107,7 +112,7 @@ void LookupTables::remove_table(size_t *offset)
|
|||
return;
|
||||
}
|
||||
|
||||
need_update = true;
|
||||
need_update_ = true;
|
||||
|
||||
list<Table>::iterator table;
|
||||
|
||||
|
|
|
@ -30,13 +30,14 @@ enum { TABLE_CHUNK_SIZE = 256 };
|
|||
enum { TABLE_OFFSET_INVALID = -1 };
|
||||
|
||||
class LookupTables {
|
||||
bool need_update_;
|
||||
|
||||
public:
|
||||
struct Table {
|
||||
size_t offset;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
bool need_update;
|
||||
list<Table> lookup_tables;
|
||||
|
||||
LookupTables();
|
||||
|
@ -45,6 +46,8 @@ class LookupTables {
|
|||
void device_update(Device *device, DeviceScene *dscene, Scene *scene);
|
||||
void device_free(Device *device, DeviceScene *dscene);
|
||||
|
||||
bool need_update() const;
|
||||
|
||||
size_t add_table(DeviceScene *dscene, vector<float> &data);
|
||||
void remove_table(size_t *offset);
|
||||
};
|
||||
|
|
|
@ -131,6 +131,14 @@ template<typename T, size_t alignment = MIN_ALIGNMENT_CPU_DATA_TYPES> class arra
|
|||
}
|
||||
}
|
||||
|
||||
void set_data(T *ptr_, size_t datasize)
|
||||
{
|
||||
clear();
|
||||
data_ = ptr_;
|
||||
datasize_ = datasize;
|
||||
capacity_ = datasize;
|
||||
}
|
||||
|
||||
T *steal_pointer()
|
||||
{
|
||||
T *ptr = data_;
|
||||
|
|
|
@ -36,7 +36,14 @@ using tbb::parallel_for;
|
|||
|
||||
static inline void parallel_for_cancel()
|
||||
{
|
||||
#if TBB_INTERFACE_VERSION_MAJOR >= 12
|
||||
tbb::task_group_context *ctx = tbb::task::current_context();
|
||||
if (ctx) {
|
||||
ctx->cancel_group_execution();
|
||||
}
|
||||
#else
|
||||
tbb::task::self().cancel_group_execution();
|
||||
#endif
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
|
|
@ -131,6 +131,7 @@ const UserDef U_default = {
|
|||
|
||||
.prefetchframes = 0,
|
||||
.pad_rot_angle = 15,
|
||||
.gizmo_size_navigate_v3d = 80,
|
||||
.rvisize = 25,
|
||||
.rvibright = 8,
|
||||
.recent_files = 10,
|
||||
|
|
|
@ -2277,7 +2277,7 @@ def km_grease_pencil(_params):
|
|||
|
||||
def _grease_pencil_selection(params):
|
||||
return [
|
||||
("gpencil.select", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
|
||||
("gpencil.select", {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True},
|
||||
{"properties": [("extend", True), ("toggle", True)]}),
|
||||
# Select all
|
||||
("gpencil.select_all", {"type": 'A', "value": 'PRESS', "ctrl": True}, {"properties": [("action", 'SELECT')]}),
|
||||
|
|
|
@ -91,7 +91,8 @@ class GPENCIL_MT_layer_context_menu(Menu):
|
|||
ob = context.object
|
||||
gpd = ob.data
|
||||
|
||||
layout.operator("gpencil.layer_duplicate", icon='DUPLICATE')
|
||||
layout.operator("gpencil.layer_duplicate", text="Duplicate", icon='DUPLICATE').mode='ALL'
|
||||
layout.operator("gpencil.layer_duplicate", text="Duplicate Empty Keyframes").mode='EMPTY'
|
||||
|
||||
layout.separator()
|
||||
|
||||
|
|
|
@ -691,6 +691,9 @@ class USERPREF_PT_viewport_display(ViewportPanel, CenterAlignMixIn, Panel):
|
|||
col.prop(view, "mini_axis_size", text="Size")
|
||||
col.prop(view, "mini_axis_brightness", text="Brightness")
|
||||
|
||||
if view.mini_axis_type == 'GIZMO':
|
||||
col.prop(view, "gizmo_size_navigate_v3d", text="Size")
|
||||
|
||||
|
||||
class USERPREF_PT_viewport_quality(ViewportPanel, CenterAlignMixIn, Panel):
|
||||
bl_label = "Quality"
|
||||
|
|
|
@ -352,10 +352,13 @@ class VIEW3D_PT_tools_particlemode(Panel, View3DPaintPanel):
|
|||
layout.row().prop(brush, "puff_mode", expand=True)
|
||||
layout.prop(brush, "use_puff_volume")
|
||||
elif tool == 'COMB':
|
||||
layout.prop(settings, "use_emitter_deflect", text="Deflect Emitter")
|
||||
col = layout.column()
|
||||
col.active = settings.use_emitter_deflect
|
||||
col.prop(settings, "emitter_distance", text="Distance")
|
||||
col = layout.column(align=False, heading="Deflect Emitter")
|
||||
row = col.row(align=True)
|
||||
sub = row.row(align=True)
|
||||
sub.prop(settings, "use_emitter_deflect", text="")
|
||||
sub = sub.row(align=True)
|
||||
sub.active = settings.use_emitter_deflect
|
||||
sub.prop(settings, "emitter_distance", text="")
|
||||
|
||||
|
||||
# TODO, move to space_view3d.py
|
||||
|
@ -1231,14 +1234,20 @@ class VIEW3D_PT_tools_particlemode_options(View3DPanel, Panel):
|
|||
|
||||
col = layout.column(align=True)
|
||||
col.active = pe.is_editable
|
||||
col.prop(ob.data, "use_mirror_x")
|
||||
if pe.tool == 'ADD':
|
||||
col.prop(ob.data, "use_mirror_topology")
|
||||
col.separator()
|
||||
col.prop(pe, "use_preserve_length", text="Preserve Strand Lengths")
|
||||
col.prop(pe, "use_preserve_root", text="Preserve Root Positions")
|
||||
|
||||
if not pe.is_hair:
|
||||
col.prop(pe, "use_auto_velocity", text="Auto-Velocity")
|
||||
col.separator()
|
||||
|
||||
sub = col.column(align=True, heading="Mirror")
|
||||
sub.prop(ob.data, "use_mirror_x")
|
||||
if pe.tool == 'ADD':
|
||||
sub.prop(ob.data, "use_mirror_topology")
|
||||
col.separator()
|
||||
|
||||
sub = col.column(align=True, heading="Preserve")
|
||||
sub.prop(pe, "use_preserve_length", text="Strand Lengths")
|
||||
sub.prop(pe, "use_preserve_root", text="Root Positions")
|
||||
|
||||
|
||||
class VIEW3D_PT_tools_particlemode_options_shapecut(View3DPanel, Panel):
|
||||
|
@ -1282,10 +1291,13 @@ class VIEW3D_PT_tools_particlemode_options_display(View3DPanel, Panel):
|
|||
else:
|
||||
if pe.type == 'PARTICLES':
|
||||
col.prop(pe, "show_particles", text="Particles")
|
||||
col.prop(pe, "use_fade_time")
|
||||
sub = col.row(align=True)
|
||||
col = layout.column(align=False, heading="Fade Time")
|
||||
row = col.row(align=True)
|
||||
sub = row.row(align=True)
|
||||
sub.prop(pe, "use_fade_time", text="")
|
||||
sub = sub.row(align=True)
|
||||
sub.active = pe.use_fade_time
|
||||
sub.prop(pe, "fade_frames", slider=True)
|
||||
sub.prop(pe, "fade_frames", slider=True, text="")
|
||||
|
||||
|
||||
# ********** grease pencil object tool panels ****************
|
||||
|
|
|
@ -489,6 +489,7 @@ geometry_node_categories = [
|
|||
NodeItem("GeometryNodeAttributeMix"),
|
||||
NodeItem("GeometryNodeAttributeColorRamp"),
|
||||
NodeItem("GeometryNodeAttributeVectorMath"),
|
||||
NodeItem("GeometryNodeAttributeSampleTexture"),
|
||||
]),
|
||||
GeometryNodeCategory("GEO_COLOR", "Color", items=[
|
||||
NodeItem("ShaderNodeValToRGB"),
|
||||
|
|
|
@ -12,5 +12,5 @@ mkdir "%temp%\blender\debug_logs" > NUL 2>&1
|
|||
echo.
|
||||
echo Starting blender and waiting for it to exit....
|
||||
set PYTHONPATH=
|
||||
"%~dp0\blender" --debug --debug-gpu --python-expr "import bpy; bpy.ops.wm.sysinfo(filepath=r'%temp%\blender\debug_logs\blender_system_info.txt')" > "%temp%\blender\debug_logs\blender_debug_output.txt" 2>&1 < %0
|
||||
"%~dp0\blender" --debug --debug-gpu --debug-cycles --python-expr "import bpy; bpy.ops.wm.sysinfo(filepath=r'%temp%\blender\debug_logs\blender_system_info.txt')" > "%temp%\blender\debug_logs\blender_debug_output.txt" 2>&1 < %0
|
||||
explorer "%temp%\blender\debug_logs"
|
|
@ -24,6 +24,7 @@
|
|||
#include "BKE_attribute.h"
|
||||
|
||||
#include "BLI_color.hh"
|
||||
#include "BLI_float2.hh"
|
||||
#include "BLI_float3.hh"
|
||||
|
||||
namespace blender::bke {
|
||||
|
@ -301,11 +302,13 @@ template<typename T> class TypedWriteAttribute {
|
|||
|
||||
using BooleanReadAttribute = TypedReadAttribute<bool>;
|
||||
using FloatReadAttribute = TypedReadAttribute<float>;
|
||||
using Float2ReadAttribute = TypedReadAttribute<float2>;
|
||||
using Float3ReadAttribute = TypedReadAttribute<float3>;
|
||||
using Int32ReadAttribute = TypedReadAttribute<int>;
|
||||
using Color4fReadAttribute = TypedReadAttribute<Color4f>;
|
||||
using BooleanWriteAttribute = TypedWriteAttribute<bool>;
|
||||
using FloatWriteAttribute = TypedWriteAttribute<float>;
|
||||
using Float2WriteAttribute = TypedWriteAttribute<float2>;
|
||||
using Float3WriteAttribute = TypedWriteAttribute<float3>;
|
||||
using Int32WriteAttribute = TypedWriteAttribute<int>;
|
||||
using Color4fWriteAttribute = TypedWriteAttribute<Color4f>;
|
||||
|
|
|
@ -39,7 +39,7 @@ extern "C" {
|
|||
|
||||
/* Blender file format version. */
|
||||
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
||||
#define BLENDER_FILE_SUBVERSION 1
|
||||
#define BLENDER_FILE_SUBVERSION 3
|
||||
|
||||
/* Minimum Blender version that supports reading file written with the current
|
||||
* version. Older Blender versions will test this and show a warning if the file
|
||||
|
|
|
@ -36,6 +36,7 @@ struct Collection;
|
|||
struct Mesh;
|
||||
struct Object;
|
||||
struct PointCloud;
|
||||
struct Volume;
|
||||
|
||||
/* Each geometry component has a specific type. The type determines what kind of data the component
|
||||
* stores. Functions modifying a geometry will usually just modify a subset of the component types.
|
||||
|
@ -44,6 +45,7 @@ enum class GeometryComponentType {
|
|||
Mesh = 0,
|
||||
PointCloud = 1,
|
||||
Instances = 2,
|
||||
Volume = 3,
|
||||
};
|
||||
|
||||
enum class GeometryOwnershipType {
|
||||
|
@ -319,10 +321,13 @@ struct GeometrySet {
|
|||
bool has_mesh() const;
|
||||
bool has_pointcloud() const;
|
||||
bool has_instances() const;
|
||||
bool has_volume() const;
|
||||
const Mesh *get_mesh_for_read() const;
|
||||
const PointCloud *get_pointcloud_for_read() const;
|
||||
const Volume *get_volume_for_read() const;
|
||||
Mesh *get_mesh_for_write();
|
||||
PointCloud *get_pointcloud_for_write();
|
||||
Volume *get_volume_for_write();
|
||||
|
||||
/* Utility methods for replacement. */
|
||||
void replace_mesh(Mesh *mesh, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
|
||||
|
@ -464,3 +469,25 @@ class InstancesComponent : public GeometryComponent {
|
|||
|
||||
static constexpr inline GeometryComponentType static_type = GeometryComponentType::Instances;
|
||||
};
|
||||
|
||||
/** A geometry component that stores volume grids. */
|
||||
class VolumeComponent : public GeometryComponent {
|
||||
private:
|
||||
Volume *volume_ = nullptr;
|
||||
GeometryOwnershipType ownership_ = GeometryOwnershipType::Owned;
|
||||
|
||||
public:
|
||||
VolumeComponent();
|
||||
~VolumeComponent();
|
||||
GeometryComponent *copy() const override;
|
||||
|
||||
void clear();
|
||||
bool has_volume() const;
|
||||
void replace(Volume *volume, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
|
||||
Volume *release();
|
||||
|
||||
const Volume *get_for_read() const;
|
||||
Volume *get_for_write();
|
||||
|
||||
static constexpr inline GeometryComponentType static_type = GeometryComponentType::Volume;
|
||||
};
|
||||
|
|
|
@ -109,8 +109,11 @@ struct bGPDframe *BKE_gpencil_frame_addcopy(struct bGPDlayer *gpl, int cframe);
|
|||
struct bGPDlayer *BKE_gpencil_layer_addnew(struct bGPdata *gpd, const char *name, bool setactive);
|
||||
struct bGPdata *BKE_gpencil_data_addnew(struct Main *bmain, const char name[]);
|
||||
|
||||
struct bGPDframe *BKE_gpencil_frame_duplicate(const struct bGPDframe *gpf_src);
|
||||
struct bGPDlayer *BKE_gpencil_layer_duplicate(const struct bGPDlayer *gpl_src);
|
||||
struct bGPDframe *BKE_gpencil_frame_duplicate(const struct bGPDframe *gpf_src,
|
||||
const bool dup_strokes);
|
||||
struct bGPDlayer *BKE_gpencil_layer_duplicate(const struct bGPDlayer *gpl_src,
|
||||
const bool dup_frames,
|
||||
const bool dup_strokes);
|
||||
void BKE_gpencil_frame_copy_strokes(struct bGPDframe *gpf_src, struct bGPDframe *gpf_dst);
|
||||
struct bGPDcurve *BKE_gpencil_stroke_curve_duplicate(struct bGPDcurve *gpc_src);
|
||||
struct bGPDstroke *BKE_gpencil_stroke_duplicate(struct bGPDstroke *gps_src,
|
||||
|
|
|
@ -106,6 +106,8 @@ typedef void (*IDTypeBlendReadUndoPreserve)(struct BlendLibReader *reader,
|
|||
struct ID *id_new,
|
||||
struct ID *id_old);
|
||||
|
||||
typedef void (*IDTypeLibOverrideApplyPost)(struct ID *id_dst, struct ID *id_src);
|
||||
|
||||
typedef struct IDTypeInfo {
|
||||
/* ********** General IDType data. ********** */
|
||||
|
||||
|
@ -207,6 +209,13 @@ typedef struct IDTypeInfo {
|
|||
* \note Called from #setup_app_data when undoing or redoing a memfile step.
|
||||
*/
|
||||
IDTypeBlendReadUndoPreserve blend_read_undo_preserve;
|
||||
|
||||
/**
|
||||
* Called after library override operations have been applied.
|
||||
*
|
||||
* \note Currently needed for some update operation on point caches.
|
||||
*/
|
||||
IDTypeLibOverrideApplyPost lib_override_apply_post;
|
||||
} IDTypeInfo;
|
||||
|
||||
/* ********** Declaration of each IDTypeInfo. ********** */
|
||||
|
|
|
@ -60,22 +60,52 @@ typedef struct BlendThumbnail {
|
|||
} BlendThumbnail;
|
||||
|
||||
/* Structs caching relations between data-blocks in a given Main. */
|
||||
typedef struct MainIDRelationsEntryItem {
|
||||
struct MainIDRelationsEntryItem *next;
|
||||
|
||||
union {
|
||||
/* For `from_ids` list, a user of the hashed ID. */
|
||||
struct ID *from;
|
||||
/* For `to_ids` list, an ID used by the hashed ID. */
|
||||
struct ID **to;
|
||||
} id_pointer;
|
||||
/* Session uuid of the `id_pointer`. */
|
||||
uint session_uuid;
|
||||
|
||||
int usage_flag; /* Using IDWALK_ enums, defined in BKE_lib_query.h */
|
||||
} MainIDRelationsEntryItem;
|
||||
|
||||
typedef struct MainIDRelationsEntry {
|
||||
struct MainIDRelationsEntry *next;
|
||||
/* WARNING! for user_to_used,
|
||||
* that pointer is really an ID** one, but for used_to_user, it’s only an ID* one! */
|
||||
struct ID **id_pointer;
|
||||
int usage_flag; /* Using IDWALK_ enums, in BKE_lib_query.h */
|
||||
/* Linked list of IDs using that ID. */
|
||||
struct MainIDRelationsEntryItem *from_ids;
|
||||
/* Linked list of IDs used by that ID. */
|
||||
struct MainIDRelationsEntryItem *to_ids;
|
||||
|
||||
/* Session uuid of the ID matching that entry. */
|
||||
uint session_uuid;
|
||||
|
||||
/* Runtime tags, users should ensure those are reset after usage. */
|
||||
uint tags;
|
||||
} MainIDRelationsEntry;
|
||||
|
||||
/* MainIDRelationsEntry.tags */
|
||||
typedef enum MainIDRelationsEntryTags {
|
||||
/* Generic tag marking the entry as to be processed. */
|
||||
MAINIDRELATIONS_ENTRY_TAGS_DOIT = 1 << 0,
|
||||
/* Generic tag marking the entry as processed. */
|
||||
MAINIDRELATIONS_ENTRY_TAGS_PROCESSED = 1 << 1,
|
||||
} MainIDRelationsEntryTags;
|
||||
|
||||
typedef struct MainIDRelations {
|
||||
struct GHash *id_user_to_used;
|
||||
struct GHash *id_used_to_user;
|
||||
/* Mapping from an ID pointer to all of its parents (IDs using it) and children (IDs it uses).
|
||||
* Values are `MainIDRelationsEntry` pointers. */
|
||||
struct GHash *relations_from_pointers;
|
||||
/* Note: we could add more mappings when needed (e.g. from session uuid?). */
|
||||
|
||||
short flag;
|
||||
|
||||
/* Private... */
|
||||
struct BLI_mempool *entry_pool;
|
||||
struct BLI_mempool *entry_items_pool;
|
||||
} MainIDRelations;
|
||||
|
||||
enum {
|
||||
|
@ -172,7 +202,6 @@ void BKE_main_unlock(struct Main *bmain);
|
|||
|
||||
void BKE_main_relations_create(struct Main *bmain, const short flag);
|
||||
void BKE_main_relations_free(struct Main *bmain);
|
||||
void BKE_main_relations_ID_remove(struct Main *bmain, struct ID *id);
|
||||
|
||||
struct GSet *BKE_main_gset_create(struct Main *bmain, struct GSet *gset);
|
||||
|
||||
|
|
|
@ -1361,6 +1361,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
|
|||
#define GEO_NODE_ALIGN_ROTATION_TO_VECTOR 1018
|
||||
#define GEO_NODE_POINT_TRANSLATE 1019
|
||||
#define GEO_NODE_POINT_SCALE 1020
|
||||
#define GEO_NODE_ATTRIBUTE_SAMPLE_TEXTURE 1021
|
||||
|
||||
/** \} */
|
||||
|
||||
|
|
|
@ -298,6 +298,8 @@ IDTypeInfo IDType_ID_AC = {
|
|||
.blend_read_expand = action_blend_read_expand,
|
||||
|
||||
.blend_read_undo_preserve = NULL,
|
||||
|
||||
.lib_override_apply_post = NULL,
|
||||
};
|
||||
|
||||
/* ***************** Library data level operations on action ************** */
|
||||
|
|
|
@ -331,6 +331,8 @@ IDTypeInfo IDType_ID_AR = {
|
|||
.blend_read_expand = armature_blend_read_expand,
|
||||
|
||||
.blend_read_undo_preserve = NULL,
|
||||
|
||||
.lib_override_apply_post = NULL,
|
||||
};
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -873,10 +873,19 @@ OutputAttributePtr::OutputAttributePtr(GeometryComponent &component,
|
|||
|
||||
const int domain_size = component.attribute_domain_size(domain);
|
||||
void *buffer = MEM_malloc_arrayN(domain_size, cpp_type->size(), __func__);
|
||||
cpp_type->construct_default_n(buffer, domain_size);
|
||||
GMutableSpan new_span{*cpp_type, buffer, domain_size};
|
||||
|
||||
/* Copy converted values from conflicting attribute, in case the value is read.
|
||||
* TODO: An optimization could be to not do this, when the caller says that the attribute will
|
||||
* only be written. */
|
||||
ReadAttributePtr src_attribute = component.attribute_get_for_read(
|
||||
final_name, domain, data_type, nullptr);
|
||||
for (const int i : blender::IndexRange(domain_size)) {
|
||||
src_attribute->get(i, new_span[i]);
|
||||
}
|
||||
|
||||
attribute_ = std::make_unique<blender::bke::TemporaryWriteAttribute>(
|
||||
domain, GMutableSpan{*cpp_type, buffer, domain_size}, component, std::move(final_name));
|
||||
domain, new_span, component, std::move(final_name));
|
||||
}
|
||||
|
||||
/* Store the computed attribute. If it was stored from the beginning already, nothing is done. This
|
||||
|
|
|
@ -647,6 +647,10 @@ UserDef *BKE_blendfile_userdef_from_defaults(void)
|
|||
BKE_studiolight_default(userdef->light_param, userdef->light_ambient);
|
||||
|
||||
BKE_preferences_asset_library_default_add(userdef);
|
||||
/* Enable asset browser features by default for alpha testing.
|
||||
* BLO_sanitize_experimental_features_userpref_blend() will disable it again for non-alpha
|
||||
* builds. */
|
||||
userdef->experimental.use_asset_browser = true;
|
||||
|
||||
return userdef;
|
||||
}
|
||||
|
|
|
@ -464,6 +464,8 @@ IDTypeInfo IDType_ID_BR = {
|
|||
.blend_read_expand = brush_blend_read_expand,
|
||||
|
||||
.blend_read_undo_preserve = brush_undo_preserve,
|
||||
|
||||
.lib_override_apply_post = NULL,
|
||||
};
|
||||
|
||||
static RNG *brush_rng;
|
||||
|
|
|
@ -142,6 +142,8 @@ IDTypeInfo IDType_ID_CF = {
|
|||
.blend_read_expand = NULL,
|
||||
|
||||
.blend_read_undo_preserve = NULL,
|
||||
|
||||
.lib_override_apply_post = NULL,
|
||||
};
|
||||
|
||||
/* TODO: make this per cache file to avoid global locks. */
|
||||
|
|
|
@ -203,6 +203,8 @@ IDTypeInfo IDType_ID_CA = {
|
|||
.blend_read_expand = camera_blend_read_expand,
|
||||
|
||||
.blend_read_undo_preserve = NULL,
|
||||
|
||||
.lib_override_apply_post = NULL,
|
||||
};
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -362,6 +362,8 @@ IDTypeInfo IDType_ID_GR = {
|
|||
.blend_read_expand = collection_blend_read_expand,
|
||||
|
||||
.blend_read_undo_preserve = NULL,
|
||||
|
||||
.lib_override_apply_post = NULL,
|
||||
};
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -327,6 +327,8 @@ IDTypeInfo IDType_ID_CU = {
|
|||
.blend_read_expand = curve_blend_read_expand,
|
||||
|
||||
.blend_read_undo_preserve = NULL,
|
||||
|
||||
.lib_override_apply_post = NULL,
|
||||
};
|
||||
|
||||
static int cu_isectLL(const float v1[3],
|
||||
|
|
|
@ -176,6 +176,8 @@ IDTypeInfo IDType_ID_VF = {
|
|||
.blend_read_expand = NULL,
|
||||
|
||||
.blend_read_undo_preserve = NULL,
|
||||
|
||||
.lib_override_apply_post = NULL,
|
||||
};
|
||||
|
||||
/***************************** VFont *******************************/
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "BKE_mesh.h"
|
||||
#include "BKE_mesh_wrapper.h"
|
||||
#include "BKE_pointcloud.h"
|
||||
#include "BKE_volume.h"
|
||||
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
|
@ -51,6 +52,8 @@ GeometryComponent *GeometryComponent::create(GeometryComponentType component_typ
|
|||
return new PointCloudComponent();
|
||||
case GeometryComponentType::Instances:
|
||||
return new InstancesComponent();
|
||||
case GeometryComponentType::Volume:
|
||||
return new VolumeComponent();
|
||||
}
|
||||
BLI_assert(false);
|
||||
return nullptr;
|
||||
|
@ -201,6 +204,13 @@ const PointCloud *GeometrySet::get_pointcloud_for_read() const
|
|||
return (component == nullptr) ? nullptr : component->get_for_read();
|
||||
}
|
||||
|
||||
/* Returns a read-only volume or null. */
|
||||
const Volume *GeometrySet::get_volume_for_read() const
|
||||
{
|
||||
const VolumeComponent *component = this->get_component_for_read<VolumeComponent>();
|
||||
return (component == nullptr) ? nullptr : component->get_for_read();
|
||||
}
|
||||
|
||||
/* Returns true when the geometry set has a point cloud component that has a point cloud. */
|
||||
bool GeometrySet::has_pointcloud() const
|
||||
{
|
||||
|
@ -215,6 +225,13 @@ bool GeometrySet::has_instances() const
|
|||
return component != nullptr && component->instances_amount() >= 1;
|
||||
}
|
||||
|
||||
/* Returns true when the geometry set has a volume component that has a volume. */
|
||||
bool GeometrySet::has_volume() const
|
||||
{
|
||||
const VolumeComponent *component = this->get_component_for_read<VolumeComponent>();
|
||||
return component != nullptr && component->has_volume();
|
||||
}
|
||||
|
||||
/* Create a new geometry set that only contains the given mesh. */
|
||||
GeometrySet GeometrySet::create_with_mesh(Mesh *mesh, GeometryOwnershipType ownership)
|
||||
{
|
||||
|
@ -262,6 +279,13 @@ PointCloud *GeometrySet::get_pointcloud_for_write()
|
|||
return component.get_for_write();
|
||||
}
|
||||
|
||||
/* Returns a mutable volume or null. No ownership is transferred. */
|
||||
Volume *GeometrySet::get_volume_for_write()
|
||||
{
|
||||
VolumeComponent &component = this->get_component_for_write<VolumeComponent>();
|
||||
return component.get_for_write();
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@ -566,6 +590,85 @@ bool InstancesComponent::is_empty() const
|
|||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Volume Component
|
||||
* \{ */
|
||||
|
||||
VolumeComponent::VolumeComponent() : GeometryComponent(GeometryComponentType::Volume)
|
||||
{
|
||||
}
|
||||
|
||||
VolumeComponent::~VolumeComponent()
|
||||
{
|
||||
this->clear();
|
||||
}
|
||||
|
||||
GeometryComponent *VolumeComponent::copy() const
|
||||
{
|
||||
VolumeComponent *new_component = new VolumeComponent();
|
||||
if (volume_ != nullptr) {
|
||||
new_component->volume_ = BKE_volume_copy_for_eval(volume_, false);
|
||||
new_component->ownership_ = GeometryOwnershipType::Owned;
|
||||
}
|
||||
return new_component;
|
||||
}
|
||||
|
||||
void VolumeComponent::clear()
|
||||
{
|
||||
BLI_assert(this->is_mutable());
|
||||
if (volume_ != nullptr) {
|
||||
if (ownership_ == GeometryOwnershipType::Owned) {
|
||||
BKE_id_free(nullptr, volume_);
|
||||
}
|
||||
volume_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool VolumeComponent::has_volume() const
|
||||
{
|
||||
return volume_ != nullptr;
|
||||
}
|
||||
|
||||
/* Clear the component and replace it with the new volume. */
|
||||
void VolumeComponent::replace(Volume *volume, GeometryOwnershipType ownership)
|
||||
{
|
||||
BLI_assert(this->is_mutable());
|
||||
this->clear();
|
||||
volume_ = volume;
|
||||
ownership_ = ownership;
|
||||
}
|
||||
|
||||
/* Return the volume and clear the component. The caller takes over responsibility for freeing the
|
||||
* volume (if the component was responsible before). */
|
||||
Volume *VolumeComponent::release()
|
||||
{
|
||||
BLI_assert(this->is_mutable());
|
||||
Volume *volume = volume_;
|
||||
volume_ = nullptr;
|
||||
return volume;
|
||||
}
|
||||
|
||||
/* Get the volume from this component. This method can be used by multiple threads at the same
|
||||
* time. Therefore, the returned volume should not be modified. No ownership is transferred. */
|
||||
const Volume *VolumeComponent::get_for_read() const
|
||||
{
|
||||
return volume_;
|
||||
}
|
||||
|
||||
/* Get the volume from this component. This method can only be used when the component is mutable,
|
||||
* i.e. it is not shared. The returned volume can be modified. No ownership is transferred. */
|
||||
Volume *VolumeComponent::get_for_write()
|
||||
{
|
||||
BLI_assert(this->is_mutable());
|
||||
if (ownership_ == GeometryOwnershipType::ReadOnly) {
|
||||
volume_ = BKE_volume_copy_for_eval(volume_, false);
|
||||
ownership_ = GeometryOwnershipType::Owned;
|
||||
}
|
||||
return volume_;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name C API
|
||||
* \{ */
|
||||
|
|
|
@ -93,7 +93,7 @@ static void greasepencil_copy_data(Main *UNUSED(bmain),
|
|||
/* make a copy of source layer and its data */
|
||||
|
||||
/* TODO here too could add unused flags... */
|
||||
bGPDlayer *gpl_dst = BKE_gpencil_layer_duplicate(gpl_src);
|
||||
bGPDlayer *gpl_dst = BKE_gpencil_layer_duplicate(gpl_src, true, true);
|
||||
|
||||
/* Apply local layer transform to all frames. Calc the active frame is not enough
|
||||
* because onion skin can use more frames. This is more slow but required here. */
|
||||
|
@ -329,6 +329,8 @@ IDTypeInfo IDType_ID_GD = {
|
|||
.blend_read_expand = greasepencil_blend_read_expand,
|
||||
|
||||
.blend_read_undo_preserve = NULL,
|
||||
|
||||
.lib_override_apply_post = NULL,
|
||||
};
|
||||
|
||||
/* ************************************************** */
|
||||
|
@ -607,7 +609,7 @@ bGPDframe *BKE_gpencil_frame_addcopy(bGPDlayer *gpl, int cframe)
|
|||
}
|
||||
|
||||
/* Create a copy of the frame */
|
||||
new_frame = BKE_gpencil_frame_duplicate(gpl->actframe);
|
||||
new_frame = BKE_gpencil_frame_duplicate(gpl->actframe, true);
|
||||
|
||||
/* Find frame to insert it before */
|
||||
LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
|
||||
|
@ -991,7 +993,7 @@ bGPDstroke *BKE_gpencil_stroke_duplicate(bGPDstroke *gps_src,
|
|||
* \param gpf_src: Source grease pencil frame
|
||||
* \return Pointer to new frame
|
||||
*/
|
||||
bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src)
|
||||
bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src, const bool dup_strokes)
|
||||
{
|
||||
bGPDstroke *gps_dst = NULL;
|
||||
bGPDframe *gpf_dst;
|
||||
|
@ -1005,12 +1007,14 @@ bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src)
|
|||
gpf_dst = MEM_dupallocN(gpf_src);
|
||||
gpf_dst->prev = gpf_dst->next = NULL;
|
||||
|
||||
/* copy strokes */
|
||||
/* Copy strokes. */
|
||||
BLI_listbase_clear(&gpf_dst->strokes);
|
||||
LISTBASE_FOREACH (bGPDstroke *, gps_src, &gpf_src->strokes) {
|
||||
/* make copy of source stroke */
|
||||
gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true, true);
|
||||
BLI_addtail(&gpf_dst->strokes, gps_dst);
|
||||
if (dup_strokes) {
|
||||
LISTBASE_FOREACH (bGPDstroke *, gps_src, &gpf_src->strokes) {
|
||||
/* make copy of source stroke */
|
||||
gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true, true);
|
||||
BLI_addtail(&gpf_dst->strokes, gps_dst);
|
||||
}
|
||||
}
|
||||
|
||||
/* return new frame */
|
||||
|
@ -1044,7 +1048,9 @@ void BKE_gpencil_frame_copy_strokes(bGPDframe *gpf_src, struct bGPDframe *gpf_ds
|
|||
* \param gpl_src: Source grease pencil layer
|
||||
* \return Pointer to new layer
|
||||
*/
|
||||
bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src)
|
||||
bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src,
|
||||
const bool dup_frames,
|
||||
const bool dup_strokes)
|
||||
{
|
||||
const bGPDframe *gpf_src;
|
||||
bGPDframe *gpf_dst;
|
||||
|
@ -1069,14 +1075,16 @@ bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src)
|
|||
|
||||
/* copy frames */
|
||||
BLI_listbase_clear(&gpl_dst->frames);
|
||||
for (gpf_src = gpl_src->frames.first; gpf_src; gpf_src = gpf_src->next) {
|
||||
/* make a copy of source frame */
|
||||
gpf_dst = BKE_gpencil_frame_duplicate(gpf_src);
|
||||
BLI_addtail(&gpl_dst->frames, gpf_dst);
|
||||
if (dup_frames) {
|
||||
for (gpf_src = gpl_src->frames.first; gpf_src; gpf_src = gpf_src->next) {
|
||||
/* make a copy of source frame */
|
||||
gpf_dst = BKE_gpencil_frame_duplicate(gpf_src, dup_strokes);
|
||||
BLI_addtail(&gpl_dst->frames, gpf_dst);
|
||||
|
||||
/* if source frame was the current layer's 'active' frame, reassign that too */
|
||||
if (gpf_src == gpl_dst->actframe) {
|
||||
gpl_dst->actframe = gpf_dst;
|
||||
/* if source frame was the current layer's 'active' frame, reassign that too */
|
||||
if (gpf_src == gpl_dst->actframe) {
|
||||
gpl_dst->actframe = gpf_dst;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -197,6 +197,8 @@ IDTypeInfo IDType_ID_HA = {
|
|||
.blend_read_expand = hair_blend_read_expand,
|
||||
|
||||
.blend_read_undo_preserve = NULL,
|
||||
|
||||
.lib_override_apply_post = NULL,
|
||||
};
|
||||
|
||||
static void hair_random(Hair *hair)
|
||||
|
|
|
@ -338,6 +338,8 @@ IDTypeInfo IDType_ID_IM = {
|
|||
.blend_read_expand = NULL,
|
||||
|
||||
.blend_read_undo_preserve = NULL,
|
||||
|
||||
.lib_override_apply_post = NULL,
|
||||
};
|
||||
|
||||
/* prototypes */
|
||||
|
|
|
@ -200,6 +200,8 @@ IDTypeInfo IDType_ID_IP = {
|
|||
.blend_read_expand = ipo_blend_read_expand,
|
||||
|
||||
.blend_read_undo_preserve = NULL,
|
||||
|
||||
.lib_override_apply_post = NULL,
|
||||
};
|
||||
|
||||
/* *************************************************** */
|
||||
|
|
|
@ -223,6 +223,8 @@ IDTypeInfo IDType_ID_KE = {
|
|||
.blend_read_expand = shapekey_blend_read_expand,
|
||||
|
||||
.blend_read_undo_preserve = NULL,
|
||||
|
||||
.lib_override_apply_post = NULL,
|
||||
};
|
||||
|
||||
#define KEY_MODE_DUMMY 0 /* use where mode isn't checked for */
|
||||
|
|
|
@ -205,6 +205,8 @@ IDTypeInfo IDType_ID_LT = {
|
|||
.blend_read_expand = lattice_blend_read_expand,
|
||||
|
||||
.blend_read_undo_preserve = NULL,
|
||||
|
||||
.lib_override_apply_post = NULL,
|
||||
};
|
||||
|
||||
int BKE_lattice_index_from_uvw(Lattice *lt, const int u, const int v, const int w)
|
||||
|
|
|
@ -112,6 +112,8 @@ IDTypeInfo IDType_ID_LINK_PLACEHOLDER = {
|
|||
.blend_read_expand = NULL,
|
||||
|
||||
.blend_read_undo_preserve = NULL,
|
||||
|
||||
.lib_override_apply_post = NULL,
|
||||
};
|
||||
|
||||
/* GS reads the memory pointed at in a specific ordering.
|
||||
|
@ -1793,32 +1795,31 @@ static void library_make_local_copying_check(ID *id,
|
|||
return; /* Already checked, nothing else to do. */
|
||||
}
|
||||
|
||||
MainIDRelationsEntry *entry = BLI_ghash_lookup(id_relations->id_used_to_user, id);
|
||||
MainIDRelationsEntry *entry = BLI_ghash_lookup(id_relations->relations_from_pointers, id);
|
||||
BLI_gset_insert(loop_tags, id);
|
||||
for (; entry != NULL; entry = entry->next) {
|
||||
|
||||
/* Used_to_user stores ID pointer, not pointer to ID pointer. */
|
||||
ID *par_id = (ID *)entry->id_pointer;
|
||||
|
||||
for (MainIDRelationsEntryItem *from_id_entry = entry->from_ids; from_id_entry != NULL;
|
||||
from_id_entry = from_id_entry->next) {
|
||||
/* Our oh-so-beloved 'from' pointers... Those should always be ignored here, since the actual
|
||||
* relation we want to check is in the other way around. */
|
||||
if (entry->usage_flag & IDWALK_CB_LOOPBACK) {
|
||||
if (from_id_entry->usage_flag & IDWALK_CB_LOOPBACK) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ID *from_id = from_id_entry->id_pointer.from;
|
||||
|
||||
/* Shape-keys are considered 'private' to their owner ID here, and never tagged
|
||||
* (since they cannot be linked), so we have to switch effective parent to their owner.
|
||||
*/
|
||||
if (GS(par_id->name) == ID_KE) {
|
||||
par_id = ((Key *)par_id)->from;
|
||||
if (GS(from_id->name) == ID_KE) {
|
||||
from_id = ((Key *)from_id)->from;
|
||||
}
|
||||
|
||||
if (par_id->lib == NULL) {
|
||||
if (from_id->lib == NULL) {
|
||||
/* Local user, early out to avoid some gset querying... */
|
||||
continue;
|
||||
}
|
||||
if (!BLI_gset_haskey(done_ids, par_id)) {
|
||||
if (BLI_gset_haskey(loop_tags, par_id)) {
|
||||
if (!BLI_gset_haskey(done_ids, from_id)) {
|
||||
if (BLI_gset_haskey(loop_tags, from_id)) {
|
||||
/* We are in a 'dependency loop' of IDs, this does not say us anything, skip it.
|
||||
* Note that this is the situation that can lead to archipelagoes of linked data-blocks
|
||||
* (since all of them have non-local users, they would all be duplicated,
|
||||
|
@ -1827,10 +1828,10 @@ static void library_make_local_copying_check(ID *id,
|
|||
continue;
|
||||
}
|
||||
/* Else, recursively check that user ID. */
|
||||
library_make_local_copying_check(par_id, loop_tags, id_relations, done_ids);
|
||||
library_make_local_copying_check(from_id, loop_tags, id_relations, done_ids);
|
||||
}
|
||||
|
||||
if (par_id->tag & LIB_TAG_DOIT) {
|
||||
if (from_id->tag & LIB_TAG_DOIT) {
|
||||
/* This user will be fully local in future, so far so good,
|
||||
* nothing to do here but check next user. */
|
||||
}
|
||||
|
|
|
@ -374,9 +374,15 @@ static bool lib_override_hierarchy_recursive_tag(Main *bmain,
|
|||
const uint missing_tag,
|
||||
Library *override_group_lib_reference)
|
||||
{
|
||||
void **entry_vp = BLI_ghash_lookup_p(bmain->relations->id_user_to_used, id);
|
||||
void **entry_vp = BLI_ghash_lookup_p(bmain->relations->relations_from_pointers, id);
|
||||
if (entry_vp == NULL) {
|
||||
/* Already processed. */
|
||||
/* This ID is not used by nor using any other ID. */
|
||||
return (id->tag & tag) != 0;
|
||||
}
|
||||
|
||||
MainIDRelationsEntry *entry = *entry_vp;
|
||||
if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) {
|
||||
/* This ID has already been processed. */
|
||||
return (id->tag & tag) != 0;
|
||||
}
|
||||
|
||||
|
@ -393,22 +399,21 @@ static bool lib_override_hierarchy_recursive_tag(Main *bmain,
|
|||
}
|
||||
|
||||
/* This way we won't process again that ID, should we encounter it again through another
|
||||
* relationship hierarchy.
|
||||
* Note that this does not free any memory from relations, so we can still use the entries.
|
||||
*/
|
||||
BKE_main_relations_ID_remove(bmain, id);
|
||||
* relationship hierarchy. */
|
||||
entry->tags |= MAINIDRELATIONS_ENTRY_TAGS_PROCESSED;
|
||||
|
||||
for (MainIDRelationsEntry *entry = *entry_vp; entry != NULL; entry = entry->next) {
|
||||
if ((entry->usage_flag & IDWALK_CB_LOOPBACK) != 0) {
|
||||
for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != NULL;
|
||||
to_id_entry = to_id_entry->next) {
|
||||
if ((to_id_entry->usage_flag & IDWALK_CB_LOOPBACK) != 0) {
|
||||
/* Never consider 'loop back' relationships ('from', 'parents', 'owner' etc. pointers) as
|
||||
* actual dependencies. */
|
||||
continue;
|
||||
}
|
||||
/* We only consider IDs from the same library. */
|
||||
if (entry->id_pointer != NULL && (*entry->id_pointer)->lib == id->lib) {
|
||||
if (lib_override_hierarchy_recursive_tag(
|
||||
bmain, *entry->id_pointer, tag, missing_tag, override_group_lib_reference) &&
|
||||
override_group_lib_reference == NULL) {
|
||||
if (*to_id_entry->id_pointer.to != NULL && (*to_id_entry->id_pointer.to)->lib == id->lib) {
|
||||
const bool needs_tag = lib_override_hierarchy_recursive_tag(
|
||||
bmain, *to_id_entry->id_pointer.to, tag, missing_tag, override_group_lib_reference);
|
||||
if (needs_tag && override_group_lib_reference == NULL) {
|
||||
id->tag |= tag;
|
||||
}
|
||||
}
|
||||
|
@ -1619,31 +1624,37 @@ static void lib_override_library_id_hierarchy_recursive_reset(Main *bmain, ID *i
|
|||
return;
|
||||
}
|
||||
|
||||
void **entry_pp = BLI_ghash_lookup(bmain->relations->id_user_to_used, id_root);
|
||||
if (entry_pp == NULL) {
|
||||
/* Already processed. */
|
||||
void **entry_vp = BLI_ghash_lookup_p(bmain->relations->relations_from_pointers, id_root);
|
||||
if (entry_vp == NULL) {
|
||||
/* This ID is not used by nor using any other ID. */
|
||||
lib_override_library_id_reset_do(bmain, id_root);
|
||||
return;
|
||||
}
|
||||
|
||||
MainIDRelationsEntry *entry = *entry_vp;
|
||||
if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) {
|
||||
/* This ID has already been processed. */
|
||||
return;
|
||||
}
|
||||
|
||||
lib_override_library_id_reset_do(bmain, id_root);
|
||||
|
||||
/* This way we won't process again that ID, should we encounter it again through another
|
||||
* relationship hierarchy.
|
||||
* Note that this does not free any memory from relations, so we can still use the entries.
|
||||
*/
|
||||
BKE_main_relations_ID_remove(bmain, id_root);
|
||||
* relationship hierarchy. */
|
||||
entry->tags |= MAINIDRELATIONS_ENTRY_TAGS_PROCESSED;
|
||||
|
||||
for (MainIDRelationsEntry *entry = *entry_pp; entry != NULL; entry = entry->next) {
|
||||
if ((entry->usage_flag & IDWALK_CB_LOOPBACK) != 0) {
|
||||
for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != NULL;
|
||||
to_id_entry = to_id_entry->next) {
|
||||
if ((to_id_entry->usage_flag & IDWALK_CB_LOOPBACK) != 0) {
|
||||
/* Never consider 'loop back' relationships ('from', 'parents', 'owner' etc. pointers) as
|
||||
* actual dependencies. */
|
||||
continue;
|
||||
}
|
||||
/* We only consider IDs from the same library. */
|
||||
if (entry->id_pointer != NULL) {
|
||||
ID *id_entry = *entry->id_pointer;
|
||||
if (id_entry->override_library != NULL) {
|
||||
lib_override_library_id_hierarchy_recursive_reset(bmain, id_entry);
|
||||
if (*to_id_entry->id_pointer.to != NULL) {
|
||||
ID *to_id = *to_id_entry->id_pointer.to;
|
||||
if (to_id->override_library != NULL) {
|
||||
lib_override_library_id_hierarchy_recursive_reset(bmain, to_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -237,9 +237,12 @@ static void library_foreach_ID_link(Main *bmain,
|
|||
* but we might as well use it (Main->relations is always assumed valid,
|
||||
* it's responsibility of code creating it to free it,
|
||||
* especially if/when it starts modifying Main database). */
|
||||
MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->id_user_to_used, id);
|
||||
for (; entry != NULL; entry = entry->next) {
|
||||
BKE_lib_query_foreachid_process(&data, entry->id_pointer, entry->usage_flag);
|
||||
MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers,
|
||||
id);
|
||||
for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != NULL;
|
||||
to_id_entry = to_id_entry->next) {
|
||||
BKE_lib_query_foreachid_process(
|
||||
&data, to_id_entry->id_pointer.to, to_id_entry->usage_flag);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -84,6 +84,8 @@ IDTypeInfo IDType_ID_LI = {
|
|||
.blend_read_expand = NULL,
|
||||
|
||||
.blend_read_undo_preserve = NULL,
|
||||
|
||||
.lib_override_apply_post = NULL,
|
||||
};
|
||||
|
||||
void BKE_library_filepath_set(Main *bmain, Library *lib, const char *filepath)
|
||||
|
|
|
@ -209,6 +209,8 @@ IDTypeInfo IDType_ID_LA = {
|
|||
.blend_read_expand = light_blend_read_expand,
|
||||
|
||||
.blend_read_undo_preserve = NULL,
|
||||
|
||||
.lib_override_apply_post = NULL,
|
||||
};
|
||||
|
||||
Light *BKE_light_add(Main *bmain, const char *name)
|
||||
|
|
|
@ -107,6 +107,8 @@ IDTypeInfo IDType_ID_LP = {
|
|||
.blend_read_expand = NULL,
|
||||
|
||||
.blend_read_undo_preserve = NULL,
|
||||
|
||||
.lib_override_apply_post = NULL,
|
||||
};
|
||||
|
||||
void BKE_lightprobe_type_set(LightProbe *probe, const short lightprobe_type)
|
||||
|
|
|
@ -767,6 +767,8 @@ IDTypeInfo IDType_ID_LS = {
|
|||
.blend_read_expand = linestyle_blend_read_expand,
|
||||
|
||||
.blend_read_undo_preserve = NULL,
|
||||
|
||||
.lib_override_apply_post = NULL,
|
||||
};
|
||||
|
||||
static const char *modifier_name[LS_MODIFIER_NUM] = {
|
||||
|
|
|
@ -211,35 +211,51 @@ void BKE_main_unlock(struct Main *bmain)
|
|||
|
||||
static int main_relations_create_idlink_cb(LibraryIDLinkCallbackData *cb_data)
|
||||
{
|
||||
MainIDRelations *rel = cb_data->user_data;
|
||||
MainIDRelations *bmain_relations = cb_data->user_data;
|
||||
ID *id_self = cb_data->id_self;
|
||||
ID **id_pointer = cb_data->id_pointer;
|
||||
const int cb_flag = cb_data->cb_flag;
|
||||
|
||||
if (*id_pointer) {
|
||||
MainIDRelationsEntry *entry, **entry_p;
|
||||
MainIDRelationsEntry **entry_p;
|
||||
|
||||
entry = BLI_mempool_alloc(rel->entry_pool);
|
||||
if (BLI_ghash_ensure_p(rel->id_user_to_used, id_self, (void ***)&entry_p)) {
|
||||
entry->next = *entry_p;
|
||||
/* Add `id_pointer` as child of `id_self`. */
|
||||
{
|
||||
if (!BLI_ghash_ensure_p(
|
||||
bmain_relations->relations_from_pointers, id_self, (void ***)&entry_p)) {
|
||||
*entry_p = MEM_callocN(sizeof(**entry_p), __func__);
|
||||
(*entry_p)->session_uuid = id_self->session_uuid;
|
||||
}
|
||||
else {
|
||||
BLI_assert((*entry_p)->session_uuid == id_self->session_uuid);
|
||||
}
|
||||
MainIDRelationsEntryItem *to_id_entry = BLI_mempool_alloc(bmain_relations->entry_items_pool);
|
||||
to_id_entry->next = (*entry_p)->to_ids;
|
||||
to_id_entry->id_pointer.to = id_pointer;
|
||||
to_id_entry->session_uuid = (*id_pointer != NULL) ? (*id_pointer)->session_uuid :
|
||||
MAIN_ID_SESSION_UUID_UNSET;
|
||||
to_id_entry->usage_flag = cb_flag;
|
||||
(*entry_p)->to_ids = to_id_entry;
|
||||
}
|
||||
else {
|
||||
entry->next = NULL;
|
||||
}
|
||||
entry->id_pointer = id_pointer;
|
||||
entry->usage_flag = cb_flag;
|
||||
*entry_p = entry;
|
||||
|
||||
entry = BLI_mempool_alloc(rel->entry_pool);
|
||||
if (BLI_ghash_ensure_p(rel->id_used_to_user, *id_pointer, (void ***)&entry_p)) {
|
||||
entry->next = *entry_p;
|
||||
/* Add `id_self` as parent of `id_pointer`. */
|
||||
if (*id_pointer != NULL) {
|
||||
if (!BLI_ghash_ensure_p(
|
||||
bmain_relations->relations_from_pointers, *id_pointer, (void ***)&entry_p)) {
|
||||
*entry_p = MEM_callocN(sizeof(**entry_p), __func__);
|
||||
(*entry_p)->session_uuid = (*id_pointer)->session_uuid;
|
||||
}
|
||||
else {
|
||||
BLI_assert((*entry_p)->session_uuid == (*id_pointer)->session_uuid);
|
||||
}
|
||||
MainIDRelationsEntryItem *from_id_entry = BLI_mempool_alloc(
|
||||
bmain_relations->entry_items_pool);
|
||||
from_id_entry->next = (*entry_p)->from_ids;
|
||||
from_id_entry->id_pointer.from = id_self;
|
||||
from_id_entry->session_uuid = id_self->session_uuid;
|
||||
from_id_entry->usage_flag = cb_flag;
|
||||
(*entry_p)->from_ids = from_id_entry;
|
||||
}
|
||||
else {
|
||||
entry->next = NULL;
|
||||
}
|
||||
entry->id_pointer = (ID **)id_self;
|
||||
entry->usage_flag = cb_flag;
|
||||
*entry_p = entry;
|
||||
}
|
||||
|
||||
return IDWALK_RET_NOP;
|
||||
|
@ -253,63 +269,46 @@ void BKE_main_relations_create(Main *bmain, const short flag)
|
|||
}
|
||||
|
||||
bmain->relations = MEM_mallocN(sizeof(*bmain->relations), __func__);
|
||||
bmain->relations->id_used_to_user = BLI_ghash_new(
|
||||
bmain->relations->relations_from_pointers = BLI_ghash_new(
|
||||
BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
|
||||
bmain->relations->id_user_to_used = BLI_ghash_new(
|
||||
BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
|
||||
bmain->relations->entry_pool = BLI_mempool_create(
|
||||
sizeof(MainIDRelationsEntry), 128, 128, BLI_MEMPOOL_NOP);
|
||||
bmain->relations->entry_items_pool = BLI_mempool_create(
|
||||
sizeof(MainIDRelationsEntryItem), 128, 128, BLI_MEMPOOL_NOP);
|
||||
|
||||
bmain->relations->flag = flag;
|
||||
|
||||
ID *id;
|
||||
FOREACH_MAIN_ID_BEGIN (bmain, id) {
|
||||
const int idwalk_flag = IDWALK_READONLY |
|
||||
((flag & MAINIDRELATIONS_INCLUDE_UI) != 0 ? IDWALK_INCLUDE_UI : 0);
|
||||
|
||||
/* Ensure all IDs do have an entry, even if they are not connected to any other. */
|
||||
MainIDRelationsEntry **entry_p;
|
||||
if (!BLI_ghash_ensure_p(bmain->relations->relations_from_pointers, id, (void ***)&entry_p)) {
|
||||
*entry_p = MEM_callocN(sizeof(**entry_p), __func__);
|
||||
(*entry_p)->session_uuid = id->session_uuid;
|
||||
}
|
||||
else {
|
||||
BLI_assert((*entry_p)->session_uuid == id->session_uuid);
|
||||
}
|
||||
|
||||
BKE_library_foreach_ID_link(
|
||||
NULL, id, main_relations_create_idlink_cb, bmain->relations, idwalk_flag);
|
||||
}
|
||||
FOREACH_MAIN_ID_END;
|
||||
|
||||
bmain->relations->flag = flag;
|
||||
}
|
||||
|
||||
void BKE_main_relations_free(Main *bmain)
|
||||
{
|
||||
if (bmain->relations) {
|
||||
if (bmain->relations->id_used_to_user) {
|
||||
BLI_ghash_free(bmain->relations->id_used_to_user, NULL, NULL);
|
||||
if (bmain->relations != NULL) {
|
||||
if (bmain->relations->relations_from_pointers != NULL) {
|
||||
BLI_ghash_free(bmain->relations->relations_from_pointers, NULL, MEM_freeN);
|
||||
}
|
||||
if (bmain->relations->id_user_to_used) {
|
||||
BLI_ghash_free(bmain->relations->id_user_to_used, NULL, NULL);
|
||||
}
|
||||
BLI_mempool_destroy(bmain->relations->entry_pool);
|
||||
BLI_mempool_destroy(bmain->relations->entry_items_pool);
|
||||
MEM_freeN(bmain->relations);
|
||||
bmain->relations = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an ID from the relations (the two entries for that ID, not the ID from entries in other
|
||||
* IDs' relationships).
|
||||
*
|
||||
* Does not free any allocated memory.
|
||||
* Allows to use those relations as a way to mark an ID as already processed, without requiring any
|
||||
* additional tagging or GSet.
|
||||
* Obviously, relations should be freed after use then, since this will make them fully invalid.
|
||||
*/
|
||||
void BKE_main_relations_ID_remove(Main *bmain, ID *id)
|
||||
{
|
||||
if (bmain->relations) {
|
||||
/* Note: we do not free the entries from the mempool, those will be dealt with when finally
|
||||
* freeing the whole relations. */
|
||||
if (bmain->relations->id_used_to_user) {
|
||||
BLI_ghash_remove(bmain->relations->id_used_to_user, id, NULL, NULL);
|
||||
}
|
||||
if (bmain->relations->id_user_to_used) {
|
||||
BLI_ghash_remove(bmain->relations->id_user_to_used, id, NULL, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a GSet storing all IDs present in given \a bmain, by their pointers.
|
||||
*
|
||||
|
|
|
@ -270,6 +270,8 @@ IDTypeInfo IDType_ID_MSK = {
|
|||
.blend_read_expand = mask_blend_read_expand,
|
||||
|
||||
.blend_read_undo_preserve = NULL,
|
||||
|
||||
.lib_override_apply_post = NULL,
|
||||
};
|
||||
|
||||
static struct {
|
||||
|
|
|
@ -274,6 +274,8 @@ IDTypeInfo IDType_ID_MA = {
|
|||
.blend_read_expand = material_blend_read_expand,
|
||||
|
||||
.blend_read_undo_preserve = NULL,
|
||||
|
||||
.lib_override_apply_post = NULL,
|
||||
};
|
||||
|
||||
void BKE_gpencil_material_attr_init(Material *ma)
|
||||
|
|
|
@ -204,6 +204,8 @@ IDTypeInfo IDType_ID_MB = {
|
|||
.blend_read_expand = metaball_blend_read_expand,
|
||||
|
||||
.blend_read_undo_preserve = NULL,
|
||||
|
||||
.lib_override_apply_post = NULL,
|
||||
};
|
||||
|
||||
/* Functions */
|
||||
|
|
|
@ -364,6 +364,8 @@ IDTypeInfo IDType_ID_ME = {
|
|||
.blend_read_expand = mesh_read_expand,
|
||||
|
||||
.blend_read_undo_preserve = NULL,
|
||||
|
||||
.lib_override_apply_post = NULL,
|
||||
};
|
||||
|
||||
enum {
|
||||
|
|
|
@ -362,6 +362,8 @@ IDTypeInfo IDType_ID_MC = {
|
|||
.blend_read_expand = NULL,
|
||||
|
||||
.blend_read_undo_preserve = NULL,
|
||||
|
||||
.lib_override_apply_post = NULL,
|
||||
};
|
||||
|
||||
/*********************** movieclip buffer loaders *************************/
|
||||
|
|
|
@ -888,6 +888,8 @@ IDTypeInfo IDType_ID_NT = {
|
|||
.blend_read_expand = ntree_blend_read_expand,
|
||||
|
||||
.blend_read_undo_preserve = NULL,
|
||||
|
||||
.lib_override_apply_post = NULL,
|
||||
};
|
||||
|
||||
static void node_add_sockets_from_type(bNodeTree *ntree, bNode *node, bNodeType *ntype)
|
||||
|
@ -4747,6 +4749,7 @@ static void registerGeometryNodes(void)
|
|||
register_node_type_geo_attribute_color_ramp();
|
||||
register_node_type_geo_point_rotate();
|
||||
register_node_type_geo_align_rotation_to_vector();
|
||||
register_node_type_geo_sample_texture();
|
||||
}
|
||||
|
||||
static void registerFunctionNodes(void)
|
||||
|
|
|
@ -1118,6 +1118,20 @@ static void object_blend_read_expand(BlendExpander *expander, ID *id)
|
|||
}
|
||||
}
|
||||
|
||||
static void object_lib_override_apply_post(ID *id_dst, ID *UNUSED(id_src))
|
||||
{
|
||||
Object *object = (Object *)id_dst;
|
||||
|
||||
ListBase pidlist;
|
||||
BKE_ptcache_ids_from_object(&pidlist, object, NULL, 0);
|
||||
LISTBASE_FOREACH (PTCacheID *, pid, &pidlist) {
|
||||
LISTBASE_FOREACH (PointCache *, point_cache, pid->ptcaches) {
|
||||
point_cache->flag |= PTCACHE_FLAG_INFO_DIRTY;
|
||||
}
|
||||
}
|
||||
BLI_freelistN(&pidlist);
|
||||
}
|
||||
|
||||
IDTypeInfo IDType_ID_OB = {
|
||||
.id_code = ID_OB,
|
||||
.id_filter = FILTER_ID_OB,
|
||||
|
@ -1141,6 +1155,8 @@ IDTypeInfo IDType_ID_OB = {
|
|||
.blend_read_expand = object_blend_read_expand,
|
||||
|
||||
.blend_read_undo_preserve = NULL,
|
||||
|
||||
.lib_override_apply_post = object_lib_override_apply_post,
|
||||
};
|
||||
|
||||
void BKE_object_workob_clear(Object *workob)
|
||||
|
@ -1506,11 +1522,11 @@ bool BKE_object_copy_gpencil_modifier(struct Object *ob_dst, GpencilModifierData
|
|||
/**
|
||||
* Copy the whole stack of modifiers from one object into another.
|
||||
*
|
||||
* \warning **Does not** clear modifier stack and related data (particle systems, softbody,
|
||||
* \warning **Does not** clear modifier stack and related data (particle systems, soft-body,
|
||||
* etc.) in `ob_dst`, if needed calling code must do it.
|
||||
*
|
||||
* @param do_copy_all If true, even modifiers that should not suport copying (like Hook one) will
|
||||
* be duplicated.
|
||||
* \param do_copy_all: If true, even modifiers that should not support copying (like Hook one)
|
||||
* will be duplicated.
|
||||
*/
|
||||
bool BKE_object_modifier_stack_copy(Object *ob_dst,
|
||||
const Object *ob_src,
|
||||
|
@ -3527,9 +3543,6 @@ static void solve_parenting(
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \note scene is the active scene while actual_scene is the scene the object resides in.
|
||||
*/
|
||||
static void object_where_is_calc_ex(Depsgraph *depsgraph,
|
||||
Scene *scene,
|
||||
Object *ob,
|
||||
|
|
|
@ -158,6 +158,8 @@ IDTypeInfo IDType_ID_PAL = {
|
|||
.blend_read_expand = NULL,
|
||||
|
||||
.blend_read_undo_preserve = palette_undo_preserve,
|
||||
|
||||
.lib_override_apply_post = NULL,
|
||||
};
|
||||
|
||||
static void paint_curve_copy_data(Main *UNUSED(bmain),
|
||||
|
@ -221,6 +223,8 @@ IDTypeInfo IDType_ID_PC = {
|
|||
.blend_read_expand = NULL,
|
||||
|
||||
.blend_read_undo_preserve = NULL,
|
||||
|
||||
.lib_override_apply_post = NULL,
|
||||
};
|
||||
|
||||
const char PAINT_CURSOR_SCULPT[3] = {255, 100, 100};
|
||||
|
|
|
@ -511,6 +511,8 @@ IDTypeInfo IDType_ID_PA = {
|
|||
.blend_read_expand = particle_settings_blend_read_expand,
|
||||
|
||||
.blend_read_undo_preserve = NULL,
|
||||
|
||||
.lib_override_apply_post = NULL,
|
||||
};
|
||||
|
||||
unsigned int PSYS_FRAND_SEED_OFFSET[PSYS_FRAND_COUNT];
|
||||
|
|
|
@ -475,20 +475,24 @@ void psys_tasks_create(ParticleThreadContext *ctx,
|
|||
{
|
||||
ParticleTask *tasks;
|
||||
int numtasks = min_ii(BLI_system_thread_count() * 4, endpart - startpart);
|
||||
float particles_per_task = numtasks > 0 ? (float)(endpart - startpart) / (float)numtasks : 0;
|
||||
int particles_per_task = numtasks > 0 ? (endpart - startpart) / numtasks : 0;
|
||||
int remainder = numtasks > 0 ? (endpart - startpart) - particles_per_task * numtasks : 0;
|
||||
|
||||
tasks = MEM_callocN(sizeof(ParticleTask) * numtasks, "ParticleThread");
|
||||
*r_numtasks = numtasks;
|
||||
*r_tasks = tasks;
|
||||
|
||||
float pnext;
|
||||
float p = (float)startpart;
|
||||
for (int i = 0; i < numtasks; i++, p = pnext) {
|
||||
pnext = p + particles_per_task;
|
||||
|
||||
int p = startpart;
|
||||
for (int i = 0; i < numtasks; i++) {
|
||||
tasks[i].ctx = ctx;
|
||||
tasks[i].begin = (int)p;
|
||||
tasks[i].end = min_ii((int)pnext, endpart);
|
||||
tasks[i].begin = p;
|
||||
p = p + particles_per_task + (i < remainder ? 1 : 0);
|
||||
tasks[i].end = p;
|
||||
}
|
||||
|
||||
/* Verify that all particles are accounted for. */
|
||||
if (numtasks > 0) {
|
||||
BLI_assert(tasks[numtasks - 1].end == endpart);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -190,6 +190,8 @@ IDTypeInfo IDType_ID_PT = {
|
|||
/* blend_read_expand */ pointcloud_blend_read_expand,
|
||||
|
||||
/* blend_read_undo_preserve */ nullptr,
|
||||
|
||||
/* lib_override_apply_post */ nullptr,
|
||||
};
|
||||
|
||||
static void pointcloud_random(PointCloud *pointcloud)
|
||||
|
|
|
@ -1687,6 +1687,19 @@ static void scene_undo_preserve(BlendLibReader *reader, ID *id_new, ID *id_old)
|
|||
}
|
||||
}
|
||||
|
||||
static void scene_lib_override_apply_post(ID *id_dst, ID *UNUSED(id_src))
|
||||
{
|
||||
Scene *scene = (Scene *)id_dst;
|
||||
|
||||
if (scene->rigidbody_world != NULL) {
|
||||
PTCacheID pid;
|
||||
BKE_ptcache_id_from_rigidbody(&pid, NULL, scene->rigidbody_world);
|
||||
LISTBASE_FOREACH (PointCache *, point_cache, pid.ptcaches) {
|
||||
point_cache->flag |= PTCACHE_FLAG_INFO_DIRTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IDTypeInfo IDType_ID_SCE = {
|
||||
.id_code = ID_SCE,
|
||||
.id_filter = FILTER_ID_SCE,
|
||||
|
@ -1712,6 +1725,8 @@ IDTypeInfo IDType_ID_SCE = {
|
|||
.blend_read_expand = scene_blend_read_expand,
|
||||
|
||||
.blend_read_undo_preserve = scene_undo_preserve,
|
||||
|
||||
.lib_override_apply_post = scene_lib_override_apply_post,
|
||||
};
|
||||
|
||||
const char *RE_engine_id_BLENDER_EEVEE = "BLENDER_EEVEE";
|
||||
|
|
|
@ -315,6 +315,8 @@ IDTypeInfo IDType_ID_SCR = {
|
|||
.blend_read_expand = NULL,
|
||||
|
||||
.blend_read_undo_preserve = NULL,
|
||||
|
||||
.lib_override_apply_post = NULL,
|
||||
};
|
||||
|
||||
/* ************ Spacetype/regiontype handling ************** */
|
||||
|
|
|
@ -173,6 +173,8 @@ IDTypeInfo IDType_ID_SIM = {
|
|||
/* blend_read_expand */ simulation_blend_read_expand,
|
||||
|
||||
/* blend_read_undo_preserve */ nullptr,
|
||||
|
||||
/* lib_override_apply_post */ nullptr,
|
||||
};
|
||||
|
||||
void *BKE_simulation_add(Main *bmain, const char *name)
|
||||
|
|
|
@ -221,6 +221,8 @@ IDTypeInfo IDType_ID_SO = {
|
|||
.blend_read_expand = sound_blend_read_expand,
|
||||
|
||||
.blend_read_undo_preserve = NULL,
|
||||
|
||||
.lib_override_apply_post = NULL,
|
||||
};
|
||||
|
||||
#ifdef WITH_AUDASPACE
|
||||
|
|
|
@ -114,6 +114,8 @@ IDTypeInfo IDType_ID_SPK = {
|
|||
.blend_read_expand = speaker_blend_read_expand,
|
||||
|
||||
.blend_read_undo_preserve = NULL,
|
||||
|
||||
.lib_override_apply_post = NULL,
|
||||
};
|
||||
|
||||
void *BKE_speaker_add(Main *bmain, const char *name)
|
||||
|
|
|
@ -258,6 +258,8 @@ IDTypeInfo IDType_ID_TXT = {
|
|||
.blend_read_expand = NULL,
|
||||
|
||||
.blend_read_undo_preserve = NULL,
|
||||
|
||||
.lib_override_apply_post = NULL,
|
||||
};
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -226,6 +226,8 @@ IDTypeInfo IDType_ID_TE = {
|
|||
.blend_read_expand = texture_blend_read_expand,
|
||||
|
||||
.blend_read_undo_preserve = NULL,
|
||||
|
||||
.lib_override_apply_post = NULL,
|
||||
};
|
||||
|
||||
/* Utils for all IDs using those texture slots. */
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue