diff options
author | Chris Dalton <csmartdalton@google.com> | 2017-07-14 15:17:41 -0600 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-07-14 21:45:35 +0000 |
commit | 1a325d25b941ef801b3e9b2c0342da43cf35cdba (patch) | |
tree | 3f65d36541399e1ae6a529a534119815a2c5ba36 /src/gpu/ccpr/GrCCPRAtlas.cpp | |
parent | 588fb040b3ad410cdb10c87f9a7884b6eb825e90 (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.cpp | 125 |
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; +} |