Files
test2/source/blender/imbuf/tests/IMB_scaling_test.cc
Aras Pranckevicius cc2c6692c0 Cleanup: Name more IMB things as "byte" or "float" instead of "rect" and "rectFloat"
- IB_rect -> IB_byte_data
- IB_rectfloat -> IB_float_data
- Rename some functions:
	- IMB_get_rect_len -> IMB_get_pixel_count
	- IMB_rect_from_float -> IMB_byte_from_float
	- IMB_float_from_rect_ex -> IMB_float_from_byte_ex
	- IMB_float_from_rect -> IMB_float_from_byte
	- imb_addrectImBuf -> IMB_alloc_byte_pixels
	- imb_freerectImBuf -> IMB_free_byte_pixels
	- imb_addrectfloatImBuf -> IMB_alloc_float_pixels
	- imb_freerectfloatImBuf -> IMB_free_float_pixels
	- imb_freemipmapImBuf -> IMB_free_mipmaps
	- imb_freerectImbuf_all -> IMB_free_all_data
- Remove IB_multiview (not used at all)
- Remove obsolete "module" comments in public IMB headers

Pull Request: https://projects.blender.org/blender/blender/pulls/135348
2025-03-03 17:11:45 +01:00

298 lines
9.7 KiB
C++

/* SPDX-FileCopyrightText: 2024 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "testing/testing.h"
#include "BLI_math_vector_types.hh"
#include "IMB_imbuf.hh"
namespace blender::imbuf::tests {
static ImBuf *create_6x2_test_image()
{
ImBuf *img = IMB_allocImBuf(6, 2, 32, IB_byte_data);
uchar4 *col = reinterpret_cast<uchar4 *>(img->byte_buffer.data);
/* Source pixels are spelled out in 2x2 blocks below:
* nearest filter results in corner pixel from each block, bilinear
* is average of each block. */
col[0] = uchar4(0, 0, 0, 255);
col[1] = uchar4(255, 0, 0, 255);
col[6] = uchar4(255, 255, 0, 255);
col[7] = uchar4(255, 255, 255, 255);
col[2] = uchar4(133, 55, 31, 13);
col[3] = uchar4(133, 55, 31, 15);
col[8] = uchar4(133, 55, 31, 17);
col[9] = uchar4(133, 55, 31, 19);
col[4] = uchar4(50, 200, 0, 255);
col[5] = uchar4(55, 0, 32, 254);
col[10] = uchar4(56, 0, 64, 253);
col[11] = uchar4(57, 0, 96, 252);
return img;
}
static ImBuf *create_6x2_test_image_fl(int channels)
{
ImBuf *img = IMB_allocImBuf(6, 2, 32, IB_float_data);
img->channels = channels;
float *col = img->float_buffer.data;
for (int y = 0; y < img->y; y++) {
for (int x = 0; x < img->x; x++) {
for (int ch = 0; ch < channels; ch++) {
*col = x * 1.25f + y * 0.5f + ch * 0.125f;
col++;
}
}
}
return img;
}
static ImBuf *scale_2x_smaller(bool nearest, bool threaded, int float_channels = 0)
{
ImBuf *img = float_channels > 0 ? create_6x2_test_image_fl(float_channels) :
create_6x2_test_image();
int ww = 3, hh = 1;
if (threaded) {
IMB_scale(img, ww, hh, IMBScaleFilter::Bilinear, true);
}
else if (nearest) {
IMB_scale(img, ww, hh, IMBScaleFilter::Nearest, false);
}
else {
IMB_scale(img, ww, hh, IMBScaleFilter::Box, false);
}
return img;
}
static ImBuf *scale_to_1x1(bool nearest, bool threaded, int float_channels = 0)
{
ImBuf *img = float_channels > 0 ? create_6x2_test_image_fl(float_channels) :
create_6x2_test_image();
int ww = 1, hh = 1;
if (threaded) {
IMB_scale(img, ww, hh, IMBScaleFilter::Bilinear, true);
}
else if (nearest) {
IMB_scale(img, ww, hh, IMBScaleFilter::Nearest, false);
}
else {
IMB_scale(img, ww, hh, IMBScaleFilter::Box, false);
}
return img;
}
static ImBuf *scale_fractional_larger(bool nearest, bool threaded, int float_channels = 0)
{
ImBuf *img = float_channels > 0 ? create_6x2_test_image_fl(float_channels) :
create_6x2_test_image();
int ww = 9, hh = 7;
if (threaded) {
IMB_scale(img, ww, hh, IMBScaleFilter::Bilinear, true);
}
else if (nearest) {
IMB_scale(img, ww, hh, IMBScaleFilter::Nearest, false);
}
else {
IMB_scale(img, ww, hh, IMBScaleFilter::Box, false);
}
return img;
}
TEST(imbuf_scaling, nearest_2x_smaller)
{
ImBuf *res = scale_2x_smaller(true, false);
const uchar4 *got = reinterpret_cast<uchar4 *>(res->byte_buffer.data);
EXPECT_EQ(uint4(got[0]), uint4(0, 0, 0, 255));
EXPECT_EQ(uint4(got[1]), uint4(133, 55, 31, 13));
EXPECT_EQ(uint4(got[2]), uint4(50, 200, 0, 255));
IMB_freeImBuf(res);
}
TEST(imbuf_scaling, threaded_2x_smaller)
{
ImBuf *res = scale_2x_smaller(false, true);
const uchar4 *got = reinterpret_cast<uchar4 *>(res->byte_buffer.data);
EXPECT_EQ(uint4(got[0]), uint4(191, 128, 64, 255));
EXPECT_EQ(uint4(got[1]), uint4(133, 55, 31, 16));
EXPECT_EQ(uint4(got[2]), uint4(55, 50, 48, 254));
IMB_freeImBuf(res);
}
TEST(imbuf_scaling, bilinear_2x_smaller)
{
ImBuf *res = scale_2x_smaller(false, false);
const uchar4 *got = reinterpret_cast<uchar4 *>(res->byte_buffer.data);
/* NOTE: #IMB_transform results in (191, 128, 64, 255), <same>,
* (55, 50, 48, 254) i.e. different rounding. */
EXPECT_EQ(uint4(got[0]), uint4(191, 127, 63, 255));
EXPECT_EQ(uint4(got[1]), uint4(133, 55, 31, 16));
EXPECT_EQ(uint4(got[2]), uint4(55, 50, 48, 253));
IMB_freeImBuf(res);
}
TEST(imbuf_scaling, nearest_to_1x1)
{
ImBuf *res = scale_to_1x1(true, false);
const uchar4 *got = reinterpret_cast<uchar4 *>(res->byte_buffer.data);
EXPECT_EQ(uint4(got[0]), uint4(0, 0, 0, 255));
IMB_freeImBuf(res);
}
TEST(imbuf_scaling, threaded_to_1x1)
{
ImBuf *res = scale_to_1x1(false, true);
const uchar4 *got = reinterpret_cast<uchar4 *>(res->byte_buffer.data);
EXPECT_EQ(uint4(got[0]), uint4(133, 55, 31, 16));
IMB_freeImBuf(res);
}
TEST(imbuf_scaling, bilinear_to_1x1)
{
ImBuf *res = scale_to_1x1(false, false);
const uchar4 *got = reinterpret_cast<uchar4 *>(res->byte_buffer.data);
EXPECT_EQ(uint4(got[0]), uint4(126, 78, 47, 174));
IMB_freeImBuf(res);
}
TEST(imbuf_scaling, nearest_fractional_larger)
{
ImBuf *res = scale_fractional_larger(true, false);
const uchar4 *got = reinterpret_cast<uchar4 *>(res->byte_buffer.data);
EXPECT_EQ(uint4(got[0 + 0 * res->x]), uint4(0, 0, 0, 255));
EXPECT_EQ(uint4(got[1 + 0 * res->x]), uint4(0, 0, 0, 255));
EXPECT_EQ(uint4(got[7 + 0 * res->x]), uint4(50, 200, 0, 255));
EXPECT_EQ(uint4(got[2 + 2 * res->x]), uint4(255, 0, 0, 255));
EXPECT_EQ(uint4(got[3 + 2 * res->x]), uint4(133, 55, 31, 13));
EXPECT_EQ(uint4(got[8 + 6 * res->x]), uint4(57, 0, 96, 252));
IMB_freeImBuf(res);
}
TEST(imbuf_scaling, bilinear_fractional_larger)
{
ImBuf *res = scale_fractional_larger(false, false);
const uchar4 *got = reinterpret_cast<uchar4 *>(res->byte_buffer.data);
EXPECT_EQ(uint4(got[0 + 0 * res->x]), uint4(0, 0, 0, 255));
EXPECT_EQ(uint4(got[1 + 0 * res->x]), uint4(127, 0, 0, 255));
EXPECT_EQ(uint4(got[7 + 0 * res->x]), uint4(52, 100, 16, 255));
EXPECT_EQ(uint4(got[2 + 2 * res->x]), uint4(235, 55, 51, 215));
EXPECT_EQ(uint4(got[3 + 2 * res->x]), uint4(153, 55, 35, 54));
EXPECT_EQ(uint4(got[8 + 5 * res->x]), uint4(57, 0, 91, 252));
EXPECT_EQ(uint4(got[0 + 6 * res->x]), uint4(164, 164, 0, 255));
EXPECT_EQ(uint4(got[7 + 6 * res->x]), uint4(55, 36, 57, 254));
EXPECT_EQ(uint4(got[8 + 6 * res->x]), uint4(56, 0, 73, 253));
IMB_freeImBuf(res);
}
static constexpr float EPS = 0.0001f;
TEST(imbuf_scaling, nearest_2x_smaller_fl1)
{
ImBuf *res = scale_2x_smaller(true, false, 1);
const float *got = res->float_buffer.data;
EXPECT_NEAR(got[0], 0.0f, EPS);
EXPECT_NEAR(got[1], 2.5f, EPS);
EXPECT_NEAR(got[2], 5.0f, EPS);
IMB_freeImBuf(res);
}
TEST(imbuf_scaling, nearest_2x_smaller_fl2)
{
ImBuf *res = scale_2x_smaller(true, false, 2);
const float2 *got = reinterpret_cast<float2 *>(res->float_buffer.data);
EXPECT_V2_NEAR(got[0], float2(0.0f, 0.125f), EPS);
EXPECT_V2_NEAR(got[1], float2(2.5f, 2.625f), EPS);
EXPECT_V2_NEAR(got[2], float2(5.0f, 5.125f), EPS);
IMB_freeImBuf(res);
}
TEST(imbuf_scaling, nearest_2x_smaller_fl3)
{
ImBuf *res = scale_2x_smaller(true, false, 3);
const float3 *got = reinterpret_cast<float3 *>(res->float_buffer.data);
EXPECT_V3_NEAR(got[0], float3(0.0f, 0.125f, 0.25f), EPS);
EXPECT_V3_NEAR(got[1], float3(2.5f, 2.625f, 2.75f), EPS);
EXPECT_V3_NEAR(got[2], float3(5.0f, 5.125f, 5.25f), EPS);
IMB_freeImBuf(res);
}
TEST(imbuf_scaling, nearest_2x_smaller_fl4)
{
ImBuf *res = scale_2x_smaller(true, false, 4);
const float4 *got = reinterpret_cast<float4 *>(res->float_buffer.data);
EXPECT_V4_NEAR(got[0], float4(0.0f, 0.125f, 0.25f, 0.375f), EPS);
EXPECT_V4_NEAR(got[1], float4(2.5f, 2.625f, 2.75f, 2.875f), EPS);
EXPECT_V4_NEAR(got[2], float4(5.0f, 5.125f, 5.25f, 5.375f), EPS);
IMB_freeImBuf(res);
}
TEST(imbuf_scaling, nearest_to_1x1_fl3)
{
ImBuf *res = scale_to_1x1(true, false, 3);
const float3 *got = reinterpret_cast<float3 *>(res->float_buffer.data);
EXPECT_V3_NEAR(got[0], float3(0, 0.125f, 0.25f), EPS);
IMB_freeImBuf(res);
}
TEST(imbuf_scaling, threaded_to_1x1_fl3)
{
ImBuf *res = scale_to_1x1(false, true, 3);
const float3 *got = reinterpret_cast<float3 *>(res->float_buffer.data);
EXPECT_V3_NEAR(got[0], float3(3.375f, 3.5f, 3.625f), EPS);
IMB_freeImBuf(res);
}
TEST(imbuf_scaling, bilinear_to_1x1_fl3)
{
ImBuf *res = scale_to_1x1(false, false, 3);
const float3 *got = reinterpret_cast<float3 *>(res->float_buffer.data);
EXPECT_V3_NEAR(got[0], float3(3.36853f, 3.49353f, 3.61853f), EPS);
IMB_freeImBuf(res);
}
TEST(imbuf_scaling, bilinear_2x_smaller_fl3)
{
ImBuf *res = scale_2x_smaller(false, false, 3);
const float3 *got = reinterpret_cast<float3 *>(res->float_buffer.data);
EXPECT_V3_NEAR(got[0], float3(0.87270f, 0.99770f, 1.12270f), EPS);
EXPECT_V3_NEAR(got[1], float3(3.36853f, 3.49353f, 3.61853f), EPS);
EXPECT_V3_NEAR(got[2], float3(5.86435f, 5.98935f, 6.11435f), EPS);
IMB_freeImBuf(res);
}
TEST(imbuf_scaling, bilinear_2x_smaller_fl4)
{
ImBuf *res = scale_2x_smaller(false, false, 4);
const float4 *got = reinterpret_cast<float4 *>(res->float_buffer.data);
EXPECT_V4_NEAR(got[0], float4(0.87270f, 0.99770f, 1.12270f, 1.24770f), EPS);
EXPECT_V4_NEAR(got[1], float4(3.36853f, 3.49353f, 3.61853f, 3.74353f), EPS);
EXPECT_V4_NEAR(got[2], float4(5.86435f, 5.98935f, 6.11435f, 6.23935f), EPS);
IMB_freeImBuf(res);
}
TEST(imbuf_scaling, threaded_2x_smaller_fl3)
{
ImBuf *res = scale_2x_smaller(false, true, 3);
const float3 *got = reinterpret_cast<float3 *>(res->float_buffer.data);
EXPECT_V3_NEAR(got[0], float3(0.875f, 1.0f, 1.125f), EPS);
EXPECT_V3_NEAR(got[1], float3(3.375f, 3.5f, 3.625f), EPS);
EXPECT_V3_NEAR(got[2], float3(5.875f, 6.0f, 6.125f), EPS);
IMB_freeImBuf(res);
}
TEST(imbuf_scaling, threaded_2x_smaller_fl4)
{
ImBuf *res = scale_2x_smaller(false, true, 4);
const float4 *got = reinterpret_cast<float4 *>(res->float_buffer.data);
EXPECT_V4_NEAR(got[0], float4(0.875f, 1.0f, 1.125f, 1.25f), EPS);
EXPECT_V4_NEAR(got[1], float4(3.375f, 3.5f, 3.625f, 3.75f), EPS);
EXPECT_V4_NEAR(got[2], float4(5.875f, 6.0f, 6.125f, 6.25f), EPS);
IMB_freeImBuf(res);
}
} // namespace blender::imbuf::tests