30std::pair<skvx::float2, skvx::float2> round_out(
const SkRect& r) {
36template<
typename T>
bool refs_atlas(
const T* proxyOwner,
const GrSurfaceProxy* atlasProxy) {
37 bool refsAtlas =
false;
39 if (proxy == atlasProxy) {
44 proxyOwner->visitProxies(checkForAtlasRef);
49bool is_visible(
const SkRect& pathDevBounds,
const SkIRect& clipBounds) {
54 if (!
all(pathTopLeft < pathBotRight)) {
59 static_assert(
sizeof(clipBounds) ==
sizeof(clipTopLeft) +
sizeof(clipBotRight));
60 return all(pathTopLeft < clipBotRight) &&
all(pathBotRight > clipTopLeft);
67void validate_atlas_dependencies(
69 for (
int i = atlasTasks.size() - 1; i >= 1; --i) {
70 auto atlasTask = atlasTasks[i].get();
71 auto previousAtlasTask = atlasTasks[i - 1].get();
76 for (
GrRenderTask* previousAtlasUser : previousAtlasTask->dependents()) {
77 SkASSERT(atlasTask->dependsOn(previousAtlasUser));
108#ifdef SK_BUILD_FOR_IOS
115#ifdef SK_BUILD_FOR_WIN
140#if defined(GR_TEST_UTILS)
141 fAtlasMaxSize = dContext->
priv().
options().fMaxTextureAtlasSize;
143 fAtlasMaxSize = 2048;
150bool AtlasPathRenderer::pathFitsInAtlas(
const SkRect& pathDevBounds,
156 auto [topLeftFloor, botRightCeil] = round_out(pathDevBounds);
157 auto size = botRightCeil - topLeftFloor;
159 all(size <= fAtlasMaxPathWidth) &&
163 size[0] * size[1] <= atlasMaxPathHeight_p2;
166void AtlasPathRenderer::AtlasPathKey::set(
const SkMatrix& m,
const SkPath& path) {
167 fPathGenID = path.getGenerationID();
168 fAffineMatrix[0] = m.getScaleX();
169 fAffineMatrix[1] = m.getSkewX();
170 fAffineMatrix[2] = m.getTranslateX();
171 fAffineMatrix[3] = m.getSkewY();
172 fAffineMatrix[4] = m.getScaleY();
173 fAffineMatrix[5] = m.getTranslateY();
180 const SkRect& pathDevBounds,
183 bool* transposedInAtlas,
184 const DrawRefsAtlasCallback& drawRefsAtlasCallback) {
191 auto [topLeftFloor, botRightCeil] = round_out(pathDevBounds);
196 int widthInAtlas = devIBounds->
width();
197 int heightInAtlas = devIBounds->
height();
199 SkASSERT(widthInAtlas > 0 && heightInAtlas > 0);
204 *transposedInAtlas = widthInAtlas > heightInAtlas;
208 *transposedInAtlas = heightInAtlas > widthInAtlas;
210 if (*transposedInAtlas) {
211 std::swap(heightInAtlas, widthInAtlas);
214 SkASSERT(widthInAtlas <= (
int)fAtlasMaxPathWidth);
218 AtlasPathKey atlasPathKey;
219 if (!
path.isVolatile()) {
220 atlasPathKey.set(viewMatrix, path);
221 if (
const SkIPoint16* existingLocation = fAtlasPathCache.find(atlasPathKey)) {
222 *locationInAtlas = *existingLocation;
227 if (fAtlasRenderTasks.empty() ||
228 !fAtlasRenderTasks.back()->addPath(viewMatrix, path, devIBounds->
topLeft(), widthInAtlas,
229 heightInAtlas, *transposedInAtlas, locationInAtlas)) {
231 auto currentAtlasTask = (!fAtlasRenderTasks.empty()) ? fAtlasRenderTasks.back().get()
233 if (currentAtlasTask &&
234 drawRefsAtlasCallback &&
235 drawRefsAtlasCallback(currentAtlasTask->atlasProxy())) {
241 auto dynamicAtlas = std::make_unique<GrDynamicAtlas>(
243 SkISize{fAtlasInitialSize, fAtlasInitialSize}, fAtlasMaxSize,
245 auto newAtlasTask = sk_make_sp<AtlasRenderTask>(rContext,
246 sk_make_sp<GrArenas>(),
247 std::move(dynamicAtlas));
250 heightInAtlas, *transposedInAtlas, locationInAtlas));
251 fAtlasRenderTasks.push_back(std::move(newAtlasTask));
252 fAtlasPathCache.reset();
256 if (!
path.isVolatile()) {
257 fAtlasPathCache.set(atlasPathKey, *locationInAtlas);
264 if (!fAtlasRenderTasks.empty()) {
267 const GrSurfaceProxy* atlasProxy = fAtlasRenderTasks.back()->atlasProxy();
268 SkASSERT(!refs_atlas(
args.fPaint->getColorFragmentProcessor(), atlasProxy));
269 SkASSERT(!refs_atlas(
args.fPaint->getCoverageFragmentProcessor(), atlasProxy));
274#ifdef SK_DISABLE_ATLAS_PATH_RENDERER_WITH_COVERAGE_AA
284 (
args.fProxy->numSamples() == 1 || !
args.fShape->knownToBeConvex()) &&
285 !
args.fShape->style().hasPathEffect() &&
286 !
args.fViewMatrix->hasPerspective() &&
287 this->pathFitsInAtlas(
args.fViewMatrix->mapRect(
args.fShape->bounds()),
294 args.fShape->asPath(&path);
296 const SkRect pathDevBounds =
args.fViewMatrix->mapRect(
args.fShape->bounds());
297 SkASSERT(this->pathFitsInAtlas(pathDevBounds,
args.fAAType));
299 if (!is_visible(pathDevBounds,
args.fClip->getConservativeBounds())) {
301 if (path.isInverseFillType()) {
302 args.fSurfaceDrawContext->drawPaint(
args.fClip, std::move(
args.fPaint),
310 bool transposedInAtlas;
312 &devIBounds, &locationInAtlas, &transposedInAtlas,
315 const SkIRect& fillBounds =
args.fShape->inverseFilled()
317 ?
args.fClip->getConservativeBounds()
318 :
args.fSurfaceDrawContext->asSurfaceProxy()->backingStoreBoundsIRect())
320 const GrCaps& caps = *
args.fSurfaceDrawContext->caps();
321 auto op = GrOp::Make<DrawAtlasPathOp>(
args.fContext,
322 args.fSurfaceDrawContext->arenaAlloc(),
323 fillBounds, *
args.fViewMatrix,
324 std::move(
args.fPaint), locationInAtlas,
325 devIBounds, transposedInAtlas,
326 fAtlasRenderTasks.back()->readView(caps),
327 args.fShape->inverseFilled());
328 args.fSurfaceDrawContext->addDrawOp(
args.fClip, std::move(op));
333 const GrOp* opBeingClipped,
334 std::unique_ptr<GrFragmentProcessor> inputFP,
342 const SkRect pathDevBounds = viewMatrix.
mapRect(path.getBounds());
343 if (!is_visible(pathDevBounds, drawBounds)) {
353 if (!this->pathFitsInAtlas(pathDevBounds, fallbackAAType)) {
360 bool transposedInAtlas;
363 auto drawRefsAtlasCallback = [opBeingClipped, &inputFP](
const GrSurfaceProxy* atlasProxy) {
364 return refs_atlas(opBeingClipped, atlasProxy) ||
365 refs_atlas(inputFP.get(), atlasProxy);
368 if (!this->addPathToAtlas(sdc->
recordingContext(), viewMatrix, path, pathDevBounds, &devIBounds,
369 &locationInAtlas, &transposedInAtlas, drawRefsAtlasCallback)) {
375 auto [atlasX, atlasY] = locationInAtlas;
376 if (!transposedInAtlas) {
379 atlasMatrix.
setAll(0, 1, atlasX - devIBounds.
top(),
380 1, 0, atlasY - devIBounds.
left(),
384 if (path.isInverseFillType()) {
387 if (!devIBounds.
contains(drawBounds)) {
395 return GrFPSuccess(std::make_unique<GrModulateAtlasCoverageEffect>(
flags, std::move(inputFP),
396 std::move(atlasView),
397 atlasMatrix, devIBounds));
401 if (fAtlasRenderTasks.empty()) {
402 SkASSERT(fAtlasPathCache.count() == 0);
407 SkDEBUGCODE(validate_atlas_dependencies(fAtlasRenderTasks);)
411#if defined(GR_TEST_UTILS)
412 if (onFlushRP->failFlushTimeCallbacks()) {
421 successful = fAtlasRenderTasks[0]->instantiate(onFlushRP);
424 GrTexture* firstAtlas = fAtlasRenderTasks[0]->atlasProxy()->peekTexture();
426 for (
int i = 1; successful && i < fAtlasRenderTasks.size(); ++i) {
427 auto atlasTask = fAtlasRenderTasks[i].get();
428 if (atlasTask->atlasProxy()->backingStoreDimensions() == firstAtlas->
dimensions()) {
429 successful &= atlasTask->instantiate(onFlushRP,
sk_ref_sp(firstAtlas));
432 SkASSERT(i == fAtlasRenderTasks.size() - 1);
433 SkASSERT(atlasTask->atlasProxy()->backingStoreDimensions().area() <
436 successful &= atlasTask->instantiate(onFlushRP);
442 fAtlasRenderTasks.clear();
443 fAtlasPathCache.reset();
static GrFPResult GrFPNullableSuccess(std::unique_ptr< GrFragmentProcessor > fp)
static GrFPResult GrFPSuccess(std::unique_ptr< GrFragmentProcessor > fp)
std::tuple< bool, std::unique_ptr< GrFragmentProcessor > > GrFPResult
static GrFPResult GrFPFailure(std::unique_ptr< GrFragmentProcessor > fp)
GrFillRule GrFillRuleForSkPath(const SkPath &path)
#define SkAssertResult(cond)
static int SkPrevPow2(int value)
static int SkNextPow2(int value)
sk_sp< T > sk_ref_sp(T *obj)
const GrContextOptions & options() const
const GrCaps * caps() const
GrBackendFormat getDefaultBackendFormat(GrColorType, GrRenderable) const
int maxPreferredRenderTargetSize() const
int internalMultisampleCount(const GrBackendFormat &format) const
virtual GrDirectContext * asDirectContext()
SK_API GrBackendApi backend() const
GrDirectContextPriv priv()
void addAtlasTask(sk_sp< GrRenderTask > atlasTask, GrRenderTask *previousAtlasTask)
GrDrawingManager * drawingManager()
GrRecordingContextPriv priv()
SkISize dimensions() const
static SkMatrix Translate(SkScalar dx, SkScalar dy)
SkMatrix & setAll(SkScalar scaleX, SkScalar skewX, SkScalar transX, SkScalar skewY, SkScalar scaleY, SkScalar transY, SkScalar persp0, SkScalar persp1, SkScalar persp2)
bool hasPerspective() const
bool mapRect(SkRect *dst, const SkRect &src, SkApplyPerspectiveClip pc=SkApplyPerspectiveClip::kYes) const
static bool IsSupported(GrRecordingContext *)
bool onDrawPath(const DrawPathArgs &) override
static sk_sp< AtlasPathRenderer > Make(GrRecordingContext *rContext)
bool preFlush(GrOnFlushResourceProvider *) override
CanDrawPath onCanDrawPath(const CanDrawPathArgs &) const override
GrFPResult makeAtlasClipEffect(const skgpu::ganesh::SurfaceDrawContext *, const GrOp *opBeingClipped, std::unique_ptr< GrFragmentProcessor > inputFP, const SkIRect &drawBounds, const SkMatrix &, const SkPath &)
CanDrawPath canDrawPath(const CanDrawPathArgs &args) const
const GrCaps * caps() const
GrRecordingContext * recordingContext() const
bool canUseDynamicMSAA() const
static bool IsSupported(const GrCaps &)
FlutterSemanticsFlag flags
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
static constexpr int kAtlasInitialSize
static constexpr int kAtlasMaxPathHeightWithMSAAFallback
static constexpr auto kAtlasAlgorithm
static constexpr int kAtlasMaxPathHeight
static constexpr auto kAtlasAlpha8Type
static constexpr int kAtlasMaxPathWidth
SIT bool all(const Vec< 1, T > &x)
SIN Vec< N, float > floor(const Vec< N, float > &x)
SIN Vec< N, float > ceil(const Vec< N, float > &x)
constexpr int32_t top() const
constexpr int32_t height() const
constexpr int32_t width() const
constexpr SkIPoint topLeft() const
int32_t fLeft
smaller x-axis bounds
constexpr int32_t left() const
bool contains(int32_t x, int32_t y) const
int32_t fRight
larger x-axis bounds
constexpr int64_t area() const
SkScalar fLeft
smaller x-axis bounds
SkScalar fRight
larger x-axis bounds
void roundOut(SkIRect *dst) const
static SKVX_ALWAYS_INLINE Vec Load(const void *ptr)