Merge branch 'master' into sculpt-dev

This commit is contained in:
Pablo Dobarro 2021-01-24 03:04:27 +01:00
commit 46582b3743
168 changed files with 2635 additions and 1403 deletions

View File

@ -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 */

View File

@ -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;
}
}

View File

@ -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());

View File

@ -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);

View File

@ -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;

View File

@ -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;
}

View File

@ -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 */

View File

@ -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;
}

View File

@ -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()

View File

@ -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;
}

View File

@ -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. */

View File

@ -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_)

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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;

View File

@ -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) {

View File

@ -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)

View File

@ -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);

View File

@ -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;
}
}
}

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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]]);
}
}

View File

@ -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);

View File

@ -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)

View File

@ -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,

View File

@ -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));

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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.";

View File

@ -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;

View File

@ -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);
};

View File

@ -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_;

View File

@ -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

View File

@ -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,

View File

@ -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')]}),

View File

@ -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()

View File

@ -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"

View File

@ -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 ****************

View File

@ -489,6 +489,7 @@ geometry_node_categories = [
NodeItem("GeometryNodeAttributeMix"),
NodeItem("GeometryNodeAttributeColorRamp"),
NodeItem("GeometryNodeAttributeVectorMath"),
NodeItem("GeometryNodeAttributeSampleTexture"),
]),
GeometryNodeCategory("GEO_COLOR", "Color", items=[
NodeItem("ShaderNodeValToRGB"),

View File

@ -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"

View File

@ -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>;

View File

@ -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

View 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;
};

View File

@ -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,

View File

@ -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. ********** */

View File

@ -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, its 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);

View File

@ -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
/** \} */

View File

@ -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 ************** */

View File

@ -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,
};
/** \} */

View File

@ -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

View File

@ -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;
}

View File

@ -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;

View File

@ -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. */

View File

@ -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,
};
/** \} */

View File

@ -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,
};
/** \} */

View File

@ -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],

View File

@ -176,6 +176,8 @@ IDTypeInfo IDType_ID_VF = {
.blend_read_expand = NULL,
.blend_read_undo_preserve = NULL,
.lib_override_apply_post = NULL,
};
/***************************** VFont *******************************/

View File

@ -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
* \{ */

View File

@ -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;
}
}
}

View File

@ -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)

View File

@ -338,6 +338,8 @@ IDTypeInfo IDType_ID_IM = {
.blend_read_expand = NULL,
.blend_read_undo_preserve = NULL,
.lib_override_apply_post = NULL,
};
/* prototypes */

View File

@ -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,
};
/* *************************************************** */

View File

@ -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 */

View File

@ -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)

View File

@ -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. */
}

View File

@ -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);
}
}
}

View File

@ -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;
}

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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] = {

View File

@ -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.
*

View File

@ -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 {

View File

@ -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)

View File

@ -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 */

View File

@ -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 {

View File

@ -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 *************************/

View File

@ -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)

View File

@ -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,

View File

@ -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};

View File

@ -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];

View File

@ -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);
}
}

View File

@ -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)

View File

@ -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";

View File

@ -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 ************** */

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -258,6 +258,8 @@ IDTypeInfo IDType_ID_TXT = {
.blend_read_expand = NULL,
.blend_read_undo_preserve = NULL,
.lib_override_apply_post = NULL,
};
/** \} */

View File

@ -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