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:
authorJeroen Bakker <jeroen@blender.org>2021-11-26 15:29:18 +0300
committerJeroen Bakker <jeroen@blender.org>2021-11-26 15:29:18 +0300
commit6cda987f592409689a384226b03a49fc32648530 (patch)
treea32afd9353e1e53e8e42eef03a10126aaae167f9
parentb30f101fc0865322bfc4451c54397075a8e02c16 (diff)
Added API documentation.temp-gpu-texture-partial-updates
-rw-r--r--source/blender/blenkernel/BKE_image_partial_update.hh200
-rw-r--r--source/blender/blenkernel/intern/image_gpu.cc10
-rw-r--r--source/blender/blenkernel/intern/image_partial_update.cc18
-rw-r--r--source/blender/blenkernel/intern/image_partial_update_test.cc8
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;