summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDr.Smile <vabnick@gmail.com>2022-08-10 09:56:14 +0300
committerDr.Smile <vabnick@gmail.com>2023-04-03 06:00:17 +0300
commit2edca16722f351061d54491e140d59f89ef64327 (patch)
treeee017109b0b4ae7070a93f112226dee4887268f7
parent0f5175743587d3bfe072e9df5784abab4cee435a (diff)
downloadlibass-2edca16722f351061d54491e140d59f89ef64327.tar.bz2
libass-2edca16722f351061d54491e140d59f89ef64327.tar.xz
checkasm: add test of rasterizer bitmap functions
-rw-r--r--Makefile_util.am1
-rw-r--r--checkasm/checkasm.c1
-rw-r--r--checkasm/checkasm.h1
-rw-r--r--checkasm/rasterizer.c210
4 files changed, 213 insertions, 0 deletions
diff --git a/Makefile_util.am b/Makefile_util.am
index 43fe5e7..df89a9b 100644
--- a/Makefile_util.am
+++ b/Makefile_util.am
@@ -50,6 +50,7 @@ endif
$(nasm_verbose)$(AS) $(ASFLAGS) -I$(top_srcdir)/libass/ -o $@ $<
checkasm_checkasm_SOURCES = \
+ checkasm/rasterizer.c \
checkasm/blend_bitmaps.c \
checkasm/be_blur.c \
checkasm/blur.c \
diff --git a/checkasm/checkasm.c b/checkasm/checkasm.c
index 148c68a..3433c6a 100644
--- a/checkasm/checkasm.c
+++ b/checkasm/checkasm.c
@@ -54,6 +54,7 @@ static const struct {
const char *name;
void (*func)(unsigned cpu_flag);
} tests[] = {
+ { "rasterizer", checkasm_check_rasterizer },
{ "blend_bitmaps", checkasm_check_blend_bitmaps },
{ "be_blur", checkasm_check_be_blur },
{ "blur", checkasm_check_blur },
diff --git a/checkasm/checkasm.h b/checkasm/checkasm.h
index c319a39..aa69c1a 100644
--- a/checkasm/checkasm.h
+++ b/checkasm/checkasm.h
@@ -56,6 +56,7 @@
int xor128_rand(void);
#define rnd xor128_rand
+void checkasm_check_rasterizer(unsigned cpu_flag);
void checkasm_check_blend_bitmaps(unsigned cpu_flag);
void checkasm_check_be_blur(unsigned cpu_flag);
void checkasm_check_blur(unsigned cpu_flag);
diff --git a/checkasm/rasterizer.c b/checkasm/rasterizer.c
new file mode 100644
index 0000000..5c4f768
--- /dev/null
+++ b/checkasm/rasterizer.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2021-2022 libass contributors
+ *
+ * This file is part of libass.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "checkasm.h"
+#include "ass_rasterizer.h"
+
+#define HEIGHT 34
+#define STRIDE 96
+#define BORD_X 32
+#define BORD_Y 1
+#define REP_COUNT 8
+#define MAX_SEG 8
+
+
+static void generate_segment(struct segment *line, int tile_size, int y1, int y2)
+{
+ unsigned flags = rnd();
+ line->a = rnd() & 0x3FFFFFFF;
+ line->b = rnd() & 0x3FFFFFFF;
+ if (flags % 3u != 1)
+ line->a |= 0x40000000;
+ if (flags % 3u != 2)
+ line->b |= 0x40000000;
+ int32_t max_ab = FFMAX(line->a, line->b); // 2^30 <= max_ab < 2^31
+ if (flags & 1)
+ line->a = -line->a;
+ if (flags & 2)
+ line->b = -line->b;
+
+ int mask = (64 * tile_size << 16) - 1;
+ int x = rnd() & mask, y = rnd() & mask;
+ line->c = (line->a * (int64_t) x + line->b * (int64_t) y + (1 << 15)) >> 16;
+ // |line->c| <= 2^(tile_order + 7) * max_ab < 2^(tile_order + 38)
+
+#if 0
+ line->scale = ((uint64_t) 1 << 60) / max_ab;
+#else
+ line->scale = (rnd() & 0x1FFFFFFF) | 0x20000000;
+ if (line->scale * (uint64_t) max_ab > (uint64_t) 1 << 60)
+ line->scale ^= 0x20000000;
+#endif
+
+ line->flags = flags & 4 ? SEGFLAG_EXACT_LEFT : 0; // only left is used
+ if (line->a >= 0)
+ line->flags ^= SEGFLAG_DN | SEGFLAG_UL_DR;
+ if (line->b > 0)
+ line->flags ^= SEGFLAG_UL_DR;
+
+ line->x_min = flags & 8 ? 0x1234ABCD : 0;
+ line->x_max = 0xDEADC0DE; // not used
+
+ y1 &= 64 * tile_size - 1;
+ y2 &= 64 * tile_size - 1;
+ line->y_min = FFMIN(y1, y2 + 1);
+ line->y_max = FFMAX(y1, y2 + 1);
+}
+
+
+static void check_fill_solid(FillSolidTileFunc func, const char *name, int tile_size)
+{
+ ALIGN(uint8_t buf_ref[STRIDE * HEIGHT], 32);
+ ALIGN(uint8_t buf_new[STRIDE * HEIGHT], 32);
+ declare_func(void,
+ uint8_t *buf, ptrdiff_t stride, int set);
+
+ if (check_func(func, name, tile_size)) {
+ for(int set = 0; set <= 1; set++) {
+ for (int i = 0; i < sizeof(buf_ref); i++)
+ buf_ref[i] = buf_new[i] = rnd();
+
+ call_ref(buf_ref + BORD_Y * STRIDE + BORD_X, STRIDE, set);
+ call_new(buf_new + BORD_Y * STRIDE + BORD_X, STRIDE, set);
+
+ if (memcmp(buf_ref, buf_new, sizeof(buf_ref))) {
+ fail();
+ break;
+ }
+ }
+
+ bench_new(buf_new + BORD_Y * STRIDE + BORD_X, STRIDE, 1);
+ }
+
+ report(name, tile_size);
+}
+
+static void check_fill_halfplane(FillHalfplaneTileFunc func, const char *name, int tile_size)
+{
+ struct segment line;
+ ALIGN(uint8_t buf_ref[STRIDE * HEIGHT], 32);
+ ALIGN(uint8_t buf_new[STRIDE * HEIGHT], 32);
+ declare_func(void,
+ uint8_t *buf, ptrdiff_t stride,
+ int32_t a, int32_t b, int64_t c, int32_t scale);
+
+ if (check_func(func, name, tile_size)) {
+ for(int rep = 0; rep < REP_COUNT; rep++) {
+ for (int i = 0; i < sizeof(buf_ref); i++)
+ buf_ref[i] = buf_new[i] = rnd();
+
+ generate_segment(&line, tile_size, 0, 0);
+ call_ref(buf_ref + BORD_Y * STRIDE + BORD_X, STRIDE, line.a, line.b, line.c, line.scale);
+ call_new(buf_new + BORD_Y * STRIDE + BORD_X, STRIDE, line.a, line.b, line.c, line.scale);
+
+ if (memcmp(buf_ref, buf_new, sizeof(buf_ref))) {
+ fail();
+ break;
+ }
+ }
+
+ bench_new(buf_new + BORD_Y * STRIDE + BORD_X, STRIDE, line.a, line.b, line.c, line.scale);
+ }
+
+ report(name, tile_size);
+}
+
+static void check_fill_generic(FillGenericTileFunc func, const char *name, int tile_size)
+{
+ struct segment line[MAX_SEG];
+ ALIGN(uint8_t buf_ref[STRIDE * HEIGHT], 32);
+ ALIGN(uint8_t buf_new[STRIDE * HEIGHT], 32);
+ declare_func(void,
+ uint8_t *buf, ptrdiff_t stride,
+ const struct segment *line, size_t n_lines,
+ int winding);
+
+ if (check_func(func, name, tile_size)) {
+ for(int rep = 0; rep < REP_COUNT; rep++) {
+ for (int i = 0; i < sizeof(buf_ref); i++)
+ buf_ref[i] = buf_new[i] = rnd();
+
+ int n = rnd() % MAX_SEG + 1;
+ for (int i = 0; i < n; i++)
+ generate_segment(line + i, tile_size, rnd(), rnd());
+
+ int winding = rnd() % 5 - 2;
+ call_ref(buf_ref + BORD_Y * STRIDE + BORD_X, STRIDE, line, n, winding);
+ call_new(buf_new + BORD_Y * STRIDE + BORD_X, STRIDE, line, n, winding);
+
+ if (memcmp(buf_ref, buf_new, sizeof(buf_ref))) {
+ fail();
+ break;
+ }
+ }
+
+ generate_segment(line + 0, tile_size, 3 * 64 + 0, 7 * 64 - 1);
+ generate_segment(line + 1, tile_size, 3 * 64 + 5, 7 * 64 - 5);
+ generate_segment(line + 2, tile_size, 5 * 64 + 3, 5 * 64 + 9);
+ generate_segment(line + 3, tile_size, 5 * 64 + 9, 5 * 64 + 8);
+ bench_new(buf_new + BORD_Y * STRIDE + BORD_X, STRIDE, line, 4, 0);
+ }
+
+ report(name, tile_size);
+}
+
+static void check_merge_tile(MergeTileFunc func, const char *name, int tile_size)
+{
+ ALIGN(uint8_t src[32 * 32], 32);
+ ALIGN(uint8_t buf_ref[STRIDE * HEIGHT], 32);
+ ALIGN(uint8_t buf_new[STRIDE * HEIGHT], 32);
+ declare_func(void,
+ uint8_t *buf, ptrdiff_t stride, const uint8_t *tile);
+
+ if (check_func(func, name, tile_size)) {
+ for (int i = 0; i < sizeof(src); i++)
+ src[i] = rnd();
+ for (int i = 0; i < sizeof(buf_ref); i++)
+ buf_ref[i] = buf_new[i] = rnd();
+
+ call_ref(buf_ref + BORD_Y * STRIDE + BORD_X, STRIDE, src);
+ call_new(buf_new + BORD_Y * STRIDE + BORD_X, STRIDE, src);
+
+ if (memcmp(buf_ref, buf_new, sizeof(buf_ref)))
+ fail();
+
+ bench_new(buf_new + BORD_Y * STRIDE + BORD_X, STRIDE, src);
+ }
+
+ report(name, tile_size);
+}
+
+
+void checkasm_check_rasterizer(unsigned cpu_flag)
+{
+ BitmapEngine engine[2] = {
+ ass_bitmap_engine_init(cpu_flag),
+ ass_bitmap_engine_init(cpu_flag | ASS_FLAG_LARGE_TILES)
+ };
+ for (int i = 0; i < 2; i++) {
+ int tile_size = 1 << engine[i].tile_order;
+ check_fill_solid(engine[i].fill_solid, "fill_solid_tile%d", tile_size);
+ check_fill_halfplane(engine[i].fill_halfplane, "fill_halfplane_tile%d", tile_size);
+ check_fill_generic(engine[i].fill_generic, "fill_generic_tile%d", tile_size);
+ check_merge_tile(engine[i].merge, "merge_tile%d", tile_size);
+ }
+}