Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Kowalski <makowalski@nvidia.com>2022-10-24 22:28:20 +0300
committerMichael Kowalski <makowalski@nvidia.com>2022-10-24 22:28:20 +0300
commit784ea87375cebd7c12faada555f65c741895bca0 (patch)
tree4dc85e7873f1917ba40b6f2cb07d89873c372907 /source/blender/blenkernel
parent75064c7024b12b845fc36d4fa3079f005651f7c7 (diff)
parent954b834053f17f1c0ff1f3096030b81d0d9ea7ec (diff)
Merge branch 'master' into universal-scene-description
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r--source/blender/blenkernel/BKE_attribute.hh2
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenkernel/BKE_brush.h21
-rw-r--r--source/blender/blenkernel/BKE_instances.hh2
-rw-r--r--source/blender/blenkernel/BKE_writeffmpeg.h2
-rw-r--r--source/blender/blenkernel/intern/attribute_access.cc17
-rw-r--r--source/blender/blenkernel/intern/blendfile_link_append.c6
-rw-r--r--source/blender/blenkernel/intern/brush.cc22
-rw-r--r--source/blender/blenkernel/intern/crazyspace.cc35
-rw-r--r--source/blender/blenkernel/intern/curve_to_mesh_convert.cc10
-rw-r--r--source/blender/blenkernel/intern/curves.cc5
-rw-r--r--source/blender/blenkernel/intern/curves_geometry.cc22
-rw-r--r--source/blender/blenkernel/intern/customdata.cc8
-rw-r--r--source/blender/blenkernel/intern/geometry_set.cc5
-rw-r--r--source/blender/blenkernel/intern/image.cc23
-rw-r--r--source/blender/blenkernel/intern/image_format.cc7
-rw-r--r--source/blender/blenkernel/intern/image_save.cc2
-rw-r--r--source/blender/blenkernel/intern/instances.cc27
-rw-r--r--source/blender/blenkernel/intern/lib_id_delete.c70
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.cc10
-rw-r--r--source/blender/blenkernel/intern/nla.c2
-rw-r--r--source/blender/blenkernel/intern/node.cc12
-rw-r--r--source/blender/blenkernel/intern/object.cc1
-rw-r--r--source/blender/blenkernel/intern/object_update.cc2
-rw-r--r--source/blender/blenkernel/intern/paint.cc2
-rw-r--r--source/blender/blenkernel/intern/volume.cc4
-rw-r--r--source/blender/blenkernel/intern/writeavi.c3
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c236
28 files changed, 438 insertions, 122 deletions
diff --git a/source/blender/blenkernel/BKE_attribute.hh b/source/blender/blenkernel/BKE_attribute.hh
index 7b13b8a2b09..a4f9d73c31e 100644
--- a/source/blender/blenkernel/BKE_attribute.hh
+++ b/source/blender/blenkernel/BKE_attribute.hh
@@ -793,7 +793,9 @@ class CustomDataAttributes {
~CustomDataAttributes();
CustomDataAttributes(const CustomDataAttributes &other);
CustomDataAttributes(CustomDataAttributes &&other);
+
CustomDataAttributes &operator=(const CustomDataAttributes &other);
+ CustomDataAttributes &operator=(CustomDataAttributes &&other);
void reallocate(int size);
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 96df8f7a443..806fff2099e 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -25,7 +25,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
-#define BLENDER_FILE_SUBVERSION 4
+#define BLENDER_FILE_SUBVERSION 5
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
index 4d728002c87..a763b3d12c2 100644
--- a/source/blender/blenkernel/BKE_brush.h
+++ b/source/blender/blenkernel/BKE_brush.h
@@ -18,7 +18,9 @@ extern "C" {
struct Brush;
struct ImBuf;
struct ImagePool;
+struct Object;
struct Main;
+struct MTex;
struct Scene;
struct ToolSettings;
struct UnifiedPaintSettings;
@@ -109,6 +111,7 @@ float BKE_brush_curve_strength(const struct Brush *br, float p, float len);
*/
float BKE_brush_sample_tex_3d(const struct Scene *scene,
const struct Brush *br,
+ const struct MTex *mtex,
const float point[3],
float rgba[4],
int thread,
@@ -120,6 +123,24 @@ float BKE_brush_sample_masktex(const struct Scene *scene,
struct ImagePool *pool);
/**
+ * Get the mask texture for this given object mode.
+ *
+ * This is preferred above using mtex/mask_mtex attributes directly as due to legacy these
+ * attributes got switched in sculpt mode.
+ */
+const struct MTex *BKE_brush_mask_texture_get(const struct Brush *brush,
+ const eObjectMode object_mode);
+
+/**
+ * Get the color texture for this given object mode.
+ *
+ * This is preferred above using mtex/mask_mtex attributes directly as due to legacy these
+ * attributes got switched in sculpt mode.
+ */
+const struct MTex *BKE_brush_color_texture_get(const struct Brush *brush,
+ const eObjectMode object_mode);
+
+/**
* Radial control.
*/
struct ImBuf *BKE_brush_gen_radial_control_imbuf(struct Brush *br,
diff --git a/source/blender/blenkernel/BKE_instances.hh b/source/blender/blenkernel/BKE_instances.hh
index 6502fefec88..f17ebba0dfa 100644
--- a/source/blender/blenkernel/BKE_instances.hh
+++ b/source/blender/blenkernel/BKE_instances.hh
@@ -5,7 +5,7 @@
/** \file
* \ingroup bke
*
- * #Instances is a container for geometry instances. It fullfills some key requirements:
+ * #Instances is a container for geometry instances. It fulfills some key requirements:
* - Support nested instances.
* - Support instance attributes.
* - Support referencing different kinds of instances (objects, collections, geometry sets).
diff --git a/source/blender/blenkernel/BKE_writeffmpeg.h b/source/blender/blenkernel/BKE_writeffmpeg.h
index 736f7548bb4..cfe246eb470 100644
--- a/source/blender/blenkernel/BKE_writeffmpeg.h
+++ b/source/blender/blenkernel/BKE_writeffmpeg.h
@@ -27,6 +27,7 @@ enum {
FFMPEG_OGG = 10,
FFMPEG_INVALID = 11,
FFMPEG_WEBM = 12,
+ FFMPEG_AV1 = 13,
};
enum {
@@ -38,6 +39,7 @@ enum {
FFMPEG_PRESET_H264 = 5,
FFMPEG_PRESET_THEORA = 6,
FFMPEG_PRESET_XVID = 7,
+ FFMPEG_PRESET_AV1 = 8,
};
struct RenderData;
diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc
index b86353bdb74..544427cfdd3 100644
--- a/source/blender/blenkernel/intern/attribute_access.cc
+++ b/source/blender/blenkernel/intern/attribute_access.cc
@@ -642,15 +642,26 @@ CustomDataAttributes::CustomDataAttributes(CustomDataAttributes &&other)
size_ = other.size_;
data = other.data;
CustomData_reset(&other.data);
+ other.size_ = 0;
}
CustomDataAttributes &CustomDataAttributes::operator=(const CustomDataAttributes &other)
{
- if (this != &other) {
- CustomData_copy(&other.data, &data, CD_MASK_ALL, CD_DUPLICATE, other.size_);
- size_ = other.size_;
+ if (this == &other) {
+ return *this;
}
+ this->~CustomDataAttributes();
+ new (this) CustomDataAttributes(other);
+ return *this;
+}
+CustomDataAttributes &CustomDataAttributes::operator=(CustomDataAttributes &&other)
+{
+ if (this == &other) {
+ return *this;
+ }
+ this->~CustomDataAttributes();
+ new (this) CustomDataAttributes(std::move(other));
return *this;
}
diff --git a/source/blender/blenkernel/intern/blendfile_link_append.c b/source/blender/blenkernel/intern/blendfile_link_append.c
index 394469e19a4..4dd225c09ec 100644
--- a/source/blender/blenkernel/intern/blendfile_link_append.c
+++ b/source/blender/blenkernel/intern/blendfile_link_append.c
@@ -1494,6 +1494,7 @@ void BKE_blendfile_library_relocate(BlendfileLinkAppendContext *lapp_context,
* code is wrong, we need to redo it here after adding them back to main. */
BKE_main_id_refcount_recompute(bmain, false);
+ BKE_layer_collection_resync_forbid();
/* Note that in reload case, we also want to replace indirect usages. */
const short remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE |
(do_reload ? 0 : ID_REMAP_SKIP_INDIRECT_USAGE);
@@ -1523,6 +1524,8 @@ void BKE_blendfile_library_relocate(BlendfileLinkAppendContext *lapp_context,
id_us_plus_no_lib(&old_key->id);
}
}
+ BKE_layer_collection_resync_allow();
+ BKE_main_collection_sync_remap(bmain);
BKE_main_unlock(bmain);
@@ -1614,6 +1617,9 @@ void BKE_blendfile_library_relocate(BlendfileLinkAppendContext *lapp_context,
(id->tag & LIB_TAG_PRE_EXISTING) == 0) {
continue;
}
+ if ((id->override_library->reference->tag & LIB_TAG_MISSING) == 0) {
+ id->tag &= ~LIB_TAG_MISSING;
+ }
if ((id->override_library->reference->tag & LIB_TAG_PRE_EXISTING) == 0) {
BKE_lib_override_library_update(bmain, id);
}
diff --git a/source/blender/blenkernel/intern/brush.cc b/source/blender/blenkernel/intern/brush.cc
index 20d86ea5a2d..6f1435e90b8 100644
--- a/source/blender/blenkernel/intern/brush.cc
+++ b/source/blender/blenkernel/intern/brush.cc
@@ -1974,19 +1974,37 @@ void BKE_brush_curve_preset(Brush *b, eCurveMappingPreset preset)
BKE_curvemapping_changed(cumap, false);
}
+const struct MTex *BKE_brush_mask_texture_get(const struct Brush *brush,
+ const eObjectMode object_mode)
+{
+ if (object_mode == OB_MODE_SCULPT) {
+ return &brush->mtex;
+ }
+ return &brush->mask_mtex;
+}
+
+const struct MTex *BKE_brush_color_texture_get(const struct Brush *brush,
+ const eObjectMode object_mode)
+{
+ if (object_mode == OB_MODE_SCULPT) {
+ return &brush->mask_mtex;
+ }
+ return &brush->mtex;
+}
+
float BKE_brush_sample_tex_3d(const Scene *scene,
const Brush *br,
+ const MTex *mtex,
const float point[3],
float rgba[4],
const int thread,
struct ImagePool *pool)
{
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
- const MTex *mtex = &br->mtex;
float intensity = 1.0;
bool hasrgb = false;
- if (!mtex->tex) {
+ if (mtex == nullptr || mtex->tex == nullptr) {
intensity = 1;
}
else if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
diff --git a/source/blender/blenkernel/intern/crazyspace.cc b/source/blender/blenkernel/intern/crazyspace.cc
index 190e2d3bb7e..f83c321c4ae 100644
--- a/source/blender/blenkernel/intern/crazyspace.cc
+++ b/source/blender/blenkernel/intern/crazyspace.cc
@@ -70,47 +70,48 @@ static void set_crazy_vertex_quat(float r_quat[4],
sub_qt_qtqt(r_quat, q2, q1);
}
-static bool modifiers_disable_subsurf_temporary(struct Scene *scene, Object *ob)
+static bool modifiers_disable_subsurf_temporary(Object *ob, const int cageIndex)
{
- bool disabled = false;
- int cageIndex = BKE_modifiers_get_cage_index(scene, ob, nullptr, true);
+ bool changed = false;
ModifierData *md = static_cast<ModifierData *>(ob->modifiers.first);
for (int i = 0; md && i <= cageIndex; i++, md = md->next) {
if (md->type == eModifierType_Subsurf) {
md->mode ^= eModifierMode_DisableTemporary;
- disabled = true;
+ changed = true;
}
}
- return disabled;
+ return changed;
}
float (*BKE_crazyspace_get_mapped_editverts(struct Depsgraph *depsgraph, Object *obedit))[3]
{
- Scene *scene = DEG_get_input_scene(depsgraph);
Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit);
- Mesh *mesh_eval = static_cast<Mesh *>(obedit_eval->data);
- BMEditMesh *editmesh_eval = mesh_eval->edit_mesh;
+ const int cageIndex = BKE_modifiers_get_cage_index(scene_eval, obedit_eval, nullptr, true);
- /* disable subsurf temporal, get mapped cos, and enable it */
- if (modifiers_disable_subsurf_temporary(scene_eval, obedit_eval)) {
- /* Need to make new derived-mesh. */
+ /* Disable subsurf temporal, get mapped cos, and enable it. */
+ if (modifiers_disable_subsurf_temporary(obedit_eval, cageIndex)) {
+ /* Need to make new cage.
+ * TODO: Avoid losing original evaluated geometry. */
makeDerivedMesh(depsgraph, scene_eval, obedit_eval, &CD_MASK_BAREMESH);
}
- /* now get the cage */
- Mesh *mesh_eval_cage = editbmesh_get_eval_cage_from_orig(
- depsgraph, scene, obedit, &CD_MASK_BAREMESH);
+ /* Now get the cage. */
+ BMEditMesh *em_eval = BKE_editmesh_from_object(obedit_eval);
+ Mesh *mesh_eval_cage = editbmesh_get_eval_cage(
+ depsgraph, scene_eval, obedit_eval, em_eval, &CD_MASK_BAREMESH);
- const int nverts = editmesh_eval->bm->totvert;
+ const int nverts = em_eval->bm->totvert;
float(*vertexcos)[3] = static_cast<float(*)[3]>(
MEM_mallocN(sizeof(*vertexcos) * nverts, "vertexcos map"));
mesh_get_mapped_verts_coords(mesh_eval_cage, vertexcos, nverts);
- /* set back the flag, no new cage needs to be built, transform does it */
- modifiers_disable_subsurf_temporary(scene_eval, obedit_eval);
+ /* Set back the flag, and ensure new cage needs to be built. */
+ if (modifiers_disable_subsurf_temporary(obedit_eval, cageIndex)) {
+ DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY);
+ }
return vertexcos;
}
diff --git a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
index b9fea2a27b8..ecf3be9bd81 100644
--- a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
+++ b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
@@ -332,7 +332,8 @@ static eAttrDomain get_attribute_domain_for_mesh(const AttributeAccessor &mesh_a
static bool should_add_attribute_to_mesh(const AttributeAccessor &curve_attributes,
const AttributeAccessor &mesh_attributes,
- const AttributeIDRef &id)
+ const AttributeIDRef &id,
+ const AttributeMetaData &meta_data)
{
/* The position attribute has special non-generic evaluation. */
@@ -346,6 +347,9 @@ static bool should_add_attribute_to_mesh(const AttributeAccessor &curve_attribut
if (!id.should_be_kept()) {
return false;
}
+ if (meta_data.data_type == CD_PROP_STRING) {
+ return false;
+ }
return true;
}
@@ -714,7 +718,7 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main,
MutableAttributeAccessor mesh_attributes = mesh->attributes_for_write();
main_attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
- if (!should_add_attribute_to_mesh(main_attributes, mesh_attributes, id)) {
+ if (!should_add_attribute_to_mesh(main_attributes, mesh_attributes, id, meta_data)) {
return true;
}
main_attributes_set.add_new(id);
@@ -751,7 +755,7 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main,
if (main_attributes.contains(id)) {
return true;
}
- if (!should_add_attribute_to_mesh(profile_attributes, mesh_attributes, id)) {
+ if (!should_add_attribute_to_mesh(profile_attributes, mesh_attributes, id, meta_data)) {
return true;
}
const eAttrDomain src_domain = meta_data.domain;
diff --git a/source/blender/blenkernel/intern/curves.cc b/source/blender/blenkernel/intern/curves.cc
index 01be22a57b0..72e53023d6d 100644
--- a/source/blender/blenkernel/intern/curves.cc
+++ b/source/blender/blenkernel/intern/curves.cc
@@ -287,7 +287,10 @@ static void curves_evaluate_modifiers(struct Depsgraph *depsgraph,
{
/* Modifier evaluation modes. */
const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
- const int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime;
+ int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime;
+ if (BKE_object_is_in_editmode(object)) {
+ required_mode = (ModifierMode)(int(required_mode) | eModifierMode_Editmode);
+ }
ModifierApplyFlag apply_flag = use_render ? MOD_APPLY_RENDER : MOD_APPLY_USECACHE;
const ModifierEvalContext mectx = {depsgraph, object, apply_flag};
diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc
index f5c845443f1..7c338480c71 100644
--- a/source/blender/blenkernel/intern/curves_geometry.cc
+++ b/source/blender/blenkernel/intern/curves_geometry.cc
@@ -9,6 +9,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_array_utils.hh"
#include "BLI_bounds.hh"
#include "BLI_index_mask_ops.hh"
#include "BLI_length_parameterize.hh"
@@ -1111,21 +1112,11 @@ static void copy_between_buffers(const CPPType &type,
src_range.size());
}
-template<typename T>
-static void copy_with_map(const Span<T> src, const Span<int> map, MutableSpan<T> dst)
-{
- threading::parallel_for(map.index_range(), 1024, [&](const IndexRange range) {
- for (const int i : range) {
- dst[i] = src[map[i]];
- }
- });
-}
-
static void copy_with_map(const GSpan src, const Span<int> map, GMutableSpan dst)
{
attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
using T = decltype(dummy);
- copy_with_map(src.typed<T>(), map, dst.typed<T>());
+ array_utils::gather(src.typed<T>(), map, dst.typed<T>());
});
}
@@ -1233,6 +1224,10 @@ static CurvesGeometry copy_with_removed_points(const CurvesGeometry &curves,
attribute.dst.finish();
}
+ if (new_curves.curves_num() != curves.curves_num()) {
+ new_curves.remove_attributes_based_on_types();
+ }
+
return new_curves;
}
@@ -1338,6 +1333,8 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves,
attribute.dst.finish();
}
+ new_curves.remove_attributes_based_on_types();
+
return new_curves;
}
@@ -1402,6 +1399,9 @@ void CurvesGeometry::reverse_curves(const IndexMask curves_to_reverse)
if (meta_data.domain != ATTR_DOMAIN_POINT) {
return true;
}
+ if (meta_data.data_type == CD_PROP_STRING) {
+ return true;
+ }
if (id.is_named() && bezier_handle_names.contains(id.name())) {
return true;
}
diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc
index 6f2390fc28f..03a0f17a4bb 100644
--- a/source/blender/blenkernel/intern/customdata.cc
+++ b/source/blender/blenkernel/intern/customdata.cc
@@ -19,6 +19,7 @@
#include "BLI_bitmap.h"
#include "BLI_color.hh"
+#include "BLI_cpp_type_make.hh"
#include "BLI_endian_switch.h"
#include "BLI_index_range.hh"
#include "BLI_math.h"
@@ -5387,6 +5388,8 @@ const blender::CPPType *custom_data_type_to_cpp_type(const eCustomDataType type)
return &CPPType::get<int8_t>();
case CD_PROP_BYTE_COLOR:
return &CPPType::get<ColorGeometry4b>();
+ case CD_PROP_STRING:
+ return &CPPType::get<MStringProperty>();
default:
return nullptr;
}
@@ -5419,6 +5422,9 @@ eCustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type)
if (type.is<ColorGeometry4b>()) {
return CD_PROP_BYTE_COLOR;
}
+ if (type.is<MStringProperty>()) {
+ return CD_PROP_STRING;
+ }
return static_cast<eCustomDataType>(-1);
}
@@ -5430,3 +5436,5 @@ size_t CustomData_get_elem_size(CustomDataLayer *layer)
{
return LAYERTYPEINFO[layer->type].size;
}
+
+BLI_CPP_TYPE_MAKE(MStringProperty, MStringProperty, CPPTypeFlags::None);
diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc
index 90568a8a080..ee4c398c3d6 100644
--- a/source/blender/blenkernel/intern/geometry_set.cc
+++ b/source/blender/blenkernel/intern/geometry_set.cc
@@ -607,7 +607,10 @@ void GeometrySet::gather_attributes_for_propagation(
return;
}
}
-
+ if (meta_data.data_type == CD_PROP_STRING) {
+ /* Propagating string attributes is not supported yet. */
+ return;
+ }
if (!attribute_id.should_be_kept()) {
return;
}
diff --git a/source/blender/blenkernel/intern/image.cc b/source/blender/blenkernel/intern/image.cc
index 19956a0349d..619416faeeb 100644
--- a/source/blender/blenkernel/intern/image.cc
+++ b/source/blender/blenkernel/intern/image.cc
@@ -3092,16 +3092,10 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
/* Free all but the first tile. */
image_remove_all_tiles(ima);
- /* If the remaining tile is generated, we need to again ensure that we
- * wouldn't continue to use the old filepath.
- *
- * Otherwise, if this used to be a UDIM image, get the concrete filepath associated
+ /* If this used to be a UDIM image, get the concrete filepath associated
* with the remaining tile and use that as the new filepath. */
ImageTile *base_tile = BKE_image_get_tile(ima, 0);
- if ((base_tile->gen_flag & IMA_GEN_TILE) != 0) {
- ima->filepath[0] = '\0';
- }
- else if (BKE_image_is_filename_tokenized(ima->filepath)) {
+ if (BKE_image_is_filename_tokenized(ima->filepath)) {
const bool was_relative = BLI_path_is_rel(ima->filepath);
eUDIM_TILE_FORMAT tile_format;
@@ -3193,10 +3187,14 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
* left. */
image_remove_all_tiles(ima);
- int remaining_tile_number = ((ImageTile *)ima->tiles.first)->tile_number;
+ ImageTile *base_tile = BKE_image_get_tile(ima, 0);
+ int remaining_tile_number = base_tile->tile_number;
bool needs_final_cleanup = true;
- /* Add in all the new tiles. */
+ /* Add in all the new tiles. As the image is proven to be on disk at this point, remove
+ * the generation flag from the remaining tile in case this was previously a generated
+ * image. */
+ base_tile->gen_flag &= ~IMA_GEN_TILE;
LISTBASE_FOREACH (LinkData *, new_tile, &new_tiles) {
int new_tile_number = POINTER_AS_INT(new_tile->data);
BKE_image_add_tile(ima, new_tile_number, nullptr);
@@ -3212,6 +3210,11 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
}
BLI_freelistN(&new_tiles);
}
+ else if (ima->filepath[0] != '\0') {
+ /* If the filepath is set at this point remove the generation flag. */
+ ImageTile *base_tile = BKE_image_get_tile(ima, 0);
+ base_tile->gen_flag &= ~IMA_GEN_TILE;
+ }
if (iuser) {
image_tag_reload(ima, nullptr, iuser, ima);
diff --git a/source/blender/blenkernel/intern/image_format.cc b/source/blender/blenkernel/intern/image_format.cc
index 8d1aeac76fb..5b861eff166 100644
--- a/source/blender/blenkernel/intern/image_format.cc
+++ b/source/blender/blenkernel/intern/image_format.cc
@@ -201,6 +201,7 @@ bool BKE_imtype_is_movie(const char imtype)
case R_IMF_IMTYPE_H264:
case R_IMF_IMTYPE_THEORA:
case R_IMF_IMTYPE_XVID:
+ case R_IMF_IMTYPE_AV1:
return true;
}
return false;
@@ -433,7 +434,8 @@ static bool do_add_image_extension(char *string,
R_IMF_IMTYPE_FFMPEG,
R_IMF_IMTYPE_H264,
R_IMF_IMTYPE_THEORA,
- R_IMF_IMTYPE_XVID)) {
+ R_IMF_IMTYPE_XVID,
+ R_IMF_IMTYPE_AV1)) {
if (!BLI_path_extension_check(string, extension_test = ".png")) {
extension = extension_test;
}
@@ -627,7 +629,8 @@ void BKE_image_format_to_imbuf(ImBuf *ibuf, const ImageFormatData *imf)
R_IMF_IMTYPE_FFMPEG,
R_IMF_IMTYPE_H264,
R_IMF_IMTYPE_THEORA,
- R_IMF_IMTYPE_XVID)) {
+ R_IMF_IMTYPE_XVID,
+ R_IMF_IMTYPE_AV1)) {
ibuf->ftype = IMB_FTYPE_PNG;
if (imtype == R_IMF_IMTYPE_PNG) {
diff --git a/source/blender/blenkernel/intern/image_save.cc b/source/blender/blenkernel/intern/image_save.cc
index 4e47e71fb2b..003211e6288 100644
--- a/source/blender/blenkernel/intern/image_save.cc
+++ b/source/blender/blenkernel/intern/image_save.cc
@@ -968,6 +968,7 @@ bool BKE_image_render_write(ReportList *reports,
/* optional preview images for exr */
if (ok && (image_format.flag & R_IMF_FLAG_PREVIEW_JPG)) {
image_format.imtype = R_IMF_IMTYPE_JPEG90;
+ image_format.depth = R_IMF_CHAN_DEPTH_8;
if (BLI_path_extension_check(filepath, ".exr")) {
filepath[strlen(filepath) - 4] = 0;
@@ -1025,6 +1026,7 @@ bool BKE_image_render_write(ReportList *reports,
/* optional preview images for exr */
if (ok && is_exr_rr && (image_format.flag & R_IMF_FLAG_PREVIEW_JPG)) {
image_format.imtype = R_IMF_IMTYPE_JPEG90;
+ image_format.depth = R_IMF_CHAN_DEPTH_8;
if (BLI_path_extension_check(filepath, ".exr")) {
filepath[strlen(filepath) - 4] = 0;
diff --git a/source/blender/blenkernel/intern/instances.cc b/source/blender/blenkernel/intern/instances.cc
index dd759453630..4675562e927 100644
--- a/source/blender/blenkernel/intern/instances.cc
+++ b/source/blender/blenkernel/intern/instances.cc
@@ -1,5 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "BLI_array_utils.hh"
#include "BLI_cpp_type_make.hh"
#include "BLI_rand.hh"
#include "BLI_task.hh"
@@ -107,18 +108,6 @@ blender::Span<InstanceReference> Instances::references() const
return references_;
}
-template<typename T>
-static void copy_data_based_on_mask(Span<T> src, MutableSpan<T> dst, IndexMask mask)
-{
- BLI_assert(src.data() != dst.data());
- using namespace blender;
- threading::parallel_for(mask.index_range(), 1024, [&](IndexRange range) {
- for (const int i : range) {
- dst[i] = src[mask[i]];
- }
- });
-}
-
void Instances::remove(const IndexMask mask)
{
using namespace blender;
@@ -129,11 +118,14 @@ void Instances::remove(const IndexMask mask)
return;
}
+ const Span<int> old_handles = this->reference_handles();
Vector<int> new_handles(mask.size());
- copy_data_based_on_mask<int>(this->reference_handles(), new_handles, mask);
+ array_utils::gather(old_handles, mask.indices(), new_handles.as_mutable_span());
reference_handles_ = std::move(new_handles);
+
+ const Span<float4x4> old_tansforms = this->transforms();
Vector<float4x4> new_transforms(mask.size());
- copy_data_based_on_mask<float4x4>(this->transforms(), new_transforms, mask);
+ array_utils::gather(old_tansforms, mask.indices(), new_transforms.as_mutable_span());
transforms_ = std::move(new_transforms);
const bke::CustomDataAttributes &src_attributes = attributes_;
@@ -150,11 +142,8 @@ void Instances::remove(const IndexMask mask)
GSpan src = *src_attributes.get_for_read(id);
dst_attributes.create(id, meta_data.data_type);
GMutableSpan dst = *dst_attributes.get_for_write(id);
+ array_utils::gather(src, mask.indices(), dst);
- attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
- using T = decltype(dummy);
- copy_data_based_on_mask<T>(src.typed<T>(), dst.typed<T>(), mask);
- });
return true;
},
ATTR_DOMAIN_INSTANCE);
@@ -266,7 +255,7 @@ bool Instances::owns_direct_data() const
void Instances::ensure_owns_direct_data()
{
for (const InstanceReference &const_reference : references_) {
- /* Const cast is fine because we are not changing anything that would change the hash of the
+ /* `const` cast is fine because we are not changing anything that would change the hash of the
* reference. */
InstanceReference &reference = const_cast<InstanceReference &>(const_reference);
reference.ensure_owns_direct_data();
diff --git a/source/blender/blenkernel/intern/lib_id_delete.c b/source/blender/blenkernel/intern/lib_id_delete.c
index f4f5ca7a1d7..1a80376f482 100644
--- a/source/blender/blenkernel/intern/lib_id_delete.c
+++ b/source/blender/blenkernel/intern/lib_id_delete.c
@@ -16,6 +16,7 @@
#include "BLI_utildefines.h"
+#include "BLI_linklist.h"
#include "BLI_listbase.h"
#include "BKE_anim_data.h"
@@ -23,10 +24,10 @@
#include "BKE_idprop.h"
#include "BKE_idtype.h"
#include "BKE_key.h"
+#include "BKE_layer.h"
#include "BKE_lib_id.h"
#include "BKE_lib_override.h"
#include "BKE_lib_remap.h"
-#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_main_namemap.h"
@@ -202,7 +203,6 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
{
const int tag = LIB_TAG_DOIT;
ListBase *lbarray[INDEX_ID_MAX];
- Link dummy_link = {0};
int base_count, i;
/* Used by batch tagged deletion, when we call BKE_id_free then, id is no more in Main database,
@@ -217,6 +217,9 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
BKE_main_lock(bmain);
if (do_tagged_deletion) {
+ struct IDRemapper *id_remapper = BKE_id_remapper_create();
+ BKE_layer_collection_resync_forbid();
+
/* Main idea of batch deletion is to remove all IDs to be deleted from Main database.
* This means that we won't have to loop over all deleted IDs to remove usages
* of other deleted IDs.
@@ -227,7 +230,6 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
bool keep_looping = true;
while (keep_looping) {
ID *id, *id_next;
- ID *last_remapped_id = tagged_deleted_ids.last;
keep_looping = false;
/* First tag and remove from Main all datablocks directly from target lib.
@@ -243,6 +245,7 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
BLI_remlink(lb, id);
BKE_main_namemap_remove_name(bmain, id, id->name + 2);
BLI_addtail(&tagged_deleted_ids, id);
+ BKE_id_remapper_add(id_remapper, id, NULL);
/* Do not tag as no_main now, we want to unlink it first (lower-level ID management
* code has some specific handling of 'no main' IDs that would be a problem in that
* case). */
@@ -251,33 +254,38 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
}
}
}
- if (last_remapped_id == NULL) {
- dummy_link.next = tagged_deleted_ids.first;
- last_remapped_id = (ID *)(&dummy_link);
- }
- for (id = last_remapped_id->next; id; id = id->next) {
- /* Will tag 'never NULL' users of this ID too.
- *
- * NOTE: #BKE_libblock_unlink() cannot be used here, since it would ignore indirect
- * links, this can lead to nasty crashing here in second, actual deleting loop.
- * Also, this will also flag users of deleted data that cannot be unlinked
- * (object using deleted obdata, etc.), so that they also get deleted. */
- BKE_libblock_remap_locked(bmain,
- id,
- NULL,
- (ID_REMAP_FLAG_NEVER_NULL_USAGE |
- ID_REMAP_FORCE_NEVER_NULL_USAGE |
- ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS));
- /* Since we removed ID from Main,
- * we also need to unlink its own other IDs usages ourself. */
- BKE_libblock_relink_ex(
- bmain,
- id,
- NULL,
- NULL,
- (ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS | ID_REMAP_SKIP_USER_CLEAR));
- }
+
+ /* Will tag 'never NULL' users of this ID too.
+ *
+ * NOTE: #BKE_libblock_unlink() cannot be used here, since it would ignore indirect
+ * links, this can lead to nasty crashing here in second, actual deleting loop.
+ * Also, this will also flag users of deleted data that cannot be unlinked
+ * (object using deleted obdata, etc.), so that they also get deleted. */
+ BKE_libblock_remap_multiple_locked(bmain,
+ id_remapper,
+ ID_REMAP_FLAG_NEVER_NULL_USAGE |
+ ID_REMAP_FORCE_NEVER_NULL_USAGE |
+ ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS);
+ BKE_id_remapper_clear(id_remapper);
+ }
+
+ /* Since we removed IDs from Main, their own other IDs usages need to be removed 'manually'. */
+ LinkNode *cleanup_ids = NULL;
+ for (ID *id = tagged_deleted_ids.first; id; id = id->next) {
+ BLI_linklist_prepend(&cleanup_ids, id);
}
+ BKE_libblock_relink_multiple(bmain,
+ cleanup_ids,
+ ID_REMAP_TYPE_CLEANUP,
+ id_remapper,
+ ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS |
+ ID_REMAP_SKIP_USER_CLEAR);
+
+ BKE_id_remapper_free(id_remapper);
+ BLI_linklist_free(cleanup_ids, NULL);
+
+ BKE_layer_collection_resync_allow();
+ BKE_main_collection_sync_remap(bmain);
/* Now we can safely mark that ID as not being in Main database anymore. */
/* NOTE: This needs to be done in a separate loop than above, otherwise some user-counts of
@@ -285,6 +293,10 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
* is never affected). */
for (ID *id = tagged_deleted_ids.first; id; id = id->next) {
id->tag |= LIB_TAG_NO_MAIN;
+ /* Usercount needs to be reset artificially, since some usages may not be cleared in batch
+ * deletion (typically, if one deleted ID uses another deleted ID, this may not be cleared by
+ * remapping code, depending on order in which these are handled). */
+ id->us = ID_FAKE_USERS(id);
}
}
else {
diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc
index 027423f5774..784d35a8d65 100644
--- a/source/blender/blenkernel/intern/mesh_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_convert.cc
@@ -1313,6 +1313,7 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob)
CustomData_duplicate_referenced_layers(&mesh_src->pdata, mesh_src->totpoly);
CustomData_duplicate_referenced_layers(&mesh_src->ldata, mesh_src->totloop);
+ const bool verts_num_changed = mesh_dst->totvert != mesh_src->totvert;
mesh_dst->totvert = mesh_src->totvert;
mesh_dst->totedge = mesh_src->totedge;
mesh_dst->totpoly = mesh_src->totpoly;
@@ -1339,11 +1340,10 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob)
const int uid_active = ob ? find_object_active_key_uid(*key_dst, *ob) : -1;
move_shapekey_layers_to_keyblocks(*mesh_dst, mesh_src->vdata, *key_dst, uid_active);
}
- else if (mesh_src->totvert != mesh_dst->totvert) {
- CLOG_ERROR(&LOG, "Mesh in Main '%s' lost shape keys", mesh_src->id.name);
- if (mesh_src->key) {
- id_us_min(&mesh_src->key->id);
- }
+ else if (verts_num_changed) {
+ CLOG_WARN(&LOG, "Shape key data lost when replacing mesh '%s' in Main", mesh_src->id.name);
+ id_us_min(&mesh_dst->key->id);
+ mesh_dst->key = nullptr;
}
}
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index ba63cdff917..24663d6db05 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -1918,7 +1918,7 @@ bool BKE_nla_action_stash(AnimData *adt, const bool is_liboverride)
* NOTE: this must be done *after* adding the strip to the track, or else
* the strip locking will prevent the strip from getting added
*/
- nlt->flag = (NLATRACK_MUTED | NLATRACK_PROTECTED);
+ nlt->flag |= (NLATRACK_MUTED | NLATRACK_PROTECTED);
strip->flag &= ~(NLASTRIP_FLAG_SELECT | NLASTRIP_FLAG_ACTIVE);
/* also mark the strip for auto syncing the length, so that the strips accurately
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index 8028f990c42..3e3a8355f98 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -516,10 +516,6 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree)
write_node_socket(writer, sock);
}
- LISTBASE_FOREACH (bNodeLink *, link, &node->internal_links) {
- BLO_write_struct(writer, bNodeLink, link);
- }
-
if (node->storage) {
if (ELEM(ntree->type, NTREE_SHADER, NTREE_GEOMETRY) &&
ELEM(node->type, SH_NODE_CURVE_VEC, SH_NODE_CURVE_RGB, SH_NODE_CURVE_FLOAT)) {
@@ -703,13 +699,7 @@ void ntreeBlendReadData(BlendDataReader *reader, ID *owner_id, bNodeTree *ntree)
BLO_read_data_address(reader, &node->prop);
IDP_BlendDataRead(reader, &node->prop);
- BLO_read_list(reader, &node->internal_links);
- LISTBASE_FOREACH (bNodeLink *, link, &node->internal_links) {
- BLO_read_data_address(reader, &link->fromnode);
- BLO_read_data_address(reader, &link->fromsock);
- BLO_read_data_address(reader, &link->tonode);
- BLO_read_data_address(reader, &link->tosock);
- }
+ BLI_listbase_clear(&node->internal_links);
if (node->type == CMP_NODE_MOVIEDISTORTION) {
/* Do nothing, this is runtime cache and hence handled by generic code using
diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc
index 2d949fb5c65..d98f5e85028 100644
--- a/source/blender/blenkernel/intern/object.cc
+++ b/source/blender/blenkernel/intern/object.cc
@@ -1902,6 +1902,7 @@ bool BKE_object_is_in_editmode(const Object *ob)
/* Grease Pencil object has no edit mode data. */
return GPENCIL_EDIT_MODE((bGPdata *)ob->data);
case OB_CURVES:
+ /* Curves object has no edit mode data. */
return ob->mode == OB_MODE_EDIT;
default:
return false;
diff --git a/source/blender/blenkernel/intern/object_update.cc b/source/blender/blenkernel/intern/object_update.cc
index ceef6404bf0..e53090bcffe 100644
--- a/source/blender/blenkernel/intern/object_update.cc
+++ b/source/blender/blenkernel/intern/object_update.cc
@@ -292,6 +292,8 @@ void BKE_object_batch_cache_dirty_tag(Object *ob)
BKE_lattice_batch_cache_dirty_tag((struct Lattice *)ob->data, BKE_LATTICE_BATCH_DIRTY_ALL);
break;
case OB_CURVES_LEGACY:
+ case OB_SURF:
+ case OB_FONT:
BKE_curve_batch_cache_dirty_tag((struct Curve *)ob->data, BKE_CURVE_BATCH_DIRTY_ALL);
break;
case OB_MBALL: {
diff --git a/source/blender/blenkernel/intern/paint.cc b/source/blender/blenkernel/intern/paint.cc
index 13243925b28..408cd117e32 100644
--- a/source/blender/blenkernel/intern/paint.cc
+++ b/source/blender/blenkernel/intern/paint.cc
@@ -1043,6 +1043,8 @@ eObjectMode BKE_paint_object_mode_from_paintmode(ePaintMode mode)
return OB_MODE_TEXTURE_PAINT;
case PAINT_MODE_SCULPT_UV:
return OB_MODE_EDIT;
+ case PAINT_MODE_SCULPT_CURVES:
+ return OB_MODE_SCULPT_CURVES;
case PAINT_MODE_INVALID:
default:
return OB_MODE_OBJECT;
diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc
index 7c54b4d3f2f..e81657f9ef0 100644
--- a/source/blender/blenkernel/intern/volume.cc
+++ b/source/blender/blenkernel/intern/volume.cc
@@ -445,7 +445,7 @@ struct VolumeGrid {
* may actually be loaded by another user while this is false. But only after
* calling load() and is_loaded changes to true is it safe to access.
*
- * Const write access to this must be protected by `entry->mutex`.
+ * `const` write access to this must be protected by `entry->mutex`.
*/
mutable bool is_loaded;
};
@@ -480,7 +480,7 @@ struct VolumeGridVector : public std::list<VolumeGrid> {
metadata.reset();
}
- /* Mutex for file loading of grids list. Const write access to the fields after this must be
+ /* Mutex for file loading of grids list. `const` write access to the fields after this must be
* protected by locking with this mutex. */
mutable std::mutex mutex;
/* Absolute file path that grids have been loaded from. */
diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c
index dbdf8cc395d..de2e196c163 100644
--- a/source/blender/blenkernel/intern/writeavi.c
+++ b/source/blender/blenkernel/intern/writeavi.c
@@ -122,7 +122,8 @@ bMovieHandle *BKE_movie_handle_get(const char imtype)
R_IMF_IMTYPE_FFMPEG,
R_IMF_IMTYPE_H264,
R_IMF_IMTYPE_XVID,
- R_IMF_IMTYPE_THEORA)) {
+ R_IMF_IMTYPE_THEORA,
+ R_IMF_IMTYPE_AV1)) {
mh.start_movie = BKE_ffmpeg_start;
mh.append_movie = BKE_ffmpeg_append;
mh.end_movie = BKE_ffmpeg_end;
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c
index 99df07b6105..0d3a790ba00 100644
--- a/source/blender/blenkernel/intern/writeffmpeg.c
+++ b/source/blender/blenkernel/intern/writeffmpeg.c
@@ -299,6 +299,10 @@ static const char **get_file_extensions(int format)
static const char *rv[] = {".webm", NULL};
return rv;
}
+ case FFMPEG_AV1: {
+ static const char *rv[] = {".mp4", ".mkv", NULL};
+ return rv;
+ }
default:
return NULL;
}
@@ -455,6 +459,204 @@ static AVRational calc_time_base(uint den, double num, int codec_id)
return time_base;
}
+static const AVCodec *get_av1_encoder(
+ FFMpegContext *context, RenderData *rd, AVDictionary **opts, int rectx, int recty)
+{
+ /* There are three possible encoders for AV1: libaom-av1, librav1e, and libsvtav1. librav1e tends
+ * to give the best compression quality while libsvtav1 tends to be the fastest encoder. One of
+ * each will be picked based on the preset setting, and if a particular encoder is not available,
+ * then use the default returned by FFMpeg. */
+ const AVCodec *codec = NULL;
+ switch (context->ffmpeg_preset) {
+ case FFM_PRESET_BEST:
+ /* Default to libaom-av1 for BEST preset due to it performing better than rav1e in terms of
+ * video quality (VMAF scores). Fallback to rav1e if libaom-av1 isn't available. */
+ codec = avcodec_find_encoder_by_name("libaom-av1");
+ if (!codec) {
+ codec = avcodec_find_encoder_by_name("librav1e");
+ }
+ break;
+ case FFM_PRESET_REALTIME:
+ codec = avcodec_find_encoder_by_name("libsvtav1");
+ break;
+ case FFM_PRESET_GOOD:
+ default:
+ codec = avcodec_find_encoder_by_name("libaom-av1");
+ break;
+ }
+
+ /* Use the default AV1 encoder if the specified encoder wasn't found. */
+ if (!codec) {
+ codec = avcodec_find_encoder(AV_CODEC_ID_AV1);
+ }
+
+ /* Apply AV1 encoder specific settings. */
+ if (codec) {
+ if (strcmp(codec->name, "librav1e") == 0) {
+ /* Set "tiles" to 8 to enable multi-threaded encoding. */
+ if (rd->threads > 8) {
+ ffmpeg_dict_set_int(opts, "tiles", rd->threads);
+ }
+ else {
+ ffmpeg_dict_set_int(opts, "tiles", 8);
+ }
+
+ /* Use a reasonable speed setting based on preset. Speed ranges from 0-10.
+ * Must check context->ffmpeg_preset again in case this encoder was selected due to the
+ * absence of another. */
+ switch (context->ffmpeg_preset) {
+ case FFM_PRESET_BEST:
+ ffmpeg_dict_set_int(opts, "speed", 4);
+ break;
+ case FFM_PRESET_REALTIME:
+ ffmpeg_dict_set_int(opts, "speed", 10);
+ break;
+ case FFM_PRESET_GOOD:
+ default:
+ ffmpeg_dict_set_int(opts, "speed", 6);
+ break;
+ }
+ if (context->ffmpeg_crf >= 0) {
+ /* librav1e does not use -crf, but uses -qp in the range of 0-255. Calculates the roughly
+ * equivalent float, and truncates it to an integer. */
+ unsigned int qp_value = ((float)context->ffmpeg_crf) * 255.0F / 51.0F;
+ if (qp_value > 255) {
+ qp_value = 255;
+ }
+ ffmpeg_dict_set_int(opts, "qp", qp_value);
+ }
+ /* Set gop_size as rav1e's "--keyint". */
+ char buffer[64];
+ BLI_snprintf(buffer, sizeof(buffer), "keyint=%d", context->ffmpeg_gop_size);
+ av_dict_set(opts, "rav1e-params", buffer, 0);
+ }
+ else if (strcmp(codec->name, "libsvtav1") == 0) {
+ /* Set preset value based on ffmpeg_preset.
+ * Must check context->ffmpeg_preset again in case this encoder was selected due to the
+ * absence of another. */
+ switch (context->ffmpeg_preset) {
+ case FFM_PRESET_REALTIME:
+ ffmpeg_dict_set_int(opts, "preset", 8);
+ break;
+ case FFM_PRESET_BEST:
+ ffmpeg_dict_set_int(opts, "preset", 3);
+ break;
+ case FFM_PRESET_GOOD:
+ default:
+ ffmpeg_dict_set_int(opts, "preset", 5);
+ break;
+ }
+ if (context->ffmpeg_crf >= 0) {
+ /* libsvtav1 does not support crf until FFmpeg builds since 2022-02-24, use qp as fallback.
+ */
+ ffmpeg_dict_set_int(opts, "qp", context->ffmpeg_crf);
+ }
+ }
+ else if (strcmp(codec->name, "libaom-av1") == 0) {
+ /* Speed up libaom-av1 encoding by enabling multithreading and setting tiles. */
+ ffmpeg_dict_set_int(opts, "row-mt", 1);
+ const char *tiles_string = NULL;
+ bool tiles_string_is_dynamic = false;
+ if (rd->threads > 0) {
+ /* See if threads is a square. */
+ int threads_sqrt = sqrtf(rd->threads);
+ if (threads_sqrt < 4) {
+ /* Ensure a default minimum. */
+ threads_sqrt = 4;
+ }
+ if (is_power_of_2_i(threads_sqrt) && threads_sqrt * threads_sqrt == rd->threads) {
+ /* Is a square num, therefore just do "sqrt x sqrt" for tiles parameter. */
+ int digits = 0;
+ for (int t_sqrt_copy = threads_sqrt; t_sqrt_copy > 0; t_sqrt_copy /= 10) {
+ ++digits;
+ }
+ /* A char array need only an alignment of 1. */
+ char *tiles_string_mut = (char *)calloc(digits * 2 + 2, 1);
+ BLI_snprintf(tiles_string_mut, digits * 2 + 2, "%dx%d", threads_sqrt, threads_sqrt);
+ tiles_string_is_dynamic = true;
+ tiles_string = tiles_string_mut;
+ }
+ else {
+ /* Is not a square num, set greater side based on longer side, or use a square if both
+ sides are equal. */
+ int sqrt_p2 = power_of_2_min_i(threads_sqrt);
+ if (sqrt_p2 < 2) {
+ /* Ensure a default minimum. */
+ sqrt_p2 = 2;
+ }
+ int sqrt_p2_next = power_of_2_min_i((int)rd->threads / sqrt_p2);
+ if (sqrt_p2_next < 1) {
+ sqrt_p2_next = 1;
+ }
+ if (sqrt_p2 > sqrt_p2_next) {
+ /* Ensure sqrt_p2_next is greater or equal to sqrt_p2. */
+ int temp = sqrt_p2;
+ sqrt_p2 = sqrt_p2_next;
+ sqrt_p2_next = temp;
+ }
+ int combined_digits = 0;
+ for (int sqrt_p2_copy = sqrt_p2; sqrt_p2_copy > 0; sqrt_p2_copy /= 10) {
+ ++combined_digits;
+ }
+ for (int sqrt_p2_copy = sqrt_p2_next; sqrt_p2_copy > 0; sqrt_p2_copy /= 10) {
+ ++combined_digits;
+ }
+ /* A char array need only an alignment of 1. */
+ char *tiles_string_mut = (char *)calloc(combined_digits + 2, 1);
+ if (rectx > recty) {
+ BLI_snprintf(tiles_string_mut, combined_digits + 2, "%dx%d", sqrt_p2_next, sqrt_p2);
+ }
+ else if (rectx < recty) {
+ BLI_snprintf(tiles_string_mut, combined_digits + 2, "%dx%d", sqrt_p2, sqrt_p2_next);
+ }
+ else {
+ BLI_snprintf(tiles_string_mut, combined_digits + 2, "%dx%d", sqrt_p2, sqrt_p2);
+ }
+ tiles_string_is_dynamic = true;
+ tiles_string = tiles_string_mut;
+ }
+ }
+ else {
+ /* Thread count unknown, default to 8. */
+ if (rectx > recty) {
+ tiles_string = "4x2";
+ }
+ else if (rectx < recty) {
+ tiles_string = "2x4";
+ }
+ else {
+ tiles_string = "2x2";
+ }
+ }
+ av_dict_set(opts, "tiles", tiles_string, 0);
+ if (tiles_string_is_dynamic) {
+ free((void *)tiles_string);
+ }
+ /* libaom-av1 uses "cpu-used" instead of "preset" for defining compression quality.
+ * This value is in a range from 0-8. 0 and 8 are extremes, but we will allow 8.
+ * Must check context->ffmpeg_preset again in case this encoder was selected due to the
+ * absence of another. */
+ switch (context->ffmpeg_preset) {
+ case FFM_PRESET_REALTIME:
+ ffmpeg_dict_set_int(opts, "cpu-used", 8);
+ break;
+ case FFM_PRESET_BEST:
+ ffmpeg_dict_set_int(opts, "cpu-used", 4);
+ break;
+ case FFM_PRESET_GOOD:
+ default:
+ ffmpeg_dict_set_int(opts, "cpu-used", 6);
+ break;
+ }
+
+ /* CRF related settings is similar to H264 for libaom-av1, so we will rely on those settings
+ * applied later. */
+ }
+ }
+
+ return codec;
+}
+
/* prepare a video stream for the output file */
static AVStream *alloc_video_stream(FFMpegContext *context,
@@ -480,7 +682,14 @@ static AVStream *alloc_video_stream(FFMpegContext *context,
/* Set up the codec context */
- codec = avcodec_find_encoder(codec_id);
+ if (codec_id == AV_CODEC_ID_AV1) {
+ /* Use get_av1_encoder() to get the ideal (hopefully) encoder for AV1 based
+ * on given parameters, and also set up opts. */
+ codec = get_av1_encoder(context, rd, &opts, rectx, recty);
+ }
+ else {
+ codec = avcodec_find_encoder(codec_id);
+ }
if (!codec) {
fprintf(stderr, "Couldn't find valid video codec\n");
context->video_codec = NULL;
@@ -568,7 +777,9 @@ static AVStream *alloc_video_stream(FFMpegContext *context,
default:
printf("Unknown preset number %i, ignoring.\n", context->ffmpeg_preset);
}
- if (preset_name != NULL) {
+ /* "codec_id != AV_CODEC_ID_AV1" is required due to "preset" already being set by an AV1 codec.
+ */
+ if (preset_name != NULL && codec_id != AV_CODEC_ID_AV1) {
av_dict_set(&opts, "preset", preset_name, 0);
}
if (deadline_name != NULL) {
@@ -951,6 +1162,9 @@ static int start_ffmpeg_impl(FFMpegContext *context,
case FFMPEG_FLV:
video_codec = AV_CODEC_ID_FLV1;
break;
+ case FFMPEG_AV1:
+ video_codec = AV_CODEC_ID_AV1;
+ break;
default:
/* These containers are not restricted to any specific codec types.
* Currently we expect these to be .avi, .mov, .mkv, and .mp4.
@@ -1482,6 +1696,18 @@ void BKE_ffmpeg_preset_set(RenderData *rd, int preset)
rd->ffcodecdata.mux_packet_size = 2048;
rd->ffcodecdata.mux_rate = 10080000;
break;
+ case FFMPEG_PRESET_AV1:
+ rd->ffcodecdata.type = FFMPEG_AV1;
+ rd->ffcodecdata.codec = AV_CODEC_ID_AV1;
+ rd->ffcodecdata.video_bitrate = 6000;
+ rd->ffcodecdata.gop_size = is_ntsc ? 18 : 15;
+ rd->ffcodecdata.rc_max_rate = 9000;
+ rd->ffcodecdata.rc_min_rate = 0;
+ rd->ffcodecdata.rc_buffer_size = 224 * 8;
+ rd->ffcodecdata.mux_packet_size = 2048;
+ rd->ffcodecdata.mux_rate = 10080000;
+
+ break;
}
}
@@ -1521,6 +1747,12 @@ void BKE_ffmpeg_image_type_verify(RenderData *rd, const ImageFormatData *imf)
audio = 1;
}
}
+ else if (imf->imtype == R_IMF_IMTYPE_AV1) {
+ if (rd->ffcodecdata.codec != AV_CODEC_ID_AV1) {
+ BKE_ffmpeg_preset_set(rd, FFMPEG_PRESET_AV1);
+ audio = 1;
+ }
+ }
if (audio && rd->ffcodecdata.audio_codec < 0) {
rd->ffcodecdata.audio_codec = AV_CODEC_ID_NONE;