Merge branch 'blender-v3.1-release'

This commit is contained in:
Jacques Lucke 2022-03-01 11:36:46 +01:00
commit 4b9c77a19a
12 changed files with 275 additions and 55 deletions

View File

@ -3569,6 +3569,7 @@ static void image_tag_reload(Image *ima, ID *iuser_id, ImageUser *iuser, void *c
/* Must copy image user changes to CoW data-block. */
DEG_id_tag_update(iuser_id, ID_RECALC_COPY_ON_WRITE);
}
BKE_image_partial_update_mark_full_update(ima);
}
}

View File

@ -322,19 +322,25 @@ static void image_gpu_texture_partial_update_changes_available(
Image *image, PartialUpdateChecker<ImageTileData>::CollectResult &changes)
{
while (changes.get_next_change() == ePartialUpdateIterResult::ChangeAvailable) {
const int tile_offset_x = changes.changed_region.region.xmin;
const int tile_offset_y = changes.changed_region.region.ymin;
const int tile_width = min_ii(changes.tile_data.tile_buffer->x,
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));
/* Calculate the clipping region with the tile buffer.
* TODO(jbakker): should become part of ImageTileData to deduplicate with image engine. */
rcti buffer_rect;
BLI_rcti_init(
&buffer_rect, 0, changes.tile_data.tile_buffer->x, 0, changes.tile_data.tile_buffer->y);
rcti clipped_update_region;
const bool has_overlap = BLI_rcti_isect(
&buffer_rect, &changes.changed_region.region, &clipped_update_region);
if (!has_overlap) {
continue;
}
image_update_gputexture_ex(image,
changes.tile_data.tile,
changes.tile_data.tile_buffer,
tile_offset_x,
tile_offset_y,
tile_width,
tile_height);
clipped_update_region.xmin,
clipped_update_region.ymin,
BLI_rcti_size_x(&clipped_update_region),
BLI_rcti_size_y(&clipped_update_region));
}
}

View File

@ -198,8 +198,8 @@ struct TileChangeset {
tile_width = image_buffer->x;
tile_height = image_buffer->y;
int chunk_x_len = tile_width / CHUNK_SIZE;
int chunk_y_len = tile_height / CHUNK_SIZE;
int chunk_x_len = (tile_width + CHUNK_SIZE - 1) / CHUNK_SIZE;
int chunk_y_len = (tile_height + CHUNK_SIZE - 1) / CHUNK_SIZE;
init_chunks(chunk_x_len, chunk_y_len);
return true;
}

View File

