Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Changes.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
11.x.x (relative to 11.0.0a4)
------


- Cycles :
- Updated to version 5.1.0.
- Applied patch to support geometry motion blur with an even number of steps (from Blender upstream).
- SSE2NEON : Added version 1.9.1 when building on macOS.

11.0.0a4 (relative to 11.0.0a3)
--------
Expand Down
8 changes: 7 additions & 1 deletion Cycles/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

"downloads" : [

"https://github.com/blender/cycles/archive/refs/tags/v5.0.0.tar.gz",
"https://github.com/blender/cycles/archive/refs/tags/v5.1.0.tar.gz",

],

Expand All @@ -12,6 +12,12 @@

"dependencies" : [ "Boost", "OpenJPEG", "OpenImageIO", "TBB", "Alembic", "Embree", "OpenColorIO", "OpenVDB", "OpenShadingLanguage", "OpenSubdiv", "OpenPGL", "LibWebP", "Zstandard" ],

"platform:macos" : {

"extraDependencies" : [ "SSE2NEON" ],

},

"environment" : {

# Needed because the build process runs oslc.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
From 677bae0b9376e7963d1c37bbf92b0db14ecfc0d8 Mon Sep 17 00:00:00 2001
From: Brecht Van Lommel <brecht@blender.org>
Date: Wed, 1 Apr 2026 19:55:32 +0200
Subject: [PATCH] Add nodetype::get_type_names() for iterating all node
types

Node types are registered lazily to ensure base types are registered
before derived types, which is tricky to ensure with static
initialization. This meant there was no more global list of types.

Preserve that behavior, and instead gather init functions on static
initialization.

Ref #155818

Pull Request: https://projects.blender.org/blender/blender/pulls/156326
---
intern/cycles/graph/node_type.cpp | 68 ++++++++++++++++++++++++++--
intern/cycles/graph/node_type.h | 7 +--
intern/cycles/scene/shader_nodes.cpp | 5 ++
intern/cycles/scene/shader_nodes.h | 1 +
4 files changed, 73 insertions(+), 8 deletions(-)

diff --git a/src/graph/node_type.cpp b/src/graph/node_type.cpp
index 16553582d2a..1cf5c5d31e1 100644
--- a/src/graph/node_type.cpp
+++ b/src/graph/node_type.cpp
@@ -205,22 +205,65 @@ const SocketType *NodeType::find_output(ustring name) const
return nullptr;
}

-/* Node Type Registry */
+/* Node Type Registry
+ *
+ * We want to be able to find and enumerate types without the need for a centralized
+ * function for all node types. Due to static initialization order issues and guarded
+ * allocators, there are some subtle implementation choices.
+ *
+ * Only the init functions are gathered on static initialization, as registering the
+ * node type itself could otherwise happen in the wrong order for base and derived
+ * types, and Blender's guarded allocator may not have been initialized yet.
+ *
+ * The initialization functions are stored in std::vector without guarded allocation
+ * as that may not been properly initialized yet. */

-thread_mutex NodeType::types_mutex_;
+static thread_mutex &types_mutex()
+{
+ static thread_mutex types_mutex_;
+ return types_mutex_;
+}

-unordered_map<ustring, NodeType> &NodeType::types()
+static unordered_map<ustring, NodeType> &types()
{
static unordered_map<ustring, NodeType> _types;
return _types;
}

