diff options
author | Jeroen Bakker <jeroen@blender.org> | 2021-11-26 15:29:18 +0300 |
---|---|---|
committer | Jeroen Bakker <jeroen@blender.org> | 2021-11-26 15:29:18 +0300 |
commit | 6cda987f592409689a384226b03a49fc32648530 (patch) | |
tree | a32afd9353e1e53e8e42eef03a10126aaae167f9 | |
parent | b30f101fc0865322bfc4451c54397075a8e02c16 (diff) |
Added API documentation.temp-gpu-texture-partial-updates
4 files changed, 159 insertions, 77 deletions
diff --git a/source/blender/blenkernel/BKE_image_partial_update.hh b/source/blender/blenkernel/BKE_image_partial_update.hh index 107e54c9351..dfc02fea742 100644 --- a/source/blender/blenkernel/BKE_image_partial_update.hh +++ b/source/blender/blenkernel/BKE_image_partial_update.hh @@ -18,6 +18,13 @@ /** \file * \ingroup bke + * + * To reduce the overhead of image processing this file contains a mechanism to detect areas of the + * image that are changed. These areas are organized in chunks. Changes that happen over time are + * organized in changesets. + * + * A common usecase is to update GPUTexture for drawing where only that part is uploaded that only + * changed. */ #pragma once @@ -104,23 +111,76 @@ ePartialUpdateCollectResult BKE_image_partial_update_collect_changes( ePartialUpdateIterResult BKE_image_partial_update_get_next_change( struct PartialUpdateUser *user, struct PartialUpdateRegion *r_region); +/** \brief Abstract class to load tile data when using the PartialUpdateChecker. */ class AbstractTileData { protected: virtual ~AbstractTileData() = default; public: + /** + * \brief Load the data for the given tile_number. + * + * Invoked when changes are on a different tile compared to the previous tile.. + */ virtual void init_data(TileNumber tile_number) = 0; + /** + * \brief Unload the data that has been loaded. + * + * Invoked when changes are on a different tile compared to the previous tile or when finished + * iterating over the changes. + */ virtual void free_data() = 0; }; -class ImageTileData : AbstractTileData { +/** + * \brief Class to not load any tile specific data when iterating over changes. + */ +class NoTileData : AbstractTileData { public: - ImageTile *tile = nullptr; - ImBuf *tile_buffer = nullptr; + NoTileData(Image *UNUSED(image), ImageUser &UNUSED(image_user)) + { + } + + void init_data(TileNumber UNUSED(new_tile_number)) override + { + } + void free_data() override + { + } +}; + +/** + * \brief Load the ImageTile and ImBuf associated with the partial change. + */ +class ImageTileData : AbstractTileData { + public: + /** + * \brief Not owned Image that is being iterated over. + */ Image *image; + + /** + * \brief Local copy of the image user. + * + * The local copy is required so we don't change the image user of the caller. + * We need to change it in order to request data for a specific tile. + */ ImageUser image_user; + /** + * \brief ImageTile associated with the loaded tile. + * Data is not owned by this instance but by the `image`. + */ + ImageTile *tile = nullptr; + + /** + * \brief ImBuf of the loaded tile. + * + * Can be nullptr when the file doesn't exist or when the tile hasn't been initialized. + */ + ImBuf *tile_buffer = nullptr; + ImageTileData(Image *image, ImageUser image_user) : image(image), image_user(image_user) { } @@ -128,7 +188,6 @@ class ImageTileData : AbstractTileData { void init_data(TileNumber new_tile_number) override { image_user.tile = new_tile_number; - tile = BKE_image_get_tile(image, new_tile_number); tile_buffer = BKE_image_acquire_ibuf(image, &image_user, NULL); } @@ -141,77 +200,79 @@ class ImageTileData : AbstractTileData { } }; -class NoTileData : AbstractTileData { - public: - NoTileData(Image *UNUSED(image), ImageUser &UNUSED(image_user)) - { - } +template<typename TileData = NoTileData> struct PartialUpdateChecker { - void init_data(TileNumber UNUSED(new_tile_number)) override - { - } - - void free_data() override - { - } -}; - -template<typename TileData = NoTileData> struct PartialUpdateCollectResult { + /** + * \brief Not owned Image that is being iterated over. + */ Image *image; - PartialUpdateUser *user; - TileData tile_data; - TileNumber last_tile_number; - PartialUpdateRegion changed_region; + ImageUser *image_user; - private: - ePartialUpdateCollectResult collect_result; + /** + * \brief the collected changes are stored inside the PartialUpdateUser. + */ + PartialUpdateUser *user; - public: - PartialUpdateCollectResult(Image *image, - ImageUser image_user, - PartialUpdateUser *user, - ePartialUpdateCollectResult collect_result) - : image(image), user(user), tile_data(image, image_user), collect_result(collect_result) - { - } + struct CollectResult { + PartialUpdateChecker<TileData> *checker; + + /** + * \brief Tile specific data. + */ + TileData tile_data; + PartialUpdateRegion changed_region; + ePartialUpdateCollectResult result_code; + + private: + TileNumber last_tile_number; + + public: + CollectResult(PartialUpdateChecker<TileData> *checker, ePartialUpdateCollectResult result_code) + : checker(checker), + tile_data(checker->image, *checker->image_user), + result_code(result_code) + { + } - const ePartialUpdateCollectResult get_collect_result() const - { - return collect_result; - } + const ePartialUpdateCollectResult get_result_code() const + { + return result_code; + } - ePartialUpdateIterResult get_next_change() - { - BLI_assert(collect_result == ePartialUpdateCollectResult::PartialChangesDetected); - ePartialUpdateIterResult result = BKE_image_partial_update_get_next_change(user, - &changed_region); - switch (result) { - case ePartialUpdateIterResult::Finished: - tile_data.free_data(); - return result; - - case ePartialUpdateIterResult::ChangeAvailable: - if (last_tile_number == changed_region.tile_number) { + /** + * \brief Load the next changed region. + * + * This member function can only be called when partial changes are detected. + * (`get_result_code()` returns `ePartialUpdateCollectResult::PartialChangesDetected`). + * + * When changes for another tile than the previous tile is loaded the #tile_data will be + * updated. + */ + ePartialUpdateIterResult get_next_change() + { + BLI_assert(result_code == ePartialUpdateCollectResult::PartialChangesDetected); + ePartialUpdateIterResult result = BKE_image_partial_update_get_next_change(checker->user, + &changed_region); + switch (result) { + case ePartialUpdateIterResult::Finished: + tile_data.free_data(); return result; - } - tile_data.free_data(); - tile_data.init_data(changed_region.tile_number); - last_tile_number = changed_region.tile_number; - return result; - - ; - default: - BLI_assert_unreachable(); - return result; - } - } -}; -template<typename TileData = NoTileData> class PartialUpdateChecker { + case ePartialUpdateIterResult::ChangeAvailable: + if (last_tile_number == changed_region.tile_number) { + return result; + } + tile_data.free_data(); + tile_data.init_data(changed_region.tile_number); + last_tile_number = changed_region.tile_number; + return result; - Image *image; - ImageUser *image_user; - PartialUpdateUser *user; + default: + BLI_assert_unreachable(); + return result; + } + } + }; public: PartialUpdateChecker(Image *image, ImageUser *image_user, PartialUpdateUser *user) @@ -219,11 +280,14 @@ template<typename TileData = NoTileData> class PartialUpdateChecker { { } - PartialUpdateCollectResult<TileData> collect_changes() + /** + * \brief Check for new changes since the last time this method was invoked for this #user. + */ + CollectResult collect_changes() { ePartialUpdateCollectResult collect_result = BKE_image_partial_update_collect_changes(image, user); - return PartialUpdateCollectResult<TileData>(image, *image_user, user, collect_result); + return CollectResult(this, collect_result); } }; diff --git a/source/blender/blenkernel/intern/image_gpu.cc b/source/blender/blenkernel/intern/image_gpu.cc index 14ea935bb36..070b6eb2a89 100644 --- a/source/blender/blenkernel/intern/image_gpu.cc +++ b/source/blender/blenkernel/intern/image_gpu.cc @@ -335,7 +335,7 @@ static void image_update_reusable_textures(Image *ima, } static void image_gpu_texture_partial_update_changes_available( - PartialUpdateCollectResult<ImageTileData> &changes) + Image *image, PartialUpdateChecker<ImageTileData>::CollectResult &changes) { while (changes.get_next_change() == ePartialUpdateIterResult::ChangeAvailable) { const int tile_offset_x = changes.changed_region.region.xmin; @@ -344,7 +344,7 @@ static void image_gpu_texture_partial_update_changes_available( BLI_rcti_size_x(&changes.changed_region.region)); const int tile_height = min_ii(changes.tile_data.tile_buffer->y, BLI_rcti_size_y(&changes.changed_region.region)); - image_update_gputexture_ex(changes.image, + image_update_gputexture_ex(image, changes.tile_data.tile, changes.tile_data.tile_buffer, tile_offset_x, @@ -357,15 +357,15 @@ static void image_gpu_texture_partial_update_changes_available( static void image_gpu_texture_try_partial_update(Image *image, ImageUser *iuser) { PartialUpdateChecker<ImageTileData> checker(image, iuser, image->runtime.partial_update_user); - PartialUpdateCollectResult<ImageTileData> changes = checker.collect_changes(); - switch (changes.get_collect_result()) { + PartialUpdateChecker<ImageTileData>::CollectResult changes = checker.collect_changes(); + switch (changes.get_result_code()) { case ePartialUpdateCollectResult::FullUpdateNeeded: { image_free_gpu(image, true); break; } case ePartialUpdateCollectResult::PartialChangesDetected: { - image_gpu_texture_partial_update_changes_available(changes); + image_gpu_texture_partial_update_changes_available(image, changes); break; } diff --git a/source/blender/blenkernel/intern/image_partial_update.cc b/source/blender/blenkernel/intern/image_partial_update.cc index 731ba879de8..59d21d66f72 100644 --- a/source/blender/blenkernel/intern/image_partial_update.cc +++ b/source/blender/blenkernel/intern/image_partial_update.cc @@ -1,5 +1,23 @@ +/* + * 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. + */ /** * \file image_gpu_partial_update.cc + * \ingroup bke * * To reduce the overhead of image processing this file contains a mechanism to detect areas of the * image that are changed. These areas are organized in chunks. Changes that happen over time are diff --git a/source/blender/blenkernel/intern/image_partial_update_test.cc b/source/blender/blenkernel/intern/image_partial_update_test.cc index 764f0b3ce6c..70aa51f7c98 100644 --- a/source/blender/blenkernel/intern/image_partial_update_test.cc +++ b/source/blender/blenkernel/intern/image_partial_update_test.cc @@ -366,11 +366,11 @@ TEST_F(ImagePartialUpdateTest, iterator) { PartialUpdateChecker<NoTileData> checker(image, &image_user, partial_update_user); /* First tile should always return a full update. */ - PartialUpdateCollectResult<NoTileData> changes = checker.collect_changes(); - EXPECT_EQ(changes.get_collect_result(), ePartialUpdateCollectResult::FullUpdateNeeded); + PartialUpdateChecker<NoTileData>::CollectResult changes = checker.collect_changes(); + EXPECT_EQ(changes.get_result_code(), ePartialUpdateCollectResult::FullUpdateNeeded); /* Second invoke should now detect no changes. */ changes = checker.collect_changes(); - EXPECT_EQ(changes.get_collect_result(), ePartialUpdateCollectResult::NoChangesDetected); + EXPECT_EQ(changes.get_result_code(), ePartialUpdateCollectResult::NoChangesDetected); /* Mark region. */ rcti region; @@ -379,7 +379,7 @@ TEST_F(ImagePartialUpdateTest, iterator) /* Partial Update should be available. */ changes = checker.collect_changes(); - EXPECT_EQ(changes.get_collect_result(), ePartialUpdateCollectResult::PartialChangesDetected); + EXPECT_EQ(changes.get_result_code(), ePartialUpdateCollectResult::PartialChangesDetected); /* Check tiles. */ int num_tiles_found = 0; |