@ -1952,6 +1952,8 @@ void nodeRemoveAllSockets(bNodeTree *ntree, bNode *node)
}
}
BLI_freelistN(&node->internal_links);
LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &node->inputs) {
node_socket_free(sock, true);
MEM_freeN(sock);

View File

@ -0,0 +1,131 @@
/*
* 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 2022, Blender Foundation.
*/
/** \file
* \ingroup draw_engine
*/
#pragma once
#include "BLI_vector.hh"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
struct FloatImageBuffer {
ImBuf *source_buffer = nullptr;
ImBuf *float_buffer = nullptr;
bool is_used = true;
FloatImageBuffer(ImBuf *source_buffer, ImBuf *float_buffer)
: source_buffer(source_buffer), float_buffer(float_buffer)
{
}
FloatImageBuffer(FloatImageBuffer &&other) noexcept
{
source_buffer = other.source_buffer;
float_buffer = other.float_buffer;
is_used = other.is_used;
other.source_buffer = nullptr;
other.float_buffer = nullptr;
}
virtual ~FloatImageBuffer()
{
IMB_freeImBuf(float_buffer);
float_buffer = nullptr;
source_buffer = nullptr;
}
FloatImageBuffer &operator=(FloatImageBuffer &&other) noexcept
{
this->source_buffer = other.source_buffer;
this->float_buffer = other.float_buffer;
is_used = other.is_used;
other.source_buffer = nullptr;
other.float_buffer = nullptr;
return *this;
}
};
struct FloatBufferCache {
private:
blender::Vector<FloatImageBuffer> cache_;
public:
ImBuf *ensure_float_buffer(ImBuf *image_buffer)
{
/* Check if we can use the float buffer of the given image_buffer. */
if (image_buffer->rect_float != nullptr) {
return image_buffer;
}
/* Do we have a cached float buffer. */
for (FloatImageBuffer &item : cache_) {
if (item.source_buffer == image_buffer) {
item.is_used = true;
return item.float_buffer;
}
}
/* Generate a new float buffer. */
IMB_float_from_rect(image_buffer);
ImBuf *new_imbuf = IMB_allocImBuf(image_buffer->x, image_buffer->y, image_buffer->planes, 0);
new_imbuf->rect_float = image_buffer->rect_float;
new_imbuf->flags |= IB_rectfloat;
new_imbuf->mall |= IB_rectfloat;
image_buffer->rect_float = nullptr;
image_buffer->flags &= ~IB_rectfloat;
image_buffer->mall &= ~IB_rectfloat;
cache_.append(FloatImageBuffer(image_buffer, new_imbuf));
return new_imbuf;
}
void reset_usage_flags()
{
for (FloatImageBuffer &buffer : cache_) {
buffer.is_used = false;
}
}
void mark_used(const ImBuf *image_buffer)
{
for (FloatImageBuffer &item : cache_) {
if (item.source_buffer == image_buffer) {
item.is_used = true;
return;
}
}
}
void remove_unused_buffers()
{
for (int64_t i = cache_.size() - 1; i >= 0; i--) {
if (!cache_[i].is_used) {
cache_.remove_and_reorder(i);
}
}
}
void clear()
{
cache_.clear();
}
};

View File

@ -157,6 +157,7 @@ template<typename TextureMethod> class ScreenSpaceDrawingMode : public AbstractD
if (tile_buffer == nullptr) {
continue;
}
instance_data.float_buffers.mark_used(tile_buffer);
BKE_image_release_ibuf(image, tile_buffer, lock);
DRWShadingGroup *shsub = DRW_shgroup_create_sub(shgrp);
@ -184,12 +185,14 @@ template<typename TextureMethod> class ScreenSpaceDrawingMode : public AbstractD
switch (changes.get_result_code()) {
case ePartialUpdateCollectResult::FullUpdateNeeded:
instance_data.mark_all_texture_slots_dirty();
instance_data.float_buffers.clear();
break;
case ePartialUpdateCollectResult::NoChangesDetected:
break;
case ePartialUpdateCollectResult::PartialChangesDetected:
/* Partial update when wrap repeat is enabled is not supported. */
if (instance_data.flags.do_tile_drawing) {
instance_data.float_buffers.clear();
instance_data.mark_all_texture_slots_dirty();
}
else {
@ -200,6 +203,34 @@ template<typename TextureMethod> class ScreenSpaceDrawingMode : public AbstractD
do_full_update_for_dirty_textures(instance_data, image_user);
}
/**
* Update the float buffer in the region given by the partial update checker.
*/
void do_partial_update_float_buffer(
ImBuf *float_buffer, PartialUpdateChecker<ImageTileData>::CollectResult &iterator) const
{
ImBuf *src = iterator.tile_data.tile_buffer;
BLI_assert(float_buffer->rect_float != nullptr);
BLI_assert(float_buffer->rect == nullptr);
BLI_assert(src->rect_float == nullptr);
BLI_assert(src->rect != nullptr);
/* Calculate the overlap between the updated region and the buffer size. Partial Update Checker
* always returns a tile (256x256). Which could lay partially outside the buffer when using
* different resolutions.
*/
rcti buffer_rect;
BLI_rcti_init(&buffer_rect, 0, float_buffer->x, 0, float_buffer->y);
rcti clipped_update_region;
const bool has_overlap = BLI_rcti_isect(
&buffer_rect, &iterator.changed_region.region, &clipped_update_region);
if (!has_overlap) {
return;
}
IMB_float_from_rect_ex(float_buffer, src, &clipped_update_region);
}
void do_partial_update(PartialUpdateChecker<ImageTileData>::CollectResult &iterator,
IMAGE_InstanceData &instance_data) const
{
@ -208,7 +239,11 @@ template<typename TextureMethod> class ScreenSpaceDrawingMode : public AbstractD
if (iterator.tile_data.tile_buffer == nullptr) {
continue;
}
const bool do_free_float_buffer = ensure_float_buffer(*iterator.tile_data.tile_buffer);
ImBuf *tile_buffer = ensure_float_buffer(instance_data, iterator.tile_data.tile_buffer);
if (tile_buffer != iterator.tile_data.tile_buffer) {
do_partial_update_float_buffer(tile_buffer, iterator);
}
const float tile_width = static_cast<float>(iterator.tile_data.tile_buffer->x);
const float tile_height = static_cast<float>(iterator.tile_data.tile_buffer->y);
@ -283,7 +318,6 @@ template<typename TextureMethod> class ScreenSpaceDrawingMode : public AbstractD
&extracted_buffer, texture_region_width, texture_region_height, 32, IB_rectfloat);
int offset = 0;
ImBuf *tile_buffer = iterator.tile_data.tile_buffer;
for (int y = gpu_texture_region_to_update.ymin; y < gpu_texture_region_to_update.ymax;
y++) {
float yf = y / (float)texture_height;
@ -314,10 +348,6 @@ template<typename TextureMethod> class ScreenSpaceDrawingMode : public AbstractD
0);
imb_freerectImbuf_all(&extracted_buffer);
}
if (do_free_float_buffer) {
imb_freerectfloatImBuf(iterator.tile_data.tile_buffer);
}
}
}
@ -376,16 +406,12 @@ template<typename TextureMethod> class ScreenSpaceDrawingMode : public AbstractD
* rect_float as the reference-counter isn't 0. To work around this we destruct any created local
* buffers ourself.
*/
bool ensure_float_buffer(ImBuf &image_buffer) const
ImBuf *ensure_float_buffer(IMAGE_InstanceData &instance_data, ImBuf *image_buffer) const
{
if (image_buffer.rect_float == nullptr) {
IMB_float_from_rect(&image_buffer);
return true;
}
return false;
return instance_data.float_buffers.ensure_float_buffer(image_buffer);
}
void do_full_update_texture_slot(const IMAGE_InstanceData &instance_data,
void do_full_update_texture_slot(IMAGE_InstanceData &instance_data,
const TextureInfo &texture_info,
ImBuf &texture_buffer,
ImBuf &tile_buffer,
@ -393,7 +419,7 @@ template<typename TextureMethod> class ScreenSpaceDrawingMode : public AbstractD
{
const int texture_width = texture_buffer.x;
const int texture_height = texture_buffer.y;
const bool do_free_float_buffer = ensure_float_buffer(tile_buffer);
ImBuf *float_tile_buffer = ensure_float_buffer(instance_data, &tile_buffer);
/* IMB_transform works in a non-consistent space. This should be documented or fixed!.
* Construct a variant of the info_uv_to_texture that adds the texel space
@ -424,16 +450,12 @@ template<typename TextureMethod> class ScreenSpaceDrawingMode : public AbstractD
transform_mode = IMB_TRANSFORM_MODE_CROP_SRC;
}
IMB_transform(&tile_buffer,
IMB_transform(float_tile_buffer,
&texture_buffer,
transform_mode,
IMB_FILTER_NEAREST,
uv_to_texel,
crop_rect_ptr);
if (do_free_float_buffer) {
imb_freerectfloatImBuf(&tile_buffer);
}
}
public:
@ -452,6 +474,7 @@ template<typename TextureMethod> class ScreenSpaceDrawingMode : public AbstractD
instance_data->partial_update.ensure_image(image);
instance_data->clear_dirty_flag();
instance_data->float_buffers.reset_usage_flags();
/* Step: Find out which screen space textures are needed to draw on the screen. Remove the
* screen space textures that aren't needed. */
@ -472,8 +495,10 @@ template<typename TextureMethod> class ScreenSpaceDrawingMode : public AbstractD
add_shgroups(instance_data);
}
void draw_finish(IMAGE_Data *UNUSED(vedata)) const override
void draw_finish(IMAGE_Data *vedata) const override
{
IMAGE_InstanceData *instance_data = vedata->instance_data;
instance_data->float_buffers.remove_unused_buffers();
}
void draw_scene(IMAGE_Data *vedata) const override

View File

@ -8,6 +8,7 @@
#pragma once
#include "image_batches.hh"
#include "image_buffer_cache.hh"
#include "image_partial_updater.hh"
#include "image_private.hh"
#include "image_shader_params.hh"
@ -48,11 +49,18 @@ struct IMAGE_InstanceData {
DRWPass *depth_pass;
} passes;
/**
* Cache containing the float buffers when drawing byte images.
*/
FloatBufferCache float_buffers;
/** \brief Transform matrix to convert a normalized screen space coordinates to texture space. */
float ss_to_texture[4][4];
TextureInfo texture_infos[SCREEN_SPACE_DRAWING_MODE_TEXTURE_LEN];
public:
virtual ~IMAGE_InstanceData() = default;
void clear_dirty_flag()
{
reset_dirty_flag(false);
@ -102,6 +110,7 @@ struct IMAGE_InstanceData {
if (last_usage != usage) {
last_usage = usage;
reset_dirty_flag(true);
float_buffers.clear();
}
}

View File

@ -23,6 +23,8 @@ struct ImageUsage {
/** IMA_ALPHA_* */
char alpha_mode;
const void *last_image = nullptr;
ImageUsage() = default;
ImageUsage(const struct Image *image, const struct ImageUser *image_user)
{
@ -31,6 +33,7 @@ struct ImageUsage {
view = image_user ? image_user->multi_index : 0;
colorspace_settings = image->colorspace_settings;
alpha_mode = image->alpha_mode;
last_image = static_cast<const void *>(image);
}
bool operator==(const ImageUsage &other) const

View File

@ -301,6 +301,7 @@ static void bake_targets_refresh(BakeTargets *targets)
Image *ima = targets->images[i].image;
if (ima) {
BKE_image_partial_update_mark_full_update(ima);
LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
BKE_image_free_gputextures(ima);
DEG_id_tag_update(&ima->id, 0);

View File

@ -560,6 +560,9 @@ bool IMB_alpha_affects_rgb(const struct ImBuf *ibuf);
* Create char buffer, color corrected if necessary, for ImBufs that lack one.
*/
void IMB_rect_from_float(struct ImBuf *ibuf);
void IMB_float_from_rect_ex(struct ImBuf *dst,
const struct ImBuf *src,
const struct rcti *region_to_update);
void IMB_float_from_rect(struct ImBuf *ibuf);
/**
* No profile conversion.

View File

@ -6,6 +6,7 @@
*/
#include "BLI_math.h"
#include "BLI_rect.h"
#include "BLI_utildefines.h"
#include "IMB_filter.h"
@ -752,6 +753,61 @@ void IMB_rect_from_float(ImBuf *ibuf)
ibuf->userflags &= ~IB_RECT_INVALID;
}
void IMB_float_from_rect_ex(struct ImBuf *dst,
const struct ImBuf *src,
const rcti *region_to_update)
{
BLI_assert_msg(dst->rect_float != NULL,
"Destination buffer should have a float buffer assigned.");
BLI_assert_msg(src->rect != NULL, "Source buffer should have a byte buffer assigned.");
BLI_assert_msg(dst->x == src->x, "Source and destination buffer should have the same dimension");
BLI_assert_msg(dst->y == src->y, "Source and destination buffer should have the same dimension");
BLI_assert_msg(dst->channels = 4, "Destination buffer should have 4 channels.");
BLI_assert_msg(region_to_update->xmin >= 0,
"Region to update should be clipped to the given buffers.");
BLI_assert_msg(region_to_update->ymin >= 0,
"Region to update should be clipped to the given buffers.");
BLI_assert_msg(region_to_update->xmax <= dst->x,
"Region to update should be clipped to the given buffers.");
BLI_assert_msg(region_to_update->ymax <= dst->y,
"Region to update should be clipped to the given buffers.");
float *rect_float = dst->rect_float;
rect_float += (region_to_update->xmin + region_to_update->ymin * dst->x) * 4;
unsigned char *rect = (unsigned char *)src->rect;
rect += (region_to_update->xmin + region_to_update->ymin * dst->x) * 4;
const int region_width = BLI_rcti_size_x(region_to_update);
const int region_height = BLI_rcti_size_y(region_to_update);
/* Convert byte buffer to float buffer without color or alpha conversion. */
IMB_buffer_float_from_byte(rect_float,
rect,
IB_PROFILE_SRGB,
IB_PROFILE_SRGB,
false,
region_width,
region_height,
src->x,
dst->x);
/* Perform color space conversion from rect color space to linear. */
float *float_ptr = rect_float;
for (int i = 0; i < region_height; i++) {
IMB_colormanagement_colorspace_to_scene_linear(
float_ptr, region_width, 1, dst->channels, src->rect_colorspace, false);
float_ptr += 4 * dst->x;
}
/* Perform alpha conversion. */
if (IMB_alpha_affects_rgb(src)) {
float_ptr = rect_float;
for (int i = 0; i < region_height; i++) {
IMB_premultiply_rect_float(float_ptr, dst->channels, region_width, 1);
float_ptr += 4 * dst->x;
}
}
}
void IMB_float_from_rect(ImBuf *ibuf)
{
float *rect_float;
@ -775,33 +831,14 @@ void IMB_float_from_rect(ImBuf *ibuf)
}
ibuf->channels = 4;
}
/* first, create float buffer in non-linear space */
IMB_buffer_float_from_byte(rect_float,
(unsigned char *)ibuf->rect,
IB_PROFILE_SRGB,
IB_PROFILE_SRGB,
false,
ibuf->x,
ibuf->y,
ibuf->x,
ibuf->x);
/* then make float be in linear space */
IMB_colormanagement_colorspace_to_scene_linear(
rect_float, ibuf->x, ibuf->y, ibuf->channels, ibuf->rect_colorspace, false);
/* byte buffer is straight alpha, float should always be premul */
if (IMB_alpha_affects_rgb(ibuf)) {
IMB_premultiply_rect_float(rect_float, ibuf->channels, ibuf->x, ibuf->y);
}
if (ibuf->rect_float == NULL) {
ibuf->rect_float = rect_float;
ibuf->mall |= IB_rectfloat;
ibuf->flags |= IB_rectfloat;
}
rcti region_to_update;
BLI_rcti_init(&region_to_update, 0, ibuf->x, 0, ibuf->y);
IMB_float_from_rect_ex(ibuf, ibuf, &region_to_update);
}
/** \} */

View File

@ -103,6 +103,7 @@ static void rna_Image_generated_update(Main *bmain, Scene *UNUSED(scene), Pointe
{
Image *ima = (Image *)ptr->owner_id;
BKE_image_signal(bmain, ima, NULL, IMA_SIGNAL_FREE);
BKE_image_partial_update_mark_full_update(ima);
}
static void rna_Image_colormanage_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
@ -141,6 +142,7 @@ static void rna_Image_views_format_update(Main *bmain, Scene *scene, PointerRNA
}
BKE_image_release_ibuf(ima, ibuf, lock);
BKE_image_partial_update_mark_full_update(ima);
}
static void rna_ImageUser_update(Main *bmain, Scene *scene, PointerRNA *ptr)