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();
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;
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) {
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()),
292bool AtlasPathRenderer::onDrawPath(
const DrawPathArgs&
args) {
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,
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();
SkAssertResult(font.textToGlyphs("Hello", 5, SkTextEncoding::kUTF8, glyphs, std::size(glyphs))==count)
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)
static int SkPrevPow2(int value)
static int SkNextPow2(int value)
sk_sp< T > sk_ref_sp(T *obj)
void swap(sk_sp< T > &a, sk_sp< T > &b)
SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID()
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()
SkSpan< GrRenderTask * > dependents()
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 *)
static sk_sp< AtlasPathRenderer > Make(GrRecordingContext *rContext)
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
static float min(float r, float g, float b)
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
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
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 to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not set
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)