[Bf-blender-cvs] [cb058490831] temp-gpu-texture-partial-updates: Replaced internal gputexture generation with new partial update.
Jeroen Bakker
noreply at git.blender.org
Wed Nov 17 15:29:45 CET 2021
Commit: cb058490831487ad808c05930916eaeed4c94b34
Author: Jeroen Bakker
Date: Tue Nov 16 16:12:24 2021 +0100
Branches: temp-gpu-texture-partial-updates
https://developer.blender.org/rBcb058490831487ad808c05930916eaeed4c94b34
Replaced internal gputexture generation with new partial update.
===================================================================
M source/blender/blenkernel/intern/image.c
M source/blender/blenkernel/intern/image_gpu.c
M source/blender/blenkernel/intern/image_partial_update.cc
M source/blender/makesdna/DNA_image_types.h
===================================================================
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 3a7c62e503c..29cb1af76e5 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -132,6 +132,7 @@ static void image_runtime_reset_on_copy(struct Image *image)
BLI_mutex_init(image->runtime.cache_mutex);
image->runtime.partial_update_register = NULL;
+ image->runtime.partial_update_user = NULL;
}
static void image_runtime_free_data(struct Image *image)
@@ -140,6 +141,10 @@ static void image_runtime_free_data(struct Image *image)
MEM_freeN(image->runtime.cache_mutex);
image->runtime.cache_mutex = NULL;
+ if (image->runtime.partial_update_user != NULL) {
+ BKE_image_partial_update_free(image->runtime.partial_update_user);
+ image->runtime.partial_update_user = NULL;
+ }
BKE_image_partial_update_register_free(image);
}
@@ -220,7 +225,6 @@ static void image_free_data(ID *id)
BKE_previewimg_free(&image->preview);
BLI_freelistN(&image->tiles);
- BLI_freelistN(&image->gpu_refresh_areas);
image_runtime_free_data(image);
}
@@ -273,7 +277,8 @@ static void image_blend_write(BlendWriter *writer, ID *id, const void *id_addres
ima->cache = NULL;
ima->gpuflag = 0;
BLI_listbase_clear(&ima->anims);
- BLI_listbase_clear(&ima->gpu_refresh_areas);
+ ima->runtime.partial_update_register = NULL;
+ ima->runtime.partial_update_user = NULL;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
@@ -353,7 +358,6 @@ static void image_blend_read_data(BlendDataReader *reader, ID *id)
ima->lastused = 0;
ima->gpuflag = 0;
- BLI_listbase_clear(&ima->gpu_refresh_areas);
image_runtime_reset(ima);
}
diff --git a/source/blender/blenkernel/intern/image_gpu.c b/source/blender/blenkernel/intern/image_gpu.c
index 330af1cc505..af28de7bf95 100644
--- a/source/blender/blenkernel/intern/image_gpu.c
+++ b/source/blender/blenkernel/intern/image_gpu.c
@@ -53,14 +53,6 @@ static void image_free_gpu_limited_scale(Image *ima);
static void image_update_gputexture_ex(
Image *ima, ImageTile *tile, ImBuf *ibuf, int x, int y, int w, int h);
-/* Internal structs. */
-#define IMA_PARTIAL_REFRESH_TILE_SIZE 256
-typedef struct ImagePartialRefresh {
- struct ImagePartialRefresh *next, *prev;
- int tile_x;
- int tile_y;
-} ImagePartialRefresh;
-
/* Is the alpha of the `GPUTexture` for a given image/ibuf premultiplied. */
bool BKE_image_has_gpu_texture_premultiplied_alpha(Image *image, ImBuf *ibuf)
{
@@ -370,28 +362,59 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
}
#undef GPU_FLAGS_TO_CHECK
- /* Check if image has been updated and tagged to be updated (full or partial). */
+ ImBuf *ibuf_intern = ibuf;
+ if (ibuf_intern == NULL) {
+ ibuf_intern = BKE_image_acquire_ibuf(ima, iuser, NULL);
+ if (ibuf_intern == NULL) {
+ return image_gpu_texture_error_create(textarget);
+ }
+ }
+
ImageTile *tile = BKE_image_get_tile(ima, 0);
- if (((ima->gpuflag & IMA_GPU_REFRESH) != 0) ||
- ((ibuf == NULL || tile == NULL) && ((ima->gpuflag & IMA_GPU_PARTIAL_REFRESH) != 0))) {
- image_free_gpu(ima, true);
- BLI_freelistN(&ima->gpu_refresh_areas);
- ima->gpuflag &= ~(IMA_GPU_REFRESH | IMA_GPU_PARTIAL_REFRESH);
+ if (tile == NULL || ibuf == NULL) {
+ ima->gpuflag |= IMA_GPU_REFRESH;
+ }
+
+ /* TODO(jbakker): bad call. Or we should do this everywhere where image is changed, or we should
+ * make it possible to initialize an empty register. */
+ if ((ima->gpuflag & IMA_GPU_REFRESH) != 0) {
+ BKE_image_partial_update_register_mark_full_update(ima, ibuf_intern);
+ ima->gpuflag &= ~IMA_GPU_REFRESH;
+ }
+
+ if (ima->runtime.partial_update_user == NULL) {
+ ima->runtime.partial_update_user = BKE_image_partial_update_create(ima);
}
- else if (ima->gpuflag & IMA_GPU_PARTIAL_REFRESH) {
- BLI_assert(ibuf);
- BLI_assert(tile);
- ImagePartialRefresh *refresh_area;
- while ((refresh_area = BLI_pophead(&ima->gpu_refresh_areas))) {
- const int tile_offset_x = refresh_area->tile_x * IMA_PARTIAL_REFRESH_TILE_SIZE;
- const int tile_offset_y = refresh_area->tile_y * IMA_PARTIAL_REFRESH_TILE_SIZE;
- const int tile_width = MIN2(IMA_PARTIAL_REFRESH_TILE_SIZE, ibuf->x - tile_offset_x);
- const int tile_height = MIN2(IMA_PARTIAL_REFRESH_TILE_SIZE, ibuf->y - tile_offset_y);
- image_update_gputexture_ex(
- ima, tile, ibuf, tile_offset_x, tile_offset_y, tile_width, tile_height);
- MEM_freeN(refresh_area);
+
+ switch (
+ BKE_image_partial_update_collect_tiles(ima, ibuf_intern, ima->runtime.partial_update_user)) {
+ case PARTIAL_UPDATE_NEED_FULL_UPDATE: {
+ image_free_gpu(ima, true);
+ break;
+ }
+
+ case PARTIAL_UPDATE_CHANGES_AVAILABLE: {
+ BLI_assert(ibuf_intern);
+ BLI_assert(tile);
+ PartialUpdateTile changed_region;
+ while (
+ BKE_image_partial_update_next_tile(ima->runtime.partial_update_user, &changed_region) ==
+ PARTIAL_UPDATE_ITER_TILE_LOADED) {
+ const int tile_offset_x = changed_region.region.xmin;
+ const int tile_offset_y = changed_region.region.ymin;
+ const int tile_width = BLI_rcti_size_x(&changed_region.region);
+ const int tile_height = BLI_rcti_size_y(&changed_region.region);
+ // TODO(jbakker): rect may not exceed image resolution.
+ image_update_gputexture_ex(
+ ima, tile, ibuf_intern, tile_offset_x, tile_offset_y, tile_width, tile_height);
+ }
+ break;
+ }
+
+ case PARTIAL_UPDATE_NO_CHANGES: {
+ /* GPUTextures are up to date. */
+ break;
}
- ima->gpuflag &= ~IMA_GPU_PARTIAL_REFRESH;
}
/* Tag as in active use for garbage collector. */
@@ -411,6 +434,9 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
IMA_TEXTURE_RESOLUTION_FULL;
GPUTexture **tex = get_image_gpu_texture_ptr(ima, textarget, current_view, texture_resolution);
if (*tex) {
+ if (ibuf == NULL) {
+ BKE_image_release_ibuf(ima, ibuf_intern, NULL);
+ }
return *tex;
}
@@ -418,18 +444,13 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
* texture with zero bind-code so we don't keep trying. */
if (tile == NULL) {
*tex = image_gpu_texture_error_create(textarget);
+ if (ibuf == NULL) {
+ BKE_image_release_ibuf(ima, ibuf_intern, NULL);
+ }
return *tex;
}
/* check if we have a valid image buffer */
- ImBuf *ibuf_intern = ibuf;
- if (ibuf_intern == NULL) {
- ibuf_intern = BKE_image_acquire_ibuf(ima, iuser, NULL);
- if (ibuf_intern == NULL) {
- *tex = image_gpu_texture_error_create(textarget);
- return *tex;
- }
- }
if (textarget == TEXTARGET_2D_ARRAY) {
*tex = gpu_texture_create_tile_array(ima, ibuf_intern, texture_resolution);
@@ -902,16 +923,12 @@ static void image_update_gputexture_ex(
/* Partial update of texture for texture painting. This is often much
* quicker than fully updating the texture for high resolution images. */
+/* TODO(jbakker): remove this function. It is only allowed to perform delayed updates as the
+ * texture user is decentralized. */
void BKE_image_update_gputexture(Image *ima, ImageUser *iuser, int x, int y, int w, int h)
{
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
- ImageTile *tile = BKE_image_get_tile_from_iuser(ima, iuser);
-
- if ((ibuf == NULL) || (w == 0) || (h == 0)) {
- /* Full reload of texture. */
- BKE_image_free_gputextures(ima);
- }
- image_update_gputexture_ex(ima, tile, ibuf, x, y, w, h);
+ BKE_image_update_gputexture_delayed(ima, ibuf, x, y, w, h);
BKE_image_release_ibuf(ima, ibuf, NULL);
}
@@ -924,70 +941,12 @@ void BKE_image_update_gputexture_delayed(
{
/* Check for full refresh. */
if (ibuf && x == 0 && y == 0 && w == ibuf->x && h == ibuf->y) {
- ima->gpuflag |= IMA_GPU_REFRESH;
- }
- /* Check if we can promote partial refresh to a full refresh. */
- if ((ima->gpuflag & (IMA_GPU_REFRESH | IMA_GPU_PARTIAL_REFRESH)) ==
- (IMA_GPU_REFRESH | IMA_GPU_PARTIAL_REFRESH)) {
- ima->gpuflag &= ~IMA_GPU_PARTIAL_REFRESH;
- BLI_freelistN(&ima->gpu_refresh_areas);
- }
- /* Image is already marked for complete refresh. */
- if (ima->gpuflag & IMA_GPU_REFRESH) {
- return;
- }
-
- /* Schedule the tiles that covers the requested area. */
- const int start_tile_x = x / IMA_PARTIAL_REFRESH_TILE_SIZE;
- const int start_tile_y = y / IMA_PARTIAL_REFRESH_TILE_SIZE;
- const int end_tile_x = (x + w) / IMA_PARTIAL_REFRESH_TILE_SIZE;
- const int end_tile_y = (y + h) / IMA_PARTIAL_REFRESH_TILE_SIZE;
- const int num_tiles_x = (end_tile_x + 1) - (start_tile_x);
- const int num_tiles_y = (end_tile_y + 1) - (start_tile_y);
- const int num_tiles = num_tiles_x * num_tiles_y;
- const bool allocate_on_heap = BLI_BITMAP_SIZE(num_tiles) > 16;
- BLI_bitmap *requested_tiles = NULL;
- if (allocate_on_heap) {
- requested_tiles = BLI_BITMAP_NEW(num_tiles, __func__);
+ BKE_image_partial_update_register_mark_full_update(ima, ibuf);
}
else {
- requested_tiles = BLI_BITMAP_NEW_ALLOCA(num_tiles);
- }
-
- /* Mark the tiles that have already been requested. They don't need to be requested again. */
- int num_tiles_not_scheduled = num_tiles;
- LISTBASE_FOREACH (ImagePartialRefresh *, area, &ima->gpu_refresh_areas) {
- if (area->tile_x < start_tile_x || area->tile_x > end_tile_x || area->tile_y < start_tile_y ||
- area->tile_y > end_tile_y) {
- continue;
- }
- int requested_tile_index = (area->tile_x - start_tile_x) +
- (area->tile_y - start_tile_y) * num_tiles_x;
- BLI_BITMAP_ENABLE(requested_tiles, requested_tile_index);
- num_tiles_not_scheduled--;
- if (num_tiles_not_scheduled == 0) {
- break;
- }
- }
-
- /* Schedule the tiles that aren't requested yet. */
- if (num_tiles_not_scheduled) {
- int tile_index = 0;
- for (int tile_y = start_tile_y; tile_y <= end_tile_y; tile_y++) {
- for (int tile_x = start_tile_x; tile_x <= end_tile_x
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list