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:
authorManuel Castilla <manzanillawork@gmail.com>2021-06-23 18:21:17 +0300
committerManuel Castilla <manzanillawork@gmail.com>2021-06-23 18:46:53 +0300
commit35db01325f41da34e5a71d2b28cc717cddbdb996 (patch)
tree923bfa9c71e1eda1f1fc25c01a7ebbd0382f0d49 /source/blender/compositor/intern
parent8f4d99159404621a9063f4bd155a519baf51f313 (diff)
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
Diffstat (limited to 'source/blender/compositor/intern')
-rw-r--r--source/blender/compositor/intern/COM_MemoryBuffer.cc316
-rw-r--r--source/blender/compositor/intern/COM_MemoryBuffer.h75
2 files changed, 374 insertions, 17 deletions
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,
+ const int elem_size,
+ const int to_x,
+ const int to_y,
+ const int to_channel_offset,
+ const bool ensure_linear_space)
+{
+ if (src->rect_float) {
+ const MemoryBuffer mem_buf(src->rect_float, src->channels, src->x, src->y, false);
+ copy_from(&mem_buf, area, channel_offset, elem_size, to_x, to_y, to_channel_offset);
}
+ else if (src->rect) {
+ const uchar *uc_buf = (uchar *)src->rect;
+ const int elem_stride = src->channels;
+ copy_from(uc_buf, area, channel_offset, elem_size, elem_stride, to_x, to_y, to_channel_offset);
+ if (ensure_linear_space) {
+ colorspace_to_scene_linear(this, area, src->rect_colorspace);
+ }
+ }
+ else {
+ /* Empty ImBuf source. Fill destination with empty values. */
+ const float *zero_elem = new float[elem_size]{0};
+ fill(area, to_channel_offset, zero_elem, elem_size);
+ delete[] zero_elem;
+ }
+}
+
+void MemoryBuffer::fill(const rcti &area, const float *value)
+{
+ fill(area, 0, value, this->get_num_channels());
+}
+
+void MemoryBuffer::fill(const rcti &area,
+ const int channel_offset,
+ const float *value,
+ const int value_size)
+{
+ const MemoryBuffer single_elem(const_cast<float *>(value), value_size, this->get_rect(), true);
+ copy_from(&single_elem, area, 0, value_size, area.xmin, area.ymin, channel_offset);
+}
+
+void MemoryBuffer::fill_from(const MemoryBuffer &src)
+{
+ rcti overlap;
+ overlap.xmin = MAX2(this->m_rect.xmin, src.m_rect.xmin);
+ overlap.xmax = MIN2(this->m_rect.xmax, src.m_rect.xmax);
+ overlap.ymin = MAX2(this->m_rect.ymin, src.m_rect.ymin);
+ overlap.ymax = MIN2(this->m_rect.ymax, src.m_rect.ymax);
+ copy_from(&src, overlap);
}
void MemoryBuffer::writePixel(int x, int y, const float color[4])
@@ -196,4 +414,70 @@ void MemoryBuffer::readEWA(float *result, const float uv[2], const float derivat
}
}
+void MemoryBuffer::copy_single_elem_from(const MemoryBuffer *src,
+ const int channel_offset,
+ const int elem_size,
+ const int to_channel_offset)
+{
+ ASSERT_VALID_ELEM_SIZE(this, to_channel_offset, elem_size);
+ ASSERT_VALID_ELEM_SIZE(src, channel_offset, elem_size);
+ BLI_assert(this->is_a_single_elem());
+
+ float *to_elem = &this->get_value(
+ this->get_rect().xmin, this->get_rect().ymin, to_channel_offset);
+ const float *from_elem = &src->get_value(
+ src->get_rect().xmin, src->get_rect().ymin, channel_offset);
+ const int elem_bytes = elem_size * sizeof(float);
+ memcpy(to_elem, from_elem, elem_bytes);
+}
+
+void MemoryBuffer::copy_rows_from(const MemoryBuffer *src,
+ const rcti &area,
+ const int to_x,
+ const int to_y)
+{
+ ASSERT_BUFFER_CONTAINS_AREA(src, area);
+ ASSERT_BUFFER_CONTAINS_AREA_AT_COORDS(this, area, to_x, to_y);
+ BLI_assert(this->get_num_channels() == src->get_num_channels());
+ BLI_assert(!this->is_a_single_elem());
+ BLI_assert(!src->is_a_single_elem());
+
+ const int width = BLI_rcti_size_x(&area);
+ const int height = BLI_rcti_size_y(&area);
+ const int row_bytes = this->get_num_channels() * width * sizeof(float);
+ for (int y = 0; y < height; y++) {
+ float *to_row = this->get_elem(to_x, to_y + y);
+ const float *from_row = src->get_elem(area.xmin, area.ymin + y);
+ memcpy(to_row, from_row, row_bytes);
+ }
+}
+
+void MemoryBuffer::copy_elems_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)
+{
+ ASSERT_BUFFER_CONTAINS_AREA(src, area);
+ ASSERT_BUFFER_CONTAINS_AREA_AT_COORDS(this, area, to_x, to_y);
+ ASSERT_VALID_ELEM_SIZE(this, to_channel_offset, elem_size);
+ ASSERT_VALID_ELEM_SIZE(src, channel_offset, elem_size);
+
+ const int width = BLI_rcti_size_x(&area);
+ const int height = BLI_rcti_size_y(&area);
+ const int elem_bytes = elem_size * sizeof(float);
+ for (int y = 0; y < height; y++) {
+ float *to_elem = &this->get_value(to_x, to_y + y, to_channel_offset);
+ const float *from_elem = &src->get_value(area.xmin, area.ymin + y, channel_offset);
+ const float *row_end = to_elem + width * this->elem_stride;
+ while (to_elem < row_end) {
+ memcpy(to_elem, from_elem, elem_bytes);
+ to_elem += this->elem_stride;
+ from_elem += src->elem_stride;
+ }
+ }
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.h b/source/blender/compositor/intern/COM_MemoryBuffer.h
index 045dc996e3e..575bb2fe383 100644
--- a/source/blender/compositor/intern/COM_MemoryBuffer.h
+++ b/source/blender/compositor/intern/COM_MemoryBuffer.h
@@ -106,6 +106,11 @@ class MemoryBuffer {
*/
bool m_is_a_single_elem;
+ /**
+ * Whether MemoryBuffer owns buffer data.
+ */
+ bool owns_data_;
+
public:
/**
* \brief construct new temporarily MemoryBuffer for an area
@@ -117,6 +122,11 @@ class MemoryBuffer {
*/
MemoryBuffer(DataType datatype, const rcti &rect, bool is_a_single_elem = false);
+ MemoryBuffer(
+ float *buffer, int num_channels, int width, int height, bool is_a_single_elem = false);
+
+ MemoryBuffer(float *buffer, int num_channels, const rcti &rect, bool is_a_single_elem = false);
+
/**
* Copy constructor
*/
@@ -223,7 +233,7 @@ class MemoryBuffer {
return is_a_single_elem() ? 1 : getHeight();
}
- uint8_t get_num_channels()
+ uint8_t get_num_channels() const
{
return this->m_num_channels;
}
@@ -404,6 +414,53 @@ class MemoryBuffer {
return this->m_state == MemoryBufferState::Temporary;
}
+ void copy_from(const MemoryBuffer *src, const rcti &area);
+ void copy_from(const MemoryBuffer *src, const rcti &area, int to_x, int to_y);
+ void copy_from(const MemoryBuffer *src,
+ const rcti &area,
+ int channel_offset,
+ int elem_size,
+ int to_channel_offset);
+ void copy_from(const MemoryBuffer *src,
+ const rcti &area,
+ int channel_offset,
+ int elem_size,
+ int to_x,
+ int to_y,
+ int to_channel_offset);
+ void copy_from(const uchar *src, const rcti &area);
+ void copy_from(const uchar *src,
+ const rcti &area,
+ int channel_offset,
+ int elem_size,
+ int elem_stride,
+ int to_channel_offset);
+ void copy_from(const uchar *src,
+ const rcti &area,
+ int channel_offset,
+ int elem_size,
+ int elem_stride,
+ int to_x,
+ int to_y,
+ int to_channel_offset);
+ void copy_from(const struct ImBuf *src, const rcti &area, bool ensure_linear_space = false);
+ void copy_from(const struct ImBuf *src,
+ const rcti &area,
+ int channel_offset,
+ int elem_size,
+ int to_channel_offset,
+ bool ensure_linear_space = false);
+ void copy_from(const struct ImBuf *src,
+ const rcti &src_area,
+ int channel_offset,
+ int elem_size,
+ int to_x,
+ int to_y,
+ int to_channel_offset,
+ bool ensure_linear_space = false);
+
+ void fill(const rcti &area, const float *value);
+ void fill(const rcti &area, int channel_offset, const float *value, int value_size);
/**
* \brief add the content from otherBuffer to this MemoryBuffer
* \param otherBuffer: source buffer
@@ -452,6 +509,22 @@ class MemoryBuffer {
return get_memory_width() * get_memory_height();
}
+ void copy_single_elem_from(const MemoryBuffer *src,
+ int channel_offset,
+ int elem_size,
+ const int to_channel_offset);
+ void copy_rows_from(const MemoryBuffer *src,
+ const rcti &src_area,
+ const int to_x,
+ const int to_y);
+ void copy_elems_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);
+
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("COM:MemoryBuffer")
#endif