Commit 9a00c990 authored by Niklas Haas's avatar Niklas Haas

tests: add a test framework and start using it

Founds and fixed plenty of bugs already
parent a206814d
......@@ -43,7 +43,13 @@ sources = [
'ta/talloc.c',
]
# Optional components, in the format [ name, dependency, extra_sources ]
tests = [
'context.c',
'colorspace.c',
]
# Optional components, in the following format:
# [ name, dependency, extra_sources, extra_tests ]
components = [
[
'shaderc',
......@@ -85,7 +91,12 @@ foreach c : components
defs += '#define PL_HAVE_@0@ @1@\n'.format(name, dep.found() ? 1 : 0)
if dep.found()
bdeps += dep
sources += c[2]
if (c.length() > 2)
sources += c[2]
endif
if (c.length() > 3)
tests += c[3]
endif
endif
endforeach
......@@ -114,3 +125,12 @@ pkg.generate(
libraries: lib,
version: version,
)
# Tests
tdeps = declare_dependency(link_with: lib)
foreach t : tests
e = executable(t, 'tests/' + t, dependencies: tdeps)
test(t, e)
endforeach
#include "tests.h"
int main() {
for (enum pl_color_system sys = 0; sys < PL_COLOR_SYSTEM_COUNT; sys++) {
bool ycbcr = sys >= PL_COLOR_SYSTEM_BT_601 && sys <= PL_COLOR_SYSTEM_YCGCO;
REQUIRE(ycbcr == pl_color_system_is_ycbcr_like(sys));
}
for (enum pl_color_transfer trc = 0; trc < PL_COLOR_TRC_COUNT; trc++) {
bool hdr = trc >= PL_COLOR_TRC_PQ && trc <= PL_COLOR_TRC_S_LOG2;
REQUIRE(hdr == pl_color_transfer_is_hdr(trc));
REQUIRE(pl_color_transfer_nominal_peak(trc) >= 1.0);
}
float pq_peak = pl_color_transfer_nominal_peak(PL_COLOR_TRC_PQ);
REQUIRE(feq(PL_COLOR_REF_WHITE * pq_peak, 10000));
struct pl_color_repr tv_repr = {
.sys = PL_COLOR_SYSTEM_BT_709,
.levels = PL_COLOR_LEVELS_TV,
};
struct pl_color_repr pc_repr = {
.sys = PL_COLOR_SYSTEM_RGB,
.levels = PL_COLOR_LEVELS_PC,
};
// Ensure this is a no-op for bits == bits
for (int bits = 1; bits <= 16; bits++) {
tv_repr.bit_depth = bits;
pc_repr.bit_depth = bits;
REQUIRE(feq(pl_color_repr_texture_mul(tv_repr, bits), 1.0));
REQUIRE(feq(pl_color_repr_texture_mul(pc_repr, bits), 1.0));
}
tv_repr.bit_depth = 8;
float tv8to10 = pl_color_repr_texture_mul(tv_repr, 10);
float tv8to12 = pl_color_repr_texture_mul(tv_repr, 12);
// Simulate the effect of GPU texture sampling on UNORM texture
REQUIRE(feq(tv8to10 * 16 /1023., 64/1023.)); // black
REQUIRE(feq(tv8to10 * 235/1023., 940/1023.)); // nominal white
REQUIRE(feq(tv8to10 * 128/1023., 512/1023.)); // achromatic
REQUIRE(feq(tv8to10 * 240/1023., 960/1023.)); // nominal chroma peak
REQUIRE(feq(tv8to12 * 16 /4095., 256 /4095.)); // black
REQUIRE(feq(tv8to12 * 235/4095., 3760/4095.)); // nominal white
REQUIRE(feq(tv8to12 * 128/4095., 2048/4095.)); // achromatic
REQUIRE(feq(tv8to12 * 240/4095., 3840/4095.)); // nominal chroma peak
// Assume we uploaded a 10-bit source directly (unshifted) as a 16-bit
// texture. This texture multiplication factor should make it behave as if
// it was uploaded as a 10-bit texture instead.
pc_repr.bit_depth = 10;
float pc10to16 = pl_color_repr_texture_mul(pc_repr, 16);
REQUIRE(feq(pc10to16 * 1000/65535., 1000/1023.));
struct pl_raw_primaries bt709 = pl_raw_primaries_get(PL_COLOR_PRIM_BT_709);
struct pl_matrix3x3 rgb2xyz, rgb2xyz_;
rgb2xyz = pl_get_rgb2xyz_matrix(bt709);
rgb2xyz_ = pl_matrix3x3_invert(pl_matrix3x3_invert(rgb2xyz));
// Make sure the double-inversion round trips
for (int y = 0; y < 3; y++) {
for (int x = 0; x < 3; x++)
REQUIRE(feq(rgb2xyz.m[y][x], rgb2xyz_.m[y][x]));
}
// Make sure mapping the spectral RGB colors (i.e. the matrix rows) matches
// our original primaries
float Y = rgb2xyz.m[1][0];
REQUIRE(feq(rgb2xyz.m[0][0], pl_cie_X(bt709.red) * Y));
REQUIRE(feq(rgb2xyz.m[2][0], pl_cie_Z(bt709.red) * Y));
Y = rgb2xyz.m[1][1];
REQUIRE(feq(rgb2xyz.m[0][1], pl_cie_X(bt709.green) * Y));
REQUIRE(feq(rgb2xyz.m[2][1], pl_cie_Z(bt709.green) * Y));
Y = rgb2xyz.m[1][2];
REQUIRE(feq(rgb2xyz.m[0][2], pl_cie_X(bt709.blue) * Y));
REQUIRE(feq(rgb2xyz.m[2][2], pl_cie_Z(bt709.blue) * Y));
// Make sure the gamut mapping round-trips
struct pl_raw_primaries bt2020 = pl_raw_primaries_get(PL_COLOR_PRIM_BT_2020);
struct pl_matrix3x3 bt709_bt2020, bt2020_bt709;
bt709_bt2020 = pl_get_color_mapping_matrix(bt709, bt2020, PL_INTENT_RELATIVE_COLORIMETRIC);
bt2020_bt709 = pl_get_color_mapping_matrix(bt2020, bt709, PL_INTENT_RELATIVE_COLORIMETRIC);
for (int n = 0; n < 10; n++) {
float vec[3] = { RANDOM, RANDOM, RANDOM };
float dst[3] = { vec[0], vec[1], vec[2] };
pl_matrix3x3_apply(bt709_bt2020, dst);
pl_matrix3x3_apply(bt2020_bt709, dst);
for (int i = 0; i < 3; i++)
REQUIRE(feq(dst[i], vec[i]));
}
// Ensure the decoding matrix round-trips to white/black
for (enum pl_color_system sys = 0; sys < PL_COLOR_SYSTEM_COUNT; sys++) {
if (sys == PL_COLOR_SYSTEM_BT_2020_C || sys == PL_COLOR_SYSTEM_XYZ)
continue;
struct pl_color_repr repr = {
.levels = PL_COLOR_LEVELS_TV,
.sys = sys,
.bit_depth = 8,
};
struct pl_color_adjustment adj = pl_color_adjustment_neutral;
struct pl_transform3x3 yuv2rgb = pl_get_decoding_matrix(repr, adj);
static const float white_ycbcr[3] = { 235/255., 128/255., 128/255. };
static const float black_ycbcr[3] = { 16/255., 128/255., 128/255. };
static const float white_other[3] = { 235/255., 235/255., 235/255. };
static const float black_other[3] = { 16/255., 16/255., 16/255. };
float white[3], black[3];
for (int i = 0; i < 3; i++) {
if (pl_color_system_is_ycbcr_like(sys)) {
white[i] = white_ycbcr[i];
black[i] = black_ycbcr[i];
} else {
white[i] = white_other[i];
black[i] = black_other[i];
}
}
pl_transform3x3_apply(yuv2rgb, white);
REQUIRE(feq(white[0], 1.0));
REQUIRE(feq(white[1], 1.0));
REQUIRE(feq(white[2], 1.0));
pl_transform3x3_apply(yuv2rgb, black);
REQUIRE(feq(black[0], 0.0));
REQUIRE(feq(black[1], 0.0));
REQUIRE(feq(black[2], 0.0));
}
// Simulate a typical 10-bit YCbCr -> 16 bit texture conversion
tv_repr.bit_depth = 10;
struct pl_transform3x3 yuv2rgb;
yuv2rgb = pl_get_scaled_decoding_matrix(tv_repr, pl_color_adjustment_neutral, 16);
float test[3] = { 575/65535., 336/65535., 640/65535. };
pl_transform3x3_apply(yuv2rgb, test);
REQUIRE(feq(test[0], 0.808305));
REQUIRE(feq(test[1], 0.553254));
REQUIRE(feq(test[2], 0.218841));
}
#include "tests.h"
int main() {
struct pl_context *ctx = pl_context_create(&ctx_params, PL_API_VER);
pl_context_destroy(&ctx);
}
/*
* This file is part of libplacebo.
*
* libplacebo is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libplacebo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "common.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
static const struct pl_context_params ctx_params = { .log_cb = pl_log_simple };
static inline void require(bool b, const char *msg)
{
if (!b) {
fprintf(stderr, msg);
exit(1);
}
}
static inline bool feq(float a, float b)
{
return fabs(a - b) < 1e-6;
}
#define REQUIRE(cond) require((cond), #cond)
#define RANDOM (random() / (float) RAND_MAX)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment