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