blob: 3d48141d0aebea63ba36598c0950eb4364eb5511 [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.
*/
#include "src/gpu/graphite/sparse_strips/StripGenerator.h"
#include "include/core/SkMatrix.h"
#include "include/core/SkPath.h"
#include "src/gpu/graphite/AtlasProvider.h"
#include "src/gpu/graphite/RecorderPriv.h"
#include "src/gpu/graphite/sparse_strips/AlphaAtlasManager.h"
#include "src/gpu/graphite/sparse_strips/Flatten.h"
#include "src/gpu/graphite/sparse_strips/MakeStrips.h"
#include "src/gpu/graphite/sparse_strips/Polyline.h"
#include "src/gpu/graphite/sparse_strips/SparseStripsConfig.h"
#include "src/gpu/graphite/sparse_strips/Tiler.h"
namespace skgpu::graphite {
StripGenerator::StripGenerator(int width,
int height,
const SparseStripConfig::LUTArray& maskLUT,
Recorder* recorder)
: fWidth(width)
, fHeight(height)
, fMaskLUT(maskLUT)
, fRecorder(recorder)
, fWindingHistogram((height + SparseStripConfig::kTileHeight - 1) /
SparseStripConfig::kTileHeight)
, fCulled(true) {}
StripGenerator::~StripGenerator() = default;
bool StripGenerator::processGeometry(const SkPath& path, const SkMatrix& ctm) {
return this->processGeometry(path, ctm, SkIRect::MakeWH(fWidth, fHeight));
}
bool StripGenerator::processGeometry(const SkPath& path, const SkMatrix& ctm, const SkIRect& clip) {
fEnds.clear();
fWides.clear();
SkIRect tileClip = clip;
if (!tileClip.intersect(SkIRect::MakeWH(fWidth, fHeight))) {
return true;
}
tileClip.fLeft =
(tileClip.fLeft / SparseStripConfig::kTileWidth) * SparseStripConfig::kTileWidth;
tileClip.fTop =
(tileClip.fTop / SparseStripConfig::kTileHeight) * SparseStripConfig::kTileHeight;
AlphaAtlasManager* atlasManager =
fRecorder->priv().getOrCreateAtlasProvider()->alphaAtlasManager();
if (!atlasManager) {
return false;
}
Flatten flattener;
Polyline polyline;
flattener.processPaths<FlattenMode::kSimd>(path, ctm, tileClip, &polyline);
if (polyline.count() == 0 && !path.isInverseFillType()) {
return true;
}
fWindingHistogram.resize((fHeight + SparseStripConfig::kTileHeight - 1) /
SparseStripConfig::kTileHeight);
if (fCulled) {
fWindingHistogram.clear();
}
#if defined(SK_DEBUG)
// Tiler only writes to the histogram when it reports a culling event, so if the previous draw
// did not cull, the histogram must still be zero from the last time it was cleared.
for (int16_t winding : fWindingHistogram.data()) {
SkASSERT(winding == 0);
}
#endif
Tiles<SparseStripConfig::kTileWidth, SparseStripConfig::kTileHeight> tiler;
fCulled = tiler.makeTilesMSAA(polyline, tileClip, &fWindingHistogram);
tiler.sortTiles();
bool success =
MakeStrips::MsaaSimd<SparseStripConfig::kTileWidth, SparseStripConfig::kTileHeight>(
tiler,
&fWides,
&fEnds,
atlasManager,
path.getFillType(),
polyline,
fMaskLUT,
fCulled,
fWindingHistogram,
tileClip);
if (!success) {
return false;
}
if (!fEnds.empty()) {
atlasManager->populateProxies(&fEnds);
}
return true;
}
bool StripGenerator::cleanupNullCaps() {
AlphaAtlasManager* atlasManager =
fRecorder->priv().getOrCreateAtlasProvider()->alphaAtlasManager();
SkASSERT(atlasManager);
return atlasManager->resolveNullCaps(&fEnds);
}
} // namespace skgpu::graphite