From 7df175c3266d550f99d74016e3603f81ea1baa44 Mon Sep 17 00:00:00 2001 From: Jorn Visser Date: Thu, 16 Oct 2025 15:29:03 +0200 Subject: [PATCH 1/4] Fix: Unused result warning Check the result of the write function to avoid an unused result warning. Pull Request: https://projects.blender.org/blender/blender/pulls/148198 --- source/blender/blenlib/intern/BLI_mmap.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/blender/blenlib/intern/BLI_mmap.cc b/source/blender/blenlib/intern/BLI_mmap.cc index d69c4637468..9fc4c747a36 100644 --- a/source/blender/blenlib/intern/BLI_mmap.cc +++ b/source/blender/blenlib/intern/BLI_mmap.cc @@ -275,7 +275,9 @@ static void print_error(const char *message) { char buffer[256]; size_t length = BLI_string_join(buffer, sizeof(buffer), "BLI_mmap: ", message, "\n"); - write(STDERR_FILENO, buffer, length); + if (write(STDERR_FILENO, buffer, length) < 0) { + /* If writing to stderr fails, there is nowhere to write an error about that. */ + } } static bool try_map_zeros(BLI_mmap_file *file) From c22db2251e9b780c00bc505fd7552cc86278dda8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Thu, 16 Oct 2025 15:36:52 +0200 Subject: [PATCH 2/4] Fix #111576: Unnecessary write operations on blender_assets.cats.txt When saving asset catalogs to an already-existing file, only perform that save when there were local changes to the catalogs. This prevents unnecessary writes to the catalog definition file, as that can cause conflicts when multiple Blender instances share the same asset library (either directly or via Syncthing/Dropbox/etc.) Pull Request: https://projects.blender.org/blender/blender/pulls/148205 --- .../blender/asset_system/AS_asset_catalog.hh | 18 +++++++++++++++--- .../asset_system/intern/asset_catalog.cc | 12 +++++++++++- .../intern/asset_catalog_definition_file.cc | 5 +++++ .../intern/asset_catalog_definition_file.hh | 5 +++++ .../asset_system/tests/asset_catalog_test.cc | 7 +++++++ 5 files changed, 43 insertions(+), 4 deletions(-) diff --git a/source/blender/asset_system/AS_asset_catalog.hh b/source/blender/asset_system/AS_asset_catalog.hh index a82b86351d0..364bebfc3f6 100644 --- a/source/blender/asset_system/AS_asset_catalog.hh +++ b/source/blender/asset_system/AS_asset_catalog.hh @@ -71,7 +71,7 @@ class AssetCatalogService { * * This "dirty" state is tracked per catalog, so that it's possible to gracefully load changes * from disk. Any catalog with unsaved changes will not be overwritten by on-disk changes. */ - void tag_has_unsaved_changes(AssetCatalog *edited_catalog); + void tag_has_unsaved_changes(AssetCatalog *edited_catalog = nullptr); bool has_unsaved_changes() const; /** @@ -159,8 +159,15 @@ class AssetCatalogService { */ AssetCatalogFilter create_catalog_filter(CatalogID active_catalog_id) const; - /** Create a catalog with some sensible auto-generated catalog ID. - * The catalog will be saved to the default catalog file. */ + /** + * Create a catalog with some sensible auto-generated catalog ID. + * The catalog will be saved to the default catalog file. + * + * NOTE: this does NOT mark the catalog service itself as 'has changes'. The caller is + * responsible for that. + * + * \see #tag_has_unsaved_changes() + */ AssetCatalog *create_catalog(const AssetCatalogPath &catalog_path); /** @@ -228,6 +235,11 @@ class AssetCatalogService { * will be removed from a CDF when saved to disk. * * This is a lower-level function than #prune_catalogs_by_path. + * + * NOTE: this does NOT mark the catalog service itself as 'has changes'. The caller is + * responsible for that. + * + * \see #tag_has_unsaved_changes() */ void delete_catalog_by_id_soft(CatalogID catalog_id); diff --git a/source/blender/asset_system/intern/asset_catalog.cc b/source/blender/asset_system/intern/asset_catalog.cc index 21efd40f20a..02ce2d581db 100644 --- a/source/blender/asset_system/intern/asset_catalog.cc +++ b/source/blender/asset_system/intern/asset_catalog.cc @@ -482,9 +482,19 @@ bool AssetCatalogService::write_to_disk_ex(const CatalogFilePath &blend_file_pat { /* TODO(Sybren): expand to support multiple CDFs. */ - /* - Already loaded a CDF from disk? -> Always write to that file. */ + /* - Already loaded a CDF from disk? -> Only write to that file when there were actual changes. + * This prevents touching the file, which can cause issues when multiple Blender instances are + * accessing the same file (like on shared storage, Syncthing, etc.). See #111576. + */ if (catalog_collection_->catalog_definition_file_) { + /* Always sync with what's on disk. */ this->reload_catalogs(); + + if (!this->has_unsaved_changes() && + catalog_collection_->catalog_definition_file_->exists_on_disk()) + { + return true; + } return catalog_collection_->catalog_definition_file_->write_to_disk(); } diff --git a/source/blender/asset_system/intern/asset_catalog_definition_file.cc b/source/blender/asset_system/intern/asset_catalog_definition_file.cc index 4364b85a75a..5cf9aff7790 100644 --- a/source/blender/asset_system/intern/asset_catalog_definition_file.cc +++ b/source/blender/asset_system/intern/asset_catalog_definition_file.cc @@ -185,6 +185,11 @@ bool AssetCatalogDefinitionFile::write_to_disk(const CatalogFilePath &dest_file_ return true; } +bool AssetCatalogDefinitionFile::exists_on_disk() const +{ + return BLI_exists(this->file_path.c_str()); +} + bool AssetCatalogDefinitionFile::write_to_disk_unsafe(const CatalogFilePath &dest_file_path) const { char directory[PATH_MAX]; diff --git a/source/blender/asset_system/intern/asset_catalog_definition_file.hh b/source/blender/asset_system/intern/asset_catalog_definition_file.hh index c7d99c9677a..870a20b64ba 100644 --- a/source/blender/asset_system/intern/asset_catalog_definition_file.hh +++ b/source/blender/asset_system/intern/asset_catalog_definition_file.hh @@ -55,6 +55,11 @@ class AssetCatalogDefinitionFile { */ bool write_to_disk(const CatalogFilePath &dest_file_path) const; + /** + * Returns whether this file exists on disk. + */ + bool exists_on_disk() const; + bool contains(CatalogID catalog_id) const; /** Add a catalog, overwriting the one with the same catalog ID. */ void add_overwrite(AssetCatalog *catalog); diff --git a/source/blender/asset_system/tests/asset_catalog_test.cc b/source/blender/asset_system/tests/asset_catalog_test.cc index 0334a203318..cbb4fb8c328 100644 --- a/source/blender/asset_system/tests/asset_catalog_test.cc +++ b/source/blender/asset_system/tests/asset_catalog_test.cc @@ -341,6 +341,7 @@ TEST_F(AssetCatalogTest, on_blendfile_save__with_existing_cdf) TestableAssetCatalogService service(cdf_filename); service.load_from_disk(); const AssetCatalog *cat = service.create_catalog("some/catalog/path"); + service.tag_has_unsaved_changes(); const CatalogFilePath blendfilename = top_level_dir + "subdir" + SEP_STR + "some_file.blend"; ASSERT_TRUE(service.write_to_disk(blendfilename)); @@ -458,6 +459,10 @@ TEST_F(AssetCatalogTest, create_first_catalog_from_scratch) /* Creating a new catalog should not save anything to disk yet. */ EXPECT_FALSE(BLI_exists(temp_lib_root.c_str())); + /* Creating a new catalog should not mark the asset service as 'dirty'; that's + * the caller's responsibility. */ + EXPECT_FALSE(service.has_unsaved_changes()); + /* Writing to disk should create the directory + the default file. */ service.write_to_disk(temp_lib_root + "phony.blend"); EXPECT_TRUE(BLI_is_dir(temp_lib_root.c_str())); @@ -498,6 +503,7 @@ TEST_F(AssetCatalogTest, create_catalog_after_loading_file) /* This should create a new catalog but not write to disk. */ const AssetCatalog *new_catalog = service.create_catalog("new/catalog"); const bUUID new_catalog_id = new_catalog->catalog_id; + service.tag_has_unsaved_changes(); /* Reload the on-disk catalog file. */ TestableAssetCatalogService loaded_service(temp_lib_root); @@ -887,6 +893,7 @@ TEST_F(AssetCatalogTest, backups) TestableAssetCatalogService service(cdf_dir); service.load_from_disk(); service.delete_catalog_by_id_soft(UUID_POSES_ELLIE); + service.tag_has_unsaved_changes(); service.write_to_disk(cdf_dir + "phony.blend"); const CatalogFilePath backup_path = writable_cdf_file + "~"; From b597c0f1edee3eae0108187e90dcdefe0d663a37 Mon Sep 17 00:00:00 2001 From: u3dreal Date: Thu, 16 Oct 2025 15:38:38 +0200 Subject: [PATCH 3/4] Fix: Cycles: IES interpolation artifacts at angular boundaries Fixes artifacts in IES data interpolation where edge samples (e.g., v == 0 or h_i == h_num-1) were clamped to 0.0f instead of valid intensity values. --- intern/cycles/kernel/util/ies.h | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/intern/cycles/kernel/util/ies.h b/intern/cycles/kernel/util/ies.h index ee09e526162..8642082c0a3 100644 --- a/intern/cycles/kernel/util/ies.h +++ b/intern/cycles/kernel/util/ies.h @@ -27,22 +27,29 @@ ccl_device_inline float interpolate_ies_vertical(KernelGlobals kg, * we can just take the corresponding value at the current horizontal coordinate. */ #define IES_LOOKUP(v) kernel_data_fetch(ies, ofs + h * v_num + (v)) - float a = 0.0f; + + /* Look up the inner two points directly. */ + const float c = IES_LOOKUP(v + 1); + const float b = IES_LOOKUP(v); + + /* Look up first point, or fall back to second point if not available. */ + float a = b; if (v > 0) { a = IES_LOOKUP(v - 1); } else if (wrap_vlow) { a = IES_LOOKUP(1); } - const float b = IES_LOOKUP(v); - const float c = IES_LOOKUP(v + 1); - float d = 0.0f; + + /* Look up last point, or fall back to third point if not available. */ + float d = c; if (v + 2 < v_num) { d = IES_LOOKUP(v + 2); } else if (wrap_vhigh) { d = IES_LOOKUP(v_num - 2); } + #undef IES_LOOKUP return cubic_interp(a, b, c, d, v_frac); @@ -105,7 +112,14 @@ ccl_device_inline float kernel_ies_interp(KernelGlobals kg, /* Skip forward to the actual intensity data. */ ofs += h_num + v_num; - float a = 0.0f; + /* Interpolate the inner two points directly. */ + const float b = interpolate_ies_vertical( + kg, ofs, wrap_vlow, wrap_vhigh, v_i, v_num, v_frac, h_i); + const float c = interpolate_ies_vertical( + kg, ofs, wrap_vlow, wrap_vhigh, v_i, v_num, v_frac, h_i + 1); + + /* Interpolate first point, or fall back to second point if not available. */ + float a = b; if (h_i > 0) { a = interpolate_ies_vertical(kg, ofs, wrap_vlow, wrap_vhigh, v_i, v_num, v_frac, h_i - 1); } @@ -113,11 +127,9 @@ ccl_device_inline float kernel_ies_interp(KernelGlobals kg, /* The last entry (360°) equals the first one, so we need to wrap around to the one before. */ a = interpolate_ies_vertical(kg, ofs, wrap_vlow, wrap_vhigh, v_i, v_num, v_frac, h_num - 2); } - const float b = interpolate_ies_vertical( - kg, ofs, wrap_vlow, wrap_vhigh, v_i, v_num, v_frac, h_i); - const float c = interpolate_ies_vertical( - kg, ofs, wrap_vlow, wrap_vhigh, v_i, v_num, v_frac, h_i + 1); - float d = 0.0f; + + /* Interpolate last point, or fall back to second point if not available. */ + float d = b; if (h_i + 2 < h_num) { d = interpolate_ies_vertical(kg, ofs, wrap_vlow, wrap_vhigh, v_i, v_num, v_frac, h_i + 2); } From 0a0d3678a69b4900cf8c462478047cc04e3fa3f7 Mon Sep 17 00:00:00 2001 From: Damien Picard Date: Thu, 16 Oct 2025 15:38:59 +0200 Subject: [PATCH 4/4] Cycles: OSL Camera: Use title case for parameters in the UI This is an alternate solution to !146889 to improve labels in the camera UI, while being much less invasive. It doesn't take custom labels into account, but it simply uses the parameter names with title case. Pull Request: https://projects.blender.org/blender/blender/pulls/148141 --- intern/cycles/blender/addon/ui.py | 2 +- scripts/templates_osl/advanced_camera.osl | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 1fc2da08bc6..e7bcfa8226d 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -1210,7 +1210,7 @@ class CYCLES_CAMERA_PT_lens_custom_parameters(CyclesButtonsPanel, Panel): col = layout.column() for key in ccam.keys(): - col.prop(ccam, f'["{key}"]') + col.prop(ccam, f'["{key}"]', text=bpy.path.display_name(key)) class CYCLES_PT_context_material(CyclesButtonsPanel, Panel): diff --git a/scripts/templates_osl/advanced_camera.osl b/scripts/templates_osl/advanced_camera.osl index f2b004968cd..3ce1d7157e8 100644 --- a/scripts/templates_osl/advanced_camera.osl +++ b/scripts/templates_osl/advanced_camera.osl @@ -35,7 +35,7 @@ shader camera(float focal_length = 50.0 [[ float min = 0.0, float sensitivity = float distortion_k3 = 0.0, float swirl_scale = 100.0, float swirl_amplitude = 0.01, - float swirl_W = 0.0 [[ float sensitivity = 1]], + float swirl_w = 0.0 [[ float sensitivity = 1]], output point position = 0.0, output vector direction = 0.0, output color throughput = 1.0) @@ -59,7 +59,7 @@ shader camera(float focal_length = 50.0 [[ float min = 0.0, float sensitivity = Pcam = Pcam * sensor_size / focal_length; if (do_swirl) { - Pcam += swirl_amplitude * noise("perlin", Pcam * swirl_scale, swirl_W); + Pcam += swirl_amplitude * noise("perlin", Pcam * swirl_scale, swirl_w); } direction = normalize(vector(Pcam.x, Pcam.y, 1.0));