/* SPDX-FileCopyrightText: 2022 Blender Authors * * SPDX-License-Identifier: GPL-2.0-or-later */ /** \file * \ingroup draw_engine */ #pragma once #include "BLI_vector.hh" #include "IMB_colormanagement.hh" #include "IMB_imbuf.hh" #include "IMB_imbuf_types.hh" namespace blender::image_engine { 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; } }; /** * \brief Float buffer cache for image buffers. * * Image buffers might not have float buffers which are required for the image engine. * Image buffers are not allowed to have both a float buffer and a byte buffer as some * functionality doesn't know what to do. * * For this reason we store the float buffer in separate image buffers. The FloatBufferCache keep * track of the cached buffers and if they are still used. */ struct FloatBufferCache { private: Vector cache_; public: ImBuf *cached_float_buffer(ImBuf *image_buffer) { /* Check if we can use the float buffer of the given image_buffer. */ if (image_buffer->float_buffer.data != nullptr) { BLI_assert_msg( IMB_colormanagement_space_name_is_scene_linear( IMB_colormanagement_get_float_colorspace(image_buffer)), "Expected float buffer to be scene_linear - if there are code paths where this " "isn't the case we should convert those and add to the FloatBufferCache as well."); 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_byte(image_buffer); ImBuf *new_imbuf = IMB_allocImBuf(image_buffer->x, image_buffer->y, image_buffer->planes, 0); IMB_assign_float_buffer(new_imbuf, IMB_steal_float_buffer(image_buffer), IB_TAKE_OWNERSHIP); 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(); } }; } // namespace blender::image_engine