diff options
author | Jacques Lucke <jacques@blender.org> | 2021-01-12 23:22:32 +0300 |
---|---|---|
committer | Jacques Lucke <jacques@blender.org> | 2021-01-12 23:22:32 +0300 |
commit | 1339e7c44f1f9a1c9bc5d6cb0a5702a6fe73515e (patch) | |
tree | 219481d8935a75ad6e2b97fe16193af3f763bb32 | |
parent | b66fcd83f6cef55a87dc9835129f8956fd6c6742 (diff) | |
parent | 719bea0d6d06be579edee2fc3d12a7828bb8e101 (diff) |
Merge branch 'master' into experiment-point-distributiontemp-point-distribution-refactor-experiment
34 files changed, 730 insertions, 214 deletions
diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py index 35fd7333cf4..495bf77b0e7 100644 --- a/release/scripts/startup/bl_ui/space_clip.py +++ b/release/scripts/startup/bl_ui/space_clip.py @@ -303,11 +303,11 @@ class CLIP_MT_masking_editor_menus(Menu): if clip: layout.menu("MASK_MT_select") - layout.menu("CLIP_MT_clip") # XXX - remove? + layout.menu("CLIP_MT_clip") layout.menu("MASK_MT_add") layout.menu("MASK_MT_mask") else: - layout.menu("CLIP_MT_clip") # XXX - remove? + layout.menu("CLIP_MT_clip") class CLIP_PT_clip_view_panel: @@ -1330,10 +1330,17 @@ class CLIP_MT_clip(Menu): layout.operator("clip.open") if clip: + layout.operator("clip.set_scene_frames") + layout.operator("clip.set_center_principal") layout.operator("clip.prefetch") layout.operator("clip.reload") layout.menu("CLIP_MT_proxy") + layout.separator() + + layout.operator("clip.set_viewport_background") + layout.operator("clip.setup_tracking_scene") + class CLIP_MT_proxy(Menu): bl_label = "Proxy" @@ -1345,65 +1352,160 @@ class CLIP_MT_proxy(Menu): layout.operator("clip.delete_proxy") -class CLIP_MT_track(Menu): - bl_label = "Track" +class CLIP_MT_track_transform(Menu): + bl_label = "Transform" def draw(self, _context): layout = self.layout - layout.operator("clip.clear_solution") - layout.operator("clip.solve_camera") + layout.operator("transform.translate") + layout.operator("transform.rotate") + layout.operator("transform.resize") + - layout.separator() - props = layout.operator("clip.clear_track_path", text="Clear After") - props.clear_active = False - props.action = 'REMAINED' +class CLIP_MT_track_motion(Menu): + bl_label = "Track Motion" + + def draw(self, _context): + layout = self.layout + + props = layout.operator("clip.track_markers", text="Backwards") + props.backwards = True + props.sequence = True + + props = layout.operator("clip.track_markers", text="Frame Backwards") + props.backwards = True + props.sequence = False + + props = layout.operator("clip.track_markers", text="Forwards") + props.backwards = False + props.sequence = True + + props = layout.operator("clip.track_markers", text="Frame Forwards") + props.backwards = False + props.sequence = False + + +class CLIP_MT_track_clear(Menu): + bl_label = "Clear" - props = layout.operator("clip.clear_track_path", text="Clear Before") + def draw(self, _context): + layout = self.layout + + props = layout.operator("clip.clear_track_path", text="Before") props.clear_active = False props.action = 'UPTO' - props = layout.operator("clip.clear_track_path", text="Clear Track Path") + props = layout.operator("clip.clear_track_path", text="After") + props.clear_active = False + props.action = 'REMAINED' + + props = layout.operator("clip.clear_track_path", text="Track Path") props.clear_active = False props.action = 'ALL' layout.separator() - layout.operator("clip.join_tracks") - layout.separator() + layout.operator("clip.clear_solution", text="Solution") + + +class CLIP_MT_track_refine(Menu): + bl_label = "Refine" + + def draw(self, _context): + layout = self.layout + + props = layout.operator("clip.refine_markers", text="Backwards") + props.backwards = True + + props = layout.operator("clip.refine_markers", text="Fowards") + props.backwards = False + + +class CLIP_MT_track_animation(Menu): + bl_label = "Animation" + + def draw(self, _context): + layout = self.layout + + layout.operator("clip.keyframe_insert") + layout.operator("clip.keyframe_delete") + + +class CLIP_MT_track_visibility(Menu): + bl_label = "Show/Hide" + + def draw(self, _context): + layout = self.layout + + layout.operator("clip.hide_tracks_clear") + layout.operator("clip.hide_tracks", text="Hide Selected").unselected = False + layout.operator("clip.hide_tracks", text="Hide Unselected").unselected = True + + +class CLIP_MT_track_cleanup(Menu): + bl_label = "Clean Up" + + def draw(self, _context): + layout = self.layout + layout.operator("clip.clean_tracks") + layout.operator("clip.filter_tracks") + + +class CLIP_MT_track(Menu): + bl_label = "Track" + + def draw(self, context): + layout = self.layout + + clip = context.space_data.clip + tracking_object = clip.tracking.objects.active + + layout.menu("CLIP_MT_track_transform") + layout.menu("CLIP_MT_track_motion") + layout.menu("CLIP_MT_track_clear") + layout.menu("CLIP_MT_track_refine") layout.separator() - layout.operator("clip.copy_tracks") - layout.operator("clip.paste_tracks") + + layout.operator("clip.add_marker_move", text="Add Marker") + layout.operator("clip.detect_features") + layout.operator("clip.create_plane_track") layout.separator() - props = layout.operator("clip.track_markers", text="Track Frame Backwards") - props.backwards = True - props.sequence = False - props = layout.operator("clip.track_markers", text="Track Backwards") - props.backwards = True - props.sequence = True + layout.operator("clip.solve_camera", + text="Solve Camera Motion" if tracking_object.is_camera + else "Solve Object Motion") - props = layout.operator("clip.track_markers", text="Track Forwards") - props.backwards = False - props.sequence = True + layout.separator() - props = layout.operator("clip.track_markers", text="Track Frame Forwards") - props.backwards = False - props.sequence = False + layout.operator("clip.join_tracks") layout.separator() - layout.operator("clip.delete_track") - layout.operator("clip.delete_marker") + + layout.operator("clip.copy_tracks", icon='COPYDOWN') + layout.operator("clip.paste_tracks", icon='PASTEDOWN') layout.separator() - layout.operator("clip.add_marker_move") + + layout.operator("clip.track_settings_as_default", text="Copy Settings to Defaults") + layout.operator("clip.track_settings_to_track", text="Apply Default Settings") + + layout.separator() + + layout.menu("CLIP_MT_track_animation") layout.separator() + layout.menu("CLIP_MT_track_visibility") - layout.menu("CLIP_MT_track_transform") + layout.menu("CLIP_MT_track_cleanup") + + layout.separator() + + layout.operator("clip.delete_track") + layout.operator("clip.delete_marker") class CLIP_MT_reconstruction(Menu): @@ -1420,6 +1522,7 @@ class CLIP_MT_reconstruction(Menu): layout.operator("clip.set_axis", text="Set Y Axis").axis = 'Y' layout.operator("clip.set_scale") + layout.operator("clip.apply_solution_scale") layout.separator() @@ -1427,25 +1530,13 @@ class CLIP_MT_reconstruction(Menu): layout.operator("clip.bundles_to_mesh") -class CLIP_MT_track_visibility(Menu): - bl_label = "Show/Hide" - - def draw(self, _context): - layout = self.layout - - layout.operator("clip.hide_tracks_clear") - layout.operator("clip.hide_tracks", text="Hide Selected").unselected = False - layout.operator("clip.hide_tracks", text="Hide Unselected").unselected = True - - -class CLIP_MT_track_transform(Menu): - bl_label = "Transform" +class CLIP_MT_select_grouped(Menu): + bl_label = "Select Grouped" def draw(self, _context): layout = self.layout - layout.operator("transform.translate") - layout.operator("transform.resize") + layout.operator_enum("clip.select_grouped", "group") class CLIP_MT_select(Menu): @@ -1459,21 +1550,15 @@ class CLIP_MT_select(Menu): layout.separator() - layout.operator("clip.select_all" - ).action = 'TOGGLE' - layout.operator("clip.select_all", - text="Inverse").action = 'INVERT' + layout.operator("clip.select_all").action = 'TOGGLE' + layout.operator("clip.select_all", text="Inverse").action = 'INVERT' layout.menu("CLIP_MT_select_grouped") + layout.separator() -class CLIP_MT_select_grouped(Menu): - bl_label = "Select Grouped" - - def draw(self, _context): - layout = self.layout - - layout.operator_enum("clip.select_grouped", "group") + layout.operator("clip.stabilize_2d_select") + layout.operator("clip.stabilize_2d_rotation_select") class CLIP_MT_tracking_context_menu(Menu): @@ -1746,7 +1831,6 @@ classes = ( CLIP_PT_display, CLIP_PT_clip_display, CLIP_PT_marker_display, - CLIP_MT_track, CLIP_MT_tracking_editor_menus, CLIP_MT_masking_editor_menus, CLIP_PT_track, @@ -1786,8 +1870,14 @@ classes = ( CLIP_MT_clip, CLIP_MT_proxy, CLIP_MT_reconstruction, - CLIP_MT_track_visibility, + CLIP_MT_track, CLIP_MT_track_transform, + CLIP_MT_track_motion, + CLIP_MT_track_clear, + CLIP_MT_track_refine, + CLIP_MT_track_animation, + CLIP_MT_track_visibility, + CLIP_MT_track_cleanup, CLIP_MT_select, CLIP_MT_select_grouped, CLIP_MT_tracking_context_menu, diff --git a/source/blender/blenkernel/BKE_cryptomatte.hh b/source/blender/blenkernel/BKE_cryptomatte.hh new file mode 100644 index 00000000000..892f228187e --- /dev/null +++ b/source/blender/blenkernel/BKE_cryptomatte.hh @@ -0,0 +1,59 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup bke + */ + +#pragma once + +#include <string> + +#include "BLI_string_ref.hh" + +namespace blender { + +/* Format to a cryptomatte meta data key. + * + * Cryptomatte stores meta data. The keys are formatted containing a hash that + * is generated from its layer name. + * + * The output of this function is: + * 'cryptomatte/{hash of layer_name}/{key_name}'. + */ +std::string BKE_cryptomatte_meta_data_key(const StringRef layer_name, + const StringRefNull key_name); + +/* Extract the cryptomatte layer name from the given `render_pass_name`. + * + * Cryptomatte passes are formatted with a trailing number for storing multiple samples that belong + * to the same cryptomatte layer. This function would remove the trailing numbers to determine the + * cryptomatte layer name. + * + * # Example + * + * A render_pass_name could be 'View Layer.CryptoMaterial02'. The cryptomatte layer would be 'View + * Layer.CryptoMaterial'. + * + * NOTE: The return type is a substring of `render_pass_name` and therefore cannot outlive the + * `render_pass_name` internal data. + */ +StringRef BKE_cryptomatte_extract_layer_name(const StringRef render_pass_name); + +} // namespace blender diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 574d70bf456..5021736dbfe 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -731,6 +731,7 @@ add_dependencies(bf_blenkernel bf_dna) if(WITH_GTESTS) set(TEST_SRC intern/armature_test.cc + intern/cryptomatte_test.cc intern/fcurve_test.cc intern/lattice_deform_test.cc intern/layer_test.cc diff --git a/source/blender/blenkernel/intern/cryptomatte.cc b/source/blender/blenkernel/intern/cryptomatte.cc index 1dd71dacc46..7ddc1474e09 100644 --- a/source/blender/blenkernel/intern/cryptomatte.cc +++ b/source/blender/blenkernel/intern/cryptomatte.cc @@ -22,6 +22,7 @@ */ #include "BKE_cryptomatte.h" +#include "BKE_cryptomatte.hh" #include "BKE_image.h" #include "BKE_main.h" @@ -43,6 +44,7 @@ #include <iomanip> #include <sstream> #include <string> +#include <string_view> enum CryptomatteLayerState { EMPTY, @@ -299,15 +301,15 @@ static uint32_t cryptomatte_determine_identifier(const std::string name) return BLI_hash_mm3(reinterpret_cast<const unsigned char *>(name.c_str()), name.length(), 0); } -static std::string cryptomatte_determine_prefix(const std::string name) +static void add_render_result_meta_data(RenderResult *render_result, + const blender::StringRef layer_name, + const blender::StringRefNull key_name, + const blender::StringRefNull value) { - std::stringstream stream; - const uint32_t render_pass_identifier = cryptomatte_determine_identifier(name); - stream << "cryptomatte/"; - stream << std::setfill('0') << std::setw(sizeof(uint32_t) * 2) << std::hex - << render_pass_identifier; - stream << "/"; - return stream.str(); + BKE_render_result_stamp_data( + render_result, + blender::BKE_cryptomatte_meta_data_key(layer_name, key_name).c_str(), + value.data()); } void BKE_cryptomatte_store_metadata(struct CryptomatteSession *session, @@ -335,12 +337,47 @@ void BKE_cryptomatte_store_metadata(struct CryptomatteSession *session, const std::string manifest = layer->manifest_get_string(); const std::string name = cryptomatte_determine_name(view_layer, cryptomatte_layer_name); - const std::string prefix = cryptomatte_determine_prefix(name); /* Store the meta data into the render result. */ - BKE_render_result_stamp_data(render_result, (prefix + "name").c_str(), name.c_str()); - BKE_render_result_stamp_data(render_result, (prefix + "hash").c_str(), "MurmurHash3_32"); - BKE_render_result_stamp_data( - render_result, (prefix + "conversion").c_str(), "uint32_to_float32"); - BKE_render_result_stamp_data(render_result, (prefix + "manifest").c_str(), manifest.c_str()); + add_render_result_meta_data(render_result, name, "name", name); + add_render_result_meta_data(render_result, name, "hash", "MurmurHash3_32"); + add_render_result_meta_data(render_result, name, "conversion", "uint32_to_float32"); + add_render_result_meta_data(render_result, name, "manifest", manifest); +} + +namespace blender { + +/* Return the hash of the given cryptomatte layer name. + * + * The cryptomatte specification limits the hash to 7 characters. + * The 7 position limitation solves issues when using cryptomatte together with OpenEXR. + * The specification suggests to use the first 7 chars of the hashed layer_name. + */ +static std::string cryptomatte_layer_name_hash(const StringRef layer_name) +{ + std::stringstream stream; + const uint32_t render_pass_identifier = cryptomatte_determine_identifier(layer_name); + stream << std::setfill('0') << std::setw(sizeof(uint32_t) * 2) << std::hex + << render_pass_identifier; + return stream.str().substr(0, 7); +} + +std::string BKE_cryptomatte_meta_data_key(const StringRef layer_name, const StringRefNull key_name) +{ + return "cryptomatte/" + cryptomatte_layer_name_hash(layer_name) + "/" + key_name; } + +/* Extracts the cryptomatte name from a render pass name. + * + * Example: A render pass could be named `CryptoObject00`. This + * function would remove the trailing digits and return `CryptoObject`. */ +StringRef BKE_cryptomatte_extract_layer_name(const StringRef render_pass_name) +{ + int64_t last_token = render_pass_name.size(); + while (last_token > 0 && std::isdigit(render_pass_name[last_token - 1])) { + last_token -= 1; + } + return render_pass_name.substr(0, last_token); +} + +} // namespace blender diff --git a/source/blender/blenkernel/intern/cryptomatte_test.cc b/source/blender/blenkernel/intern/cryptomatte_test.cc new file mode 100644 index 00000000000..3773b2b3bf9 --- /dev/null +++ b/source/blender/blenkernel/intern/cryptomatte_test.cc @@ -0,0 +1,44 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 by Blender Foundation. + */ +#include "testing/testing.h" + +#include "BKE_cryptomatte.hh" + +namespace blender::bke::tests { + +TEST(cryptomatte, meta_data_key) +{ + ASSERT_EQ("cryptomatte/c7dbf5e/key", + BKE_cryptomatte_meta_data_key("ViewLayer.CryptoMaterial", "key")); + ASSERT_EQ("cryptomatte/b990b65/𝓴𝓮𝔂", + BKE_cryptomatte_meta_data_key("𝖚𝖓𝖎𝖈𝖔𝖉𝖊.CryptoMaterial", "𝓴𝓮𝔂")); +} + +TEST(cryptomatte, extract_layer_name) +{ + ASSERT_EQ("ViewLayer.CryptoMaterial", + BKE_cryptomatte_extract_layer_name("ViewLayer.CryptoMaterial00")); + ASSERT_EQ("𝖚𝖓𝖎𝖈𝖔𝖉𝖊", BKE_cryptomatte_extract_layer_name("𝖚𝖓𝖎𝖈𝖔𝖉𝖊13")); + ASSERT_EQ("NoTrailingSampleNumber", + BKE_cryptomatte_extract_layer_name("NoTrailingSampleNumber")); + ASSERT_EQ("W1thM1dd13Numb3rs", BKE_cryptomatte_extract_layer_name("W1thM1dd13Numb3rs09")); + ASSERT_EQ("", BKE_cryptomatte_extract_layer_name("0123")); + ASSERT_EQ("", BKE_cryptomatte_extract_layer_name("")); +} + +} // namespace blender::bke::tests diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt index 19eeb90c822..a226b009ec9 100644 --- a/source/blender/compositor/CMakeLists.txt +++ b/source/blender/compositor/CMakeLists.txt @@ -71,6 +71,8 @@ set(SRC intern/COM_MemoryBuffer.h intern/COM_MemoryProxy.cpp intern/COM_MemoryProxy.h + intern/COM_MetaData.cpp + intern/COM_MetaData.h intern/COM_Node.cpp intern/COM_Node.h intern/COM_NodeConverter.cpp diff --git a/source/blender/compositor/intern/COM_MetaData.cpp b/source/blender/compositor/intern/COM_MetaData.cpp new file mode 100644 index 00000000000..2b75947ff89 --- /dev/null +++ b/source/blender/compositor/intern/COM_MetaData.cpp @@ -0,0 +1,71 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2021, Blender Foundation. + */ + +#include "COM_MetaData.h" + +#include "BKE_cryptomatte.hh" +#include "BKE_image.h" + +#include "RE_pipeline.h" + +#include <string_view> + +void MetaData::add(const blender::StringRef key, const blender::StringRef value) +{ + entries_.add(key, value); +} + +void MetaData::addCryptomatteEntry(const blender::StringRef layer_name, + const blender::StringRefNull key, + const blender::StringRef value) +{ + add(blender::BKE_cryptomatte_meta_data_key(layer_name, key), value); +} + +/* Replace the hash neutral cryptomatte keys with hashed versions. + * + * When a conversion happens it will also add the cryptomatte name key with the given + * `layer_name`.*/ +void MetaData::replaceHashNeutralCryptomatteKeys(const blender::StringRef layer_name) +{ + std::string cryptomatte_hash = entries_.pop_default(META_DATA_KEY_CRYPTOMATTE_HASH, ""); + std::string cryptomatte_conversion = entries_.pop_default(META_DATA_KEY_CRYPTOMATTE_CONVERSION, + ""); + std::string cryptomatte_manifest = entries_.pop_default(META_DATA_KEY_CRYPTOMATTE_MANIFEST, ""); + + if (cryptomatte_hash.length() || cryptomatte_conversion.length() || + cryptomatte_manifest.length()) { + addCryptomatteEntry(layer_name, "name", layer_name); + } + if (cryptomatte_hash.length()) { + addCryptomatteEntry(layer_name, "hash", cryptomatte_hash); + } + if (cryptomatte_conversion.length()) { + addCryptomatteEntry(layer_name, "conversion", cryptomatte_conversion); + } + if (cryptomatte_manifest.length()) { + addCryptomatteEntry(layer_name, "manifest", cryptomatte_manifest); + } +} + +void MetaData::addToRenderResult(RenderResult *render_result) const +{ + for (blender::Map<std::string, std::string>::Item entry : entries_.items()) { + BKE_render_result_stamp_data(render_result, entry.key.c_str(), entry.value.c_str()); + } +} diff --git a/source/blender/compositor/intern/COM_MetaData.h b/source/blender/compositor/intern/COM_MetaData.h new file mode 100644 index 00000000000..22988b0b7ee --- /dev/null +++ b/source/blender/compositor/intern/COM_MetaData.h @@ -0,0 +1,56 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2021, Blender Foundation. + */ + +#pragma once + +#include <string> + +#include "BLI_map.hh" + +#include "MEM_guardedalloc.h" + +/* Forward declarations. */ +struct StampData; +struct RenderResult; + +/* Cryptomatte includes hash in its meta data keys. The hash is generated from the render + * layer/pass name. Compositing happens without the knowledge of the original layer and pass. The + * next keys are used to transfer the cryptomatte meta data in a neutral way. The file output node + * will generate a hash based on the layer name configured by the user. + * + * The `{hash}` has no special meaning except to make sure that the meta data stays unique. */ +constexpr blender::StringRef META_DATA_KEY_CRYPTOMATTE_HASH("cryptomatte/{hash}/hash"); +constexpr blender::StringRef META_DATA_KEY_CRYPTOMATTE_CONVERSION("cryptomatte/{hash}/conversion"); +constexpr blender::StringRef META_DATA_KEY_CRYPTOMATTE_MANIFEST("cryptomatte/{hash}/manifest"); +constexpr blender::StringRef META_DATA_KEY_CRYPTOMATTE_NAME("cryptomatte/{hash}/name"); + +class MetaData { + private: + blender::Map<std::string, std::string> entries_; + void addCryptomatteEntry(const blender::StringRef layer_name, + const blender::StringRefNull key, + const blender::StringRef value); + + public: + void add(const blender::StringRef key, const blender::StringRef value); + void replaceHashNeutralCryptomatteKeys(const blender::StringRef layer_name); + void addToRenderResult(RenderResult *render_result) const; +#ifdef WITH_CXX_GUARDEDALLOC + MEM_CXX_CLASS_ALLOC_FUNCS("COM:MetaData") +#endif +}; diff --git a/source/blender/compositor/intern/COM_SocketReader.h b/source/blender/compositor/intern/COM_SocketReader.h index ee2a6e0e1bf..7c4132efe60 100644 --- a/source/blender/compositor/intern/COM_SocketReader.h +++ b/source/blender/compositor/intern/COM_SocketReader.h @@ -19,8 +19,12 @@ #pragma once #include "BLI_rect.h" +#include "COM_MetaData.h" #include "COM_defines.h" +#include <memory> +#include <optional> + #ifdef WITH_CXX_GUARDEDALLOC # include "MEM_guardedalloc.h" #endif @@ -32,6 +36,7 @@ typedef enum PixelSampler { } PixelSampler; class MemoryBuffer; + /** * \brief Helper class for reading socket data. * Only use this class for dispatching (un-ary and n-ary) executions. @@ -134,6 +139,14 @@ class SocketReader { return this->m_height; } + /* Return the meta data associated with this branch. + * + * The return parameter holds an instance or is an nullptr. */ + virtual std::unique_ptr<MetaData> getMetaData() const + { + return std::unique_ptr<MetaData>(); + } + #ifdef WITH_CXX_GUARDEDALLOC MEM_CXX_CLASS_ALLOC_FUNCS("COM:SocketReader") #endif diff --git a/source/blender/compositor/nodes/COM_OutputFileNode.cpp b/source/blender/compositor/nodes/COM_OutputFileNode.cpp index 09528e09f1f..e0cff1de276 100644 --- a/source/blender/compositor/nodes/COM_OutputFileNode.cpp +++ b/source/blender/compositor/nodes/COM_OutputFileNode.cpp @@ -50,7 +50,8 @@ void OutputFileNode::convertToOperations(NodeConverter &converter, OutputOpenExrMultiLayerOperation *outputOperation; if (is_multiview && storage->format.views_format == R_IMF_VIEWS_MULTIVIEW) { - outputOperation = new OutputOpenExrMultiLayerMultiViewOperation(context.getRenderData(), + outputOperation = new OutputOpenExrMultiLayerMultiViewOperation(context.getScene(), + context.getRenderData(), context.getbNodeTree(), storage->base_path, storage->format.exr_codec, @@ -58,7 +59,8 @@ void OutputFileNode::convertToOperations(NodeConverter &converter, context.getViewName()); } else { - outputOperation = new OutputOpenExrMultiLayerOperation(context.getRenderData(), + outputOperation = new OutputOpenExrMultiLayerOperation(context.getScene(), + context.getRenderData(), context.getbNodeTree(), storage->base_path, storage->format.exr_codec, diff --git a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp index 21d9177ddd5..0b732357c92 100644 --- a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp +++ b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp @@ -143,13 +143,14 @@ void OutputOpenExrSingleLayerMultiViewOperation::deinitExecution() /************************************ OpenEXR Multilayer Multiview *******************************/ OutputOpenExrMultiLayerMultiViewOperation::OutputOpenExrMultiLayerMultiViewOperation( + const Scene *scene, const RenderData *rd, const bNodeTree *tree, const char *path, char exr_codec, bool exr_half_float, const char *viewName) - : OutputOpenExrMultiLayerOperation(rd, tree, path, exr_codec, exr_half_float, viewName) + : OutputOpenExrMultiLayerOperation(scene, rd, tree, path, exr_codec, exr_half_float, viewName) { } @@ -195,12 +196,16 @@ void *OutputOpenExrMultiLayerMultiViewOperation::get_handle(const char *filename BLI_make_existing_file(filename); /* prepare the file with all the channels for the header */ - if (IMB_exr_begin_write(exrhandle, filename, width, height, this->m_exr_codec, nullptr) == 0) { + StampData *stamp_data = createStampData(); + if (IMB_exr_begin_write(exrhandle, filename, width, height, this->m_exr_codec, stamp_data) == + 0) { printf("Error Writing Multilayer Multiview Openexr\n"); IMB_exr_close(exrhandle); + BKE_stamp_data_free(stamp_data); } else { IMB_exr_clear_channels(exrhandle); + BKE_stamp_data_free(stamp_data); return exrhandle; } } diff --git a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h index 1deaf121173..bc057355cef 100644 --- a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h +++ b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h @@ -48,7 +48,8 @@ class OutputOpenExrSingleLayerMultiViewOperation : public OutputSingleLayerOpera class OutputOpenExrMultiLayerMultiViewOperation : public OutputOpenExrMultiLayerOperation { private: public: - OutputOpenExrMultiLayerMultiViewOperation(const RenderData *rd, + OutputOpenExrMultiLayerMultiViewOperation(const Scene *scene, + const RenderData *rd, const bNodeTree *tree, const char *path, char exr_codec, diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.cpp b/source/blender/compositor/operations/COM_OutputFileOperation.cpp index 2676ab1b9ca..216b754f676 100644 --- a/source/blender/compositor/operations/COM_OutputFileOperation.cpp +++ b/source/blender/compositor/operations/COM_OutputFileOperation.cpp @@ -18,12 +18,15 @@ #include "COM_OutputFileOperation.h" +#include "COM_MetaData.h" + #include <cstring> #include "BLI_listbase.h" #include "BLI_path_util.h" #include "BLI_string.h" +#include "BKE_cryptomatte.hh" #include "BKE_global.h" #include "BKE_image.h" #include "BKE_main.h" @@ -36,6 +39,8 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" +#include "RE_pipeline.h" + void add_exr_channels(void *exrhandle, const char *layerName, const DataType datatype, @@ -299,13 +304,15 @@ OutputOpenExrLayer::OutputOpenExrLayer(const char *name_, DataType datatype_, bo this->imageInput = nullptr; } -OutputOpenExrMultiLayerOperation::OutputOpenExrMultiLayerOperation(const RenderData *rd, +OutputOpenExrMultiLayerOperation::OutputOpenExrMultiLayerOperation(const Scene *scene, + const RenderData *rd, const bNodeTree *tree, const char *path, char exr_codec, bool exr_half_float, const char *viewName) { + this->m_scene = scene; this->m_rd = rd; this->m_tree = tree; @@ -323,6 +330,26 @@ void OutputOpenExrMultiLayerOperation::add_layer(const char *name, this->m_layers.push_back(OutputOpenExrLayer(name, datatype, use_layer)); } +StampData *OutputOpenExrMultiLayerOperation::createStampData() const +{ + /* StampData API doesn't provide functions to modify an instance without having a RenderResult. + */ + RenderResult render_result; + StampData *stamp_data = BKE_stamp_info_from_scene_static(m_scene); + render_result.stamp_data = stamp_data; + for (int i = 0; i < this->m_layers.size(); i++) { + const OutputOpenExrLayer *layer = &this->m_layers[i]; + std::unique_ptr<MetaData> meta_data = layer->imageInput->getMetaData(); + if (meta_data) { + blender::StringRef layer_name = blender::BKE_cryptomatte_extract_layer_name( + blender::StringRef(layer->name, BLI_strnlen(layer->name, sizeof(layer->name)))); + meta_data->replaceHashNeutralCryptomatteKeys(layer_name); + meta_data->addToRenderResult(&render_result); + } + } + return stamp_data; +} + void OutputOpenExrMultiLayerOperation::initExecution() { for (unsigned int i = 0; i < this->m_layers.size(); i++) { @@ -386,7 +413,8 @@ void OutputOpenExrMultiLayerOperation::deinitExecution() } /* when the filename has no permissions, this can fail */ - if (IMB_exr_begin_write(exrhandle, filename, width, height, this->m_exr_codec, nullptr)) { + StampData *stamp_data = createStampData(); + if (IMB_exr_begin_write(exrhandle, filename, width, height, this->m_exr_codec, stamp_data)) { IMB_exr_write_channels(exrhandle); } else { @@ -404,5 +432,6 @@ void OutputOpenExrMultiLayerOperation::deinitExecution() this->m_layers[i].imageInput = nullptr; } + BKE_stamp_data_free(stamp_data); } } diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.h b/source/blender/compositor/operations/COM_OutputFileOperation.h index b2454e17e3f..915d59599e2 100644 --- a/source/blender/compositor/operations/COM_OutputFileOperation.h +++ b/source/blender/compositor/operations/COM_OutputFileOperation.h @@ -91,6 +91,7 @@ class OutputOpenExrMultiLayerOperation : public NodeOperation { protected: typedef std::vector<OutputOpenExrLayer> LayerList; + const Scene *m_scene; const RenderData *m_rd; const bNodeTree *m_tree; @@ -100,8 +101,11 @@ class OutputOpenExrMultiLayerOperation : public NodeOperation { LayerList m_layers; const char *m_viewName; + StampData *createStampData() const; + public: - OutputOpenExrMultiLayerOperation(const RenderData *rd, + OutputOpenExrMultiLayerOperation(const Scene *scene, + const RenderData *rd, const bNodeTree *tree, const char *path, char exr_codec, diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.cpp b/source/blender/compositor/operations/COM_RenderLayersProg.cpp index 11f64aa4d6a..2a0a6e33b6a 100644 --- a/source/blender/compositor/operations/COM_RenderLayersProg.cpp +++ b/source/blender/compositor/operations/COM_RenderLayersProg.cpp @@ -18,8 +18,16 @@ #include "COM_RenderLayersProg.h" +#include "COM_MetaData.h" + +#include "BKE_cryptomatte.hh" +#include "BKE_image.h" #include "BKE_scene.h" + #include "BLI_listbase.h" +#include "BLI_string.h" +#include "BLI_string_ref.hh" + #include "DNA_scene_types.h" #include "RE_pipeline.h" @@ -209,6 +217,82 @@ void RenderLayersProg::determineResolution(unsigned int resolution[2], } } +struct CallbackData { + std::unique_ptr<MetaData> meta_data; + std::string hash_key; + std::string conversion_key; + std::string manifest_key; + + void addMetaData(blender::StringRef key, blender::StringRefNull value) + { + if (!meta_data) { + meta_data = std::make_unique<MetaData>(); + } + meta_data->add(key, value); + } + + void setCryptomatteKeys(blender::StringRef cryptomatte_layer_name) + { + manifest_key = blender::BKE_cryptomatte_meta_data_key(cryptomatte_layer_name, "manifest"); + hash_key = blender::BKE_cryptomatte_meta_data_key(cryptomatte_layer_name, "hash"); + conversion_key = blender::BKE_cryptomatte_meta_data_key(cryptomatte_layer_name, "conversion"); + } +}; + +/* C type callback function (StampCallback). */ +static void extract_cryptomatte_meta_data(void *_data, + const char *propname, + char *propvalue, + int UNUSED(len)) +{ + CallbackData *data = static_cast<CallbackData *>(_data); + blender::StringRefNull key(propname); + if (key == data->hash_key) { + data->addMetaData(META_DATA_KEY_CRYPTOMATTE_HASH, propvalue); + } + else if (key == data->conversion_key) { + data->addMetaData(META_DATA_KEY_CRYPTOMATTE_CONVERSION, propvalue); + } + else if (key == data->manifest_key) { + data->addMetaData(META_DATA_KEY_CRYPTOMATTE_MANIFEST, propvalue); + } +} + +std::unique_ptr<MetaData> RenderLayersProg::getMetaData() const +{ + Scene *scene = this->getScene(); + Render *re = (scene) ? RE_GetSceneRender(scene) : nullptr; + RenderResult *rr = nullptr; + CallbackData callback_data = {nullptr}; + + if (re) { + rr = RE_AcquireResultRead(re); + } + + if (rr && rr->stamp_data) { + ViewLayer *view_layer = (ViewLayer *)BLI_findlink(&scene->view_layers, getLayerId()); + if (view_layer) { + std::string full_layer_name = std::string( + view_layer->name, + BLI_strnlen(view_layer->name, sizeof(view_layer->name))) + + "." + m_passName; + blender::StringRef cryptomatte_layer_name = blender::BKE_cryptomatte_extract_layer_name( + full_layer_name); + callback_data.setCryptomatteKeys(cryptomatte_layer_name); + + BKE_stamp_info_callback( + &callback_data, rr->stamp_data, extract_cryptomatte_meta_data, false); + } + } + + if (re) { + RE_ReleaseResult(re); + re = nullptr; + } + + return std::move(callback_data.meta_data); +} + /* ******** Render Layers AO Operation ******** */ void RenderLayersAOOperation::executePixelSampled(float output[4], float x, diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.h b/source/blender/compositor/operations/COM_RenderLayersProg.h index abfcac1f80d..ec98969b223 100644 --- a/source/blender/compositor/operations/COM_RenderLayersProg.h +++ b/source/blender/compositor/operations/COM_RenderLayersProg.h @@ -121,6 +121,8 @@ class RenderLayersProg : public NodeOperation { void initExecution(); void deinitExecution(); void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + + std::unique_ptr<MetaData> getMetaData() const override; }; class RenderLayersAOOperation : public RenderLayersProg { diff --git a/source/blender/compositor/operations/COM_SocketProxyOperation.cpp b/source/blender/compositor/operations/COM_SocketProxyOperation.cpp index baeb2f44303..53f5fea8795 100644 --- a/source/blender/compositor/operations/COM_SocketProxyOperation.cpp +++ b/source/blender/compositor/operations/COM_SocketProxyOperation.cpp @@ -24,3 +24,8 @@ SocketProxyOperation::SocketProxyOperation(DataType type, bool use_conversion) this->addInputSocket(type); this->addOutputSocket(type); } + +std::unique_ptr<MetaData> SocketProxyOperation::getMetaData() const +{ + return this->getInputSocket(0)->getReader()->getMetaData(); +} diff --git a/source/blender/compositor/operations/COM_SocketProxyOperation.h b/source/blender/compositor/operations/COM_SocketProxyOperation.h index 22c144598f6..435083f5008 100644 --- a/source/blender/compositor/operations/COM_SocketProxyOperation.h +++ b/source/blender/compositor/operations/COM_SocketProxyOperation.h @@ -41,6 +41,7 @@ class SocketProxyOperation : public NodeOperation { { m_use_conversion = use_conversion; } + std::unique_ptr<MetaData> getMetaData() const override; private: bool m_use_conversion; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index eb20dfb69a2..dcdf2f48607 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -83,6 +83,7 @@ #include "BKE_key.h" #include "BKE_lattice.h" #include "BKE_layer.h" +#include "BKE_lib_id.h" #include "BKE_light.h" #include "BKE_mask.h" #include "BKE_material.h" @@ -152,12 +153,14 @@ DepsgraphNodeBuilder::~DepsgraphNodeBuilder() IDNode *DepsgraphNodeBuilder::add_id_node(ID *id) { + BLI_assert(id->session_uuid != MAIN_ID_SESSION_UUID_UNSET); + IDNode *id_node = nullptr; ID *id_cow = nullptr; IDComponentsMask previously_visible_components_mask = 0; uint32_t previous_eval_flags = 0; DEGCustomDataMeshMasks previous_customdata_masks; - IDInfo *id_info = id_info_hash_.lookup_default(id, nullptr); + IDInfo *id_info = id_info_hash_.lookup_default(id->session_uuid, nullptr); if (id_info != nullptr) { id_cow = id_info->id_cow; previously_visible_components_mask = id_info->previously_visible_components_mask; @@ -334,7 +337,8 @@ void DepsgraphNodeBuilder::begin_build() id_info->previously_visible_components_mask = id_node->visible_components_mask; id_info->previous_eval_flags = id_node->eval_flags; id_info->previous_customdata_masks = id_node->customdata_masks; - id_info_hash_.add_new(id_node->id_orig, id_info); + BLI_assert(!id_info_hash_.contains(id_node->id_orig_session_uuid)); + id_info_hash_.add_new(id_node->id_orig_session_uuid, id_info); id_node->id_cow = nullptr; } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h index 6f7a8b1c6b5..174f9b129f9 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h @@ -285,8 +285,8 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder { * very root is visible (aka not restricted.). */ bool is_parent_collection_visible_; - /* Indexed by original ID, values are IDInfo. */ - Map<const ID *, IDInfo *> id_info_hash_; + /* Indexed by original ID.session_uuid, values are IDInfo. */ + Map<uint, IDInfo *> id_info_hash_; /* Set of IDs which were already build. Makes it easier to keep track of * what was already built and what was not. */ diff --git a/source/blender/depsgraph/intern/node/deg_node_id.cc b/source/blender/depsgraph/intern/node/deg_node_id.cc index 4f2fcab5823..8e159a7ff08 100644 --- a/source/blender/depsgraph/intern/node/deg_node_id.cc +++ b/source/blender/depsgraph/intern/node/deg_node_id.cc @@ -80,6 +80,7 @@ void IDNode::init(const ID *id, const char *UNUSED(subdata)) /* Store ID-pointer. */ id_type = GS(id->name); id_orig = (ID *)id; + id_orig_session_uuid = id->session_uuid; eval_flags = 0; previous_eval_flags = 0; customdata_masks = DEGCustomDataMeshMasks(); diff --git a/source/blender/depsgraph/intern/node/deg_node_id.h b/source/blender/depsgraph/intern/node/deg_node_id.h index 04a9006ac10..c4d36685bb8 100644 --- a/source/blender/depsgraph/intern/node/deg_node_id.h +++ b/source/blender/depsgraph/intern/node/deg_node_id.h @@ -74,12 +74,22 @@ struct IDNode : public Node { IDComponentsMask get_visible_components_mask() const; - /* ID Block referenced. */ /* Type of the ID stored separately, so it's possible to perform check whether CoW is needed * without de-referencing the id_cow (which is not safe when ID is NOT covered by CoW and has * been deleted from the main database.) */ ID_Type id_type; + + /* ID Block referenced. */ ID *id_orig; + + /* Session-wide UUID of the id_orig. + * Is used on relations update to map evaluated state from old nodes to the new ones, without + * relying on pointers (which are not guaranteed to be unique) and without dereferencing id_orig + * which could be "stale" pointer. */ + uint id_orig_session_uuid; + + /* Evaluated datablock. + * Will be covered by the copy-on-write system if the ID Type needs it. */ ID *id_cow; /* Hash to make it faster to look up components. */ diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index 6cb829d3a23..05cbb3ef48f 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -892,7 +892,7 @@ static void acf_group_name(bAnimListElem *ale, char *name) /* name property for group entries */ static bool acf_group_name_prop(bAnimListElem *ale, PointerRNA *ptr, PropertyRNA **prop) { - RNA_pointer_create(ale->id, &RNA_ActionGroup, ale->data, ptr); + RNA_pointer_create(ale->fcurve_owner_id, &RNA_ActionGroup, ale->data, ptr); *prop = RNA_struct_name_property(ptr->type); return (*prop != NULL); @@ -1013,7 +1013,7 @@ static bool acf_fcurve_name_prop(bAnimListElem *ale, PointerRNA *ptr, PropertyRN * as our "name" so that user can perform quick fixes */ if (fcu->flag & FCURVE_DISABLED) { - RNA_pointer_create(ale->id, &RNA_FCurve, ale->data, ptr); + RNA_pointer_create(ale->fcurve_owner_id, &RNA_FCurve, ale->data, ptr); *prop = RNA_struct_find_property(ptr, "data_path"); } else { @@ -3965,7 +3965,7 @@ static void acf_nlaaction_name(bAnimListElem *ale, char *name) static bool acf_nlaaction_name_prop(bAnimListElem *ale, PointerRNA *ptr, PropertyRNA **prop) { if (ale->data) { - RNA_pointer_create(ale->id, &RNA_Action, ale->data, ptr); + RNA_pointer_create(ale->fcurve_owner_id, &RNA_Action, ale->data, ptr); *prop = RNA_struct_name_property(ptr->type); return (*prop != NULL); diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c index 920f1d346b9..51be5afafe5 100644 --- a/source/blender/editors/space_graph/graph_buttons.c +++ b/source/blender/editors/space_graph/graph_buttons.c @@ -181,7 +181,7 @@ static void graph_panel_properties(const bContext *C, Panel *panel) } /* F-Curve pointer */ - RNA_pointer_create(ale->id, &RNA_FCurve, fcu, &fcu_ptr); + RNA_pointer_create(ale->fcurve_owner_id, &RNA_FCurve, fcu, &fcu_ptr); /* user-friendly 'name' for F-Curve */ col = uiLayoutColumn(layout, false); @@ -366,7 +366,7 @@ static void graph_panel_key_properties(const bContext *C, Panel *panel) int unit = B_UNIT_NONE; /* RNA pointer to keyframe, to allow editing */ - RNA_pointer_create(ale->id, &RNA_Keyframe, bezt, &bezt_ptr); + RNA_pointer_create(ale->fcurve_owner_id, &RNA_Keyframe, bezt, &bezt_ptr); /* get property that F-Curve affects, for some unit-conversion magic */ RNA_id_pointer_create(ale->id, &id_ptr); diff --git a/source/blender/gpu/opengl/gl_backend.cc b/source/blender/gpu/opengl/gl_backend.cc index 5c43a8990d7..29ff1b3e81a 100644 --- a/source/blender/gpu/opengl/gl_backend.cc +++ b/source/blender/gpu/opengl/gl_backend.cc @@ -159,11 +159,6 @@ void GLBackend::platform_init() GPG.support_level = GPU_SUPPORT_LEVEL_LIMITED; } } - if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_OFFICIAL)) { - if (is_faulty_T82856_platform(version, renderer)) { - GPG.support_level = GPU_SUPPORT_LEVEL_LIMITED; - } - } } GPG.create_key(GPG.support_level, vendor, renderer, version); GPG.create_gpu_name(vendor, renderer, version); diff --git a/source/blender/imbuf/intern/IMB_indexer.h b/source/blender/imbuf/intern/IMB_indexer.h index 07c47965262..363ad45e0e6 100644 --- a/source/blender/imbuf/intern/IMB_indexer.h +++ b/source/blender/imbuf/intern/IMB_indexer.h @@ -48,9 +48,9 @@ typedef struct anim_index_entry { int frameno; - unsigned long long seek_pos; - unsigned long long seek_pos_dts; - unsigned long long pts; + uint64_t seek_pos; + uint64_t seek_pos_dts; + uint64_t pts; } anim_index_entry; struct anim_index { @@ -77,28 +77,25 @@ typedef struct anim_index_builder { } anim_index_builder; anim_index_builder *IMB_index_builder_create(const char *name); -void IMB_index_builder_add_entry(anim_index_builder *fp, - int frameno, - unsigned long long seek_pos, - unsigned long long seek_pos_dts, - unsigned long long pts); +void IMB_index_builder_add_entry( + anim_index_builder *fp, int frameno, uint64_t seek_pos, uint64_t seek_pos_dts, uint64_t pts); void IMB_index_builder_proc_frame(anim_index_builder *fp, unsigned char *buffer, int data_size, int frameno, - unsigned long long seek_pos, - unsigned long long seek_pos_dts, - unsigned long long pts); + uint64_t seek_pos, + uint64_t seek_pos_dts, + uint64_t pts); void IMB_index_builder_finish(anim_index_builder *fp, int rollback); struct anim_index *IMB_indexer_open(const char *name); -unsigned long long IMB_indexer_get_seek_pos(struct anim_index *idx, int frame_index); -unsigned long long IMB_indexer_get_seek_pos_dts(struct anim_index *idx, int frame_index); +uint64_t IMB_indexer_get_seek_pos(struct anim_index *idx, int frame_index); +uint64_t IMB_indexer_get_seek_pos_dts(struct anim_index *idx, int frame_index); int IMB_indexer_get_frame_index(struct anim_index *idx, int frameno); -unsigned long long IMB_indexer_get_pts(struct anim_index *idx, int frame_index); +uint64_t IMB_indexer_get_pts(struct anim_index *idx, int frame_index); int IMB_indexer_get_duration(struct anim_index *idx); int IMB_indexer_can_scan(struct anim_index *idx, int old_frame_index, int new_frame_index); diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c index 9b01ea0840f..c40e65b1c5c 100644 --- a/source/blender/imbuf/intern/anim_movie.c +++ b/source/blender/imbuf/intern/anim_movie.c @@ -892,13 +892,12 @@ static int ffmpeg_decode_video_frame(struct anim *anim) while ((rval = av_read_frame(anim->pFormatCtx, &anim->next_packet)) >= 0) { av_log(anim->pFormatCtx, AV_LOG_DEBUG, - "%sREAD: strID=%d (VID: %d) dts=%lld pts=%lld " - "%s\n", + "%sREAD: strID=%d (VID: %d) dts=%" PRId64 " pts=%" PRId64 " %s\n", (anim->next_packet.stream_index == anim->videoStream) ? "->" : " ", anim->next_packet.stream_index, anim->videoStream, - (anim->next_packet.dts == AV_NOPTS_VALUE) ? -1 : (long long int)anim->next_packet.dts, - (anim->next_packet.pts == AV_NOPTS_VALUE) ? -1 : (long long int)anim->next_packet.pts, + (anim->next_packet.dts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->next_packet.dts, + (anim->next_packet.pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->next_packet.pts, (anim->next_packet.flags & AV_PKT_FLAG_KEY) ? " KEY" : ""); if (anim->next_packet.stream_index == anim->videoStream) { anim->pFrameComplete = 0; @@ -911,12 +910,10 @@ static int ffmpeg_decode_video_frame(struct anim *anim) av_log(anim->pFormatCtx, AV_LOG_DEBUG, - " FRAME DONE: next_pts=%lld " - "pkt_pts=%lld, guessed_pts=%lld\n", - (anim->pFrame->pts == AV_NOPTS_VALUE) ? -1 : (long long int)anim->pFrame->pts, - (anim->pFrame->pkt_pts == AV_NOPTS_VALUE) ? -1 : - (long long int)anim->pFrame->pkt_pts, - (long long int)anim->next_pts); + " FRAME DONE: next_pts=%" PRId64 " pkt_pts=%" PRId64 ", guessed_pts=%" PRId64 "\n", + (anim->pFrame->pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->pFrame->pts, + (anim->pFrame->pkt_pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->pFrame->pkt_pts, + (int64_t)anim->next_pts); break; } } @@ -946,11 +943,11 @@ static int ffmpeg_decode_video_frame(struct anim *anim) av_log(anim->pFormatCtx, AV_LOG_DEBUG, - " FRAME DONE (after EOF): next_pts=%lld " - "pkt_pts=%lld, guessed_pts=%lld\n", - (anim->pFrame->pts == AV_NOPTS_VALUE) ? -1 : (long long int)anim->pFrame->pts, - (anim->pFrame->pkt_pts == AV_NOPTS_VALUE) ? -1 : (long long int)anim->pFrame->pkt_pts, - (long long int)anim->next_pts); + " FRAME DONE (after EOF): next_pts=%" PRId64 " pkt_pts=%" PRId64 + ", guessed_pts=%" PRId64 "\n", + (anim->pFrame->pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->pFrame->pts, + (anim->pFrame->pkt_pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->pFrame->pkt_pts, + (int64_t)anim->next_pts); rval = 0; } } @@ -975,16 +972,16 @@ static void ffmpeg_decode_video_frame_scan(struct anim *anim, int64_t pts_to_sea av_log(anim->pFormatCtx, AV_LOG_DEBUG, - "SCAN start: considering pts=%lld in search of %lld\n", - (long long int)anim->next_pts, - (long long int)pts_to_search); + "SCAN start: considering pts=%" PRId64 " in search of %" PRId64 "\n", + (int64_t)anim->next_pts, + (int64_t)pts_to_search); while (count > 0 && anim->next_pts < pts_to_search) { av_log(anim->pFormatCtx, AV_LOG_DEBUG, - " WHILE: pts=%lld in search of %lld\n", - (long long int)anim->next_pts, - (long long int)pts_to_search); + " WHILE: pts=%" PRId64 " in search of %" PRId64 "\n", + (int64_t)anim->next_pts, + (int64_t)pts_to_search); if (!ffmpeg_decode_video_frame(anim)) { break; } @@ -994,9 +991,9 @@ static void ffmpeg_decode_video_frame_scan(struct anim *anim, int64_t pts_to_sea av_log(anim->pFormatCtx, AV_LOG_ERROR, "SCAN failed: completely lost in stream, " - "bailing out at PTS=%lld, searching for PTS=%lld\n", - (long long int)anim->next_pts, - (long long int)pts_to_search); + "bailing out at PTS=%" PRId64 ", searching for PTS=%" PRId64 "\n", + (int64_t)anim->next_pts, + (int64_t)pts_to_search); } if (anim->next_pts == pts_to_search) { av_log(anim->pFormatCtx, AV_LOG_DEBUG, "SCAN HAPPY: we found our PTS!\n"); @@ -1091,9 +1088,9 @@ static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position, IMB_Timecode_Typ av_log(anim->pFormatCtx, AV_LOG_DEBUG, - "FETCH: looking for PTS=%lld " - "(pts_timebase=%g, frame_rate=%g, st_time=%lld)\n", - (long long int)pts_to_search, + "FETCH: looking for PTS=%" PRId64 " (pts_timebase=%g, frame_rate=%g, st_time=%" PRId64 + ")\n", + (int64_t)pts_to_search, pts_time_base, frame_rate, st_time); @@ -1101,9 +1098,9 @@ static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position, IMB_Timecode_Typ if (anim->last_frame && anim->last_pts <= pts_to_search && anim->next_pts > pts_to_search) { av_log(anim->pFormatCtx, AV_LOG_DEBUG, - "FETCH: frame repeat: last: %lld next: %lld\n", - (long long int)anim->last_pts, - (long long int)anim->next_pts); + "FETCH: frame repeat: last: %" PRId64 " next: %" PRId64 "\n", + (int64_t)anim->last_pts, + (int64_t)anim->next_pts); IMB_refImBuf(anim->last_frame); anim->curposition = position; return anim->last_frame; @@ -1128,13 +1125,13 @@ static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position, IMB_Timecode_Typ int ret; if (tc_index) { - unsigned long long dts; + uint64_t dts; pos = IMB_indexer_get_seek_pos(tc_index, new_frame_index); dts = IMB_indexer_get_seek_pos_dts(tc_index, new_frame_index); - av_log(anim->pFormatCtx, AV_LOG_DEBUG, "TC INDEX seek pos = %lld\n", pos); - av_log(anim->pFormatCtx, AV_LOG_DEBUG, "TC INDEX seek dts = %llu\n", dts); + av_log(anim->pFormatCtx, AV_LOG_DEBUG, "TC INDEX seek pos = %" PRId64 "\n", pos); + av_log(anim->pFormatCtx, AV_LOG_DEBUG, "TC INDEX seek dts = %" PRIu64 "\n", dts); if (ffmpeg_seek_by_byte(anim->pFormatCtx)) { av_log(anim->pFormatCtx, AV_LOG_DEBUG, "... using BYTE pos\n"); @@ -1152,7 +1149,7 @@ static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position, IMB_Timecode_Typ av_log(anim->pFormatCtx, AV_LOG_DEBUG, - "NO INDEX seek pos = %lld, st_time = %lld\n", + "NO INDEX seek pos = %" PRId64 ", st_time = %" PRId64 "\n", pos, (st_time != AV_NOPTS_VALUE) ? st_time : 0); @@ -1164,7 +1161,7 @@ static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position, IMB_Timecode_Typ pos += st_time; } - av_log(anim->pFormatCtx, AV_LOG_DEBUG, "NO INDEX final seek pos = %lld\n", pos); + av_log(anim->pFormatCtx, AV_LOG_DEBUG, "NO INDEX final seek pos = %" PRId64 "\n", pos); ret = av_seek_frame(anim->pFormatCtx, -1, pos, AVSEEK_FLAG_BACKWARD); } @@ -1173,11 +1170,11 @@ static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position, IMB_Timecode_Typ av_log(anim->pFormatCtx, AV_LOG_ERROR, "FETCH: " - "error while seeking to DTS = %lld " - "(frameno = %d, PTS = %lld): errcode = %d\n", + "error while seeking to DTS = %" PRId64 " (frameno = %d, PTS = %" PRId64 + "): errcode = %d\n", pos, position, - (long long int)pts_to_search, + (int64_t)pts_to_search, ret); } diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c index 09f37d733de..20e1febedd7 100644 --- a/source/blender/imbuf/intern/indexer.c +++ b/source/blender/imbuf/intern/indexer.c @@ -99,25 +99,22 @@ anim_index_builder *IMB_index_builder_create(const char *name) return rv; } -void IMB_index_builder_add_entry(anim_index_builder *fp, - int frameno, - unsigned long long seek_pos, - unsigned long long seek_pos_dts, - unsigned long long pts) +void IMB_index_builder_add_entry( + anim_index_builder *fp, int frameno, uint64_t seek_pos, uint64_t seek_pos_dts, uint64_t pts) { fwrite(&frameno, sizeof(int), 1, fp->fp); - fwrite(&seek_pos, sizeof(unsigned long long), 1, fp->fp); - fwrite(&seek_pos_dts, sizeof(unsigned long long), 1, fp->fp); - fwrite(&pts, sizeof(unsigned long long), 1, fp->fp); + fwrite(&seek_pos, sizeof(uint64_t), 1, fp->fp); + fwrite(&seek_pos_dts, sizeof(uint64_t), 1, fp->fp); + fwrite(&pts, sizeof(uint64_t), 1, fp->fp); } void IMB_index_builder_proc_frame(anim_index_builder *fp, - unsigned char *buffer, + uchar *buffer, int data_size, int frameno, - unsigned long long seek_pos, - unsigned long long seek_pos_dts, - unsigned long long pts) + uint64_t seek_pos, + uint64_t seek_pos_dts, + uint64_t pts) { if (fp->proc_frame) { anim_index_entry e; @@ -186,10 +183,10 @@ struct anim_index *IMB_indexer_open(const char *name) fseek(fp, 0, SEEK_END); - idx->num_entries = (ftell(fp) - 12) / (sizeof(int) + /* framepos */ - sizeof(unsigned long long) + /* seek_pos */ - sizeof(unsigned long long) + /* seek_pos_dts */ - sizeof(unsigned long long) /* pts */ + idx->num_entries = (ftell(fp) - 12) / (sizeof(int) + /* framepos */ + sizeof(uint64_t) + /* seek_pos */ + sizeof(uint64_t) + /* seek_pos_dts */ + sizeof(uint64_t) /* pts */ ); fseek(fp, 12, SEEK_SET); @@ -197,28 +194,28 @@ struct anim_index *IMB_indexer_open(const char *name) idx->entries = MEM_callocN(sizeof(struct anim_index_entry) * idx->num_entries, "anim_index_entries"); + size_t items_read = 0; for (i = 0; i < idx->num_entries; i++) { - size_t items_read = 0; items_read += fread(&idx->entries[i].frameno, sizeof(int), 1, fp); - items_read += fread(&idx->entries[i].seek_pos, sizeof(unsigned long long), 1, fp); - items_read += fread(&idx->entries[i].seek_pos_dts, sizeof(unsigned long long), 1, fp); - items_read += fread(&idx->entries[i].pts, sizeof(unsigned long long), 1, fp); - - if (items_read < 4) { - perror("error reading animation index file"); - MEM_freeN(idx->entries); - MEM_freeN(idx); - fclose(fp); - return NULL; - } + items_read += fread(&idx->entries[i].seek_pos, sizeof(uint64_t), 1, fp); + items_read += fread(&idx->entries[i].seek_pos_dts, sizeof(uint64_t), 1, fp); + items_read += fread(&idx->entries[i].pts, sizeof(uint64_t), 1, fp); + } + + if (UNLIKELY(items_read != idx->num_entries * 4)) { + perror("error reading animation index file"); + MEM_freeN(idx->entries); + MEM_freeN(idx); + fclose(fp); + return NULL; } if (((ENDIAN_ORDER == B_ENDIAN) != (header[8] == 'V'))) { for (i = 0; i < idx->num_entries; i++) { BLI_endian_switch_int32(&idx->entries[i].frameno); - BLI_endian_switch_int64((int64_t *)&idx->entries[i].seek_pos); - BLI_endian_switch_int64((int64_t *)&idx->entries[i].seek_pos_dts); - BLI_endian_switch_int64((int64_t *)&idx->entries[i].pts); + BLI_endian_switch_uint64(&idx->entries[i].seek_pos); + BLI_endian_switch_uint64(&idx->entries[i].seek_pos_dts); + BLI_endian_switch_uint64(&idx->entries[i].pts); } } @@ -227,7 +224,7 @@ struct anim_index *IMB_indexer_open(const char *name) return idx; } -unsigned long long IMB_indexer_get_seek_pos(struct anim_index *idx, int frame_index) +uint64_t IMB_indexer_get_seek_pos(struct anim_index *idx, int frame_index) { if (frame_index < 0) { frame_index = 0; @@ -238,7 +235,7 @@ unsigned long long IMB_indexer_get_seek_pos(struct anim_index *idx, int frame_in return idx->entries[frame_index].seek_pos; } -unsigned long long IMB_indexer_get_seek_pos_dts(struct anim_index *idx, int frame_index) +uint64_t IMB_indexer_get_seek_pos_dts(struct anim_index *idx, int frame_index) { if (frame_index < 0) { frame_index = 0; @@ -281,7 +278,7 @@ int IMB_indexer_get_frame_index(struct anim_index *idx, int frameno) return first; } -unsigned long long IMB_indexer_get_pts(struct anim_index *idx, int frame_index) +uint64_t IMB_indexer_get_pts(struct anim_index *idx, int frame_index) { if (frame_index < 0) { frame_index = 0; @@ -707,12 +704,12 @@ typedef struct FFmpegIndexBuilderContext { IMB_Timecode_Type tcs_in_use; IMB_Proxy_Size proxy_sizes_in_use; - unsigned long long seek_pos; - unsigned long long last_seek_pos; - unsigned long long seek_pos_dts; - unsigned long long seek_pos_pts; - unsigned long long last_seek_pos_dts; - unsigned long long start_pts; + uint64_t seek_pos; + uint64_t last_seek_pos; + uint64_t seek_pos_dts; + uint64_t seek_pos_pts; + uint64_t last_seek_pos_dts; + uint64_t start_pts; double frame_rate; double pts_time_base; int frameno, frameno_gapless; @@ -847,9 +844,9 @@ static void index_rebuild_ffmpeg_proc_decoded_frame(FFmpegIndexBuilderContext *c AVFrame *in_frame) { int i; - unsigned long long s_pos = context->seek_pos; - unsigned long long s_dts = context->seek_pos_dts; - unsigned long long pts = av_get_pts_from_frame(context->iFormatCtx, in_frame); + uint64_t s_pos = context->seek_pos; + uint64_t s_dts = context->seek_pos_dts; + uint64_t pts = av_get_pts_from_frame(context->iFormatCtx, in_frame); for (i = 0; i < context->num_proxy_sizes; i++) { add_to_proxy_output_ffmpeg(context->proxy_ctx[i], in_frame); diff --git a/source/blender/nodes/geometry/node_geometry_util.cc b/source/blender/nodes/geometry/node_geometry_util.cc index eace75b46b6..53af6073793 100644 --- a/source/blender/nodes/geometry/node_geometry_util.cc +++ b/source/blender/nodes/geometry/node_geometry_util.cc @@ -58,7 +58,7 @@ static int attribute_data_type_complexity(const CustomDataType data_type) return 4; case CD_PROP_COLOR: return 5; -#if 0 /* Attribute types are not supported yet. */ +#if 0 /* These attribute types are not supported yet. */ case CD_MLOOPCOL: return 3; case CD_PROP_STRING: @@ -71,7 +71,7 @@ static int attribute_data_type_complexity(const CustomDataType data_type) } } -CustomDataType attribute_domain_highest_complexity(Span<CustomDataType> data_types) +CustomDataType attribute_data_type_highest_complexity(Span<CustomDataType> data_types) { int highest_complexity = INT_MIN; CustomDataType most_complex_type = CD_PROP_COLOR; diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh index 12ede8b6ee0..b7b2afeefcb 100644 --- a/source/blender/nodes/geometry/node_geometry_util.hh +++ b/source/blender/nodes/geometry/node_geometry_util.hh @@ -44,7 +44,7 @@ void update_attribute_input_socket_availabilities(bNode &node, const GeometryNodeAttributeInputMode mode, const bool name_is_available = true); -CustomDataType attribute_domain_highest_complexity(Span<CustomDataType>); +CustomDataType attribute_data_type_highest_complexity(Span<CustomDataType>); Array<uint32_t> get_geometry_element_ids_as_uints(const GeometryComponent &component, const AttributeDomain domain); diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc index 8a96a6ea866..7d49253c6a3 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc @@ -37,12 +37,14 @@ static void execute_on_component(const GeoNodeExecParams ¶ms, GeometryCompon const bNode &bnode = params.node(); NodeAttributeColorRamp *node_storage = (NodeAttributeColorRamp *)bnode.storage; + /* Use the type of the input attribute, but create a color attribute if it doesn't exist yet. */ + const CustomDataType result_type = params.get_input_attribute_data_type( + "Attribute", component, CD_PROP_COLOR); + const std::string result_name = params.get_input<std::string>("Result"); /* Once we support more domains at the user level, we have to decide how the result domain is * chosen. */ const AttributeDomain result_domain = ATTR_DOMAIN_POINT; - const CustomDataType result_type = CD_PROP_COLOR; - WriteAttributePtr attribute_result = component.attribute_try_ensure_for_write( result_name, result_domain, result_type); if (!attribute_result) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc index abfe3b43cb5..5d6e2412a3d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc @@ -216,14 +216,12 @@ static CustomDataType get_data_type(GeometryComponent &component, const NodeAttributeCompare &node_storage) { if (operation_tests_equality(node_storage)) { - CustomDataType data_type_a = params.get_input_attribute_data_type( - "A", component, CD_PROP_FLOAT); - CustomDataType data_type_b = params.get_input_attribute_data_type( - "B", component, CD_PROP_FLOAT); - /* Convert the input attributes to the same data type for the equality tests. Use the higher * complexity attribute type, otherwise information necessary to the comparison may be lost. */ - return attribute_domain_highest_complexity({data_type_a, data_type_b}); + return attribute_data_type_highest_complexity({ + params.get_input_attribute_data_type("A", component, CD_PROP_FLOAT), + params.get_input_attribute_data_type("B", component, CD_PROP_FLOAT), + }); } /* Use float compare for every operation besides equality. */ diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc index 3d3a72dd910..9a780e1212b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc @@ -136,14 +136,21 @@ static void attribute_mix_calc(GeometryComponent &component, const GeoNodeExecPa const bNode &node = params.node(); const NodeAttributeMix *node_storage = (const NodeAttributeMix *)node.storage; - CustomDataType result_type = CD_PROP_COLOR; + /* Use the highest complexity data type among the inputs and outputs, that way the node will + * never "remove information". Use CD_PROP_BOOL as the lowest complexity data type, but in any + * real situation it won't be returned. */ + const CustomDataType result_type = attribute_data_type_highest_complexity({ + params.get_input_attribute_data_type("A", component, CD_PROP_BOOL), + params.get_input_attribute_data_type("B", component, CD_PROP_BOOL), + params.get_input_attribute_data_type("Result", component, CD_PROP_BOOL), + }); + + /* Once we support more domains at the user level, we have to decide how the result domain is + * chosen. */ AttributeDomain result_domain = ATTR_DOMAIN_POINT; - - /* Use type and domain from the result attribute, if it exists already. */ const std::string result_name = params.get_input<std::string>("Result"); const ReadAttributePtr result_attribute_read = component.attribute_try_get_for_read(result_name); if (result_attribute_read) { - result_type = result_attribute_read->custom_data_type(); result_domain = result_attribute_read->domain(); } diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt index f33bb81d6b0..2ca21a315e4 100644 --- a/tests/python/CMakeLists.txt +++ b/tests/python/CMakeLists.txt @@ -228,13 +228,15 @@ add_blender_test( --run-all-tests ) -add_blender_test( - physics_ocean - ${TEST_SRC_DIR}/physics/ocean_test.blend - --python ${TEST_PYTHON_DIR}/physics_ocean.py - -- - --run-all-tests -) +if(WITH_MOD_OCEANSIM) + add_blender_test( + physics_ocean + ${TEST_SRC_DIR}/physics/ocean_test.blend + --python ${TEST_PYTHON_DIR}/physics_ocean.py + -- + --run-all-tests + ) +endif() add_blender_test( |