blob: 4c6e6614f13d7903b82eb9fab7d4c8a4ca656942 [file]
/*
* Copyright 2026 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef skgpu_graphite_sparse_strips_FastValidator_DEFINED
#define skgpu_graphite_sparse_strips_FastValidator_DEFINED
#include "src/gpu/graphite/sparse_strips/SparseStripsConfig.h"
#include "src/gpu/graphite/sparse_strips/SparseStripsTypes.h"
#include "tests/Test.h"
#include <array>
#include <cstdint>
class SkMatrix;
class SkPath;
enum class SkPathFillType : uint8_t;
struct SkIRect;
template <typename T> class SkTDArray;
namespace skgpu::graphite {
class AlphaAtlasManager;
class EndCaps;
class Polyline;
class Recorder;
class WideTiles;
class WindingHistogram;
template <uint16_t kTileWidth, uint16_t kTileHeight> class Tiles;
// The FastValidator is a faster alternative to the Oracle that is intended to run on CQ. Like the
// Oracle, it validates subpixel winding by naively carrying the scanline across the viewport.
// Unlike the Oracle, the FastValidator implicitly assumes that the flattenning and tiling are
// correct; it calculates winding by consuming the polyline produced by flattenning and therefore
// does not root solve. It only validates the condensed geometric tiles produced by the
// StripProcessors: the EndCaps per subsample, and every other tile of the viewport, which must be
// covered by exactly one WideTile if all of its subsamples are inside the path, or else be empty.
template <uint16_t kTileWidth, uint16_t kTileHeight> class FastValidator {
public:
static constexpr float kTileWidthF = static_cast<float>(kTileWidth);
static constexpr float kTileHeightF = static_cast<float>(kTileHeight);
using StripFunc = void (*)(const Tiles<kTileWidth, kTileHeight>&,
WideTiles* wides,
EndCaps* ends,
AlphaAtlasManager* atlasManager,
SkPathFillType fillType,
const Polyline& polyline,
const SparseStripConfig::LUTArray& msaaLut,
bool isCulled,
const WindingHistogram& windingHistogram,
const SkIRect& clipRect,
MsaaExactMaskObserver observer);
static void RunScalarWinding(const Tiles<kTileWidth, kTileHeight>& tileContainer,
WideTiles* wides,
EndCaps* ends,
AlphaAtlasManager* atlasManager,
SkPathFillType fillType,
const Polyline& polyline,
const SparseStripConfig::LUTArray& maskLut,
bool isCulled,
const WindingHistogram& windingHistogram,
const SkIRect& clipRect,
MsaaExactMaskObserver observer);
static void RunSimdWinding(const Tiles<kTileWidth, kTileHeight>& tileContainer,
WideTiles* wides,
EndCaps* ends,
AlphaAtlasManager* atlasManager,
SkPathFillType fillType,
const Polyline& polyline,
const SparseStripConfig::LUTArray& maskLut,
bool isCulled,
const WindingHistogram& windingHistogram,
const SkIRect& clipRect,
MsaaExactMaskObserver observer);
// Validates a single path end-to-end:
// 1. Flattens using unculled Flatten::processPathsSimdTest to get ground-truth polyline.
// 2. Runs the production pipeline under test (culled Flatten -> Tiler -> MakeStrips).
// 3. Evaluates 8-subsample winding across the tiles of interest (ends.caps()).
// 4. Verifies actual masks and alpha reduction against expected ground truth.
// 5. Verifies that every other tile of the viewport is covered by exactly one WideTile if it is
// inside the path, and is empty if it is outside.
static bool ValidatePath(skiatest::Reporter* reporter,
Recorder* recorder,
const SkPath& path,
const SkMatrix& ctm,
uint16_t viewportWidth,
uint16_t viewportHeight,
const char* testName,
const SparseStripConfig::LUTArray& maskLut,
StripFunc stripFunc = nullptr,
std::array<uint32_t, 3>* minorErrorCount = nullptr);
// As above, but for a draw restricted to `clipRect` rather than a viewport anchored at the
// origin. Like the clips passed by StripGenerator, `clipRect` must have a tile aligned left and
// top. Only the pixels inside of `clipRect` are validated, and every tile outside of it must be
// empty.
static bool ValidatePath(skiatest::Reporter* reporter,
Recorder* recorder,
const SkPath& path,
const SkMatrix& ctm,
const SkIRect& clipRect,
const char* testName,
const SparseStripConfig::LUTArray& maskLut,
StripFunc stripFunc = nullptr,
std::array<uint32_t, 3>* minorErrorCount = nullptr);
// Validates precomputed strip output against an unculled reference polyline.
static bool ValidateStripOutput(skiatest::Reporter* reporter,
const SkPath& path,
const Polyline& polyline,
const Polyline& unculledPolyline,
const Tiles<kTileWidth, kTileHeight>& tiler,
const WideTiles& wides,
const EndCaps& ends,
const AlphaAtlasManager& atlasManager,
const SkTDArray<uint8_t>& exactMasks,
const SkIRect& clip,
SkPathFillType fillType,
const char* testName,
std::array<uint32_t, 3>* minorErrorCount = nullptr);
};
} // namespace skgpu::graphite
#endif // skgpu_graphite_sparse_strips_FastValidator_DEFINED