Blender  V3.3
COM_BuffersIterator_test.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2021 Blender Foundation. */
3 
4 #include "testing/testing.h"
5 
6 #include "BLI_array.hh"
7 #include "COM_BuffersIterator.h"
8 
10 
11 constexpr int BUFFER_WIDTH = 5;
12 constexpr int BUFFER_HEIGHT = 4;
13 constexpr int BUFFER_OFFSET_X = 5;
14 constexpr int BUFFER_OFFSET_Y = 6;
15 constexpr int NUM_CHANNELS = 4;
18 constexpr int NUM_INPUTS = 2;
19 
20 static float *create_buffer(int len)
21 {
22  return (float *)MEM_callocN(len * sizeof(float), "COM_BuffersIteratorTest");
23 }
24 
25 static const float *create_input_buffer(int input_idx, bool is_a_single_elem)
26 {
27  const int len = is_a_single_elem ? SINGLE_ELEM_BUFFER_LEN : FULL_BUFFER_LEN;
28  float *buf = create_buffer(len);
29  /* Fill buffer with variable data. */
30  for (int i = 0; i < len; i++) {
31  buf[i] = input_idx * 1.5f * (i + 1) + i * 0.9f;
32  }
33  return buf;
34 }
35 
36 using IterFunc = std::function<void(BuffersIterator<float> &it, const rcti &area)>;
37 using ValidateElemFunc = std::function<void(float *out, Span<const float *> ins, int x, int y)>;
38 
39 class BuffersIteratorTest : public testing::Test {
40  private:
41  float *output_;
42  bool use_offsets_;
43  bool use_single_elem_inputs_;
44  bool use_inputs_;
45 
46  static rcti buffer_area;
47  static rcti buffer_offset_area;
48  static Array<const float *, NUM_INPUTS> single_elem_inputs;
49  static Array<const float *, NUM_INPUTS> full_buffer_inputs;
50 
51  public:
52  void set_inputs_enabled(bool value)
53  {
54  use_inputs_ = value;
55  }
56 
57  void test_iteration(IterFunc iter_func, ValidateElemFunc validate_elem_func = {})
58  {
59  use_single_elem_inputs_ = false;
60  validate_iteration(iter_func, validate_elem_func);
61  if (use_inputs_) {
62  use_single_elem_inputs_ = true;
63  validate_iteration(iter_func, validate_elem_func);
64  }
65  }
66 
67  protected:
68  static void SetUpTestCase()
69  {
70  BLI_rcti_init(&buffer_area, 0, BUFFER_WIDTH, 0, BUFFER_HEIGHT);
71  BLI_rcti_init(&buffer_offset_area,
76  for (int i = 0; i < NUM_INPUTS; i++) {
77  single_elem_inputs[i] = create_input_buffer(i, true);
78  full_buffer_inputs[i] = create_input_buffer(i, false);
79  }
80  }
81 
82  static void TearDownTestCase()
83  {
84  for (int i = 0; i < NUM_INPUTS; i++) {
85  MEM_freeN((void *)single_elem_inputs[i]);
86  single_elem_inputs[i] = nullptr;
87  MEM_freeN((void *)full_buffer_inputs[i]);
88  full_buffer_inputs[i] = nullptr;
89  }
90  }
91 
92  void SetUp() override
93  {
94  use_offsets_ = false;
95  use_single_elem_inputs_ = false;
96  use_inputs_ = false;
97  output_ = create_buffer(FULL_BUFFER_LEN);
98  }
99 
100  void TearDown() override
101  {
102  MEM_freeN(output_);
103  }
104 
105  private:
106  void validate_iteration(IterFunc iter_func, ValidateElemFunc validate_elem_func)
107  {
108  {
109  use_offsets_ = false;
110  BuffersIterator<float> it = iterate();
111  iter_func(it, buffer_area);
112  validate_result(buffer_area, validate_elem_func);
113  }
114  {
115  use_offsets_ = true;
116  BuffersIterator<float> it = offset_iterate(buffer_offset_area);
117  iter_func(it, buffer_offset_area);
118  validate_result(buffer_offset_area, validate_elem_func);
119  }
120  {
121  use_offsets_ = true;
122  rcti area = buffer_offset_area;
123  area.xmin += 1;
124  area.ymin += 1;
125  area.xmax -= 1;
126  area.ymax -= 1;
127  BuffersIterator<float> it = offset_iterate(area);
128  iter_func(it, area);
129  validate_result(area, validate_elem_func);
130  }
131  }
132 
133  void validate_result(rcti &area, ValidateElemFunc validate_elem_func)
134  {
135  Span<const float *> inputs = get_inputs();
136  Array<const float *> ins(inputs.size());
137  for (int y = area.ymin; y < area.ymax; y++) {
138  for (int x = area.xmin; x < area.xmax; x++) {
139  const int out_offset = get_buffer_relative_y(y) * BUFFER_WIDTH * NUM_CHANNELS +
140  get_buffer_relative_x(x) * NUM_CHANNELS;
141  float *out = &output_[out_offset];
142 
143  const int in_offset = use_single_elem_inputs_ ? 0 : out_offset;
144  for (int i = 0; i < inputs.size(); i++) {
145  ins[i] = &inputs[i][in_offset];
146  }
147 
148  if (validate_elem_func) {
149  validate_elem_func(out, ins, x, y);
150  }
151  }
152  }
153  }
154 
155  Span<const float *> get_inputs()
156  {
157  if (use_inputs_) {
158  return use_single_elem_inputs_ ? single_elem_inputs : full_buffer_inputs;
159  }
160  return {};
161  }
162 
163  int get_buffer_relative_x(int x)
164  {
165  return use_offsets_ ? x - BUFFER_OFFSET_X : x;
166  }
167  int get_buffer_relative_y(int y)
168  {
169  return use_offsets_ ? y - BUFFER_OFFSET_Y : y;
170  }
171 
173  BuffersIterator<float> iterate()
174  {
175  BLI_assert(!use_offsets_);
176  BuffersIteratorBuilder<float> builder(output_, BUFFER_WIDTH, BUFFER_HEIGHT, NUM_CHANNELS);
177  if (use_inputs_) {
178  const int input_stride = use_single_elem_inputs_ ? 0 : NUM_CHANNELS;
179  for (const float *input : get_inputs()) {
180  builder.add_input(input, BUFFER_WIDTH, input_stride);
181  }
182  }
183  return builder.build();
184  }
185 
187  BuffersIterator<float> offset_iterate(const rcti &area)
188  {
189  BLI_assert(use_offsets_);
190  const rcti &buf_area = buffer_offset_area;
191  BuffersIteratorBuilder<float> builder(output_, buf_area, area, NUM_CHANNELS);
192  if (use_inputs_) {
193  const int input_stride = use_single_elem_inputs_ ? 0 : NUM_CHANNELS;
194  for (const float *input : get_inputs()) {
195  builder.add_input(input, buf_area, input_stride);
196  }
197  }
198  return builder.build();
199  }
200 };
201 
202 rcti BuffersIteratorTest::buffer_area;
203 rcti BuffersIteratorTest::buffer_offset_area;
204 Array<const float *, NUM_INPUTS> BuffersIteratorTest::single_elem_inputs(NUM_INPUTS);
205 Array<const float *, NUM_INPUTS> BuffersIteratorTest::full_buffer_inputs(NUM_INPUTS);
206 
208 {
209  int x = area.xmin;
210  int y = area.ymin;
211  for (; !it.is_end(); ++it) {
212  EXPECT_EQ(x, it.x);
213  EXPECT_EQ(y, it.y);
214  x++;
215  if (x == area.xmax) {
216  x = area.xmin;
217  y++;
218  }
219  }
220  EXPECT_EQ(x, area.xmin);
221  EXPECT_EQ(y, area.ymax);
222 }
223 
224 TEST_F(BuffersIteratorTest, CoordinatesIterationWithNoInputs)
225 {
226  set_inputs_enabled(false);
227  test_iteration(iterate_coordinates);
228 }
229 
230 TEST_F(BuffersIteratorTest, CoordinatesIterationWithInputs)
231 {
232  set_inputs_enabled(true);
233  test_iteration(iterate_coordinates);
234 }
235 
236 TEST_F(BuffersIteratorTest, OutputIteration)
237 {
238  set_inputs_enabled(false);
239  test_iteration(
240  [](BuffersIterator<float> &it, const rcti &UNUSED(area)) {
241  EXPECT_EQ(it.get_num_inputs(), 0);
242  for (; !it.is_end(); ++it) {
243  const int dummy = it.y * BUFFER_WIDTH + it.x;
244  it.out[0] = dummy + 1.0f;
245  it.out[1] = dummy + 2.0f;
246  it.out[2] = dummy + 3.0f;
247  it.out[3] = dummy + 4.0f;
248  }
249  },
250  [](float *out, Span<const float *> UNUSED(ins), const int x, const int y) {
251  const int dummy = y * BUFFER_WIDTH + x;
252  EXPECT_NEAR(out[0], dummy + 1.0f, FLT_EPSILON);
253  EXPECT_NEAR(out[1], dummy + 2.0f, FLT_EPSILON);
254  EXPECT_NEAR(out[2], dummy + 3.0f, FLT_EPSILON);
255  EXPECT_NEAR(out[3], dummy + 4.0f, FLT_EPSILON);
256  });
257 }
258 
259 TEST_F(BuffersIteratorTest, OutputAndInputsIteration)
260 {
261  set_inputs_enabled(true);
262  test_iteration(
263  [](BuffersIterator<float> &it, const rcti &UNUSED(area)) {
264  EXPECT_EQ(it.get_num_inputs(), NUM_INPUTS);
265  for (; !it.is_end(); ++it) {
266  const float *in1 = it.in(0);
267  const float *in2 = it.in(1);
268  it.out[0] = in1[0] + in2[0];
269  it.out[1] = in1[1] + in2[3];
270  it.out[2] = in1[2] - in2[2];
271  it.out[3] = in1[3] - in2[1];
272  }
273  },
274  [](float *out, Span<const float *> ins, const int UNUSED(x), const int UNUSED(y)) {
275  const float *in1 = ins[0];
276  const float *in2 = ins[1];
277  EXPECT_NEAR(out[0], in1[0] + in2[0], FLT_EPSILON);
278  EXPECT_NEAR(out[1], in1[1] + in2[3], FLT_EPSILON);
279  EXPECT_NEAR(out[2], in1[2] - in2[2], FLT_EPSILON);
280  EXPECT_NEAR(out[3], in1[3] - in2[1], FLT_EPSILON);
281  });
282 }
283 
284 } // namespace blender::compositor::tests
#define BLI_assert(a)
Definition: BLI_assert.h:46
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax)
Definition: rct.c:417
#define UNUSED(x)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
void test_iteration(IterFunc iter_func, ValidateElemFunc validate_elem_func={})
SyclQueue void void size_t num_bytes void
int len
Definition: draw_manager.c:108
ccl_global KernelShaderEvalInput * input
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
std::function< void(BuffersIterator< float > &it, const rcti &area)> IterFunc
TEST_F(BuffersIteratorTest, CoordinatesIterationWithNoInputs)
static void iterate_coordinates(BuffersIterator< float > &it, const rcti &area)
static const float * create_input_buffer(int input_idx, bool is_a_single_elem)
std::function< void(float *out, Span< const float * > ins, int x, int y)> ValidateElemFunc
static float * create_buffer(int len)
static void area(int d1, int d2, int e1, int e2, float weights[2])
typename BuffersIteratorBuilder< T >::Iterator BuffersIterator
static const pxr::TfToken out("out", pxr::TfToken::Immortal)
static bNodeSocketTemplate inputs[]