Refactor: Cycles: Replace new/delete with unique_ptr also for nodes

Using new unique_ptr_vector utility class.

Pull Request: https://projects.blender.org/blender/blender/pulls/132361
This commit is contained in:
Brecht Van Lommel
2024-12-30 02:20:36 +01:00
parent 9971648783
commit 988c1798ac
28 changed files with 517 additions and 465 deletions

View File

@@ -357,8 +357,7 @@ static void xml_read_shader_graph(XMLReadState &state, Shader *shader, const xml
continue;
}
snode = (ShaderNode *)node_type->create(node_type);
snode->set_owner(graph.get());
snode = graph->create_node(node_type);
}
xml_read_node(graph_reader, snode, node);
@@ -373,11 +372,6 @@ static void xml_read_shader_graph(XMLReadState &state, Shader *shader, const xml
const ustring filename(path_join(state.base, env->get_filename().string()));
env->set_filename(filename);
}
if (snode) {
/* add to graph */
graph->add(snode);
}
}
shader->set_graph(std::move(graph));
@@ -386,9 +380,8 @@ static void xml_read_shader_graph(XMLReadState &state, Shader *shader, const xml
static void xml_read_shader(XMLReadState &state, const xml_node node)
{
Shader *shader = new Shader();
Shader *shader = state.scene->create_node<Shader>();
xml_read_shader_graph(state, shader, node);
state.scene->shaders.push_back(shader);
}
/* Background */
@@ -415,14 +408,12 @@ static Mesh *xml_add_mesh(Scene *scene, const Transform &tfm, Object *object)
}
/* Create mesh */
Mesh *mesh = new Mesh();
scene->geometry.push_back(mesh);
Mesh *mesh = scene->create_node<Mesh>();
/* Create object. */
object = new Object();
object = scene->create_node<Object>();
object->set_geometry(mesh);
object->set_tfm(tfm);
scene->objects.push_back(object);
return mesh;
}
@@ -649,12 +640,10 @@ static void xml_read_mesh(const XMLReadState &state, const xml_node node)
static void xml_read_light(XMLReadState &state, const xml_node node)
{
Light *light = new Light();
Light *light = state.scene->create_node<Light>();
light->set_shader(state.shader);
xml_read_node(state, light, node);
state.scene->lights.push_back(light);
}
/* Transform */
@@ -748,17 +737,14 @@ static void xml_read_object(XMLReadState &state, const xml_node node)
Scene *scene = state.scene;
/* create mesh */
Mesh *mesh = new Mesh();
scene->geometry.push_back(mesh);
Mesh *mesh = scene->create_node<Mesh>();
/* create object */
Object *object = new Object();
Object *object = scene->create_node<Object>();
object->set_geometry(mesh);
object->set_tfm(state.tfm);
xml_read_node(state, object, node);
scene->objects.push_back(object);
}
/* Scene */

View File