+static thread_mutex &types_on_init_mutex()
+{
+ static thread_mutex types_on_init_mutex_;
+ return types_on_init_mutex_;
+}
+
+static std::vector<const NodeType *(*)()> &types_on_init()
+{
+ static std::vector<const NodeType *(*)()> _types_on_init;
+ return _types_on_init;
+}
+
+static void ensure_types_initialized()
+{
+ thread_scoped_lock lock(types_on_init_mutex());
+ for (const auto &init_func : types_on_init()) {
+ init_func();
+ }
+ types_on_init().clear();
+}
+
+bool NodeType::register_on_init(const NodeType *(*init_func)())
+{
+ thread_scoped_lock lock(types_on_init_mutex());
+ types_on_init().push_back(init_func);
+ return true;
+}
+
NodeType *NodeType::add(const char *name_, CreateFunc create_, Type type_, const NodeType *base_)
{
const ustring name(name_);

/* Types can be lazily registered from multiple threads. */
- thread_scoped_lock lock(types_mutex_);
+ thread_scoped_lock lock(types_mutex());

if (types().find(name) != types().end()) {
LOG_ERROR << "Node type " << name_ << " registered twice";
@@ -238,9 +281,24 @@ NodeType *NodeType::add(const char *name_, CreateFunc create_, Type type_, const

const NodeType *NodeType::find(ustring name)
{
- thread_scoped_lock lock(types_mutex_);
+ ensure_types_initialized();
+
+ thread_scoped_lock lock(types_mutex());
const unordered_map<ustring, NodeType>::iterator it = types().find(name);
return (it == types().end()) ? nullptr : &it->second;
}

+vector<ustring> NodeType::type_names()
+{
+ ensure_types_initialized();
+
+ thread_scoped_lock lock(types_mutex());
+ vector<ustring> names;
+ for (const auto &pair : types()) {
+ names.push_back(pair.first);
+ }
+
+ return names;
+}
+
CCL_NAMESPACE_END
diff --git a/src/graph/node_type.h b/src/graph/node_type.h
index 572a3ab6d88..69515033b3d 100644
--- a/src/graph/node_type.h
+++ b/src/graph/node_type.h
@@ -134,10 +134,9 @@ struct NodeType {
Type type = NONE,
const NodeType *base = nullptr);
static const NodeType *find(ustring name);
+ static vector<ustring> type_names();

- private:
- static unordered_map<ustring, NodeType> &types();
- static thread_mutex types_mutex_;
+ static bool register_on_init(const NodeType *(*init_func)());
};

/* Node Definition Macros
@@ -155,6 +154,8 @@ struct NodeType {
#define NODE_DEFINE(structname) \
const NodeType *structname::node_type_ = nullptr; \
thread_mutex structname::node_type_mutex_; \
+ static bool structname##_register_on_init = NodeType::register_on_init( \
+ structname::get_node_type); \
unique_ptr<Node> structname::create(const NodeType *) \
{ \
return make_unique<structname>(); \
diff --git a/src/scene/shader_nodes.cpp b/src/scene/shader_nodes.cpp
index f6935675f5e..9a5fb808a6c 100644
--- a/src/scene/shader_nodes.cpp
+++ b/src/scene/shader_nodes.cpp
@@ -2070,6 +2070,11 @@ const NodeType *(&ConvertNode::get_node_types())[ConvertNode::MAX_TYPE][ConvertN
return node_types;
}

+bool ConvertNode::register_on_init = NodeType::register_on_init([] {
+ ConvertNode::get_node_types();
+ return static_cast<const NodeType *>(nullptr);
+});
+
unique_ptr<Node> ConvertNode::create(const NodeType *type)
{
return make_unique<ConvertNode>(type->inputs[0].type, type->outputs[0].type);
diff --git a/src/scene/shader_nodes.h b/src/scene/shader_nodes.h
index c7a6fbd4837..37300fbf033 100644
--- a/src/scene/shader_nodes.h
+++ b/src/scene/shader_nodes.h
@@ -468,6 +468,7 @@ class ConvertNode : public ShaderNode {
static const int MAX_TYPE = 13;
static unique_ptr<Node> create(const NodeType *type);
static const NodeType *(&get_node_types())[MAX_TYPE][MAX_TYPE];
+ static bool register_on_init;
};

class BsdfBaseNode : public ShaderNode {
--
2.47.1.windows.2

Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
From 500936c42f6421a47ae61f102557da9f33cbb272 Mon Sep 17 00:00:00 2001
From: Brecht Van Lommel <brecht@blender.org>
Date: Wed, 8 Apr 2026 15:33:16 +0200
Subject: [PATCH] Support geometry motion blur with an even number of
steps

Some of the math assume and uneven number of steps with one center step,
particularly for BVH2 while OptiX and Embree mostly worked. Tweak the
formulas so any number of steps works, even though we still have some
assumption of a "center" step used for things like adaptive subdivision.
---
intern/cycles/kernel/geom/motion_curve.h | 14 ++++++++------
intern/cycles/kernel/geom/motion_point.h | 7 ++++---
intern/cycles/kernel/geom/motion_triangle.h | 14 ++++++++------
intern/cycles/scene/object.cpp | 2 +-
4 files changed, 21 insertions(+), 16 deletions(-)

diff --git a/src/kernel/geom/motion_curve.h b/src/kernel/geom/motion_curve.h
index f6c0f2427c4..9236bd5ff19 100644
--- a/src/kernel/geom/motion_curve.h
+++ b/src/kernel/geom/motion_curve.h
@@ -30,14 +30,15 @@ ccl_device_inline void motion_curve_keys_for_step_linear(KernelGlobals kg,
const int k1,
float4 keys[2])
{
- if (step == numsteps) {
+ const int center_step = (numsteps - 1) / 2;
+ if (step == center_step) {
/* center step: regular key location */
keys[0] = kernel_data_fetch(curve_keys, k0);
keys[1] = kernel_data_fetch(curve_keys, k1);
}
else {
/* center step is not stored in this array */
- if (step > numsteps) {
+ if (step > center_step) {
step--;
}

@@ -61,7 +62,7 @@ ccl_device_inline void motion_curve_keys_linear(KernelGlobals kg,
const int numverts = kernel_data_fetch(objects, object).numverts;

/* figure out which steps we need to fetch and their interpolation factor */
- const int maxstep = numsteps * 2;
+ const int maxstep = numsteps - 1;
const int step = min((int)(time * maxstep), maxstep - 1);
const float t = time * maxstep - step;

@@ -91,7 +92,8 @@ ccl_device_inline void motion_curve_keys_for_step(KernelGlobals kg,
const int k3,
float4 keys[4])
{
- if (step == numsteps) {
+ const int center_step = (numsteps - 1) / 2;
+ if (step == center_step) {
/* center step: regular key location */
keys[0] = kernel_data_fetch(curve_keys, k0);
keys[1] = kernel_data_fetch(curve_keys, k1);
@@ -100,7 +102,7 @@ ccl_device_inline void motion_curve_keys_for_step(KernelGlobals kg,
}
else {
/* center step is not stored in this array */
- if (step > numsteps) {
+ if (step > center_step) {
step--;
}

@@ -128,7 +130,7 @@ ccl_device_inline void motion_curve_keys(KernelGlobals kg,
const int numverts = kernel_data_fetch(objects, object).numverts;

/* figure out which steps we need to fetch and their interpolation factor */
- const int maxstep = numsteps * 2;
+ const int maxstep = numsteps - 1;
const int step = min((int)(time * maxstep), maxstep - 1);
const float t = time * maxstep - step;

diff --git a/src/kernel/geom/motion_point.h b/src/kernel/geom/motion_point.h
index ccde301c200..4e2ad0ad93f 100644
--- a/src/kernel/geom/motion_point.h
+++ b/src/kernel/geom/motion_point.h
@@ -24,12 +24,13 @@ CCL_NAMESPACE_BEGIN
ccl_device_inline float4 motion_point_for_step(
KernelGlobals kg, int offset, const int numverts, const int numsteps, int step, const int prim)
{
- if (step == numsteps) {
+ const int center_step = (numsteps - 1) / 2;
+ if (step == center_step) {
/* center step: regular key location */
return kernel_data_fetch(points, prim);
}
/* center step is not stored in this array */
- if (step > numsteps) {
+ if (step > center_step) {
step--;
}

@@ -49,7 +50,7 @@ ccl_device_inline float4 motion_point(KernelGlobals kg,
const int numverts = kernel_data_fetch(objects, object).numverts;

/* figure out which steps we need to fetch and their interpolation factor */
- const int maxstep = numsteps * 2;
+ const int maxstep = numsteps - 1;
const int step = min((int)(time * maxstep), maxstep - 1);
const float t = time * maxstep - step;

diff --git a/src/kernel/geom/motion_triangle.h b/src/kernel/geom/motion_triangle.h
index dff17f5d38a..8159a840314 100644
--- a/src/kernel/geom/motion_triangle.h
+++ b/src/kernel/geom/motion_triangle.h
@@ -32,15 +32,16 @@ ccl_device_inline void motion_triangle_verts_for_step(KernelGlobals kg,
int step,
float3 verts[3])
{
- if (step == numsteps) {
+ const int center_step = (numsteps - 1) / 2;
+ if (step == center_step) {
/* center step: regular vertex location */
verts[0] = kernel_data_fetch(tri_verts, tri_vindex.x);
verts[1] = kernel_data_fetch(tri_verts, tri_vindex.y);
verts[2] = kernel_data_fetch(tri_verts, tri_vindex.z);
}
else {
- /* center step not store in this array */
- if (step > numsteps) {
+ /* center step not stored in this array */
+ if (step > center_step) {
step--;
}

@@ -62,14 +63,15 @@ ccl_device_inline void motion_triangle_normals_for_step(KernelGlobals kg,
int step,
float3 normals[3])
{
- const bool is_center_step = step == numsteps;
+ const int center_step = (numsteps - 1) / 2;
+ const bool is_center_step = step == center_step;
if (is_center_step) {
/* Center step in the regular attribute. */
offset = kernel_data_fetch(objects, object).normal_attr_offset;
}
else {
/* Other steps in the motion attribute, compensate for missing center step. */
- if (step > numsteps) {
+ if (step > center_step) {
step--;
}
}
@@ -111,7 +113,7 @@ ccl_device_inline void motion_triangle_compute_info(KernelGlobals kg,
*numsteps = kernel_data_fetch(objects, object).num_geom_steps;

/* Figure out which steps we need to fetch and their interpolation factor. */
- const int maxstep = *numsteps * 2;
+ const int maxstep = *numsteps - 1;
*step = min((int)(time * maxstep), maxstep - 1);
*t = time * maxstep - *step;

diff --git a/src/scene/object.cpp b/src/scene/object.cpp
index f7034dc0167..94ccdb14523 100644
--- a/src/scene/object.cpp
+++ b/src/scene/object.cpp
@@ -645,7 +645,7 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
kobject.dupli_generated[2] = ob->dupli_generated[2];
kobject.dupli_uv[0] = ob->dupli_uv[0];
kobject.dupli_uv[1] = ob->dupli_uv[1];
- kobject.num_geom_steps = (geom->get_motion_steps() - 1) / 2;
+ kobject.num_geom_steps = geom->get_motion_steps();
kobject.num_tfm_steps = ob->motion.size();
kobject.numverts = object_num_motion_verts(geom);
kobject.numprims = (geom->is_mesh() || geom->is_volume()) ?
--
2.47.1.windows.2

Loading
Loading