Modules/Sketch2D/tests/DabMaskBenchTests.cpp
Шурупов Илья Викторович 37eb17b3dc Snap dab positions and shapes and reuse rasterised dab masks
Dab centres snap to 1/16 px, or 1/8, 1/4 and 1/2 px above 16, 64 and
256 px, and dab size, angle, hardness and interior snap to fixed
steps, so dabs with the same shape and sub-pixel phase share one
rasterised coverage mask from a process wide cache. Masks above 256
px are not cached and use the direct shape evaluation. The normal,
masked and level paint paths share one loop over the mask.
2026-10-20 14:36:38 +03:00

44 lines
1.4 KiB
C++

#include "DabMask.hpp"
#include "StrokePainter.hpp"
#include "UnitTest++/UnitTest++.h"
#include <chrono>
#include <cstdio>
using namespace tp;
using namespace tp::sketch2d;
SUITE(BenchDabMasks) {
TEST(CachedMasksAgainstShapeMathPerDabSize) {
for (const halnf size : { 4.0f, 12.0f, 40.0f, 120.0f, 400.0f }) {
Brush brush;
brush.setSize(size);
DabWork work;
work.dab = PreparedDab(DabQuantizer::shape(brush.dabAt(1.0f)));
work.strength = 0.5f;
work.opacity = 1;
Tile tile;
const int4 dabs = (int4) (2.0e6f / (size * size)) + 200;
double cachedMs = 0;
double directMs = 0;
for (int4 pass = 0; pass < 2; pass++) {
const auto start = std::chrono::steady_clock::now();
for (int4 index = 0; index < dabs; index++) {
work.center = { 64.0f + (halnf) (index % 37) * 0.37f, 64.0f + (halnf) (index % 23) * 0.29f };
if (pass == 0) StrokePainter::paint(work, tile, { 0, 0 }, 0, 0, kTileSize, kTileSize);
else {
const DabPlacement placement = DabPlacement::snap(work.center, size);
const auto mask = DabMaskCache::rasterize(work.dab, placement, 1);
CHECK(!mask->isEmpty());
}
}
const double ms = std::chrono::duration<double, std::milli>(std::chrono::steady_clock::now() - start).count();
(pass == 0 ? cachedMs : directMs) = ms;
}
std::printf(
"[dab-mask] size %6.0f dabs %6d paint %8.2f ms shape math only %8.2f ms\n", size, dabs, cachedMs, directMs
);
}
}
}