@@ -1124,7 +1124,6 @@ static ShaderNode *add_node(Scene *scene,
if (node) {
node->name = b_node.name();
graph->add(node);
}
return node;
@@ -1277,8 +1276,6 @@ static void add_nodes(Scene *scene,
* input socket, so this needs to be a multimap. */
input_map.emplace(b_link.from_socket().ptr.data, proxy->inputs[0]);
output_map[b_link.to_socket().ptr.data] = proxy->outputs[0];
graph->add(proxy);
}
}
else if (b_node.is_a(&RNA_ShaderNodeGroup) || b_node.is_a(&RNA_NodeCustomGroup) ||
@@ -1310,7 +1307,6 @@ static void add_nodes(Scene *scene,
}
ConvertNode *proxy = graph->create_node<ConvertNode>(input_type, input_type, true);
graph->add(proxy);
/* register the proxy node for internal binding */
group_proxy_input_map[b_input.identifier()] = proxy;
@@ -1326,7 +1322,6 @@ static void add_nodes(Scene *scene,
}
ConvertNode *proxy = graph->create_node<ConvertNode>(output_type, output_type, true);
graph->add(proxy);
/* register the proxy node for internal binding */
group_proxy_output_map[b_output.identifier()] = proxy;
@@ -1590,7 +1585,6 @@ void BlenderSync::sync_materials(BL::Depsgraph &b_depsgraph, bool update_all)
else {
DiffuseBsdfNode *diffuse = graph->create_node<DiffuseBsdfNode>();
diffuse->set_color(get_float3(b_mat.diffuse_color()));
graph->add(diffuse);
ShaderNode *out = graph->output();
graph->connect(diffuse->output("BSDF"), out->input("Surface"));
@@ -1681,7 +1675,6 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d,
else if (new_viewport_parameters.use_scene_world && b_world) {
BackgroundNode *background = graph->create_node<BackgroundNode>();
background->set_color(get_float3(b_world.color()));
graph->add(background);
ShaderNode *out = graph->output();
graph->connect(background->output("Background"), out->input("Surface"));
@@ -1696,14 +1689,10 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d,
}
BackgroundNode *background = graph->create_node<BackgroundNode>();
graph->add(background);
LightPathNode *light_path = graph->create_node<LightPathNode>();
graph->add(light_path);
MixNode *mix_scene_with_background = graph->create_node<MixNode>();
mix_scene_with_background->set_color2(world_color);
graph->add(mix_scene_with_background);
EnvironmentTextureNode *texture_environment = graph->create_node<EnvironmentTextureNode>();
texture_environment->set_tex_mapping_type(TextureMapping::VECTOR);
@@ -1711,7 +1700,6 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d,
rotation_z[2] = new_viewport_parameters.studiolight_rotate_z;
texture_environment->set_tex_mapping_rotation(rotation_z);
texture_environment->set_filename(new_viewport_parameters.studiolight_path);
graph->add(texture_environment);
MixNode *mix_intensity = graph->create_node<MixNode>();
mix_intensity->set_mix_type(NODE_MIX_MUL);
@@ -1719,16 +1707,13 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d,
mix_intensity->set_color2(make_float3(new_viewport_parameters.studiolight_intensity,
new_viewport_parameters.studiolight_intensity,
new_viewport_parameters.studiolight_intensity));
graph->add(mix_intensity);
TextureCoordinateNode *texture_coordinate = graph->create_node<TextureCoordinateNode>();
graph->add(texture_coordinate);
MixNode *mix_background_with_environment = graph->create_node<MixNode>();
mix_background_with_environment->set_fac(
new_viewport_parameters.studiolight_background_alpha);
mix_background_with_environment->set_color1(world_color);
graph->add(mix_background_with_environment);
ShaderNode *out = graph->output();
@@ -1844,7 +1829,6 @@ void BlenderSync::sync_lights(BL::Depsgraph &b_depsgraph, bool update_all)
EmissionNode *emission = graph->create_node<EmissionNode>();
emission->set_color(one_float3());
emission->set_strength(1.0f);
graph->add(emission);
ShaderNode *out = graph->output();
graph->connect(emission->output("Emission"), out->input("Surface"));

View File

@@ -722,8 +722,8 @@ static Pass *pass_add(Scene *scene,
void BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, BL::ViewLayer &b_view_layer)
{
/* Delete all existing passes. */
const set<Pass *> clear_passes(scene->passes.begin(), scene->passes.end());
scene->delete_nodes(clear_passes);
const vector<Pass *> &scene_passes = scene->passes;
scene->delete_nodes(set<Pass *>(scene_passes.begin(), scene_passes.end()));
/* Always add combined pass. */
pass_add(scene, PASS_COMBINED, "Combined");

View File

@@ -8,6 +8,7 @@
#include "util/array.h" // IWYU pragma: keep
#include "util/map.h"
#include "util/param.h"
#include "util/unique_ptr.h"
#include "util/vector.h"
CCL_NAMESPACE_BEGIN
@@ -116,7 +117,7 @@ struct NodeType {
const SocketType *find_input(ustring name) const;
const SocketType *find_output(ustring name) const;
using CreateFunc = Node *(*)(const NodeType *);
using CreateFunc = unique_ptr<Node> (*)(const NodeType *);
ustring name;
Type type;
@@ -141,14 +142,14 @@ struct NodeType {
#define NODE_DECLARE \
static const NodeType *get_node_type(); \
template<typename T> static const NodeType *register_type(); \
static Node *create(const NodeType *type); \
static unique_ptr<Node> create(const NodeType *type); \
static const NodeType *node_type;
#define NODE_DEFINE(structname) \
const NodeType *structname::node_type = structname::register_type<structname>(); \
Node *structname::create(const NodeType *) \
unique_ptr<Node> structname::create(const NodeType *) \
{ \
return new structname(); \
return make_unique<structname>(); \
} \
const NodeType *structname::get_node_type() \
{ \

View File

@@ -197,7 +197,6 @@ void HdCyclesLight::PopulateShaderGraph(HdSceneDelegate *sceneDelegate)
BackgroundNode *bgNode = graph->create_node<BackgroundNode>();
// Bake strength into shader graph, since only the shader is used for background lights
bgNode->set_color(_light->get_strength());
graph->add(bgNode);
graph->connect(bgNode->output("Background"), graph->output()->input("Surface"));
@@ -212,7 +211,6 @@ void HdCyclesLight::PopulateShaderGraph(HdSceneDelegate *sceneDelegate)
if (strVal == "Constant" || strVal == "Linear" || strVal == "Quadratic") {
LightFalloffNode *lfoNode = graph->create_node<LightFalloffNode>();
lfoNode->set_strength(1.f);
graph->add(lfoNode);
graph->connect(lfoNode->output(strVal.c_str()), graph->output()->input("Surface"));
outputNode = lfoNode;
}
@@ -223,7 +221,6 @@ void HdCyclesLight::PopulateShaderGraph(HdSceneDelegate *sceneDelegate)
EmissionNode *emissionNode = graph->create_node<EmissionNode>();
emissionNode->set_color(one_float3());
emissionNode->set_strength(1.0f);
graph->add(emissionNode);
graph->connect(emissionNode->output("Emission"), graph->output()->input("Surface"));
@@ -244,13 +241,11 @@ void HdCyclesLight::PopulateShaderGraph(HdSceneDelegate *sceneDelegate)
if (value.IsHolding<float>()) {
BlackbodyNode *blackbodyNode = graph->create_node<BlackbodyNode>();
blackbodyNode->set_temperature(value.UncheckedGet<float>());
graph->add(blackbodyNode);
if (_lightType == HdPrimTypeTokens->domeLight) {
VectorMathNode *mathNode = graph->create_node<VectorMathNode>();
mathNode->set_math_type(NODE_VECTOR_MATH_MULTIPLY);
mathNode->set_vector2(_light->get_strength());
graph->add(mathNode);
graph->connect(blackbodyNode->output("Color"), mathNode->input("Vector1"));
graph->connect(mathNode->output("Vector"), outputNode->input("Color"));
@@ -273,7 +268,6 @@ void HdCyclesLight::PopulateShaderGraph(HdSceneDelegate *sceneDelegate)
TextureCoordinateNode *coordNode = graph->create_node<TextureCoordinateNode>();
coordNode->set_ob_tfm(_light->get_tfm());
coordNode->set_use_transform(true);
graph->add(coordNode);
IESLightNode *iesNode = graph->create_node<IESLightNode>();
iesNode->set_filename(ustring(filename));
@@ -299,11 +293,9 @@ void HdCyclesLight::PopulateShaderGraph(HdSceneDelegate *sceneDelegate)
TextureCoordinateNode *coordNode = graph->create_node<TextureCoordinateNode>();
coordNode->set_ob_tfm(tfm);
coordNode->set_use_transform(true);
graph->add(coordNode);
textureNode = graph->create_node<EnvironmentTextureNode>();
static_cast<EnvironmentTextureNode *>(textureNode)->set_filename(ustring(filename));
graph->add(textureNode);
graph->connect(coordNode->output("Object"), textureNode->input("Vector"));
@@ -311,11 +303,9 @@ void HdCyclesLight::PopulateShaderGraph(HdSceneDelegate *sceneDelegate)
}
else {
GeometryNode *coordNode = graph->create_node<GeometryNode>();
graph->add(coordNode);
textureNode = graph->create_node<ImageTextureNode>();
static_cast<ImageTextureNode *>(textureNode)->set_filename(ustring(filename));
graph->add(textureNode);
graph->connect(coordNode->output("Parametric"), textureNode->input("Vector"));
}
@@ -323,7 +313,6 @@ void HdCyclesLight::PopulateShaderGraph(HdSceneDelegate *sceneDelegate)
if (hasColorTemperature) {
VectorMathNode *mathNode = graph->create_node<VectorMathNode>();
mathNode->set_math_type(NODE_VECTOR_MATH_MULTIPLY);
graph->add(mathNode);
graph->connect(textureNode->output("Color"), mathNode->input("Vector1"));
ShaderInput *const outputNodeInput = outputNode->input("Color");
@@ -335,7 +324,6 @@ void HdCyclesLight::PopulateShaderGraph(HdSceneDelegate *sceneDelegate)
VectorMathNode *mathNode = graph->create_node<VectorMathNode>();
mathNode->set_math_type(NODE_VECTOR_MATH_MULTIPLY);
mathNode->set_vector2(_light->get_strength());
graph->add(mathNode);
graph->connect(textureNode->output("Color"), mathNode->input("Vector1"));
graph->connect(mathNode->output("Vector"), outputNode->input("Color"));

View File

@@ -447,11 +447,7 @@ void HdCyclesMaterial::PopulateShaderGraph(const HdMaterialNetwork2 &networkMap)
// If it's a native Cycles' node-type, just do the lookup now.
if (const NodeType *nodeType = NodeType::find(cyclesType)) {
nodeDesc.node = static_cast<ShaderNode *>(nodeType->create(nodeType));
nodeDesc.node->set_owner(graph.get());
graph->add(nodeDesc.node);
nodeDesc.node = graph->create_node(nodeType);
_nodes.emplace(nodePath, nodeDesc);
}
else {
@@ -547,11 +543,9 @@ void HdCyclesMaterial::PopulateShaderGraph(const HdMaterialNetwork2 &networkMap)
OutputAOVNode *aovNode = graph->create_node<OutputAOVNode>();
aovNode->set_name(instanceId);
graph->add(aovNode);
AttributeNode *instanceIdNode = graph->create_node<AttributeNode>();
instanceIdNode->set_attribute(instanceId);
graph->add(instanceIdNode);
graph->connect(instanceIdNode->output("Fac"), aovNode->input("Value"));
}

View File

@@ -51,7 +51,6 @@ HdCyclesSession::HdCyclesSession(const SessionParams &params)
BackgroundNode *bgNode = graph->create_node<BackgroundNode>();
bgNode->set_color(one_float3());
graph->add(bgNode);
graph->connect(bgNode->output("Background"), graph->output()->input("Surface"));
@@ -64,10 +63,8 @@ HdCyclesSession::HdCyclesSession(const SessionParams &params)
unique_ptr<ShaderGraph> graph = make_unique<ShaderGraph>();
ObjectInfoNode *objectNode = graph->create_node<ObjectInfoNode>();
graph->add(objectNode);
DiffuseBsdfNode *diffuseNode = graph->create_node<DiffuseBsdfNode>();
graph->add(diffuseNode);
graph->connect(objectNode->output("Color"), diffuseNode->input("Color"));
graph->connect(diffuseNode->output("BSDF"), graph->output()->input("Surface"));
@@ -77,11 +74,9 @@ HdCyclesSession::HdCyclesSession(const SessionParams &params)
OutputAOVNode *aovNode = graph->create_node<OutputAOVNode>();
aovNode->set_name(instanceId);
graph->add(aovNode);
AttributeNode *instanceIdNode = graph->create_node<AttributeNode>();
instanceIdNode->set_attribute(instanceId);
graph->add(instanceIdNode);
graph->connect(instanceIdNode->output("Fac"), aovNode->input("Value"));
@@ -138,7 +133,8 @@ void HdCyclesSession::SyncAovBindings(const HdRenderPassAovBindingVector &aovBin
Scene *const scene = session->scene.get();
// Delete all existing passes
scene->delete_nodes(set<Pass *>(scene->passes.begin(), scene->passes.end()));
const vector<Pass *> &scene_passes = scene->passes;
scene->delete_nodes(set<Pass *>(scene_passes.begin(), scene_passes.end()));
// Update passes with requested AOV bindings
_aovBindings = aovBindings;

View File

@@ -16,6 +16,7 @@
#include "util/log.h"
#include "util/progress.h"
#include "util/set.h"
#include "util/transform.h"
#include "util/vector.h"
@@ -752,7 +753,7 @@ static void update_attributes(AttributeSet &attributes,
continue;
}
const ccl::array<char> &attr_data = result.get_data();
const array<char> &attr_data = result.get_data();
/* weak way of detecting if the topology has changed
* todo: reuse code from device_update patch */
@@ -790,8 +791,6 @@ NODE_DEFINE(AlembicProcedural)
SOCKET_FLOAT(default_radius, "Default Radius", 0.01f);
SOCKET_FLOAT(scale, "Scale", 1.0f);
SOCKET_NODE_ARRAY(objects, "Objects", AlembicObject::get_node_type());
SOCKET_BOOLEAN(use_prefetch, "Use Prefetch", true);
SOCKET_INT(prefetch_cache_size, "Prefetch Cache Size", 4096);
@@ -810,7 +809,7 @@ AlembicProcedural::~AlembicProcedural()
ccl::set<Object *> objects_set;
const ccl::set<AlembicObject *> abc_objects_set;
for (Node *node : objects) {
for (Node *node : nodes) {
AlembicObject *abc_object = static_cast<AlembicObject *>(node);
if (abc_object->get_object()) {
@@ -842,13 +841,14 @@ void AlembicProcedural::generate(Scene *scene, Progress &progress)
if (frame < start_frame || frame > end_frame) {
clear_modified();
objects_modified = false;
return;
}
bool need_shader_updates = false;
bool need_data_updates = false;
for (Node *object_node : objects) {
for (Node *object_node : nodes) {
AlembicObject *object = static_cast<AlembicObject *>(object_node);
if (object->is_modified()) {
@@ -876,7 +876,7 @@ void AlembicProcedural::generate(Scene *scene, Progress &progress)
}
}
if (!is_modified() && !need_shader_updates && !need_data_updates) {
if (!(is_modified() || objects_modified) && !need_shader_updates && !need_data_updates) {
return;
}
@@ -901,11 +901,12 @@ void AlembicProcedural::generate(Scene *scene, Progress &progress)
filepath.clear();
layers.clear();
clear_modified();
objects_modified = false;
return;
}
}
if (!objects_loaded || objects_is_modified()) {
if (!objects_loaded || objects_modified) {
load_objects(progress);
objects_loaded = true;
}
@@ -913,7 +914,7 @@ void AlembicProcedural::generate(Scene *scene, Progress &progress)
const chrono_t frame_time = (chrono_t)((frame - frame_offset) / frame_rate);
/* Clear the subdivision caches as the data is stored differently. */
for (Node *node : objects) {
for (Node *node : nodes) {
AlembicObject *object = static_cast<AlembicObject *>(node);
if (object->schema_type != AlembicObject::SUBD) {
@@ -927,7 +928,7 @@ void AlembicProcedural::generate(Scene *scene, Progress &progress)
if (use_prefetch_is_modified()) {
if (!use_prefetch) {
for (Node *node : objects) {
for (Node *node : nodes) {
AlembicObject *object = static_cast<AlembicObject *>(node);
object->clear_cache();
}
@@ -938,7 +939,7 @@ void AlembicProcedural::generate(Scene *scene, Progress &progress)
/* Check whether the current memory usage fits in the new requested size,
* abort the render if it is any higher. */
size_t memory_used = 0ul;
for (Node *node : objects) {
for (Node *node : nodes) {
AlembicObject *object = static_cast<AlembicObject *>(node);
memory_used += object->get_cached_data().memory_used();
}
@@ -951,7 +952,7 @@ void AlembicProcedural::generate(Scene *scene, Progress &progress)
build_caches(progress);
for (Node *node : objects) {
for (Node *node : nodes) {
AlembicObject *object = static_cast<AlembicObject *>(node);
if (progress.get_cancel()) {
@@ -983,12 +984,7 @@ void AlembicProcedural::generate(Scene *scene, Progress &progress)
}
clear_modified();
}
void AlembicProcedural::add_object(AlembicObject *object)
{
objects.push_back_slow(object);
tag_objects_modified();
objects_modified = false;
}
void AlembicProcedural::tag_update(Scene *scene)
@@ -998,7 +994,7 @@ void AlembicProcedural::tag_update(Scene *scene)
AlembicObject *AlembicProcedural::get_or_create_object(const ustring &path)
{
for (Node *node : objects) {
for (Node *node : nodes) {
AlembicObject *object = static_cast<AlembicObject *>(node);
if (object->get_path() == path) {
@@ -1008,8 +1004,7 @@ AlembicObject *AlembicProcedural::get_or_create_object(const ustring &path)
AlembicObject *object = create_node<AlembicObject>();
object->set_path(path);
add_object(object);
objects_modified = true;
return object;
}
@@ -1018,7 +1013,7 @@ void AlembicProcedural::load_objects(Progress &progress)
{
unordered_map<string, AlembicObject *> object_map;
for (Node *node : objects) {
for (Node *node : nodes) {
AlembicObject *object = static_cast<AlembicObject *>(node);
/* only consider newly added objects */
@@ -1071,7 +1066,7 @@ void AlembicProcedural::load_objects(Progress &progress)
}
/* Share geometries between instances. */
for (Node *node : objects) {
for (Node *node : nodes) {
AlembicObject *abc_object = static_cast<AlembicObject *>(node);
if (abc_object->instance_of) {
@@ -1498,7 +1493,7 @@ void AlembicProcedural::build_caches(Progress &progress)
{
size_t memory_used = 0;
for (Node *node : objects) {
for (Node *node : nodes) {
AlembicObject *object = static_cast<AlembicObject *>(node);
if (progress.get_cancel()) {

View File

@@ -461,8 +461,9 @@ class AlembicObject : public Node {
*/
class AlembicProcedural : public Procedural {
Alembic::AbcGeom::IArchive archive;
bool objects_loaded;
Scene *scene_;
bool objects_loaded = false;
bool objects_modified = false;
Scene *scene_ = nullptr;
public:
NODE_DECLARE
@@ -489,9 +490,6 @@ class AlembicProcedural : public Procedural {
/* The frame rate used for rendering in units of frames per second. */
NODE_SOCKET_API(float, frame_rate)
/* List of AlembicObjects to render. */
NODE_SOCKET_API_ARRAY(array<Node *>, objects)
/* Set the default radius to use for curves when the Alembic Curves Schemas do not have radius
* information. */
NODE_SOCKET_API(float, default_radius)
@@ -528,9 +526,6 @@ class AlembicProcedural : public Procedural {
AlembicObject *get_or_create_object(const ustring &path);
private:
/* Add an object to our list of objects, and tag the socket as modified. */
void add_object(AlembicObject *object);
/* Load the data for all the objects whose data has not yet been loaded. */
void load_objects(Progress &progress);

View File

@@ -14,8 +14,6 @@
#include "scene/stats.h"
#include "scene/tables.h"
#include "util/algorithm.h"
#include "util/math.h"
#include "util/math_cdf.h"
#include "util/time.h"
@@ -612,31 +610,29 @@ void Film::add_auto_pass(Scene *scene, PassType type, const char *name)
void Film::add_auto_pass(Scene *scene, PassType type, PassMode mode, const char *name)
{
Pass *pass = new Pass();
unique_ptr<Pass> pass = make_unique<Pass>();
pass->set_type(type);
pass->set_mode(mode);
pass->set_name(ustring((name) ? name : ""));
pass->is_auto_ = true;
pass->set_owner(scene);
scene->passes.push_back(pass);
scene->passes.push_back(std::move(pass));
}
void Film::remove_auto_passes(Scene *scene)
{
/* Remove all passes which were automatically created. */
vector<Pass *> new_passes;
unique_ptr_vector<Pass> new_passes;
for (Pass *pass : scene->passes) {
for (size_t i = 0; i < scene->passes.size(); i++) {
unique_ptr<Pass> pass = scene->passes.steal(i);
if (!pass->is_auto_) {
new_passes.push_back(pass);
}
else {
delete pass;
new_passes.push_back(std::move(pass));
}
}
scene->passes = new_passes;
scene->passes = std::move(new_passes);
}
static bool compare_pass_order(const Pass *a, const Pass *b)
@@ -662,9 +658,11 @@ static bool compare_pass_order(const Pass *a, const Pass *b)
void Film::finalize_passes(Scene *scene, const bool use_denoise)
{
/* Remove duplicate passes. */
vector<Pass *> new_passes;
unique_ptr_vector<Pass> new_passes;
for (size_t i = 0; i < scene->passes.size(); i++) {
unique_ptr<Pass> pass = scene->passes.steal(i);
for (Pass *pass : scene->passes) {
/* Disable denoising on passes if denoising is disabled, or if the
* pass does not support it. */
pass->set_mode((use_denoise && pass->get_info().support_denoise) ? pass->get_mode() :
@@ -696,19 +694,16 @@ void Film::finalize_passes(Scene *scene, const bool use_denoise)
}
if (!duplicate_found) {
new_passes.push_back(pass);
}
else {
delete pass;
new_passes.push_back(std::move(pass));
}
}
/* Order from by components and type, This is required to for AOVs and cryptomatte passes,
* which the kernel assumes to be in order. Note this must use stable sort so cryptomatte
* passes remain in the right order. */
stable_sort(new_passes.begin(), new_passes.end(), compare_pass_order);
new_passes.stable_sort(compare_pass_order);
scene->passes = new_passes;
scene->passes = std::move(new_passes);
}
uint Film::get_kernel_features(const Scene *scene) const

View File

@@ -5,12 +5,13 @@
#pragma once
#include "scene/pass.h"
#include "util/string.h"
#include "kernel/types.h"
#include "graph/node.h"
#include "util/string.h"
CCL_NAMESPACE_BEGIN
class Device;

View File

@@ -1123,7 +1123,7 @@ bool GeometryManager::need_update() const
void GeometryManager::collect_statistics(const Scene *scene, RenderStats *stats)
{
for (Geometry *geometry : scene->geometry) {
for (const Geometry *geometry : scene->geometry) {
stats->mesh.geometry.add_entry(
NamedSizeEntry(string(geometry->name.c_str()), geometry->get_total_size_in_bytes()));
}

View File

@@ -364,7 +364,7 @@ PassInfo Pass::get_info(const PassType type, const bool include_albedo, const bo
return pass_info;
}
bool Pass::contains(const vector<Pass *> &passes, PassType type)
bool Pass::contains(const unique_ptr_vector<Pass> &passes, PassType type)
{
for (const Pass *pass : passes) {
if (pass->get_type() != type) {
@@ -377,7 +377,7 @@ bool Pass::contains(const vector<Pass *> &passes, PassType type)
return false;
}
const Pass *Pass::find(const vector<Pass *> &passes, const string &name)
const Pass *Pass::find(const unique_ptr_vector<Pass> &passes, const string &name)
{
for (const Pass *pass : passes) {
if (pass->get_name() == name) {
@@ -388,7 +388,7 @@ const Pass *Pass::find(const vector<Pass *> &passes, const string &name)
return nullptr;
}
const Pass *Pass::find(const vector<Pass *> &passes,
const Pass *Pass::find(const unique_ptr_vector<Pass> &passes,
PassType type,
PassMode mode,
const ustring &lightgroup)
@@ -405,7 +405,7 @@ const Pass *Pass::find(const vector<Pass *> &passes,
return nullptr;
}
int Pass::get_offset(const vector<Pass *> &passes, const Pass *pass)
int Pass::get_offset(const unique_ptr_vector<Pass> &passes, const Pass *pass)
{
int pass_offset = 0;

View File

@@ -7,7 +7,7 @@
#include <iosfwd>
#include "util/string.h"
#include "util/vector.h"
#include "util/unique_ptr_vector.h"
#include "kernel/types.h"
@@ -78,17 +78,17 @@ class Pass : public Node {
const bool include_albedo = false,
const bool is_lightgroup = false);
static bool contains(const vector<Pass *> &passes, PassType type);
static bool contains(const unique_ptr_vector<Pass> &passes, PassType type);
/* Returns nullptr if there is no pass with the given name or type+mode. */
static const Pass *find(const vector<Pass *> &passes, const string &name);
static const Pass *find(const vector<Pass *> &passes,
static const Pass *find(const unique_ptr_vector<Pass> &passes, const string &name);
static const Pass *find(const unique_ptr_vector<Pass> &passes,
PassType type,
PassMode mode = PassMode::NOISY,
const ustring &lightgroup = ustring());
/* Returns PASS_UNUSED if there is no corresponding pass. */
static int get_offset(const vector<Pass *> &passes, const Pass *pass);
static int get_offset(const unique_ptr_vector<Pass> &passes, const Pass *pass);
friend class Film;
};

View File

@@ -6,6 +6,8 @@
#include "graph/node.h"
#include "util/unique_ptr_vector.h"
CCL_NAMESPACE_BEGIN
class Progress;
@@ -31,17 +33,22 @@ class Procedural : public Node, public NodeOwner {
/* Create a node and set this Procedural as the owner. */
template<typename T> T *create_node()
{
T *node = new T();
unique_ptr<T> node = make_unique<T>();
T *node_ptr = node.get();
node->set_owner(this);
return node;
nodes.push_back(std::move(node));
return node_ptr;
}
/* Delete a Node created and owned by this Procedural. */
template<typename T> void delete_node(T *node)
{
assert(node->get_owner() == this);
delete node;
nodes.erase(node);
}
protected:
unique_ptr_vector<Node> nodes;
};
class ProceduralManager {

View File

@@ -96,30 +96,11 @@ void Scene::free_memory(bool final)
* Similarly, we first delete all nodes and their associated device data, and
* then the managers and their associated device data.
*/
for (Procedural *p : procedurals) {
delete p;
}
for (Object *o : objects) {
delete o;
}
for (Geometry *g : geometry) {
delete g;
}
for (ParticleSystem *p : particle_systems) {
delete p;
}
for (Light *l : lights) {
delete l;
}
for (Pass *p : passes) {
delete p;
}
geometry.clear();
procedurals.clear();
objects.clear();
geometry.clear();
lights.clear();
particle_systems.clear();
procedurals.clear();
passes.clear();
if (device) {
@@ -130,19 +111,20 @@ void Scene::free_memory(bool final)
}
if (final) {
delete camera;
delete dicing_camera;
delete film;
delete background;
delete integrator;
cameras.clear();
integrators.clear();
films.clear();
backgrounds.clear();
camera = nullptr;
dicing_camera = nullptr;
integrator = nullptr;
film = nullptr;
background = nullptr;
}
/* Delete Shaders after every other nodes to ensure that we do not try to
* decrement the reference count on some dangling pointer. */
for (Shader *s : shaders) {
delete s;
}
shaders.clear();
/* Now that all nodes have been deleted, we can safely delete managers and
@@ -756,84 +738,93 @@ void Scene::tag_shadow_catcher_modified()
template<> Light *Scene::create_node<Light>()
{
Light *node = new Light();
unique_ptr<Light> node = make_unique<Light>();
Light *node_ptr = node.get();
node->set_owner(this);
lights.push_back(node);
lights.push_back(std::move(node));
light_manager->tag_update(this, LightManager::LIGHT_ADDED);
return node;
return node_ptr;
}
template<> Mesh *Scene::create_node<Mesh>()
{
Mesh *node = new Mesh();
unique_ptr<Mesh> node = make_unique<Mesh>();
Mesh *node_ptr = node.get();
node->set_owner(this);
geometry.push_back(node);
geometry.push_back(std::move(node));
geometry_manager->tag_update(this, GeometryManager::MESH_ADDED);
return node;
return node_ptr;
}
template<> Hair *Scene::create_node<Hair>()
{
Hair *node = new Hair();
unique_ptr<Hair> node = make_unique<Hair>();
Hair *node_ptr = node.get();
node->set_owner(this);
geometry.push_back(node);
geometry.push_back(std::move(node));
geometry_manager->tag_update(this, GeometryManager::HAIR_ADDED);
return node;
return node_ptr;
}
template<> Volume *Scene::create_node<Volume>()
{
Volume *node = new Volume();
unique_ptr<Volume> node = make_unique<Volume>();
Volume *node_ptr = node.get();
node->set_owner(this);
geometry.push_back(node);
geometry.push_back(std::move(node));
geometry_manager->tag_update(this, GeometryManager::MESH_ADDED);
return node;
return node_ptr;
}
template<> PointCloud *Scene::create_node<PointCloud>()
{
PointCloud *node = new PointCloud();
unique_ptr<PointCloud> node = make_unique<PointCloud>();
PointCloud *node_ptr = node.get();
node->set_owner(this);
geometry.push_back(node);
geometry.push_back(std::move(node));
geometry_manager->tag_update(this, GeometryManager::POINT_ADDED);
return node;
return node_ptr;
}
template<> Object *Scene::create_node<Object>()
{
Object *node = new Object();
unique_ptr<Object> node = make_unique<Object>();
Object *node_ptr = node.get();
node->set_owner(this);
objects.push_back(node);
objects.push_back(std::move(node));
object_manager->tag_update(this, ObjectManager::OBJECT_ADDED);
return node;
return node_ptr;
}
template<> ParticleSystem *Scene::create_node<ParticleSystem>()
{
ParticleSystem *node = new ParticleSystem();
unique_ptr<ParticleSystem> node = make_unique<ParticleSystem>();
ParticleSystem *node_ptr = node.get();
node->set_owner(this);
particle_systems.push_back(node);
particle_systems.push_back(std::move(node));
particle_system_manager->tag_update(this);
return node;
return node_ptr;
}
template<> Shader *Scene::create_node<Shader>()
{
Shader *node = new Shader();
unique_ptr<Shader> node = make_unique<Shader>();
Shader *node_ptr = node.get();
node->set_owner(this);
shaders.push_back(node);
shaders.push_back(std::move(node));
shader_manager->tag_update(this, ShaderManager::SHADER_ADDED);
return node;
return node_ptr;
}
template<> AlembicProcedural *Scene::create_node<AlembicProcedural>()
{
#ifdef WITH_ALEMBIC
AlembicProcedural *node = new AlembicProcedural();
unique_ptr<AlembicProcedural> node = make_unique<AlembicProcedural>();
AlembicProcedural *node_ptr = node.get();
node->set_owner(this);
procedurals.push_back(node);
procedurals.push_back(std::move(node));
procedural_manager->tag_update();
return node;
return node_ptr;
#else
return nullptr;
#endif
@@ -841,59 +832,89 @@ template<> AlembicProcedural *Scene::create_node<AlembicProcedural>()
template<> Pass *Scene::create_node<Pass>()
{
Pass *node = new Pass();
unique_ptr<Pass> node = make_unique<Pass>();
Pass *node_ptr = node.get();
node->set_owner(this);
passes.push_back(node);
passes.push_back(std::move(node));
film->tag_modified();
return node;
return node_ptr;
}
template<typename T> void delete_node_from_array(vector<T> &nodes, T node)
template<> Camera *Scene::create_node<Camera>()
{
for (size_t i = 0; i < nodes.size(); ++i) {
if (nodes[i] == node) {
std::swap(nodes[i], nodes[nodes.size() - 1]);
break;
}
}
nodes.resize(nodes.size() - 1);
delete node;
unique_ptr<Camera> node = make_unique<Camera>();
Camera *node_ptr = node.get();
node->set_owner(this);
cameras.push_back(std::move(node));
return node_ptr;
}
template<> void Scene::delete_node_impl(Light *node)
template<> Integrator *Scene::create_node<Integrator>()
{
delete_node_from_array(lights, node);
unique_ptr<Integrator> node = make_unique<Integrator>();
Integrator *node_ptr = node.get();
node->set_owner(this);
integrators.push_back(std::move(node));
return node_ptr;
}
template<> Background *Scene::create_node<Background>()
{
unique_ptr<Background> node = make_unique<Background>();
Background *node_ptr = node.get();
node->set_owner(this);
backgrounds.push_back(std::move(node));
return node_ptr;
}
template<> Film *Scene::create_node<Film>()
{
unique_ptr<Film> node = make_unique<Film>();
Film *node_ptr = node.get();
node->set_owner(this);
films.push_back(std::move(node));
return node_ptr;
}
template<> void Scene::delete_node(Light *node)
{
assert(node->get_owner() == this);
lights.erase_by_swap(node);
light_manager->tag_update(this, LightManager::LIGHT_REMOVED);
}
template<> void Scene::delete_node_impl(Mesh *node)
template<> void Scene::delete_node(Mesh *node)
{
delete_node_from_array(geometry, static_cast<Geometry *>(node));
assert(node->get_owner() == this);
geometry.erase_by_swap(node);
geometry_manager->tag_update(this, GeometryManager::MESH_REMOVED);
}
template<> void Scene::delete_node_impl(Hair *node)
template<> void Scene::delete_node(Hair *node)
{
delete_node_from_array(geometry, static_cast<Geometry *>(node));
assert(node->get_owner() == this);
geometry.erase_by_swap(node);
geometry_manager->tag_update(this, GeometryManager::HAIR_REMOVED);
}
template<> void Scene::delete_node_impl(Volume *node)
template<> void Scene::delete_node(Volume *node)
{
delete_node_from_array(geometry, static_cast<Geometry *>(node));
assert(node->get_owner() == this);
geometry.erase_by_swap(node);
geometry_manager->tag_update(this, GeometryManager::MESH_REMOVED);
}
template<> void Scene::delete_node_impl(PointCloud *node)
template<> void Scene::delete_node(PointCloud *node)
{
delete_node_from_array(geometry, static_cast<Geometry *>(node));
assert(node->get_owner() == this);
geometry.erase_by_swap(node);
geometry_manager->tag_update(this, GeometryManager::POINT_REMOVED);
}
template<> void Scene::delete_node_impl(Geometry *node)
template<> void Scene::delete_node(Geometry *node)
{
assert(node->get_owner() == this);
uint flag;
if (node->is_hair()) {
flag = GeometryManager::HAIR_REMOVED;
@@ -902,95 +923,91 @@ template<> void Scene::delete_node_impl(Geometry *node)
flag = GeometryManager::MESH_REMOVED;
}
delete_node_from_array(geometry, node);
geometry.erase_by_swap(node);
geometry_manager->tag_update(this, flag);
}
template<> void Scene::delete_node_impl(Object *node)
template<> void Scene::delete_node(Object *node)
{
delete_node_from_array(objects, node);
assert(node->get_owner() == this);
objects.erase_by_swap(node);
object_manager->tag_update(this, ObjectManager::OBJECT_REMOVED);
}
template<> void Scene::delete_node_impl(ParticleSystem *node)
template<> void Scene::delete_node(ParticleSystem *node)
{
delete_node_from_array(particle_systems, node);
assert(node->get_owner() == this);
particle_systems.erase_by_swap(node);
particle_system_manager->tag_update(this);
}
template<> void Scene::delete_node_impl(Shader *node)
template<> void Scene::delete_node(Shader *node)
{
assert(node->get_owner() == this);
/* don't delete unused shaders, not supported */
node->clear_reference_count();
}
template<> void Scene::delete_node_impl(Procedural *node)
template<> void Scene::delete_node(Procedural *node)
{
delete_node_from_array(procedurals, node);
assert(node->get_owner() == this);
procedurals.erase_by_swap(node);
procedural_manager->tag_update();
}
template<> void Scene::delete_node_impl(AlembicProcedural *node)
template<> void Scene::delete_node(AlembicProcedural *node)
{
#ifdef WITH_ALEMBIC
delete_node_impl(static_cast<Procedural *>(node));
delete_node(static_cast<Procedural *>(node));
#else
(void)node;
#endif
}
template<> void Scene::delete_node_impl(Pass *node)
template<> void Scene::delete_node(Pass *node)
{
delete_node_from_array(passes, node);
assert(node->get_owner() == this);
passes.erase_by_swap(node);
film->tag_modified();
}
template<typename T>
static void remove_nodes_in_set(const set<T *> &nodes_set,
vector<T *> &nodes_array,
const NodeOwner *owner)
template<typename T> static void assert_same_owner(const set<T *> &nodes, const NodeOwner *owner)
{
size_t new_size = nodes_array.size();
for (size_t i = 0; i < new_size; ++i) {
T *node = nodes_array[i];
if (nodes_set.find(node) != nodes_set.end()) {
std::swap(nodes_array[i], nodes_array[new_size - 1]);
assert(node->get_owner() == owner);
delete node;
i -= 1;
new_size -= 1;
}
}
nodes_array.resize(new_size);
#ifdef NDEBUG
(void)nodes;
(void)owner;
#else
for (const T *node : nodes) {
assert(node->get_owner() == owner);
}
#endif
}
template<> void Scene::delete_nodes(const set<Light *> &nodes, const NodeOwner *owner)
{
remove_nodes_in_set(nodes, lights, owner);
assert_same_owner(nodes, owner);
lights.erase_in_set(nodes);
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);
assert_same_owner(nodes, owner);
geometry.erase_in_set(nodes);
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);
assert_same_owner(nodes, owner);
objects.erase_in_set(nodes);
object_manager->tag_update(this, ObjectManager::OBJECT_REMOVED);
}
template<> void Scene::delete_nodes(const set<ParticleSystem *> &nodes, const NodeOwner *owner)
{
remove_nodes_in_set(nodes, particle_systems, owner);
assert_same_owner(nodes, owner);
particle_systems.erase_in_set(nodes);
particle_system_manager->tag_update(this);
}
@@ -1004,13 +1021,15 @@ template<> void Scene::delete_nodes(const set<Shader *> &nodes, const NodeOwner
template<> void Scene::delete_nodes(const set<Procedural *> &nodes, const NodeOwner *owner)
{
remove_nodes_in_set(nodes, procedurals, owner);
assert_same_owner(nodes, owner);
procedurals.erase_in_set(nodes);
procedural_manager->tag_update();
}
template<> void Scene::delete_nodes(const set<Pass *> &nodes, const NodeOwner *owner)
{
remove_nodes_in_set(nodes, passes, owner);
assert_same_owner(nodes, owner);
passes.erase_in_set(nodes);
film->tag_modified();
}

View File

@@ -14,6 +14,8 @@
#include "util/param.h"
#include "util/string.h"
#include "util/thread.h"
#include "util/unique_ptr.h"
#include "util/unique_ptr_vector.h"
CCL_NAMESPACE_BEGIN
@@ -127,13 +129,17 @@ class Scene : public NodeOwner {
Integrator *integrator;
/* data lists */
vector<Object *> objects;
vector<Geometry *> geometry;
vector<Shader *> shaders;
vector<Light *> lights;
vector<ParticleSystem *> particle_systems;
vector<Pass *> passes;
vector<Procedural *> procedurals;
unique_ptr_vector<Background> backgrounds;
unique_ptr_vector<Film> films;
unique_ptr_vector<Integrator> integrators;
unique_ptr_vector<Camera> cameras;
unique_ptr_vector<Shader> shaders;
unique_ptr_vector<Pass> passes;
unique_ptr_vector<ParticleSystem> particle_systems;
unique_ptr_vector<Light> lights;
unique_ptr_vector<Geometry> geometry;
unique_ptr_vector<Object> objects;
unique_ptr_vector<Procedural> procedurals;
/* data managers */
unique_ptr<ImageManager> image_manager;
@@ -199,12 +205,7 @@ class Scene : public NodeOwner {
* node array (e.g. Scene::geometry for Geometry nodes) and tag the appropriate
* manager for an update.
*/
template<typename T, typename... Args> T *create_node(Args &&...args)
{
T *node = new T(args...);
node->set_owner(this);
return node;
}
template<typename T, typename... Args> T *create_node(Args &&.../*args*/) = delete;
/* This function is used to delete a node from the scene instead of calling 'delete'
* and manually removing the node from the data array. It also tags the
@@ -212,20 +213,7 @@ class Scene : public NodeOwner {
* the owner of the node. Calling this function on a node not owned by the scene
* will likely cause a crash which we want in order to detect such cases.
*/
template<typename T> void delete_node(T *node)
{
assert(node->get_owner() == this);
delete_node_impl(node);
}
/* Same as above, but specify the actual owner.
*/
template<typename T> void delete_node(T *node, const NodeOwner *owner)
{
assert(node->get_owner() == owner);
delete_node_impl(node);
(void)owner;
}
template<typename T> void delete_node(T *node) = delete;
/* Remove all nodes in the set from the appropriate data arrays, and tag the
* specific managers for an update. This assumes that the scene owns the nodes.
@@ -263,69 +251,42 @@ class Scene : public NodeOwner {
/* Get size of a volume stack needed to render this scene. */
int get_volume_stack_size() const;
template<typename T> void delete_node_impl(T *node)
{
delete node;
}
};
template<> Light *Scene::create_node<Light>();
template<> Mesh *Scene::create_node<Mesh>();
template<> Object *Scene::create_node<Object>();
template<> Hair *Scene::create_node<Hair>();
template<> Volume *Scene::create_node<Volume>();
template<> PointCloud *Scene::create_node<PointCloud>();
template<> ParticleSystem *Scene::create_node<ParticleSystem>();
template<> Shader *Scene::create_node<Shader>();
template<> AlembicProcedural *Scene::create_node<AlembicProcedural>();
template<> Pass *Scene::create_node<Pass>();
template<> Camera *Scene::create_node<Camera>();
template<> Background *Scene::create_node<Background>();
template<> Film *Scene::create_node<Film>();
template<> Integrator *Scene::create_node<Integrator>();
template<> void Scene::delete_node_impl(Light *node);
template<> void Scene::delete_node_impl(Mesh *node);
template<> void Scene::delete_node_impl(Volume *node);
template<> void Scene::delete_node_impl(PointCloud *node);
template<> void Scene::delete_node_impl(Hair *node);
template<> void Scene::delete_node_impl(Geometry *node);
template<> void Scene::delete_node_impl(Object *node);
template<> void Scene::delete_node_impl(ParticleSystem *node);
template<> void Scene::delete_node_impl(Shader *node);
template<> void Scene::delete_node_impl(Procedural *node);
template<> void Scene::delete_node_impl(AlembicProcedural *node);
template<> void Scene::delete_node_impl(Pass *node);
template<> void Scene::delete_node(Light *node);
template<> void Scene::delete_node(Mesh *node);
template<> void Scene::delete_node(Volume *node);
template<> void Scene::delete_node(PointCloud *node);
template<> void Scene::delete_node(Hair *node);
template<> void Scene::delete_node(Geometry *node);
template<> void Scene::delete_node(Object *node);
template<> void Scene::delete_node(ParticleSystem *node);
template<> void Scene::delete_node(Shader *node);
template<> void Scene::delete_node(Procedural *node);
template<> void Scene::delete_node(AlembicProcedural *node);
template<> void Scene::delete_node(Pass *node);
template<> void Scene::delete_nodes(const set<Light *> &nodes, const NodeOwner *owner);
template<> void Scene::delete_nodes(const set<Geometry *> &nodes, const NodeOwner *owner);
template<> void Scene::delete_nodes(const set<Object *> &nodes, const NodeOwner *owner);
template<> void Scene::delete_nodes(const set<ParticleSystem *> &nodes, const NodeOwner *owner);
template<> void Scene::delete_nodes(const set<Shader *> &nodes, const NodeOwner *owner);
template<> void Scene::delete_nodes(const set<Procedural *> &nodes, const NodeOwner *owner);
template<> void Scene::delete_nodes(const set<Pass *> &nodes, const NodeOwner *owner);
CCL_NAMESPACE_END

View File

@@ -348,7 +348,6 @@ void Shader::tag_update(Scene *scene)
for (const ShaderInput *in : node->inputs) {
if (in->link) {
TransparentBsdfNode *transparent = graph->create_node<TransparentBsdfNode>();
graph->add(transparent);
graph->connect(transparent->output("BSDF"), output->input("Surface"));
has_surface = true;
break;
@@ -659,7 +658,6 @@ void ShaderManager::add_default(Scene *scene)
DiffuseBsdfNode *diffuse = graph->create_node<DiffuseBsdfNode>();
diffuse->set_color(make_float3(0.8f, 0.8f, 0.8f));
graph->add(diffuse);
graph->connect(diffuse->output("BSDF"), graph->output()->input("Surface"));
@@ -676,7 +674,6 @@ void ShaderManager::add_default(Scene *scene)
unique_ptr<ShaderGraph> graph = make_unique<ShaderGraph>();
PrincipledVolumeNode *principled = graph->create_node<PrincipledVolumeNode>();
graph->add(principled);
graph->connect(principled->output("Volume"), graph->output()->input("Volume"));
@@ -696,7 +693,6 @@ void ShaderManager::add_default(Scene *scene)
EmissionNode *emission = graph->create_node<EmissionNode>();
emission->set_color(make_float3(0.8f, 0.8f, 0.8f));
emission->set_strength(0.0f);
graph->add(emission);
graph->connect(emission->output("Emission"), graph->output()->input("Surface"));

View File

@@ -66,35 +66,27 @@ void ShaderOutput::disconnect()
ShaderNode::ShaderNode(const NodeType *type) : Node(type)
{
name = type->name;
id = -1;
bump = SHADER_BUMP_NONE;
special_type = SHADER_SPECIAL_TYPE_NONE;
create_inputs_outputs(type);
}
ShaderNode::~ShaderNode()
ShaderNode::ShaderNode(const ShaderNode &other)
: Node(other.type), bump(other.bump), special_type(other.special_type)
{
for (ShaderInput *socket : inputs) {
delete socket;
}
for (ShaderOutput *socket : outputs) {
delete socket;
}
/* Inputs and outputs are recreated, no links to other nodes will remain. */
name = other.name;
create_inputs_outputs(type);
}
void ShaderNode::create_inputs_outputs(const NodeType *type)
{
for (const SocketType &socket : type->inputs) {
if (socket.flags & SocketType::LINKABLE) {
inputs.push_back(new ShaderInput(socket, this));
inputs.push_back(make_unique<ShaderInput>(socket, this));
}
}
for (const SocketType &socket : type->outputs) {
outputs.push_back(new ShaderOutput(socket, this));
outputs.push_back(make_unique<ShaderOutput>(socket, this));
}
}
@@ -145,8 +137,7 @@ ShaderOutput *ShaderNode::output(ustring name)
void ShaderNode::remove_input(ShaderInput *input)
{
assert(input->link == nullptr);
delete input;
inputs.erase(remove(inputs.begin(), inputs.end(), input), inputs.end());
inputs.erase(input);
}
void ShaderNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@@ -221,7 +212,7 @@ ShaderGraph::ShaderGraph()
finalized = false;
simplified = false;
num_node_ids = 0;
add(create_node<OutputNode>());
create_node<OutputNode>();
}
ShaderGraph::~ShaderGraph()
@@ -229,19 +220,19 @@ ShaderGraph::~ShaderGraph()
clear_nodes();
}
ShaderNode *ShaderGraph::add(ShaderNode *node)
void ShaderGraph::add_node(unique_ptr<ShaderNode> &&node)
{
assert(!finalized);
simplified = false;
node->set_owner(this);
node->id = num_node_ids++;
nodes.push_back(node);
return node;
nodes.push_back(std::move(node));
}
OutputNode *ShaderGraph::output()
{
return (OutputNode *)nodes.front();
return static_cast<OutputNode *>(nodes[0]);
}
void ShaderGraph::connect(ShaderOutput *from, ShaderInput *to)
@@ -276,7 +267,7 @@ void ShaderGraph::connect(ShaderOutput *from, ShaderInput *to)
emission->from_auto_conversion = true;
emission->set_color(one_float3());
emission->set_strength(1.0f);
convert = add(emission);
convert = emission;
/* Connect float inputs to Strength to save an additional Value->Color conversion. */
if (from->type() == SocketType::FLOAT) {
convert_in = convert->input("Strength");
@@ -286,7 +277,7 @@ void ShaderGraph::connect(ShaderOutput *from, ShaderInput *to)
}
}
else {
convert = add(create_node<ConvertNode>(from->type(), to->type(), true));
convert = create_node<ConvertNode>(from->type(), to->type(), true);
convert_in = convert->inputs[0];
}
@@ -420,9 +411,6 @@ void ShaderGraph::find_dependencies(ShaderNodeSet &dependencies, ShaderInput *in
void ShaderGraph::clear_nodes()
{
for (ShaderNode *node : nodes) {
delete_node(node);
}
nodes.clear();
}
@@ -435,13 +423,6 @@ void ShaderGraph::copy_nodes(ShaderNodeSet &nodes, ShaderNodeMap &nnodemap)
for (ShaderNode *node : nodes) {
ShaderNode *nnode = node->clone(this);
nnodemap[node] = nnode;
/* create new inputs and outputs to recreate links and ensure
* that we still point to valid SocketType if the NodeType
* changed in cloning, as it does for OSL nodes */
nnode->inputs.clear();
nnode->outputs.clear();
nnode->create_inputs_outputs(nnode->type);
}
/* recreate links */
@@ -525,18 +506,16 @@ void ShaderGraph::remove_proxy_nodes()
/* remove nodes */
if (any_node_removed) {
list<ShaderNode *> newnodes;
unique_ptr_vector<ShaderNode> newnodes;
for (ShaderNode *node : nodes) {
for (size_t i = 0; i < nodes.size(); i++) {
unique_ptr<ShaderNode> node = nodes.steal(i);
if (!removed[node->id]) {
newnodes.push_back(node);
}
else {
delete_node(node);
newnodes.push_back(std::move(node));
}
}
nodes = newnodes;
nodes = std::move(newnodes);
}
}
@@ -596,7 +575,7 @@ void ShaderGraph::constant_fold(Scene *scene)
* that happens to ensure there is still a valid graph for displacement.
*/
if (has_displacement && !output()->input("Displacement")->link) {
ColorNode *value = (ColorNode *)add(create_node<ColorNode>());
ColorNode *value = create_node<ColorNode>();
value->set_value(output()->get_displacement());
connect(value->output("Color"), output()->input("Displacement"));
@@ -828,24 +807,25 @@ void ShaderGraph::clean(Scene *scene)
}
/* remove unused nodes */
list<ShaderNode *> newnodes;
unique_ptr_vector<ShaderNode> newnodes;
for (ShaderNode *node : nodes) {
for (size_t i = 0; i < nodes.size(); i++) {
unique_ptr<ShaderNode> node = nodes.steal(i);
if (visited[node->id]) {
newnodes.push_back(node);
}
else {
delete_node(node);
newnodes.push_back(std::move(node));
}
}
nodes = newnodes;
nodes = std::move(newnodes);
}
void ShaderGraph::expand()
{
/* Call expand on all nodes, to generate additional nodes. */
for (ShaderNode *node : nodes) {
/* Call expand on all nodes, to generate additional nodes.
* No range based for loop because we modify the vector, and want to expand
* newly generated nodes too. */
for (size_t i = 0; i < nodes.size(); i++) {
ShaderNode *node = nodes[i];
node->expand(this);
}
}
@@ -859,7 +839,9 @@ void ShaderGraph::default_inputs(bool do_osl)
TextureCoordinateNode *texco = nullptr;
VectorTransformNode *normal_transform = nullptr;
for (ShaderNode *node : nodes) {
for (size_t i = 0; i < nodes.size(); i++) {
ShaderNode *node = nodes[i];
for (ShaderInput *input : node->inputs) {
if (!input->link && (!(input->flags() & SocketType::OSL_INTERNAL) || do_osl)) {
if (input->flags() & SocketType::LINK_TEXTURE_GENERATED) {
@@ -928,16 +910,6 @@ void ShaderGraph::default_inputs(bool do_osl)
}
}
}
if (geom) {
add(geom);
}
if (texco) {
add(texco);
}
if (normal_transform) {
add(normal_transform);
}
}
void ShaderGraph::refine_bump_nodes()
@@ -947,7 +919,10 @@ void ShaderGraph::refine_bump_nodes()
* input to the inputs "center","dx" and "dy" What is in "bump" input is moved
* to "center" input. */
for (ShaderNode *node : nodes) {
/* No range based for loop because we modify the vector. */
for (int i = 0; i < nodes.size(); i++) {
ShaderNode *node = nodes[i];
if (node->special_type == SHADER_SPECIAL_TYPE_BUMP && node->input("Height")->link) {
ShaderInput *bump_input = node->input("Height");
ShaderNodeSet nodes_bump;
@@ -981,14 +956,6 @@ void ShaderGraph::refine_bump_nodes()
connect(out_dx, node->input("SampleX"));
connect(out_dy, node->input("SampleY"));
/* Add generated nodes. */
for (const NodePair &pair : nodes_dx) {
add(pair.second);
}
for (const NodePair &pair : nodes_dy) {
add(pair.second);
}
/* Connect what is connected is bump to sample-center input. */
connect(out, node->input("SampleCenter"));
@@ -1050,10 +1017,10 @@ void ShaderGraph::bump_from_displacement(bool use_object_space)
* output, so it can finally set the shader normal, note we are only doing
* this for bump from displacement, this will be the only bump allowed to
* overwrite the shader normal */
ShaderNode *set_normal = add(create_node<SetNormalNode>());
ShaderNode *set_normal = create_node<SetNormalNode>();
/* add bump node and connect copied graphs to it */
BumpNode *bump = (BumpNode *)add(create_node<BumpNode>());
BumpNode *bump = create_node<BumpNode>();
bump->set_use_object_space(use_object_space);
bump->set_distance(1.0f);
@@ -1063,15 +1030,15 @@ void ShaderGraph::bump_from_displacement(bool use_object_space)
ShaderOutput *out_dy = nodes_dy[out->parent]->output(out->name());
/* convert displacement vector to height */
VectorMathNode *dot_center = (VectorMathNode *)add(create_node<VectorMathNode>());
VectorMathNode *dot_dx = (VectorMathNode *)add(create_node<VectorMathNode>());
VectorMathNode *dot_dy = (VectorMathNode *)add(create_node<VectorMathNode>());
VectorMathNode *dot_center = create_node<VectorMathNode>();
VectorMathNode *dot_dx = create_node<VectorMathNode>();
VectorMathNode *dot_dy = create_node<VectorMathNode>();
dot_center->set_math_type(NODE_VECTOR_MATH_DOT_PRODUCT);
dot_dx->set_math_type(NODE_VECTOR_MATH_DOT_PRODUCT);
dot_dy->set_math_type(NODE_VECTOR_MATH_DOT_PRODUCT);
GeometryNode *geom = (GeometryNode *)add(create_node<GeometryNode>());
GeometryNode *geom = create_node<GeometryNode>();
connect(geom->output("Normal"), bump->input("Normal"));
connect(geom->output("Normal"), dot_center->input("Vector2"));
connect(geom->output("Normal"), dot_dx->input("Vector2"));
@@ -1090,18 +1057,6 @@ void ShaderGraph::bump_from_displacement(bool use_object_space)
/* connect to output node */
connect(set_normal->output("Normal"), output()->input("Normal"));
/* finally, add the copied nodes to the graph. we can't do this earlier
* because we would create dependency cycles in the above loop */
for (const NodePair &pair : nodes_center) {
add(pair.second);
}
for (const NodePair &pair : nodes_dx) {
add(pair.second);
}
for (const NodePair &pair : nodes_dy) {
add(pair.second);
}
}
void ShaderGraph::transform_multi_closure(ShaderNode *node, ShaderOutput *weight_out, bool volume)
@@ -1121,7 +1076,6 @@ void ShaderGraph::transform_multi_closure(ShaderNode *node, ShaderOutput *weight
if (fin) {
/* mix closure: add node to mix closure weights */
MixClosureWeightNode *mix_node = create_node<MixClosureWeightNode>();
add(mix_node);
ShaderInput *fac_in = mix_node->input("Fac");
ShaderInput *weight_in = mix_node->input("Weight");
@@ -1164,7 +1118,6 @@ void ShaderGraph::transform_multi_closure(ShaderNode *node, ShaderOutput *weight
const float weight_value = node->get_float(weight_in->socket_type);
if (weight_in->link || weight_value != 0.0f) {
MathNode *math_node = create_node<MathNode>();
add(math_node);
if (weight_in->link) {
connect(weight_in->link, math_node->input("Value1"));
@@ -1214,8 +1167,8 @@ int ShaderGraph::get_num_closures()
num_closures += 12;
}
else if (CLOSURE_IS_VOLUME(closure_type)) {
/* TODO(sergey): Verify this is still needed, since we have special minimized volume storage
* for the volume steps. */
/* TODO(sergey): Verify this is still needed, since we have special minimized volume
* storage for the volume steps. */
num_closures += MAX_VOLUME_STACK_SIZE;
}
else if (closure_type == CLOSURE_BSDF_PHYSICAL_CONDUCTOR ||

View File

@@ -9,12 +9,12 @@
#include "kernel/types.h"
#include "util/list.h"
#include "util/map.h"
#include "util/param.h"
#include "util/set.h"
#include "util/string.h"
#include "util/types.h"
#include "util/unique_ptr_vector.h"
#include "util/vector.h"
CCL_NAMESPACE_BEGIN
@@ -146,7 +146,7 @@ class ShaderOutput {
class ShaderNode : public Node {
public:
explicit ShaderNode(const NodeType *type);
~ShaderNode() override;
ShaderNode(const ShaderNode &other);
void create_inputs_outputs(const NodeType *type);
void remove_input(ShaderInput *input);
@@ -205,13 +205,15 @@ class ShaderNode : public Node {
{
return false;
}
vector<ShaderInput *> inputs;
vector<ShaderOutput *> outputs;
unique_ptr_vector<ShaderInput> inputs;
unique_ptr_vector<ShaderOutput> outputs;
int id; /* index in graph node array */
ShaderBump bump; /* for bump mapping utility */
ShaderNodeSpecialType special_type; /* special node type */
/* index in graph node array */
int id = -1;
/* for bump mapping utility */
ShaderBump bump = SHADER_BUMP_NONE;
/* special node type */
ShaderNodeSpecialType special_type = SHADER_SPECIAL_TYPE_NONE;
/* ** Selective nodes compilation ** */
@@ -290,7 +292,7 @@ using ShaderNodeMap = map<ShaderNode *, ShaderNode *, ShaderNodeIDComparator>;
class ShaderGraph : public NodeOwner {
public:
list<ShaderNode *> nodes;
unique_ptr_vector<ShaderNode> nodes;
size_t num_node_ids;
bool finalized;
bool simplified;
@@ -299,7 +301,6 @@ class ShaderGraph : public NodeOwner {
ShaderGraph();
~ShaderGraph() override;
ShaderNode *add(ShaderNode *node);
OutputNode *output();
void connect(ShaderOutput *from, ShaderInput *to);
@@ -318,26 +319,39 @@ class ShaderGraph : public NodeOwner {
void dump_graph(const char *filename);
/* This function is used to create a node of a specified type instead of
* calling 'new', and sets the graph as the owner of the node.
*/
/* Create node from class and add it to the shader graph. */
template<typename T, typename... Args> T *create_node(Args &&...args)
{
T *node = new T(args...);
node->set_owner(this);
return node;
unique_ptr<T> node = make_unique<T>(args...);
T *node_ptr = node.get();
this->add_node(std::move(node));
return node_ptr;
}
/* This function is used to delete a node created and owned by the graph. */
template<typename T> void delete_node(T *node)
/* Create OSL node from class and add it to the shader graph. */
template<typename T, typename... Args> T *create_osl_node(void *node_memory, Args &&...args)
{
assert(node->get_owner() == this);
delete node;
T *node_ptr = new (node_memory) T(args...);
unique_ptr<T> node(node_ptr);
this->add_node(std::move(node));
return node_ptr;
}
/* Create node from node type and add it to the shader graph. */
ShaderNode *create_node(const NodeType *node_type)
{
unique_ptr<Node> node = node_type->create(node_type);
unique_ptr<ShaderNode> shader_node(static_cast<ShaderNode *>(node.release()));
ShaderNode *shader_node_ptr = shader_node.get();
this->add_node(std::move(shader_node));
return shader_node_ptr;
}
protected:
using NodePair = pair<ShaderNode *const, ShaderNode *>;
void add_node(unique_ptr<ShaderNode> &&node);
void find_dependencies(ShaderNodeSet &dependencies, ShaderInput *input);
void clear_nodes();
void copy_nodes(ShaderNodeSet &nodes, ShaderNodeMap &nnodemap);

View File

@@ -2147,9 +2147,9 @@ void RGBToBWNode::compile(OSLCompiler &compiler)
const NodeType *ConvertNode::node_types[ConvertNode::MAX_TYPE][ConvertNode::MAX_TYPE];
bool ConvertNode::initialized = ConvertNode::register_types();
Node *ConvertNode::create(const NodeType *type)
unique_ptr<Node> ConvertNode::create(const NodeType *type)
{
return new ConvertNode(type->inputs[0].type, type->outputs[0].type);
return make_unique<ConvertNode>(type->inputs[0].type, type->outputs[0].type);
}
bool ConvertNode::register_types()
@@ -4778,7 +4778,6 @@ void VolumeInfoNode::expand(ShaderGraph *graph)
if (!color_out->links.empty()) {
AttributeNode *attr = graph->create_node<AttributeNode>();
attr->set_attribute(ustring("color"));
graph->add(attr);
graph->relink(color_out, attr->output("Color"));
}
@@ -4786,7 +4785,6 @@ void VolumeInfoNode::expand(ShaderGraph *graph)
if (!density_out->links.empty()) {
AttributeNode *attr = graph->create_node<AttributeNode>();
attr->set_attribute(ustring("density"));
graph->add(attr);
graph->relink(density_out, attr->output("Fac"));
}
@@ -4794,7 +4792,6 @@ void VolumeInfoNode::expand(ShaderGraph *graph)
if (!flame_out->links.empty()) {
AttributeNode *attr = graph->create_node<AttributeNode>();
attr->set_attribute(ustring("flame"));
graph->add(attr);
graph->relink(flame_out, attr->output("Fac"));
}
@@ -4802,7 +4799,6 @@ void VolumeInfoNode::expand(ShaderGraph *graph)
if (!temperature_out->links.empty()) {
AttributeNode *attr = graph->create_node<AttributeNode>();
attr->set_attribute(ustring("temperature"));
graph->add(attr);
graph->relink(temperature_out, attr->output("Fac"));
}
}
@@ -6403,7 +6399,6 @@ void MapRangeNode::expand(ShaderGraph *graph)
if (!result_out->links.empty()) {
ClampNode *clamp_node = graph->create_node<ClampNode>();
clamp_node->set_clamp_type(NODE_CLAMP_RANGE);
graph->add(clamp_node);
graph->relink(result_out, clamp_node->output("Result"));
graph->connect(result_out, clamp_node->input("Value"));
if (input("To Min")->link) {
@@ -6706,7 +6701,6 @@ void MathNode::expand(ShaderGraph *graph)
clamp_node->set_clamp_type(NODE_CLAMP_MINMAX);
clamp_node->set_min(0.0f);
clamp_node->set_max(1.0f);
graph->add(clamp_node);
graph->relink(result_out, clamp_node->output("Result"));
graph->connect(result_out, clamp_node->input("Value"));
}
@@ -7033,7 +7027,6 @@ void BumpNode::constant_fold(const ConstantFolder &folder)
if (height_in->link == nullptr) {
if (normal_in->link == nullptr) {
GeometryNode *geom = folder.graph->create_node<GeometryNode>();
folder.graph->add(geom);
folder.bypass(geom->output("Normal"));
}
else {
@@ -7415,16 +7408,13 @@ OSLNode *OSLNode::create(ShaderGraph *graph, const size_t num_inputs, const OSLN
memset(node_memory, 0, node_size + inputs_size);
if (!from) {
OSLNode *node = new (node_memory) OSLNode();
node->set_owner(graph);
return node;
return graph->create_osl_node<OSLNode>(node_memory);
}
/* copy input default values and node type for cloning */
memcpy(node_memory + node_size, (char *)from + node_size, inputs_size);
OSLNode *node = new (node_memory) OSLNode(*from);
OSLNode *node = graph->create_osl_node<OSLNode>(node_memory, *from);
node->type = new NodeType(*(from->type));
node->set_owner(from->owner);
return node;
}

View File

@@ -10,6 +10,7 @@
#include "util/array.h"
#include "util/string.h"
#include "util/unique_ptr.h"
CCL_NAMESPACE_BEGIN
@@ -451,7 +452,7 @@ class ConvertNode : public ShaderNode {
static const int MAX_TYPE = 13;
static bool register_types();
static Node *create(const NodeType *type);
static unique_ptr<Node> create(const NodeType *type);
static const NodeType *node_types[MAX_TYPE][MAX_TYPE];
static bool initialized;
};

View File

@@ -129,7 +129,7 @@ void BufferParams::update_passes()
}
}
void BufferParams::update_passes(const vector<Pass *> &scene_passes)
void BufferParams::update_passes(const unique_ptr_vector<Pass> &scene_passes)
{
passes.clear();

View File

@@ -117,7 +117,7 @@ class BufferParams : public Node {
* The `update_passes()` without parameters updates offsets and strides which are stored outside
* of the passes. */
void update_passes();
void update_passes(const vector<Pass *> &scene_passes);
void update_passes(const unique_ptr_vector<Pass> &scene_passes);
/* Returns PASS_UNUSED if there is no such pass in the buffer. */
int get_pass_offset(PassType type, PassMode mode = PassMode::NOISY) const;

View File

@@ -194,13 +194,15 @@ bool DenoiseTask::load_input_pixels(const int layer)
/* Task stages */
static void add_pass(vector<Pass *> &passes, PassType type, PassMode mode = PassMode::NOISY)
static void add_pass(unique_ptr_vector<Pass> &passes,
PassType type,
PassMode mode = PassMode::NOISY)
{
Pass *pass = new Pass();
unique_ptr<Pass> pass = make_unique<Pass>();
pass->set_type(type);
pass->set_mode(mode);
passes.push_back(pass);
passes.push_back(std::move(pass));
}
bool DenoiseTask::load()
@@ -227,7 +229,7 @@ bool DenoiseTask::load()
denoiser->denoiser->set_params(params);
/* Allocate device buffer. */
vector<Pass *> passes;
unique_ptr_vector<Pass> passes;
add_pass(passes, PassType::PASS_COMBINED);
add_pass(passes, PassType::PASS_DENOISING_ALBEDO);
add_pass(passes, PassType::PASS_DENOISING_NORMAL);
@@ -244,9 +246,7 @@ bool DenoiseTask::load()
buffer_params.full_height = image.height;
buffer_params.update_passes(passes);
for (Pass *pass : passes) {
delete pass;
}
passes.clear();
buffers.reset(buffer_params);

View File

@@ -85,7 +85,6 @@ class ShaderGraphBuilder {
template<typename T> ShaderGraphBuilder &add_node(const T &node)
{
EXPECT_EQ(find_node(node.name()), (void *)nullptr);
graph_->add(node.node());
node_map_[node.name()] = node.node();
return *this;
}

View File

@@ -118,6 +118,7 @@ set(SRC_HEADERS
types_uint4.h
types_ushort4.h
unique_ptr.h
unique_ptr_vector.h
vector.h
version.h
windows.h

View File

@@ -0,0 +1,176 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: Apache-2.0 */
#pragma once
#include <cassert>
#include "util/algorithm.h"
#include "util/set.h"
#include "util/unique_ptr.h"
#include "util/vector.h"
CCL_NAMESPACE_BEGIN
/* Convenient vector of unique_ptr.
* - Indexing and iterators return the pointer value directly.
* - Utility functions for erase by swapping elements, for nodes.
*/
template<typename T> class unique_ptr_vector {
protected:
vector<unique_ptr<T>> data;
public:
T *operator[](const size_t i) const
{
return data[i].get();
}
unique_ptr<T> steal(const size_t i)
{
unique_ptr<T> local;
swap(data[i], local);
return local;
}
void push_back(unique_ptr<T> &&value)
{
data.push_back(std::move(value));
}
bool empty() const
{
return data.empty();
}
size_t size() const
{
return data.size();
}
void clear()
{
data.clear();
}
void free_memory()
{
data.free_memory();
}
void erase(const T *value)
{
const int size = data.size();
for (size_t i = 0; i < size; i++) {
if (data[i].get() == value) {
data.erase(data.begin() + i);
return;
}
}
assert(0);
}
/* Slightly faster erase swapping with other element instead of moving many,
* but will change element order. */
void erase_by_swap(const T *value)
{
const int size = data.size();
for (size_t i = 0; i < size; i++) {
if (data[i].get() == value) {
swap(data[i], data[data.size() - 1]);
break;
}
}
data.resize(data.size() - 1);
}
void erase_in_set(const set<T *> &values)
{
size_t new_size = data.size();
for (size_t i = 0; i < new_size; i++) {
T *value = data[i].get();
if (values.find(value) != values.end()) {
swap(data[i], data[new_size - 1]);
i -= 1;
new_size -= 1;
}
}
data.resize(new_size);
}
/* Basic iterators for range based for loop. */
struct ConstIterator {
typename vector<unique_ptr<T>>::const_iterator it;
const T *operator*() const
{
return it->get();
}
bool operator!=(const ConstIterator &other) const
{
return it != other.it;
}
void operator++()
{
++it;
}
};
ConstIterator begin() const
{
return ConstIterator{data.begin()};
}
ConstIterator end() const
{
return ConstIterator{data.end()};
}
struct Iterator {
typename vector<unique_ptr<T>>::const_iterator it;
T *operator*() const
{
return it->get();
}
bool operator!=(const Iterator &other) const
{
return it != other.it;
}
void operator++()
{
++it;
}
};
Iterator begin()
{
return Iterator{data.begin()};
}
Iterator end()
{
return Iterator{data.end()};
}
/* Cast to read-only regular vector for easier interop.
* Assumes unique_ptr is zero overhead. */
operator const vector<T *> &()
{
static_assert(sizeof(unique_ptr<T>) == sizeof(T *));
return reinterpret_cast<vector<T *> &>(*this);
}
/* For sorting unique_ptr instead of pointer. */
template<typename Compare> void stable_sort(Compare compare)
{
auto compare_unique_ptr = [compare](const unique_ptr<T> &a, const unique_ptr<T> &b) {
return compare(a.get(), b.get());
};
std::stable_sort(data.begin(), data.end(), compare_unique_ptr);
}
};
CCL_NAMESPACE_END