odin-blend2d

Odin bindings to Blend2D
Log | Files | Refs | README | LICENSE

analyticrasterizer_test.cpp (6766B)


      1 // This file is part of Blend2D project <https://blend2d.com>
      2 //
      3 // See blend2d.h or LICENSE.md for license and copyright information
      4 // SPDX-License-Identifier: Zlib
      5 
      6 #include "../api-build_test_p.h"
      7 #if defined(BL_TEST)
      8 
      9 #include "../random.h"
     10 #include "../pipeline/pipedefs_p.h"
     11 #include "../raster/analyticrasterizer_p.h"
     12 #include "../support/intops_p.h"
     13 
     14 // bl::RasterEngine - AnalyticRasterizer - Tests
     15 // =============================================
     16 
     17 namespace bl::RasterEngine {
     18 
     19 static bool check_rasterizer_state(const AnalyticState& a, const AnalyticState& b) noexcept {
     20   int yDltMask = (a._dy >= a._dx) ? 255 : -1;
     21 
     22   return a._dx   == b._dx   && a._dy   == b._dy   &&
     23          a._ex0  == b._ex0  && a._ey0  == b._ey0  &&
     24          a._ex1  == b._ex1  && a._ey1  == b._ey1  &&
     25          a._fx0  == b._fx0  && a._fy0  == b._fy0  &&
     26          a._fx1  == b._fx1  && a._fy1  == b._fy1  &&
     27          a._xErr == b._xErr && a._yErr == b._yErr &&
     28          a._xDlt == b._xDlt && (a._yDlt & yDltMask) == (b._yDlt & yDltMask) &&
     29          a._xRem == b._xRem && a._yRem == b._yRem &&
     30          a._xLift == b._xLift && a._yLift == b._yLift &&
     31          a._savedFy1 == b._savedFy1;
     32 }
     33 
     34 UNIT(analytic_rasterizer, BL_TEST_GROUP_RENDERING_UTILITIES) {
     35   int w = 1000;
     36   int h = 1000;
     37 
     38   typedef Pipeline::A8Info A8Info;
     39 
     40   uint32_t max_band_height = 64;
     41   uint32_t edge_count = BrokenAPI::has_arg("--quick") ? 5000 : 100000;
     42 
     43   for (uint32_t band_height_shift = 0; band_height_shift < IntOps::ctz(max_band_height); band_height_shift++) {
     44     uint32_t band_height = 1 << band_height_shift;
     45     INFO("Testing advanceToY() correctness [band_height=%u]", band_height);
     46 
     47     // TODO: Wrap this logic into something, now it's duplicated 3x.
     48     size_t required_width = IntOps::align_up(uint32_t(w) + 1u + BL_PIPE_PIXELS_PER_ONE_BIT, BL_PIPE_PIXELS_PER_ONE_BIT);
     49     size_t required_height = band_height;
     50     size_t cell_alignment = 16;
     51 
     52     size_t bit_stride = IntOps::word_count_from_bit_count<BLBitWord>(required_width / BL_PIPE_PIXELS_PER_ONE_BIT) * sizeof(BLBitWord);
     53     size_t cell_stride = required_width * sizeof(uint32_t);
     54 
     55     size_t bits_start = 0;
     56     size_t bits_size = required_height * bit_stride;
     57 
     58     size_t cells_start = IntOps::align_up(bits_start + bits_size, cell_alignment);
     59     size_t cells_size = required_height * cell_stride;
     60 
     61     uint8_t* buffer = static_cast<uint8_t*>(calloc(bits_size + cells_size + cell_alignment, 1));
     62     EXPECT_NE(buffer, nullptr);
     63 
     64     AnalyticCellStorage cell_storage;
     65     cell_storage.init(
     66       reinterpret_cast<BLBitWord*>(buffer + bits_start), bit_stride,
     67       IntOps::align_up(reinterpret_cast<uint32_t*>(buffer + cells_start), cell_alignment), cell_stride);
     68 
     69     BLRandom rnd(0x1234);
     70     for (uint32_t i = 0; i < edge_count; i++) {
     71       int x0 = int(rnd.next_double() * double(w) * double(A8Info::kScale));
     72       int y0 = int(rnd.next_double() * double(h) * double(A8Info::kScale));
     73       int x1 = int(rnd.next_double() * double(w) * double(A8Info::kScale));
     74       int y1 = int(rnd.next_double() * double(h) * double(A8Info::kScale));
     75 
     76       // At least one horizontal line.
     77       if (i == 0)
     78         x1 = x0;
     79 
     80       if (y0 > y1) {
     81         BLInternal::swap(x0, x1);
     82         BLInternal::swap(y0, y1);
     83       }
     84 
     85       y1 += int((band_height + 1) * A8Info::kScale);
     86       if (y1 > (h << A8Info::kShift))
     87         y1 = (h << A8Info::kShift);
     88 
     89       uint32_t bandY0 = uint32_t(y0 >> A8Info::kShift);
     90       uint32_t bandY1 = bandY0 + band_height;
     91 
     92       AnalyticRasterizer a;
     93       AnalyticRasterizer b;
     94 
     95       // We don't really care of the cell storage here, can be the same...
     96       a.init(cell_storage.bit_ptr_top, cell_storage.bit_stride,
     97              cell_storage.cell_ptr_top, cell_storage.cell_stride, bandY0, band_height);
     98       b.init(cell_storage.bit_ptr_top, cell_storage.bit_stride,
     99              cell_storage.cell_ptr_top, cell_storage.cell_stride, bandY0, band_height);
    100 
    101       bool a_prepared = a.prepare_ref(EdgePoint<int>{x0, y0}, EdgePoint<int>{x1, y1});
    102       bool b_prepared = b.prepare(EdgePoint<int>{x0, y0}, EdgePoint<int>{x1, y1});
    103 
    104       bool prepare_must_match = check_rasterizer_state(a, b);
    105       EXPECT_TRUE(prepare_must_match)
    106         .message("Rasterizer preparation failed [TestId=%u]:\n"
    107                  "    Line: int x0=%d, y0=%d, x1=%d, y1=%d;\n"
    108                  "    A: x0={%d.%d} y0={%d.%d} x1={%d.%d} y1={%d.%d} err={%d|%d} dlt={%d|%d} rem={%d|%d} lift={%d|%d} dx|dy={%d|%d}\n"
    109                  "    B: x0={%d.%d} y0={%d.%d} x1={%d.%d} y1={%d.%d} err={%d|%d} dlt={%d|%d} rem={%d|%d} lift={%d|%d} dx|dy={%d|%d}",
    110                  i,
    111                  x0, y0, x1, y1,
    112                  a._ex0, a._fx0, a._ey0, a._fy0, a._ex1, a._fx1, a._ey1, a._fy1, a._xErr, a._yErr, a._xDlt, a._yDlt, a._xRem, a._yRem, a._xLift, a._yLift, a._dx, a._dy,
    113                  b._ex0, b._fx0, b._ey0, b._fy0, b._ex1, b._fx1, b._ey1, b._fy1, b._xErr, b._yErr, b._xDlt, b._yDlt, b._xRem, b._yRem, b._xLift, b._yLift, b._dx, b._dy);
    114 
    115       EXPECT_TRUE(a_prepared);
    116       EXPECT_TRUE(b_prepared);
    117 
    118       constexpr uint32_t kRasterizerOptions =
    119         AnalyticRasterizer::kOptionBandOffset |
    120         AnalyticRasterizer::kOptionBandingMode;
    121 
    122       uint32_t iteration = 0;
    123       for (;;) {
    124         bool is_finished = a.template rasterize<kRasterizerOptions>();
    125 
    126         // We cannot advance beyond the end of the edge.
    127         if (is_finished)
    128           break;
    129 
    130         b.advanceToY(int(bandY1));
    131         bool states_must_match = check_rasterizer_state(a, b);
    132 
    133         EXPECT_TRUE(states_must_match)
    134           .message("Rasterizer states are different [TestId=%u, Iteration=%u, BandY0=%u, BandY1=%u]:\n"
    135                    "    Line: int x0=%d, y0=%d, x1=%d, y1=%d;\n"
    136                    "    A: x0={%d.%d} y0={%d.%d} x1={%d.%d} y1={%d.%d} err={%d|%d} dlt={%d|%d} rem={%d|%d} lift={%d|%d} dx|dy={%d|%d}\n"
    137                    "    B: x0={%d.%d} y0={%d.%d} x1={%d.%d} y1={%d.%d} err={%d|%d} dlt={%d|%d} rem={%d|%d} lift={%d|%d} dx|dy={%d|%d}",
    138                    i, iteration, bandY0, bandY1,
    139                    x0, y0, x1, y1,
    140                    a._ex0, a._fx0, a._ey0, a._fy0, a._ex1, a._fx1, a._ey1, a._fy1, a._xErr, a._yErr, a._xDlt, a._yDlt, a._xRem, a._yRem, a._xLift, a._yLift, a._dx, a._dy,
    141                    b._ex0, b._fx0, b._ey0, b._fy0, b._ex1, b._fx1, b._ey1, b._fy1, b._xErr, b._yErr, b._xDlt, b._yDlt, b._xRem, b._yRem, b._xLift, b._yLift, b._dx, b._dy);
    142 
    143         bandY0 = bandY1;
    144         bandY1 += band_height;
    145 
    146         a._band_offset = bandY0;
    147         a._band_end = bl_min(bandY1 - 1, uint32_t((y1 - 1) >> A8Info::kShift));
    148 
    149         b._band_offset = a._band_offset;
    150         b._band_end = a._band_end;
    151 
    152         iteration++;
    153       }
    154     }
    155 
    156     free(buffer);
    157   }
    158 }
    159 
    160 } // {bl::RasterEngine}
    161 
    162 #endif // BL_TEST