Commit: 35db01325f41da34e5a71d2b28cc717cddbdb996 Author: Manuel Castilla Date: Wed Jun 23 17:21:17 2021 +0200 Branches: master https://developer.blender.org/rB35db01325f41da34e5a71d2b28cc717cddbdb996
Compositor: Full frame Image node Adds full frame implementation to Image node operations. Mostly refactored into buffer utility methods for reuse in other operations. No functional changes. 1.8x faster than tiled fallback. Reviewed By: jbakker Differential Revision: https://developer.blender.org/D11559 =================================================================== M source/blender/compositor/COM_defines.h M source/blender/compositor/intern/COM_MemoryBuffer.cc M source/blender/compositor/intern/COM_MemoryBuffer.h M source/blender/compositor/operations/COM_ImageOperation.cc M source/blender/compositor/operations/COM_ImageOperation.h M source/blender/compositor/operations/COM_MultilayerImageOperation.cc M source/blender/compositor/operations/COM_MultilayerImageOperation.h =================================================================== diff --git a/source/blender/compositor/COM_defines.h b/source/blender/compositor/COM_defines.h index 5a52d216117..857cbf0beee 100644 --- a/source/blender/compositor/COM_defines.h +++ b/source/blender/compositor/COM_defines.h @@ -62,6 +62,24 @@ constexpr int COM_data_type_num_channels(const DataType datatype) constexpr int COM_DATA_TYPE_VALUE_CHANNELS = COM_data_type_num_channels(DataType::Value); constexpr int COM_DATA_TYPE_COLOR_CHANNELS = COM_data_type_num_channels(DataType::Color); +constexpr float COM_VALUE_ZERO[1] = {0.0f}; + +/** + * Utility to get data type for given number of channels. + */ +constexpr DataType COM_num_channels_data_type(const int num_channels) +{ + switch (num_channels) { + case 1: + return DataType::Value; + case 3: + return DataType::Vector; + case 4: + default: + return DataType::Color; + } +} + // configurable items // chunk size determination diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.cc b/source/blender/compositor/intern/COM_MemoryBuffer.cc index 8c30d3215d7..44d3f059374 100644 --- a/source/blender/compositor/intern/COM_MemoryBuffer.cc +++ b/source/blender/compositor/intern/COM_MemoryBuffer.cc @@ -18,10 +18,31 @@ #include "COM_MemoryBuffer.h" +#include "IMB_colormanagement.h" +#include "IMB_imbuf_types.h" #include "MEM_guardedalloc.h" +#define ASSERT_BUFFER_CONTAINS_AREA(buf, area) \ + BLI_assert(BLI_rcti_inside_rcti(&(buf)->get_rect(), &(area))) + +#define ASSERT_BUFFER_CONTAINS_AREA_AT_COORDS(buf, area, x, y) \ + BLI_assert((buf)->get_rect().xmin <= (x)); \ + BLI_assert((buf)->get_rect().ymin <= (y)); \ + BLI_assert((buf)->get_rect().xmax >= (x) + BLI_rcti_size_x(&(area))); \ + BLI_assert((buf)->get_rect().ymax >= (y) + BLI_rcti_size_y(&(area))) + +#define ASSERT_VALID_ELEM_SIZE(buf, channel_offset, elem_size) \ + BLI_assert((buf)->get_num_channels() <= (channel_offset) + (elem_size)) + namespace blender::compositor { +static rcti create_rect(const int width, const int height) +{ + rcti rect; + BLI_rcti_init(&rect, 0, width, 0, height); + return rect; +} + MemoryBuffer::MemoryBuffer(MemoryProxy *memoryProxy, const rcti &rect, MemoryBufferState state) { m_rect = rect; @@ -30,6 +51,7 @@ MemoryBuffer::MemoryBuffer(MemoryProxy *memoryProxy, const rcti &rect, MemoryBuf this->m_num_channels = COM_data_type_num_channels(memoryProxy->getDataType()); this->m_buffer = (float *)MEM_mallocN_aligned( sizeof(float) * buffer_len() * this->m_num_channels, 16, "COM_MemoryBuffer"); + owns_data_ = true; this->m_state = state; this->m_datatype = memoryProxy->getDataType(); @@ -44,12 +66,44 @@ MemoryBuffer::MemoryBuffer(DataType dataType, const rcti &rect, bool is_a_single this->m_num_channels = COM_data_type_num_channels(dataType); this->m_buffer = (float *)MEM_mallocN_aligned( sizeof(float) * buffer_len() * this->m_num_channels, 16, "COM_MemoryBuffer"); + owns_data_ = true; this->m_state = MemoryBufferState::Temporary; this->m_datatype = dataType; set_strides(); } +/** + * Construct MemoryBuffer from a float buffer. MemoryBuffer is not responsible for + * freeing it. + */ +MemoryBuffer::MemoryBuffer( + float *buffer, int num_channels, int width, int height, bool is_a_single_elem) + : MemoryBuffer(buffer, num_channels, create_rect(width, height), is_a_single_elem) +{ +} + +/** + * Construct MemoryBuffer from a float buffer area. MemoryBuffer is not responsible for + * freeing given buffer. + */ +MemoryBuffer::MemoryBuffer(float *buffer, + const int num_channels, + const rcti &rect, + const bool is_a_single_elem) +{ + m_rect = rect; + m_is_a_single_elem = is_a_single_elem; + m_memoryProxy = nullptr; + m_num_channels = num_channels; + m_datatype = COM_num_channels_data_type(num_channels); + m_buffer = buffer; + owns_data_ = false; + m_state = MemoryBufferState::Temporary; + + set_strides(); +} + MemoryBuffer::MemoryBuffer(const MemoryBuffer &src) : MemoryBuffer(src.m_datatype, src.m_rect, false) { @@ -112,31 +166,195 @@ float MemoryBuffer::get_max_value(const rcti &rect) const MemoryBuffer::~MemoryBuffer() { - if (this->m_buffer) { + if (this->m_buffer && owns_data_) { MEM_freeN(this->m_buffer); this->m_buffer = nullptr; } } -void MemoryBuffer::fill_from(const MemoryBuffer &src) +void MemoryBuffer::copy_from(const MemoryBuffer *src, const rcti &area) { - BLI_assert(!this->is_a_single_elem()); + copy_from(src, area, area.xmin, area.ymin); +} + +void MemoryBuffer::copy_from(const MemoryBuffer *src, + const rcti &area, + const int to_x, + const int to_y) +{ + BLI_assert(this->get_num_channels() == src->get_num_channels()); + copy_from(src, area, 0, src->get_num_channels(), to_x, to_y, 0); +} + +void MemoryBuffer::copy_from(const MemoryBuffer *src, + const rcti &area, + const int channel_offset, + const int elem_size, + const int to_channel_offset) +{ + copy_from(src, area, channel_offset, elem_size, area.xmin, area.ymin, to_channel_offset); +} + +void MemoryBuffer::copy_from(const MemoryBuffer *src, + const rcti &area, + const int channel_offset, + const int elem_size, + const int to_x, + const int to_y, + const int to_channel_offset) +{ + if (this->is_a_single_elem()) { + copy_single_elem_from(src, channel_offset, elem_size, to_channel_offset); + } + else if (!src->is_a_single_elem() && elem_size == src->get_num_channels() && + elem_size == this->get_num_channels()) { + BLI_assert(to_channel_offset == 0); + BLI_assert(channel_offset == 0); + copy_rows_from(src, area, to_x, to_y); + } + else { + copy_elems_from(src, area, channel_offset, elem_size, to_x, to_y, to_channel_offset); + } +} + +void MemoryBuffer::copy_from(const uchar *src, const rcti &area) +{ + copy_from(src, area, 0, this->get_num_channels(), this->get_num_channels(), 0); +} + +void MemoryBuffer::copy_from(const uchar *src, + const rcti &area, + const int channel_offset, + const int elem_size, + const int elem_stride, + const int to_channel_offset) +{ + copy_from( + src, area, channel_offset, elem_size, elem_stride, area.xmin, area.ymin, to_channel_offset); +} + +void MemoryBuffer::copy_from(const uchar *src, + const rcti &area, + const int channel_offset, + const int elem_size, + const int elem_stride, + const int to_x, + const int to_y, + const int to_channel_offset) +{ + ASSERT_BUFFER_CONTAINS_AREA_AT_COORDS(this, area, to_x, to_y); + ASSERT_VALID_ELEM_SIZE(this, to_channel_offset, elem_size); + + const int width = BLI_rcti_size_x(&area); + const int height = BLI_rcti_size_y(&area); + const int src_row_stride = width * elem_stride; + const uchar *const src_start = src + area.ymin * src_row_stride + channel_offset; + for (int y = 0; y < height; y++) { + const uchar *from_elem = src_start + y * src_row_stride; + float *to_elem = &this->get_value(to_x, to_y + y, to_channel_offset); + const float *row_end = to_elem + width * this->elem_stride; + while (to_elem < row_end) { + for (int i = 0; i < elem_size; i++) { + to_elem[i] = ((float)from_elem[i]) * (1.0f / 255.0f); + } + to_elem += this->elem_stride; + from_elem += elem_stride; + } + } +} + +static void colorspace_to_scene_linear(MemoryBuffer *buf, const rcti &area, ColorSpace *colorspace) +{ + const int width = BLI_rcti_size_x(&area); + const int height = BLI_rcti_size_y(&area); + float *out = buf->get_elem(area.xmin, area.ymin); + /* If area allows continuous memory do conversion in one step. Otherwise per row. */ + if (buf->getWidth() == width) { + IMB_colormanagement_colorspace_to_scene_linear( + out, width, height, buf->get_num_channels(), colorspace, false); + } + else { + for (int y = 0; y < height; y++) { + IMB_colormanagement_colorspace_to_scene_linear( + out, width, 1, buf->get_num_channels(), colorspace, false); + out += buf->row_stride; + } + } +} + +void MemoryBuffer::copy_from(const ImBuf *src, const rcti &area, const bool ensure_linear_space) +{ + copy_from(src, area, 0, this->get_num_channels(), 0, ensure_linear_space); +} - unsigned int otherY; - unsigned int minX = MAX2(this->m_rect.xmin, src.m_rect.xmin); - unsigned int maxX = MIN2(this->m_rect.xmax, src.m_rect.xmax); - unsigned int minY = MAX2(this->m_rect.ymin, src.m_rect.ymin); - unsigned int maxY = MIN2(this->m_rect.ymax, src.m_rect.ymax); - int offset; - int otherOffset; +void MemoryBuffer::copy_from(const ImBuf *src, + const rcti &area, + const int channel_offset, + const int elem_size, + const int to_channel_offset, + const bool ensure_linear_space) +{ + copy_from(src, + area, + channel_offset, + elem_size, + area.xmin, + area.ymin, + to_channel_offset, + ensure_linear_space); +} - for (otherY = minY; otherY < maxY; otherY++) { - otherOffset = src.get_coords_offset(minX, otherY); - offset = this->get_coords_offset(minX, otherY); - memcpy(&this->m_buffer[offset], - &src.m_buffer[otherOffset], - (maxX - minX) * this->m_num_channels * sizeof(float)); +void MemoryBuffer::copy_from(const ImBuf *src, + const rcti &area, + const int channel_offset, + @@ Diff output truncated at 10240 characters. @@ _______________________________________________ Bf-blender-cvs mailing list [email protected] List details, subscription details or unsubscribe: https://lists.blender.org/mailman/listinfo/bf-blender-cvs
