aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/ccpr/GrCCPRAtlas.cpp
diff options
context:
space:
mode:
authorGravatar Chris Dalton <csmartdalton@google.com>2017-07-14 15:17:41 -0600
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-07-14 21:45:35 +0000
commit1a325d25b941ef801b3e9b2c0342da43cf35cdba (patch)
tree3f65d36541399e1ae6a529a534119815a2c5ba36 /src/gpu/ccpr/GrCCPRAtlas.cpp
parent588fb040b3ad410cdb10c87f9a7884b6eb825e90 (diff)
Coverage counting path renderer
Initial implementation of a GPU path renderer that draws antialiased paths by counting coverage in an offscreen buffer. Initially disabled until it has had time to soak. Bug: skia: Change-Id: I003d8cfdf8dc62641581b5ea2dc4f0aa00108df6 Reviewed-on: https://skia-review.googlesource.com/21541 Commit-Queue: Chris Dalton <csmartdalton@google.com> Reviewed-by: Greg Daniel <egdaniel@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Robert Phillips <robertphillips@google.com>
Diffstat (limited to 'src/gpu/ccpr/GrCCPRAtlas.cpp')
-rw-r--r--src/gpu/ccpr/GrCCPRAtlas.cpp125
1 files changed, 125 insertions, 0 deletions
diff --git a/src/gpu/ccpr/GrCCPRAtlas.cpp b/src/gpu/ccpr/GrCCPRAtlas.cpp
new file mode 100644
index 0000000000..8eb3086945
--- /dev/null
+++ b/src/gpu/ccpr/GrCCPRAtlas.cpp
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrCCPRAtlas.h"
+
+#include "GrOnFlushResourceProvider.h"
+#include "GrClip.h"
+#include "GrRectanizer_skyline.h"
+#include "GrTextureProxy.h"
+#include "GrRenderTargetContext.h"
+#include "SkMakeUnique.h"
+#include "SkMathPriv.h"
+#include "ccpr/GrCCPRCoverageProcessor.h"
+#include "ops/GrDrawOp.h"
+
+class GrCCPRAtlas::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) {
+ static constexpr int kPad = 1;
+
+ if (!fRectanizer.addRect(w + kPad, h + kPad, loc)) {
+ return false;
+ }
+ loc->fX += fX;
+ loc->fY += fY;
+ return true;
+ }
+
+private:
+ const std::unique_ptr<Node> fPrevious;
+ const int fX, fY;
+ GrRectanizerSkyline fRectanizer;
+};
+
+GrCCPRAtlas::GrCCPRAtlas(const GrCaps& caps, int minWidth, int minHeight)
+ : fMaxAtlasSize(caps.maxRenderTargetSize())
+ , fDrawBounds{0, 0} {
+ SkASSERT(fMaxAtlasSize <= caps.maxTextureSize());
+ SkASSERT(SkTMax(minWidth, minHeight) <= fMaxAtlasSize);
+ int initialSize = GrNextPow2(SkTMax(minWidth, minHeight));
+ initialSize = SkTMax(int(kMinSize), initialSize);
+ initialSize = SkTMin(initialSize, fMaxAtlasSize);
+ fHeight = fWidth = initialSize;
+ fTopNode = skstd::make_unique<Node>(nullptr, 0, 0, initialSize, initialSize);
+}
+
+GrCCPRAtlas::~GrCCPRAtlas() {
+}
+
+bool GrCCPRAtlas::addRect(int w, int h, SkIPoint16* loc) {
+ // This can't be called anymore once finalize() has been called.
+ SkASSERT(!fTextureProxy);
+
+ if (!this->internalPlaceRect(w, h, loc)) {
+ return false;
+ }
+
+ fDrawBounds.fWidth = SkTMax(fDrawBounds.width(), loc->x() + w);
+ fDrawBounds.fHeight = SkTMax(fDrawBounds.height(), loc->y() + h);
+ return true;
+}
+
+bool GrCCPRAtlas::internalPlaceRect(int w, int h, SkIPoint16* loc) {
+ SkASSERT(SkTMax(w, h) < fMaxAtlasSize);
+
+ 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 {
+ SkASSERT(SkTMax(fWidth, fHeight) <= fMaxAtlasSize);
+ if (fWidth == fMaxAtlasSize && fHeight == fMaxAtlasSize) {
+ return false;
+ }
+ if (fHeight <= fWidth) {
+ int top = fHeight;
+ fHeight = SkTMin(fHeight * 2, fMaxAtlasSize);
+ fTopNode = skstd::make_unique<Node>(std::move(fTopNode), 0, top, fWidth, fHeight);
+ } else {
+ int left = fWidth;
+ fWidth = SkTMin(fWidth * 2, fMaxAtlasSize);
+ fTopNode = skstd::make_unique<Node>(std::move(fTopNode), left, 0, fWidth, fHeight);
+ }
+ } while (!fTopNode->addRect(w, h, loc));
+
+ return true;
+}
+
+sk_sp<GrRenderTargetContext> GrCCPRAtlas::finalize(GrOnFlushResourceProvider* onFlushRP,
+ std::unique_ptr<GrDrawOp> atlasOp) {
+ SkASSERT(!fTextureProxy);
+
+ GrSurfaceDesc desc;
+ desc.fOrigin = GrCCPRCoverageProcessor::kAtlasOrigin;
+ desc.fWidth = fWidth;
+ desc.fHeight = fHeight;
+ desc.fConfig = kAlpha_half_GrPixelConfig;
+ sk_sp<GrRenderTargetContext> rtc = onFlushRP->makeRenderTargetContext(desc, nullptr, nullptr);
+ if (!rtc) {
+ 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, 0, true);
+ rtc->addDrawOp(GrNoClip(), std::move(atlasOp));
+
+ fTextureProxy = sk_ref_sp(rtc->asTextureProxy());
+ return rtc;
+}