Extract a GrDynamicAtlas base class from GrCCAtlas
Change-Id: I85fd3a3ccc34b5616a75e2c7ddcc33af18809144
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/268723
Commit-Queue: Chris Dalton <csmartdalton@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/gn/gpu.gni b/gn/gpu.gni
index c36c167..6717e5c 100644
--- a/gn/gpu.gni
+++ b/gn/gpu.gni
@@ -89,6 +89,8 @@
"$_src/gpu/GrDrawOpTest.cpp",
"$_src/gpu/GrDrawOpTest.h",
"$_src/gpu/GrDriverBugWorkarounds.cpp",
+ "$_src/gpu/GrDynamicAtlas.cpp",
+ "$_src/gpu/GrDynamicAtlas.h",
"$_src/gpu/GrEagerVertexAllocator.h",
"$_src/gpu/GrFixedClip.cpp",
"$_src/gpu/GrFixedClip.h",
diff --git a/src/gpu/GrDynamicAtlas.cpp b/src/gpu/GrDynamicAtlas.cpp
new file mode 100644
index 0000000..5cd8a5f
--- /dev/null
+++ b/src/gpu/GrDynamicAtlas.cpp
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2020 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "src/gpu/GrDynamicAtlas.h"
+
+#include "src/gpu/GrOnFlushResourceProvider.h"
+#include "src/gpu/GrProxyProvider.h"
+#include "src/gpu/GrRectanizerSkyline.h"
+#include "src/gpu/GrRenderTarget.h"
+#include "src/gpu/GrRenderTargetContext.h"
+
+// Each Node covers a sub-rectangle of the final atlas. When a GrDynamicAtlas runs out of room, we
+// create a new Node the same size as all combined nodes in the atlas as-is, and then place the new
+// Node immediately below or beside the others (thereby doubling the size of the GyDynamicAtlas).
+class GrDynamicAtlas::Node {
+public:
+ Node(std::unique_ptr<Node> previous, int l, int t, int r, int b)
+ : fPrevious(std::move(previous)), fX(l), fY(t), fRectanizer(r - l, b - t) {}
+
+ Node* previous() const { return fPrevious.get(); }
+
+ bool addRect(int w, int h, SkIPoint16* loc) {
+ // Pad all paths except those that are expected to take up an entire physical texture.
+ if (w < fRectanizer.width()) {
+ w = std::min(w + kPadding, fRectanizer.width());
+ }
+ if (h < fRectanizer.height()) {
+ h = std::min(h + kPadding, fRectanizer.height());
+ }
+ if (!fRectanizer.addRect(w, h, loc)) {
+ return false;
+ }
+ loc->fX += fX;
+ loc->fY += fY;
+ return true;
+ }
+
+private:
+ const std::unique_ptr<Node> fPrevious;
+ const int fX, fY;
+ GrRectanizerSkyline fRectanizer;
+};
+
+sk_sp<GrTextureProxy> GrDynamicAtlas::MakeLazyAtlasProxy(
+ const LazyInstantiateAtlasCallback& callback, GrColorType colorType,
+ InternalMultisample internalMultisample, const GrCaps& caps,
+ GrSurfaceProxy::UseAllocator useAllocator) {
+ GrBackendFormat format = caps.getDefaultBackendFormat(colorType, GrRenderable::kYes);
+ int sampleCount = (InternalMultisample::kYes == internalMultisample) ?
+ caps.internalMultisampleCount(format) : 1;
+
+ auto instantiate = [cb = std::move(callback), format, sampleCount](GrResourceProvider* rp) {
+ return cb(rp, format, sampleCount);
+ };
+
+ GrSwizzle readSwizzle = caps.getReadSwizzle(format, colorType);
+
+ sk_sp<GrTextureProxy> proxy = GrProxyProvider::MakeFullyLazyProxy(
+ std::move(instantiate), format, readSwizzle, GrRenderable::kYes, sampleCount,
+ GrProtected::kNo, kTextureOrigin, caps, useAllocator);
+
+ return proxy;
+}
+
+GrDynamicAtlas::GrDynamicAtlas(GrColorType colorType, InternalMultisample internalMultisample,
+ SkISize initialSize, int maxAtlasSize, const GrCaps& caps)
+ : fColorType(colorType)
+ , fInternalMultisample(internalMultisample)
+ , fMaxAtlasSize(maxAtlasSize) {
+ SkASSERT(fMaxAtlasSize <= caps.maxTextureSize());
+ this->reset(initialSize, caps);
+}
+
+GrDynamicAtlas::~GrDynamicAtlas() {
+}
+
+void GrDynamicAtlas::reset(SkISize initialSize, const GrCaps& caps) {
+ fWidth = std::min(SkNextPow2(initialSize.width()), fMaxAtlasSize);
+ fHeight = std::min(SkNextPow2(initialSize.height()), fMaxAtlasSize);
+ fTopNode = nullptr;
+ fDrawBounds.setEmpty();
+ fTextureProxy = MakeLazyAtlasProxy(
+ [this](GrResourceProvider* resourceProvider, const GrBackendFormat& format,
+ int sampleCount) {
+ if (!fBackingTexture) {
+ fBackingTexture = resourceProvider->createTexture(
+ {fWidth, fHeight}, format, GrRenderable::kYes, sampleCount,
+ GrMipMapped::kNo, SkBudgeted::kYes, GrProtected::kNo);
+ }
+ return GrSurfaceProxy::LazyCallbackResult(fBackingTexture);
+ },
+ fColorType, fInternalMultisample, caps, GrSurfaceProxy::UseAllocator::kNo);
+ fBackingTexture = nullptr;
+}
+
+bool GrDynamicAtlas::addRect(const SkIRect& devIBounds, SkIVector* offset) {
+ // This can't be called anymore once instantiate() has been called.
+ SkASSERT(!this->isInstantiated());
+
+ SkIPoint16 location;
+ if (!this->internalPlaceRect(devIBounds.width(), devIBounds.height(), &location)) {
+ return false;
+ }
+ offset->set(location.x() - devIBounds.left(), location.y() - devIBounds.top());
+
+ fDrawBounds.fWidth = std::max(fDrawBounds.width(), location.x() + devIBounds.width());
+ fDrawBounds.fHeight = std::max(fDrawBounds.height(), location.y() + devIBounds.height());
+ return true;
+}
+
+bool GrDynamicAtlas::internalPlaceRect(int w, int h, SkIPoint16* loc) {
+ if (std::max(h, w) > fMaxAtlasSize) {
+ return false;
+ }
+ if (std::min(h, w) <= 0) {
+ loc->set(0, 0);
+ return true;
+ }
+
+ if (!fTopNode) {
+ if (w > fWidth) {
+ fWidth = std::min(SkNextPow2(w), fMaxAtlasSize);
+ }
+ if (h > fHeight) {
+ fHeight = std::min(SkNextPow2(h), fMaxAtlasSize);
+ }
+ fTopNode = std::make_unique<Node>(nullptr, 0, 0, fWidth, fHeight);
+ }
+
+ for (Node* node = fTopNode.get(); node; node = node->previous()) {
+ if (node->addRect(w, h, loc)) {
+ return true;
+ }
+ }
+
+ // The rect didn't fit. Grow the atlas and try again.
+ do {
+ if (fWidth >= fMaxAtlasSize && fHeight >= fMaxAtlasSize) {
+ return false;
+ }
+ if (fHeight <= fWidth) {
+ int top = fHeight;
+ fHeight = std::min(fHeight * 2, fMaxAtlasSize);
+ fTopNode = std::make_unique<Node>(std::move(fTopNode), 0, top, fWidth, fHeight);
+ } else {
+ int left = fWidth;
+ fWidth = std::min(fWidth * 2, fMaxAtlasSize);
+ fTopNode = std::make_unique<Node>(std::move(fTopNode), left, 0, fWidth, fHeight);
+ }
+ } while (!fTopNode->addRect(w, h, loc));
+
+ return true;
+}
+
+std::unique_ptr<GrRenderTargetContext> GrDynamicAtlas::instantiate(
+ GrOnFlushResourceProvider* onFlushRP, sk_sp<GrTexture> backingTexture) {
+ SkASSERT(!this->isInstantiated()); // This method should only be called once.
+ // Caller should have cropped any paths to the destination render target instead of asking for
+ // an atlas larger than maxRenderTargetSize.
+ SkASSERT(std::max(fHeight, fWidth) <= fMaxAtlasSize);
+ SkASSERT(fMaxAtlasSize <= onFlushRP->caps()->maxRenderTargetSize());
+
+ // Finalize the content size of our proxy. The GPU can potentially make optimizations if it
+ // knows we only intend to write out a smaller sub-rectangle of the backing texture.
+ fTextureProxy->priv().setLazyDimensions(fDrawBounds);
+
+ if (backingTexture) {
+#ifdef SK_DEBUG
+ auto backingRT = backingTexture->asRenderTarget();
+ SkASSERT(backingRT);
+ SkASSERT(backingRT->backendFormat() == fTextureProxy->backendFormat());
+ SkASSERT(backingRT->numSamples() == fTextureProxy->asRenderTargetProxy()->numSamples());
+ SkASSERT(backingRT->width() == fWidth);
+ SkASSERT(backingRT->height() == fHeight);
+#endif
+ fBackingTexture = std::move(backingTexture);
+ }
+ auto rtc = onFlushRP->makeRenderTargetContext(fTextureProxy, fColorType, nullptr, nullptr);
+ if (!rtc) {
+#if GR_TEST_UTILS
+ if (!onFlushRP->testingOnly_getSuppressAllocationWarnings())
+#endif
+ {
+ SkDebugf("WARNING: failed to allocate a %ix%i atlas. Some masks will not be drawn.\n",
+ fWidth, fHeight);
+ }
+ return nullptr;
+ }
+
+ SkIRect clearRect = SkIRect::MakeSize(fDrawBounds);
+ rtc->clear(&clearRect, SK_PMColor4fTRANSPARENT,
+ GrRenderTargetContext::CanClearFullscreen::kYes);
+ return rtc;
+}
diff --git a/src/gpu/GrDynamicAtlas.h b/src/gpu/GrDynamicAtlas.h
new file mode 100644
index 0000000..b37cbc1
--- /dev/null
+++ b/src/gpu/GrDynamicAtlas.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2020 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrDynamicAtlas_DEFINED
+#define GrDynamicAtlas_DEFINED
+
+#include "src/gpu/GrAllocator.h"
+#include "src/gpu/GrTextureProxy.h"
+
+class GrOnFlushResourceProvider;
+class GrRenderTargetContext;
+class GrResourceProvider;
+struct SkIPoint16;
+struct SkIRect;
+
+/**
+ * This class implements a dynamic size GrRectanizer that grows until it reaches the implementation-
+ * dependent max texture size. When finalized, it also creates and stores a GrTextureProxy for the
+ * underlying atlas.
+ */
+class GrDynamicAtlas {
+public:
+ // As long as GrSurfaceOrigin exists, we just have to decide on one for the atlas texture.
+ static constexpr GrSurfaceOrigin kTextureOrigin = kTopLeft_GrSurfaceOrigin;
+ static constexpr int kPadding = 1; // Amount of padding below and to the right of each path.
+
+ using LazyInstantiateAtlasCallback = std::function<GrSurfaceProxy::LazyCallbackResult(
+ GrResourceProvider*, const GrBackendFormat&, int sampleCount)>;
+
+ enum class InternalMultisample : bool {
+ kNo = false,
+ kYes = true
+ };
+
+ static sk_sp<GrTextureProxy> MakeLazyAtlasProxy(const LazyInstantiateAtlasCallback&,
+ GrColorType colorType, InternalMultisample,
+ const GrCaps&, GrSurfaceProxy::UseAllocator);
+
+ GrDynamicAtlas(GrColorType colorType, InternalMultisample, SkISize initialSize,
+ int maxAtlasSize, const GrCaps&);
+ virtual ~GrDynamicAtlas();
+
+ void reset(SkISize initialSize, const GrCaps& caps);
+
+ GrTextureProxy* textureProxy() const { return fTextureProxy.get(); }
+ bool isInstantiated() const { return fTextureProxy->isInstantiated(); }
+ int currentWidth() const { return fWidth; }
+ int currentHeight() const { return fHeight; }
+
+ // Attempts to add a rect to the atlas. If successful, returns the integer offset from
+ // device-space pixels where the path will be drawn, to atlas pixels where its mask resides.
+ bool addRect(const SkIRect& devIBounds, SkIVector* atlasOffset);
+ const SkISize& drawBounds() { return fDrawBounds; }
+
+ // Instantiates our texture proxy for the atlas and returns a pre-cleared GrRenderTargetContext
+ // that the caller may use to render the content. After this call, it is no longer valid to call
+ // addRect(), setUserBatchID(), or this method again.
+ //
+ // 'backingTexture', if provided, is a renderable texture with which to instantiate our proxy.
+ // If null then we will create a texture using the resource provider. The purpose of this param
+ // is to provide a guaranteed way to recycle a stashed atlas texture from a previous flush.
+ std::unique_ptr<GrRenderTargetContext> instantiate(
+ GrOnFlushResourceProvider*, sk_sp<GrTexture> backingTexture = nullptr);
+
+private:
+ class Node;
+
+ bool internalPlaceRect(int w, int h, SkIPoint16* loc);
+
+ const GrColorType fColorType;
+ const InternalMultisample fInternalMultisample;
+ const int fMaxAtlasSize;
+ int fWidth;
+ int fHeight;
+ std::unique_ptr<Node> fTopNode;
+ SkISize fDrawBounds;
+
+ sk_sp<GrTextureProxy> fTextureProxy;
+ sk_sp<GrTexture> fBackingTexture;
+};
+
+#endif
diff --git a/src/gpu/GrRectanizerSkyline.h b/src/gpu/GrRectanizerSkyline.h
index 638d893..36af34d 100644
--- a/src/gpu/GrRectanizerSkyline.h
+++ b/src/gpu/GrRectanizerSkyline.h
@@ -49,10 +49,10 @@
// at x,y.
void addSkylineLevel(int skylineIndex, int x, int y, int width, int height);
+ const int fWidth;
+ const int fHeight;
SkTDArray<SkylineSegment> fSkyline;
int32_t fAreaSoFar;
- int fWidth;
- int fHeight;
};
#endif // GrRectanizerSkyline_DEFINED
diff --git a/src/gpu/ccpr/GrCCAtlas.cpp b/src/gpu/ccpr/GrCCAtlas.cpp
index 82f89a6..a980f68 100644
--- a/src/gpu/ccpr/GrCCAtlas.cpp
+++ b/src/gpu/ccpr/GrCCAtlas.cpp
@@ -7,181 +7,53 @@
#include "src/gpu/ccpr/GrCCAtlas.h"
-#include "include/gpu/GrTexture.h"
-#include "src/core/SkIPoint16.h"
-#include "src/core/SkMathPriv.h"
-#include "src/gpu/GrCaps.h"
#include "src/gpu/GrOnFlushResourceProvider.h"
-#include "src/gpu/GrProxyProvider.h"
-#include "src/gpu/GrRectanizerSkyline.h"
-#include "src/gpu/GrRenderTarget.h"
-#include "src/gpu/GrRenderTargetContext.h"
-#include "src/gpu/GrTextureProxy.h"
#include "src/gpu/ccpr/GrCCPathCache.h"
-#include <atomic>
-class GrCCAtlas::Node {
-public:
- Node(std::unique_ptr<Node> previous, int l, int t, int r, int b)
- : fPrevious(std::move(previous)), fX(l), fY(t), fRectanizer(r - l, b - t) {}
-
- Node* previous() const { return fPrevious.get(); }
-
- bool addRect(int w, int h, SkIPoint16* loc, int maxAtlasSize) {
- // Pad all paths except those that are expected to take up an entire physical texture.
- if (w < maxAtlasSize) {
- w = std::min(w + kPadding, maxAtlasSize);
- }
- if (h < maxAtlasSize) {
- h = std::min(h + kPadding, maxAtlasSize);
- }
- if (!fRectanizer.addRect(w, h, loc)) {
- return false;
- }
- loc->fX += fX;
- loc->fY += fY;
- return true;
- }
-
-private:
- const std::unique_ptr<Node> fPrevious;
- const int fX, fY;
- GrRectanizerSkyline fRectanizer;
-};
-
-sk_sp<GrTextureProxy> GrCCAtlas::MakeLazyAtlasProxy(const LazyInstantiateAtlasCallback& callback,
- CoverageType coverageType,
- const GrCaps& caps,
- GrSurfaceProxy::UseAllocator useAllocator) {
- int sampleCount;
-
- auto colorType = CoverageTypeToColorType(coverageType);
- GrBackendFormat format = caps.getDefaultBackendFormat(colorType, GrRenderable::kYes);
- switch (coverageType) {
- case CoverageType::kFP16_CoverageCount:
- sampleCount = 1;
- break;
- case CoverageType::kA8_Multisample:
- SkASSERT(caps.internalMultisampleCount(format) > 1);
- sampleCount = (caps.mixedSamplesSupport()) ? 1 : caps.internalMultisampleCount(format);
- break;
- case CoverageType::kA8_LiteralCoverage:
- sampleCount = 1;
- break;
- }
-
- auto instantiate = [cb = std::move(callback), format, sampleCount](GrResourceProvider* rp) {
- return cb(rp, format, sampleCount);
- };
-
- GrSwizzle readSwizzle = caps.getReadSwizzle(format, colorType);
-
- sk_sp<GrTextureProxy> proxy = GrProxyProvider::MakeFullyLazyProxy(
- std::move(instantiate), format, readSwizzle, GrRenderable::kYes, sampleCount,
- GrProtected::kNo, kTextureOrigin, caps, useAllocator);
-
- return proxy;
-}
-
-GrCCAtlas::GrCCAtlas(CoverageType coverageType, const Specs& specs, const GrCaps& caps)
- : fCoverageType(coverageType)
- , fMaxTextureSize(std::max(std::max(specs.fMinHeight, specs.fMinWidth),
- specs.fMaxPreferredTextureSize)) {
- // Caller should have cropped any paths to the destination render target instead of asking for
- // an atlas larger than maxRenderTargetSize.
- SkASSERT(fMaxTextureSize <= caps.maxTextureSize());
- SkASSERT(specs.fMaxPreferredTextureSize > 0);
-
+static SkISize choose_initial_atlas_size(const GrCCAtlas::Specs& specs) {
// Begin with the first pow2 dimensions whose area is theoretically large enough to contain the
// pending paths, favoring height over width if necessary.
int log2area = SkNextLog2(std::max(specs.fApproxNumPixels, 1));
- fHeight = 1 << ((log2area + 1) / 2);
- fWidth = 1 << (log2area / 2);
+ int height = 1 << ((log2area + 1) / 2);
+ int width = 1 << (log2area / 2);
- fWidth = SkTPin(fWidth, specs.fMinTextureSize, specs.fMaxPreferredTextureSize);
- fHeight = SkTPin(fHeight, specs.fMinTextureSize, specs.fMaxPreferredTextureSize);
+ width = SkTPin(width, specs.fMinTextureSize, specs.fMaxPreferredTextureSize);
+ height = SkTPin(height, specs.fMinTextureSize, specs.fMaxPreferredTextureSize);
- if (fWidth < specs.fMinWidth || fHeight < specs.fMinHeight) {
- // They want to stuff a particularly large path into the atlas. Just punt and go with their
- // min width and height. The atlas will grow as needed.
- fWidth = std::min(specs.fMinWidth + kPadding, fMaxTextureSize);
- fHeight = std::min(specs.fMinHeight + kPadding, fMaxTextureSize);
- }
+ return SkISize::Make(width, height);
+}
- fTopNode = std::make_unique<Node>(nullptr, 0, 0, fWidth, fHeight);
+static int choose_max_atlas_size(const GrCCAtlas::Specs& specs, const GrCaps& caps) {
+ return (std::max(specs.fMinHeight, specs.fMinWidth) <= specs.fMaxPreferredTextureSize) ?
+ specs.fMaxPreferredTextureSize : caps.maxRenderTargetSize();
+}
- fTextureProxy = MakeLazyAtlasProxy(
- [this](GrResourceProvider* resourceProvider,const GrBackendFormat& format,
- int sampleCount) {
- if (!fBackingTexture) {
- fBackingTexture = resourceProvider->createTexture(
- {fWidth, fHeight}, format, GrRenderable::kYes, sampleCount,
- GrMipMapped::kNo, SkBudgeted::kYes, GrProtected::kNo);
- }
- return GrSurfaceProxy::LazyCallbackResult(fBackingTexture);
- },
- fCoverageType, caps, GrSurfaceProxy::UseAllocator::kNo);
+GrCCAtlas::GrCCAtlas(CoverageType coverageType, const Specs& specs, const GrCaps& caps)
+ : GrDynamicAtlas(CoverageTypeToColorType(coverageType),
+ CoverageTypeHasInternalMultisample(coverageType),
+ choose_initial_atlas_size(specs), choose_max_atlas_size(specs, caps), caps)
+ , fCoverageType(coverageType) {
+ SkASSERT(specs.fMaxPreferredTextureSize > 0);
}
GrCCAtlas::~GrCCAtlas() {
}
-bool GrCCAtlas::addRect(const SkIRect& devIBounds, SkIVector* offset) {
- // This can't be called anymore once makeRenderTargetContext() has been called.
- SkASSERT(!fTextureProxy->isInstantiated());
-
- SkIPoint16 location;
- if (!this->internalPlaceRect(devIBounds.width(), devIBounds.height(), &location)) {
- return false;
- }
- offset->set(location.x() - devIBounds.left(), location.y() - devIBounds.top());
-
- fDrawBounds.fWidth = std::max(fDrawBounds.width(), location.x() + devIBounds.width());
- fDrawBounds.fHeight = std::max(fDrawBounds.height(), location.y() + devIBounds.height());
- return true;
-}
-
-bool GrCCAtlas::internalPlaceRect(int w, int h, SkIPoint16* loc) {
- for (Node* node = fTopNode.get(); node; node = node->previous()) {
- if (node->addRect(w, h, loc, fMaxTextureSize)) {
- return true;
- }
- }
-
- // The rect didn't fit. Grow the atlas and try again.
- do {
- if (fWidth == fMaxTextureSize && fHeight == fMaxTextureSize) {
- return false;
- }
- if (fHeight <= fWidth) {
- int top = fHeight;
- fHeight = std::min(fHeight * 2, fMaxTextureSize);
- fTopNode = std::make_unique<Node>(std::move(fTopNode), 0, top, fWidth, fHeight);
- } else {
- int left = fWidth;
- fWidth = std::min(fWidth * 2, fMaxTextureSize);
- fTopNode = std::make_unique<Node>(std::move(fTopNode), left, 0, fWidth, fHeight);
- }
- } while (!fTopNode->addRect(w, h, loc, fMaxTextureSize));
-
- return true;
-}
-
void GrCCAtlas::setFillBatchID(int id) {
// This can't be called anymore once makeRenderTargetContext() has been called.
- SkASSERT(!fTextureProxy->isInstantiated());
+ SkASSERT(!this->isInstantiated());
fFillBatchID = id;
}
void GrCCAtlas::setStrokeBatchID(int id) {
// This can't be called anymore once makeRenderTargetContext() has been called.
- SkASSERT(!fTextureProxy->isInstantiated());
+ SkASSERT(!this->isInstantiated());
fStrokeBatchID = id;
}
void GrCCAtlas::setEndStencilResolveInstance(int idx) {
// This can't be called anymore once makeRenderTargetContext() has been called.
- SkASSERT(!fTextureProxy->isInstantiated());
+ SkASSERT(!this->isInstantiated());
fEndStencilResolveInstance = idx;
}
@@ -199,59 +71,17 @@
builder[0] = next_atlas_unique_id();
builder.finish();
- onFlushRP->assignUniqueKeyToProxy(atlasUniqueKey, fTextureProxy.get());
+ onFlushRP->assignUniqueKeyToProxy(atlasUniqueKey, this->textureProxy());
- fCachedAtlas = sk_make_sp<GrCCCachedAtlas>(fCoverageType, atlasUniqueKey, fTextureProxy);
+ fCachedAtlas = sk_make_sp<GrCCCachedAtlas>(fCoverageType, atlasUniqueKey,
+ sk_ref_sp(this->textureProxy()));
}
SkASSERT(fCachedAtlas->coverageType() == fCoverageType);
- SkASSERT(fCachedAtlas->getOnFlushProxy() == fTextureProxy.get());
+ SkASSERT(fCachedAtlas->getOnFlushProxy() == this->textureProxy());
return fCachedAtlas;
}
-std::unique_ptr<GrRenderTargetContext> GrCCAtlas::makeRenderTargetContext(
- GrOnFlushResourceProvider* onFlushRP, sk_sp<GrTexture> backingTexture) {
- SkASSERT(!fTextureProxy->isInstantiated()); // This method should only be called once.
- // Caller should have cropped any paths to the destination render target instead of asking for
- // an atlas larger than maxRenderTargetSize.
- SkASSERT(std::max(fHeight, fWidth) <= fMaxTextureSize);
- SkASSERT(fMaxTextureSize <= onFlushRP->caps()->maxRenderTargetSize());
-
- // Finalize the content size of our proxy. The GPU can potentially make optimizations if it
- // knows we only intend to write out a smaller sub-rectangle of the backing texture.
- fTextureProxy->priv().setLazyDimensions(fDrawBounds);
-
- if (backingTexture) {
-#ifdef SK_DEBUG
- auto backingRT = backingTexture->asRenderTarget();
- SkASSERT(backingRT);
- SkASSERT(backingRT->backendFormat() == fTextureProxy->backendFormat());
- SkASSERT(backingRT->numSamples() == fTextureProxy->asRenderTargetProxy()->numSamples());
- SkASSERT(backingRT->width() == fWidth);
- SkASSERT(backingRT->height() == fHeight);
-#endif
- fBackingTexture = std::move(backingTexture);
- }
- auto colorType = (CoverageType::kFP16_CoverageCount == fCoverageType)
- ? GrColorType::kAlpha_F16 : GrColorType::kAlpha_8;
- auto rtc = onFlushRP->makeRenderTargetContext(fTextureProxy, colorType, nullptr, nullptr);
- if (!rtc) {
-#if GR_TEST_UTILS
- if (!onFlushRP->testingOnly_getSuppressAllocationWarnings())
-#endif
- {
- SkDebugf("WARNING: failed to allocate a %ix%i atlas. Some paths will not be drawn.\n",
- fWidth, fHeight);
- }
- return nullptr;
- }
-
- SkIRect clearRect = SkIRect::MakeSize(fDrawBounds);
- rtc->clear(&clearRect, SK_PMColor4fTRANSPARENT,
- GrRenderTargetContext::CanClearFullscreen::kYes);
- return rtc;
-}
-
GrCCAtlas* GrCCAtlasStack::addRect(const SkIRect& devIBounds, SkIVector* devToAtlasOffset) {
GrCCAtlas* retiredAtlas = nullptr;
if (fAtlases.empty() || !fAtlases.back().addRect(devIBounds, devToAtlasOffset)) {
diff --git a/src/gpu/ccpr/GrCCAtlas.h b/src/gpu/ccpr/GrCCAtlas.h
index 06909ae..9a1b9f5 100644
--- a/src/gpu/ccpr/GrCCAtlas.h
+++ b/src/gpu/ccpr/GrCCAtlas.h
@@ -8,33 +8,17 @@
#ifndef GrCCAtlas_DEFINED
#define GrCCAtlas_DEFINED
-#include "include/core/SkRefCnt.h"
-#include "include/core/SkSize.h"
-#include "include/gpu/GrTexture.h"
-#include "include/private/GrResourceKey.h"
-#include "src/gpu/GrAllocator.h"
-#include "src/gpu/GrNonAtomicRef.h"
-#include "src/gpu/GrSurfaceProxy.h"
+#include "src/gpu/GrDynamicAtlas.h"
+
+#include "src/gpu/ccpr/GrCCPathProcessor.h"
class GrCCCachedAtlas;
-class GrOnFlushResourceProvider;
-class GrRenderTargetContext;
-class GrResourceProvider;
-class GrTextureProxy;
-struct SkIPoint16;
-struct SkIRect;
/**
- * This class implements a dynamic size GrRectanizer that grows until it reaches the implementation-
- * dependent max texture size. When finalized, it also creates and stores a GrTextureProxy for the
- * underlying atlas.
+ * GrDynamicAtlas with CCPR caching capabilities.
*/
-class GrCCAtlas {
+class GrCCAtlas : public GrDynamicAtlas {
public:
- // As long as GrSurfaceOrigin exists, we just have to decide on one for the atlas texture.
- static constexpr GrSurfaceOrigin kTextureOrigin = kTopLeft_GrSurfaceOrigin;
- static constexpr int kPadding = 1; // Amount of padding below and to the right of each path.
-
// This struct encapsulates the minimum and desired requirements for an atlas, as well as an
// approximate number of pixels to help select a good initial size.
struct Specs {
@@ -65,25 +49,36 @@
SkUNREACHABLE;
}
- using LazyInstantiateAtlasCallback = std::function<GrSurfaceProxy::LazyCallbackResult(
- GrResourceProvider*, const GrBackendFormat&, int sampleCount)>;
+ static constexpr InternalMultisample CoverageTypeHasInternalMultisample(
+ CoverageType coverageType) {
+ switch (coverageType) {
+ case CoverageType::kFP16_CoverageCount:
+ case CoverageType::kA8_LiteralCoverage:
+ return InternalMultisample::kNo;
+ case CoverageType::kA8_Multisample:
+ return InternalMultisample::kYes;
+ }
+ SkUNREACHABLE;
+ }
- static sk_sp<GrTextureProxy> MakeLazyAtlasProxy(const LazyInstantiateAtlasCallback&,
- CoverageType,
- const GrCaps&,
- GrSurfaceProxy::UseAllocator);
+ static constexpr GrCCPathProcessor::CoverageMode CoverageTypeToPathCoverageMode(
+ CoverageType coverageType) {
+ return (GrCCAtlas::CoverageType::kFP16_CoverageCount == coverageType)
+ ? GrCCPathProcessor::CoverageMode::kCoverageCount
+ : GrCCPathProcessor::CoverageMode::kLiteral;
+ }
+
+
+ static sk_sp<GrTextureProxy> MakeLazyAtlasProxy(const LazyInstantiateAtlasCallback& callback,
+ CoverageType coverageType, const GrCaps& caps,
+ GrSurfaceProxy::UseAllocator useAllocator) {
+ return GrDynamicAtlas::MakeLazyAtlasProxy(callback, CoverageTypeToColorType(coverageType),
+ CoverageTypeHasInternalMultisample(coverageType),
+ caps, useAllocator);
+ }
GrCCAtlas(CoverageType, const Specs&, const GrCaps&);
- ~GrCCAtlas();
-
- GrTextureProxy* textureProxy() const { return fTextureProxy.get(); }
- int currentWidth() const { return fWidth; }
- int currentHeight() const { return fHeight; }
-
- // Attempts to add a rect to the atlas. If successful, returns the integer offset from
- // device-space pixels where the path will be drawn, to atlas pixels where its mask resides.
- bool addRect(const SkIRect& devIBounds, SkIVector* atlasOffset);
- const SkISize& drawBounds() { return fDrawBounds; }
+ ~GrCCAtlas() override;
// This is an optional space for the caller to jot down user-defined instance data to use when
// rendering atlas content.
@@ -96,34 +91,12 @@
sk_sp<GrCCCachedAtlas> refOrMakeCachedAtlas(GrOnFlushResourceProvider*);
- // Instantiates our texture proxy for the atlas and returns a pre-cleared GrRenderTargetContext
- // that the caller may use to render the content. After this call, it is no longer valid to call
- // addRect(), setUserBatchID(), or this method again.
- //
- // 'backingTexture', if provided, is a renderable texture with which to instantiate our proxy.
- // If null then we will create a texture using the resource provider. The purpose of this param
- // is to provide a guaranteed way to recycle a stashed atlas texture from a previous flush.
- std::unique_ptr<GrRenderTargetContext> makeRenderTargetContext(
- GrOnFlushResourceProvider*, sk_sp<GrTexture> backingTexture = nullptr);
-
private:
- class Node;
-
- bool internalPlaceRect(int w, int h, SkIPoint16* loc);
-
const CoverageType fCoverageType;
- const int fMaxTextureSize;
- int fWidth, fHeight;
- std::unique_ptr<Node> fTopNode;
- SkISize fDrawBounds = {0, 0};
-
int fFillBatchID;
int fStrokeBatchID;
int fEndStencilResolveInstance;
-
sk_sp<GrCCCachedAtlas> fCachedAtlas;
- sk_sp<GrTextureProxy> fTextureProxy;
- sk_sp<GrTexture> fBackingTexture;
};
/**
diff --git a/src/gpu/ccpr/GrCCDrawPathsOp.cpp b/src/gpu/ccpr/GrCCDrawPathsOp.cpp
index 4dbe087..3ce17ae 100644
--- a/src/gpu/ccpr/GrCCDrawPathsOp.cpp
+++ b/src/gpu/ccpr/GrCCDrawPathsOp.cpp
@@ -358,7 +358,7 @@
== fCacheEntry->cachedAtlas()->coverageType())
? SkPMColor4f{0,0,.25,.25} : SkPMColor4f{0,.25,0,.25};
#endif
- auto coverageMode = GrCCPathProcessor::GetCoverageMode(
+ auto coverageMode = GrCCAtlas::CoverageTypeToPathCoverageMode(
fCacheEntry->cachedAtlas()->coverageType());
op->recordInstance(coverageMode, fCacheEntry->cachedAtlas()->getOnFlushProxy(),
resources->nextPathInstanceIdx());
@@ -386,7 +386,7 @@
if (auto atlas = resources->renderShapeInAtlas(
fMaskDevIBounds, fMatrix, fShape, fStrokeDevWidth, &octoBounds, &devIBounds,
&devToAtlasOffset)) {
- auto coverageMode = GrCCPathProcessor::GetCoverageMode(
+ auto coverageMode = GrCCAtlas::CoverageTypeToPathCoverageMode(
resources->renderedPathCoverageType());
op->recordInstance(coverageMode, atlas->textureProxy(), resources->nextPathInstanceIdx());
resources->appendDrawPathInstance().set(
diff --git a/src/gpu/ccpr/GrCCPathProcessor.h b/src/gpu/ccpr/GrCCPathProcessor.h
index 3f13647..5273607 100644
--- a/src/gpu/ccpr/GrCCPathProcessor.h
+++ b/src/gpu/ccpr/GrCCPathProcessor.h
@@ -13,7 +13,6 @@
#include "src/gpu/GrCaps.h"
#include "src/gpu/GrGeometryProcessor.h"
#include "src/gpu/GrPipeline.h"
-#include "src/gpu/ccpr/GrCCAtlas.h"
#include "src/gpu/ccpr/GrOctoBounds.h"
class GrCCPathCacheEntry;
@@ -54,16 +53,9 @@
kLiteral
};
- static CoverageMode GetCoverageMode(GrCCAtlas::CoverageType coverageType) {
- return (GrCCAtlas::CoverageType::kFP16_CoverageCount == coverageType)
- ? CoverageMode::kCoverageCount
- : CoverageMode::kLiteral;
- }
-
- GrCCPathProcessor(
- CoverageMode, const GrTexture* atlasTexture, const GrSwizzle&,
- GrSurfaceOrigin atlasOrigin,
- const SkMatrix& viewMatrixIfUsingLocalCoords = SkMatrix::I());
+ GrCCPathProcessor(CoverageMode, const GrTexture* atlasTexture, const GrSwizzle&,
+ GrSurfaceOrigin atlasOrigin,
+ const SkMatrix& viewMatrixIfUsingLocalCoords = SkMatrix::I());
const char* name() const override { return "GrCCPathProcessor"; }
void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {
diff --git a/src/gpu/ccpr/GrCCPerFlushResources.cpp b/src/gpu/ccpr/GrCCPerFlushResources.cpp
index bc3e8ac..a7ebf66 100644
--- a/src/gpu/ccpr/GrCCPerFlushResources.cpp
+++ b/src/gpu/ccpr/GrCCPerFlushResources.cpp
@@ -85,7 +85,7 @@
GrSurfaceProxy* srcProxy = fSrcProxy.get();
SkASSERT(srcProxy->isInstantiated());
- auto coverageMode = GrCCPathProcessor::GetCoverageMode(
+ auto coverageMode = GrCCAtlas::CoverageTypeToPathCoverageMode(
fResources->renderedPathCoverageType());
GrCCPathProcessor pathProc(coverageMode, srcProxy->peekTexture(),
srcProxy->textureSwizzle(), srcProxy->origin());
@@ -533,7 +533,7 @@
int endCopyRange = atlas->getFillBatchID();
SkASSERT(endCopyRange > copyRangeIdx);
- auto rtc = atlas->makeRenderTargetContext(onFlushRP);
+ auto rtc = atlas->instantiate(onFlushRP);
for (; copyRangeIdx < endCopyRange; ++copyRangeIdx) {
const CopyPathRange& copyRange = fCopyPathRanges[copyRangeIdx];
int endCopyInstance = baseCopyInstance + copyRange.fCount;
@@ -564,7 +564,7 @@
}
}
- if (auto rtc = atlas->makeRenderTargetContext(onFlushRP, std::move(backingTexture))) {
+ if (auto rtc = atlas->instantiate(onFlushRP, std::move(backingTexture))) {
std::unique_ptr<GrDrawOp> op;
if (CoverageType::kA8_Multisample == fRenderedAtlasStack.coverageType()) {
op = GrStencilAtlasOp::Make(