aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar Robert Phillips <robertphillips@google.com>2018-05-31 12:43:27 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-05-31 17:27:43 +0000
commit774168efac172d096cd7f09841bce51650cb6e84 (patch)
tree1433b93978baaf92439289fe5a0a3e648a73974f /src
parente304a8a21b0bc40c3a7d85a96371a21180750076 (diff)
Allow CCPR in DDL mode (take 2)
A lot of the changes to get this compiling on the win_chromium_compile_dbg_ng bot (i.e., moving a lot of header files to private) should be undone if that bot is ever "fixed". Bug: skia:7988 Change-Id: I704ff793d80b18e7312048538874498824803580 Reviewed-on: https://skia-review.googlesource.com/130920 Reviewed-by: Chris Dalton <csmartdalton@google.com> Commit-Queue: Robert Phillips <robertphillips@google.com>
Diffstat (limited to 'src')
-rw-r--r--src/core/SkArenaAlloc.h250
-rw-r--r--src/core/SkDeferredDisplayList.cpp3
-rw-r--r--src/core/SkTInternalLList.h318
-rw-r--r--src/gpu/GrContext.cpp1
-rw-r--r--src/gpu/GrDrawingManager.cpp12
-rw-r--r--src/gpu/ccpr/GrCCClipPath.h79
-rw-r--r--src/gpu/ccpr/GrCCClipProcessor.cpp2
-rw-r--r--src/gpu/ccpr/GrCCDrawPathsOp.h2
-rw-r--r--src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp22
-rw-r--r--src/gpu/ccpr/GrCoverageCountingPathRenderer.h43
10 files changed, 51 insertions, 681 deletions
diff --git a/src/core/SkArenaAlloc.h b/src/core/SkArenaAlloc.h
deleted file mode 100644
index c9e7274e63..0000000000
--- a/src/core/SkArenaAlloc.h
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkArenaAlloc_DEFINED
-#define SkArenaAlloc_DEFINED
-
-#include "SkRefCnt.h"
-#include "SkTFitsIn.h"
-#include "SkTypes.h"
-#include <cstddef>
-#include <new>
-#include <type_traits>
-#include <utility>
-#include <vector>
-
-// SkArenaAlloc allocates object and destroys the allocated objects when destroyed. It's designed
-// to minimize the number of underlying block allocations. SkArenaAlloc allocates first out of an
-// (optional) user-provided block of memory, and when that's exhausted it allocates on the heap,
-// starting with an allocation of extraSize bytes. If your data (plus a small overhead) fits in
-// the user-provided block, SkArenaAlloc never uses the heap, and if it fits in extraSize bytes,
-// it'll use the heap only once. If you pass extraSize = 0, it allocates blocks for each call to
-// make<T>.
-//
-// Examples:
-//
-// char block[mostCasesSize];
-// SkArenaAlloc arena(block, almostAllCasesSize);
-//
-// If mostCasesSize is too large for the stack, you can use the following pattern.
-//
-// std::unique_ptr<char[]> block{new char[mostCasesSize]};
-// SkArenaAlloc arena(block.get(), mostCasesSize, almostAllCasesSize);
-//
-// If the program only sometimes allocates memory, use the following.
-//
-// SkArenaAlloc arena(nullptr, 0, almostAllCasesSize);
-//
-// The storage does not necessarily need to be on the stack. Embedding the storage in a class also
-// works.
-//
-// class Foo {
-// char storage[mostCasesSize];
-// SkArenaAlloc arena (storage, almostAllCasesSize);
-// };
-//
-// In addition, the system is optimized to handle POD data including arrays of PODs (where
-// POD is really data with no destructors). For POD data it has zero overhead per item, and a
-// typical block overhead of 8 bytes. For non-POD objects there is a per item overhead of 4 bytes.
-// For arrays of non-POD objects there is a per array overhead of typically 8 bytes. There is an
-// addition overhead when switching from POD data to non-POD data of typically 8 bytes.
-//
-// You can track memory use by adding SkArenaAlloc::kTrack as the last parameter to any constructor.
-//
-// char storage[someNumber];
-// SkArenaAlloc alloc{storage, SkArenaAlloc::kTrack};
-//
-// This will print out a line for every destructor or reset call that has the total memory
-// allocated, the total slop (the unused portion of a block), and the slop of the last block.
-//
-// If additional blocks are needed they are increased exponentially. This strategy bounds the
-// recursion of the RunDtorsOnBlock to be limited to O(log size-of-memory). Block size grow using
-// the Fibonacci sequence which means that for 2^32 memory there are 48 allocations, and for 2^48
-// there are 71 allocations.
-class SkArenaAlloc {
-public:
- enum Tracking {kDontTrack, kTrack};
- SkArenaAlloc(char* block, size_t size, size_t, Tracking tracking = kDontTrack);
-
- SkArenaAlloc(size_t extraSize, Tracking tracking = kDontTrack)
- : SkArenaAlloc(nullptr, 0, extraSize, tracking)
- {}
-
- ~SkArenaAlloc();
-
- template <typename T, typename... Args>
- T* make(Args&&... args) {
- uint32_t size = SkTo<uint32_t>(sizeof(T));
- uint32_t alignment = SkTo<uint32_t>(alignof(T));
- char* objStart;
- if (skstd::is_trivially_destructible<T>::value) {
- objStart = this->allocObject(size, alignment);
- fCursor = objStart + size;
- } else {
- objStart = this->allocObjectWithFooter(size + sizeof(Footer), alignment);
- // Can never be UB because max value is alignof(T).
- uint32_t padding = SkTo<uint32_t>(objStart - fCursor);
-
- // Advance to end of object to install footer.
- fCursor = objStart + size;
- FooterAction* releaser = [](char* objEnd) {
- char* objStart = objEnd - (sizeof(T) + sizeof(Footer));
- ((T*)objStart)->~T();
- return objStart;
- };
- this->installFooter(releaser, padding);
- }
-
- // This must be last to make objects with nested use of this allocator work.
- return new(objStart) T(std::forward<Args>(args)...);
- }
-
- template <typename T, typename... Args>
- sk_sp<T> makeSkSp(Args&&... args) {
- SkASSERT(SkTFitsIn<uint32_t>(sizeof(T)));
-
- // The arena takes a ref for itself to account for the destructor. The sk_sp count can't
- // become zero or the sk_sp will try to call free on the pointer.
- return sk_sp<T>(SkRef(this->make<T>(std::forward<Args>(args)...)));
- }
-
- template <typename T>
- T* makeArrayDefault(size_t count) {
- uint32_t safeCount = SkTo<uint32_t>(count);
- T* array = (T*)this->commonArrayAlloc<T>(safeCount);
-
- // If T is primitive then no initialization takes place.
- for (size_t i = 0; i < safeCount; i++) {
- new (&array[i]) T;
- }
- return array;
- }
-
- template <typename T>
- T* makeArray(size_t count) {
- uint32_t safeCount = SkTo<uint32_t>(count);
- T* array = (T*)this->commonArrayAlloc<T>(safeCount);
-
- // If T is primitive then the memory is initialized. For example, an array of chars will
- // be zeroed.
- for (size_t i = 0; i < safeCount; i++) {
- new (&array[i]) T();
- }
- return array;
- }
-
- // Only use makeBytesAlignedTo if none of the typed variants are impractical to use.
- void* makeBytesAlignedTo(size_t size, size_t align) {
- auto objStart = this->allocObject(SkTo<uint32_t>(size), SkTo<uint32_t>(align));
- fCursor = objStart + size;
- return objStart;
- }
-
- // Destroy all allocated objects, free any heap allocations.
- void reset();
-
-private:
- using Footer = int64_t;
- using FooterAction = char* (char*);
-
- static char* SkipPod(char* footerEnd);
- static void RunDtorsOnBlock(char* footerEnd);
- static char* NextBlock(char* footerEnd);
-
- void installFooter(FooterAction* releaser, uint32_t padding);
- void installUint32Footer(FooterAction* action, uint32_t value, uint32_t padding);
- void installPtrFooter(FooterAction* action, char* ptr, uint32_t padding);
-
- void ensureSpace(uint32_t size, uint32_t alignment);
-
- char* allocObject(uint32_t size, uint32_t alignment) {
- uintptr_t mask = alignment - 1;
- uintptr_t alignedOffset = (~reinterpret_cast<uintptr_t>(fCursor) + 1) & mask;
- uintptr_t totalSize = size + alignedOffset;
- if (totalSize < size) {
- SK_ABORT("The total size of allocation overflowed uintptr_t.");
- }
- if (totalSize > static_cast<uintptr_t>(fEnd - fCursor)) {
- this->ensureSpace(size, alignment);
- alignedOffset = (~reinterpret_cast<uintptr_t>(fCursor) + 1) & mask;
- }
- return fCursor + alignedOffset;
- }
-
- char* allocObjectWithFooter(uint32_t sizeIncludingFooter, uint32_t alignment);
-
- template <typename T>
- char* commonArrayAlloc(uint32_t count) {
- char* objStart;
- SkASSERT_RELEASE(count <= std::numeric_limits<uint32_t>::max() / sizeof(T));
- uint32_t arraySize = SkTo<uint32_t>(count * sizeof(T));
- uint32_t alignment = SkTo<uint32_t>(alignof(T));
-
- if (skstd::is_trivially_destructible<T>::value) {
- objStart = this->allocObject(arraySize, alignment);
- fCursor = objStart + arraySize;
- } else {
- constexpr uint32_t overhead = sizeof(Footer) + sizeof(uint32_t);
- SkASSERT_RELEASE(arraySize <= std::numeric_limits<uint32_t>::max() - overhead);
- uint32_t totalSize = arraySize + overhead;
- objStart = this->allocObjectWithFooter(totalSize, alignment);
-
- // Can never be UB because max value is alignof(T).
- uint32_t padding = SkTo<uint32_t>(objStart - fCursor);
-
- // Advance to end of array to install footer.?
- fCursor = objStart + arraySize;
- this->installUint32Footer(
- [](char* footerEnd) {
- char* objEnd = footerEnd - (sizeof(Footer) + sizeof(uint32_t));
- uint32_t count;
- memmove(&count, objEnd, sizeof(uint32_t));
- char* objStart = objEnd - count * sizeof(T);
- T* array = (T*) objStart;
- for (uint32_t i = 0; i < count; i++) {
- array[i].~T();
- }
- return objStart;
- },
- SkTo<uint32_t>(count),
- padding);
- }
-
- return objStart;
- }
-
- char* fDtorCursor;
- char* fCursor;
- char* fEnd;
- char* const fFirstBlock;
- const uint32_t fFirstSize;
- const uint32_t fExtraSize;
-
- // Track some useful stats. Track stats if fTotalSlop is >= 0;
- uint32_t fTotalAlloc { 0};
- int32_t fTotalSlop {-1};
-
- // Use the Fibonacci sequence as the growth factor for block size. The size of the block
- // allocated is fFib0 * fExtraSize. Using 2 ^ n * fExtraSize had too much slop for Android.
- uint32_t fFib0 {1}, fFib1 {1};
-};
-
-// Helper for defining allocators with inline/reserved storage.
-// For argument declarations, stick to the base type (SkArenaAlloc).
-template <size_t InlineStorageSize>
-class SkSTArenaAlloc : public SkArenaAlloc {
-public:
- explicit SkSTArenaAlloc(size_t extraSize = InlineStorageSize, Tracking tracking = kDontTrack)
- : INHERITED(fInlineStorage, InlineStorageSize, extraSize, tracking) {}
-
-private:
- char fInlineStorage[InlineStorageSize];
-
- using INHERITED = SkArenaAlloc;
-};
-
-#endif // SkArenaAlloc_DEFINED
diff --git a/src/core/SkDeferredDisplayList.cpp b/src/core/SkDeferredDisplayList.cpp
index 530523a4b6..50c8648776 100644
--- a/src/core/SkDeferredDisplayList.cpp
+++ b/src/core/SkDeferredDisplayList.cpp
@@ -15,3 +15,6 @@ SkDeferredDisplayList::SkDeferredDisplayList(const SkSurfaceCharacterization& ch
: fCharacterization(characterization)
, fLazyProxyData(std::move(lazyProxyData)) {
}
+
+SkDeferredDisplayList::~SkDeferredDisplayList() {
+}
diff --git a/src/core/SkTInternalLList.h b/src/core/SkTInternalLList.h
deleted file mode 100644
index 2f43f1c1eb..0000000000
--- a/src/core/SkTInternalLList.h
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkTInternalLList_DEFINED
-#define SkTInternalLList_DEFINED
-
-#include "SkTypes.h"
-
-/**
- * Helper class to automatically initialize the doubly linked list created pointers.
- */
-template <typename T> class SkPtrWrapper {
- public:
- SkPtrWrapper() : fPtr(nullptr) {}
- SkPtrWrapper& operator =(T* ptr) { fPtr = ptr; return *this; }
- operator T*() const { return fPtr; }
- T* operator->() { return fPtr; }
- private:
- T* fPtr;
-};
-
-
-/**
- * This macro creates the member variables required by the SkTInternalLList class. It should be
- * placed in the private section of any class that will be stored in a double linked list.
- */
-#define SK_DECLARE_INTERNAL_LLIST_INTERFACE(ClassName) \
- friend class SkTInternalLList<ClassName>; \
- /* back pointer to the owning list - for debugging */ \
- SkDEBUGCODE(SkPtrWrapper<SkTInternalLList<ClassName> > fList;) \
- SkPtrWrapper<ClassName> fPrev; \
- SkPtrWrapper<ClassName> fNext
-
-/**
- * This class implements a templated internal doubly linked list data structure.
- */
-template <class T> class SkTInternalLList : SkNoncopyable {
-public:
- SkTInternalLList()
- : fHead(nullptr)
- , fTail(nullptr) {
- }
-
- void reset() {
- fHead = nullptr;
- fTail = nullptr;
- }
-
- void remove(T* entry) {
- SkASSERT(fHead && fTail);
- SkASSERT(this->isInList(entry));
-
- T* prev = entry->fPrev;
- T* next = entry->fNext;
-
- if (prev) {
- prev->fNext = next;
- } else {
- fHead = next;
- }
- if (next) {
- next->fPrev = prev;
- } else {
- fTail = prev;
- }
-
- entry->fPrev = nullptr;
- entry->fNext = nullptr;
-
-#ifdef SK_DEBUG
- entry->fList = nullptr;
-#endif
- }
-
- void addToHead(T* entry) {
- SkASSERT(nullptr == entry->fPrev && nullptr == entry->fNext);
- SkASSERT(nullptr == entry->fList);
-
- entry->fPrev = nullptr;
- entry->fNext = fHead;
- if (fHead) {
- fHead->fPrev = entry;
- }
- fHead = entry;
- if (nullptr == fTail) {
- fTail = entry;
- }
-
-#ifdef SK_DEBUG
- entry->fList = this;
-#endif
- }
-
- void addToTail(T* entry) {
- SkASSERT(nullptr == entry->fPrev && nullptr == entry->fNext);
- SkASSERT(nullptr == entry->fList);
-
- entry->fPrev = fTail;
- entry->fNext = nullptr;
- if (fTail) {
- fTail->fNext = entry;
- }
- fTail = entry;
- if (nullptr == fHead) {
- fHead = entry;
- }
-
-#ifdef SK_DEBUG
- entry->fList = this;
-#endif
- }
-
- /**
- * Inserts a new list entry before an existing list entry. The new entry must not already be
- * a member of this or any other list. If existingEntry is NULL then the new entry is added
- * at the tail.
- */
- void addBefore(T* newEntry, T* existingEntry) {
- SkASSERT(newEntry);
-
- if (nullptr == existingEntry) {
- this->addToTail(newEntry);
- return;
- }
-
- SkASSERT(this->isInList(existingEntry));
- newEntry->fNext = existingEntry;
- T* prev = existingEntry->fPrev;
- existingEntry->fPrev = newEntry;
- newEntry->fPrev = prev;
- if (nullptr == prev) {
- SkASSERT(fHead == existingEntry);
- fHead = newEntry;
- } else {
- prev->fNext = newEntry;
- }
-#ifdef SK_DEBUG
- newEntry->fList = this;
-#endif
- }
-
- /**
- * Inserts a new list entry after an existing list entry. The new entry must not already be
- * a member of this or any other list. If existingEntry is NULL then the new entry is added
- * at the head.
- */
- void addAfter(T* newEntry, T* existingEntry) {
- SkASSERT(newEntry);
-
- if (nullptr == existingEntry) {
- this->addToHead(newEntry);
- return;
- }
-
- SkASSERT(this->isInList(existingEntry));
- newEntry->fPrev = existingEntry;
- T* next = existingEntry->fNext;
- existingEntry->fNext = newEntry;
- newEntry->fNext = next;
- if (nullptr == next) {
- SkASSERT(fTail == existingEntry);
- fTail = newEntry;
- } else {
- next->fPrev = newEntry;
- }
-#ifdef SK_DEBUG
- newEntry->fList = this;
-#endif
- }
-
- void concat(SkTInternalLList&& list) {
- if (list.isEmpty()) {
- return;
- }
-
- list.fHead->fPrev = fTail;
- if (!fHead) {
- SkASSERT(!list.fHead->fPrev);
- fHead = list.fHead;
- } else {
- SkASSERT(fTail);
- fTail->fNext = list.fHead;
- }
- fTail = list.fTail;
-
-#ifdef SK_DEBUG
- for (T* node = list.fHead; node; node = node->fNext) {
- SkASSERT(node->fList == &list);
- node->fList = this;
- }
-#endif
-
- list.fHead = list.fTail = nullptr;
- }
-
- bool isEmpty() const {
- SkASSERT(SkToBool(fHead) == SkToBool(fTail));
- return !fHead;
- }
-
- T* head() { return fHead; }
- T* tail() { return fTail; }
-
- class Iter {
- public:
- enum IterStart {
- kHead_IterStart,
- kTail_IterStart
- };
-
- Iter() : fCurr(nullptr) {}
- Iter(const Iter& iter) : fCurr(iter.fCurr) {}
- Iter& operator= (const Iter& iter) { fCurr = iter.fCurr; return *this; }
-
- T* init(const SkTInternalLList& list, IterStart startLoc) {
- if (kHead_IterStart == startLoc) {
- fCurr = list.fHead;
- } else {
- SkASSERT(kTail_IterStart == startLoc);
- fCurr = list.fTail;
- }
-
- return fCurr;
- }
-
- T* get() { return fCurr; }
-
- /**
- * Return the next/previous element in the list or NULL if at the end.
- */
- T* next() {
- if (nullptr == fCurr) {
- return nullptr;
- }
-
- fCurr = fCurr->fNext;
- return fCurr;
- }
-
- T* prev() {
- if (nullptr == fCurr) {
- return nullptr;
- }
-
- fCurr = fCurr->fPrev;
- return fCurr;
- }
-
- /**
- * C++11 range-for interface.
- */
- bool operator!=(const Iter& that) { return fCurr != that.fCurr; }
- T* operator*() { return this->get(); }
- void operator++() { this->next(); }
-
- private:
- T* fCurr;
- };
-
- Iter begin() const {
- Iter iter;
- iter.init(*this, Iter::kHead_IterStart);
- return iter;
- }
-
- Iter end() const { return Iter(); }
-
-#ifdef SK_DEBUG
- void validate() const {
- SkASSERT(!fHead == !fTail);
- Iter iter;
- for (T* item = iter.init(*this, Iter::kHead_IterStart); item; item = iter.next()) {
- SkASSERT(this->isInList(item));
- if (nullptr == item->fPrev) {
- SkASSERT(fHead == item);
- } else {
- SkASSERT(item->fPrev->fNext == item);
- }
- if (nullptr == item->fNext) {
- SkASSERT(fTail == item);
- } else {
- SkASSERT(item->fNext->fPrev == item);
- }
- }
- }
-
- /**
- * Debugging-only method that uses the list back pointer to check if 'entry' is indeed in 'this'
- * list.
- */
- bool isInList(const T* entry) const {
- return entry->fList == this;
- }
-
- /**
- * Debugging-only method that laboriously counts the list entries.
- */
- int countEntries() const {
- int count = 0;
- for (T* entry = fHead; entry; entry = entry->fNext) {
- ++count;
- }
- return count;
- }
-#endif // SK_DEBUG
-
-private:
- T* fHead;
- T* fTail;
-
- typedef SkNoncopyable INHERITED;
-};
-
-#endif
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 572f58972b..3d57f9818d 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -113,7 +113,6 @@ bool GrContext::initCommon(const GrContextOptions& options) {
// Disable the small path renderer bc of the proxies in the atlas. They need to be
// unified when the opLists are added back to the destination drawing manager.
prcOptions.fGpuPathRenderers &= ~GpuPathRenderers::kSmall;
- prcOptions.fGpuPathRenderers &= ~GpuPathRenderers::kCoverageCounting;
}
GrTextContext::Options textContextOptions;
diff --git a/src/gpu/GrDrawingManager.cpp b/src/gpu/GrDrawingManager.cpp
index 158239e460..99eb04b918 100644
--- a/src/gpu/GrDrawingManager.cpp
+++ b/src/gpu/GrDrawingManager.cpp
@@ -26,6 +26,7 @@
#include "SkSurface_Gpu.h"
#include "SkTTopoSort.h"
#include "GrTracing.h"
+#include "ccpr/GrCoverageCountingPathRenderer.h"
#include "text/GrTextContext.h"
// Turn on/off the sorting of opLists at flush time
@@ -383,6 +384,11 @@ void GrDrawingManager::moveOpListsToDDL(SkDeferredDisplayList* ddl) {
}
ddl->fOpLists = std::move(fOpLists);
+ if (fPathRendererChain) {
+ if (auto ccpr = fPathRendererChain->getCoverageCountingPathRenderer()) {
+ ddl->fPendingPaths = ccpr->detachPendingPaths();
+ }
+ }
}
void GrDrawingManager::copyOpListsFromDDL(const SkDeferredDisplayList* ddl,
@@ -390,6 +396,12 @@ void GrDrawingManager::copyOpListsFromDDL(const SkDeferredDisplayList* ddl,
// Here we jam the proxy that backs the current replay SkSurface into the LazyProxyData.
// The lazy proxy that references it (in the copied opLists) will steal its GrTexture.
ddl->fLazyProxyData->fReplayDest = newDest;
+
+ if (ddl->fPendingPaths.size()) {
+ GrCoverageCountingPathRenderer* ccpr = this->getCoverageCountingPathRenderer();
+
+ ccpr->mergePendingPaths(ddl->fPendingPaths);
+ }
fOpLists.push_back_n(ddl->fOpLists.count(), ddl->fOpLists.begin());
}
diff --git a/src/gpu/ccpr/GrCCClipPath.h b/src/gpu/ccpr/GrCCClipPath.h
deleted file mode 100644
index f15cc9c756..0000000000
--- a/src/gpu/ccpr/GrCCClipPath.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright 2018 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef GrCCClipPath_DEFINED
-#define GrCCClipPath_DEFINED
-
-#include "GrTextureProxy.h"
-#include "SkPath.h"
-
-class GrCCAtlas;
-class GrCCPerFlushResources;
-class GrOnFlushResourceProvider;
-class GrProxyProvider;
-
-/**
- * These are keyed by SkPath generation ID, and store which device-space paths are accessed and
- * where by clip FPs in a given opList. A single GrCCClipPath can be referenced by multiple FPs. At
- * flush time their coverage count masks are packed into atlas(es) alongside normal DrawPathOps.
- */
-class GrCCClipPath {
-public:
- GrCCClipPath() = default;
- GrCCClipPath(const GrCCClipPath&) = delete;
-
- ~GrCCClipPath() {
- // Ensure no clip FPs exist with a dangling pointer back into this class.
- SkASSERT(!fAtlasLazyProxy || fAtlasLazyProxy->isUnique_debugOnly());
- // Ensure no lazy proxy callbacks exist with a dangling pointer back into this class.
- SkASSERT(fHasAtlasTransform);
- }
-
- bool isInitialized() const { return fAtlasLazyProxy != nullptr; }
- void init(GrProxyProvider* proxyProvider,
- const SkPath& deviceSpacePath, const SkIRect& accessRect,
- int rtWidth, int rtHeight);
-
- void addAccess(const SkIRect& accessRect) {
- SkASSERT(this->isInitialized());
- fAccessRect.join(accessRect);
- }
- GrTextureProxy* atlasLazyProxy() const {
- SkASSERT(this->isInitialized());
- return fAtlasLazyProxy.get();
- }
- const SkPath& deviceSpacePath() const {
- SkASSERT(this->isInitialized());
- return fDeviceSpacePath;
- }
- const SkIRect& pathDevIBounds() const {
- SkASSERT(this->isInitialized());
- return fPathDevIBounds;
- }
-
- void renderPathInAtlas(GrCCPerFlushResources*, GrOnFlushResourceProvider*);
-
- const SkVector& atlasScale() const { SkASSERT(fHasAtlasTransform); return fAtlasScale; }
- const SkVector& atlasTranslate() const { SkASSERT(fHasAtlasTransform); return fAtlasTranslate; }
-
-private:
- sk_sp<GrTextureProxy> fAtlasLazyProxy;
- SkPath fDeviceSpacePath;
- SkIRect fPathDevIBounds;
- SkIRect fAccessRect;
-
- const GrCCAtlas* fAtlas = nullptr;
- int16_t fAtlasOffsetX;
- int16_t fAtlasOffsetY;
- SkDEBUGCODE(bool fHasAtlas = false);
-
- SkVector fAtlasScale;
- SkVector fAtlasTranslate;
- SkDEBUGCODE(bool fHasAtlasTransform = false);
-};
-
-#endif
diff --git a/src/gpu/ccpr/GrCCClipProcessor.cpp b/src/gpu/ccpr/GrCCClipProcessor.cpp
index d4da596039..91d689246c 100644
--- a/src/gpu/ccpr/GrCCClipProcessor.cpp
+++ b/src/gpu/ccpr/GrCCClipProcessor.cpp
@@ -7,10 +7,10 @@
#include "GrCCClipProcessor.h"
+#include "GrCCClipPath.h"
#include "GrTexture.h"
#include "GrTextureProxy.h"
#include "SkMakeUnique.h"
-#include "ccpr/GrCCClipPath.h"
#include "glsl/GrGLSLFragmentProcessor.h"
#include "glsl/GrGLSLFragmentShaderBuilder.h"
diff --git a/src/gpu/ccpr/GrCCDrawPathsOp.h b/src/gpu/ccpr/GrCCDrawPathsOp.h
index 92ba3dd4c7..9189e5a757 100644
--- a/src/gpu/ccpr/GrCCDrawPathsOp.h
+++ b/src/gpu/ccpr/GrCCDrawPathsOp.h
@@ -16,7 +16,7 @@
class GrCCAtlas;
class GrCCPerFlushResources;
-struct GrCCPerOpListPaths;
+class GrCCPerOpListPaths;
/**
* This is the Op that draws paths to the actual canvas, using atlases generated by CCPR.
diff --git a/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp b/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp
index d51c0b525a..c8fafeb566 100644
--- a/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp
+++ b/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp
@@ -32,6 +32,18 @@ static void crop_path(const SkPath& path, const SkIRect& cropbox, SkPath* out) {
out->setIsVolatile(true);
}
+
+GrCCPerOpListPaths::~GrCCPerOpListPaths() {
+ // Ensure there are no surviving DrawPathsOps with a dangling pointer into this class.
+ if (!fDrawOps.isEmpty()) {
+ SK_ABORT("GrCCDrawPathsOp(s) not deleted during flush");
+ }
+ // Clip lazy proxies also reference this class from their callbacks, but those callbacks
+ // are only invoked at flush time while we are still alive. (Unlike DrawPathsOps, that
+ // unregister themselves upon destruction.) So it shouldn't matter if any clip proxies
+ // are still around.
+}
+
bool GrCoverageCountingPathRenderer::IsSupported(const GrCaps& caps) {
const GrShaderCaps& shaderCaps = *caps.shaderCaps();
return shaderCaps.integerSupport() && shaderCaps.flatInterpolationSupport() &&
@@ -50,7 +62,7 @@ sk_sp<GrCoverageCountingPathRenderer> GrCoverageCountingPathRenderer::CreateIfSu
GrCCPerOpListPaths* GrCoverageCountingPathRenderer::lookupPendingPaths(uint32_t opListID) {
auto it = fPendingPaths.find(opListID);
if (fPendingPaths.end() == it) {
- auto paths = skstd::make_unique<GrCCPerOpListPaths>();
+ sk_sp<GrCCPerOpListPaths> paths = sk_make_sp<GrCCPerOpListPaths>();
it = fPendingPaths.insert(std::make_pair(opListID, std::move(paths))).first;
}
return it->second.get();
@@ -227,6 +239,7 @@ void GrCoverageCountingPathRenderer::preFlush(GrOnFlushResourceProvider* onFlush
// Commit flushing paths to the resources once they are successfully completed.
for (auto& flushingPaths : fFlushingPaths) {
+ SkASSERT(!flushingPaths->fFlushResources);
flushingPaths->fFlushResources = resources;
}
}
@@ -234,6 +247,13 @@ void GrCoverageCountingPathRenderer::preFlush(GrOnFlushResourceProvider* onFlush
void GrCoverageCountingPathRenderer::postFlush(GrDeferredUploadToken, const uint32_t* opListIDs,
int numOpListIDs) {
SkASSERT(fFlushing);
+
+ // In DDL mode these aren't guaranteed to be deleted so we must clear out the perFlush
+ // resources manually.
+ for (auto& flushingPaths : fFlushingPaths) {
+ flushingPaths->fFlushResources = nullptr;
+ }
+
// We wait to erase these until after flush, once Ops and FPs are done accessing their data.
fFlushingPaths.reset();
SkDEBUGCODE(fFlushing = false);
diff --git a/src/gpu/ccpr/GrCoverageCountingPathRenderer.h b/src/gpu/ccpr/GrCoverageCountingPathRenderer.h
index d10186601c..4032bd51d5 100644
--- a/src/gpu/ccpr/GrCoverageCountingPathRenderer.h
+++ b/src/gpu/ccpr/GrCoverageCountingPathRenderer.h
@@ -8,38 +8,15 @@
#ifndef GrCoverageCountingPathRenderer_DEFINED
#define GrCoverageCountingPathRenderer_DEFINED
+#include "GrCCPerOpListPaths.h"
#include "GrPathRenderer.h"
#include "GrRenderTargetOpList.h"
-#include "SkArenaAlloc.h"
-#include "SkTInternalLList.h"
-#include "ccpr/GrCCClipPath.h"
#include "ccpr/GrCCPerFlushResources.h"
#include <map>
class GrCCDrawPathsOp;
/**
- * Tracks all the paths in a given opList that will be drawn when it flushes.
- */
-struct GrCCPerOpListPaths {
- ~GrCCPerOpListPaths() {
- // Ensure there are no surviving DrawPathsOps with a dangling pointer into this class.
- if (!fDrawOps.isEmpty()) {
- SK_ABORT("GrCCDrawPathsOp(s) not deleted during flush");
- }
- // Clip lazy proxies also reference this class from their callbacks, but those callbacks
- // are only invoked at flush time while we are still alive. (Unlike DrawPathsOps, that
- // unregister themselves upon destruction.) So it shouldn't matter if any clip proxies
- // are still around.
- }
-
- SkTInternalLList<GrCCDrawPathsOp> fDrawOps;
- std::map<uint32_t, GrCCClipPath> fClipPaths;
- SkSTArenaAlloc<10 * 1024> fAllocator{10 * 1024 * 2};
- sk_sp<const GrCCPerFlushResources> fFlushResources;
-};
-
-/**
* This is a path renderer that draws antialiased paths by counting coverage in an offscreen
* buffer. (See GrCCCoverageProcessor, GrCCPathProcessor.)
*
@@ -57,17 +34,23 @@ public:
SkASSERT(!fFlushing);
}
- using PendingPathsMap = std::map<uint32_t, std::unique_ptr<GrCCPerOpListPaths>>;
+ using PendingPathsMap = std::map<uint32_t, sk_sp<GrCCPerOpListPaths>>;
// In DDL mode, Ganesh needs to be able to move the pending GrCCPerOpListPaths to the DDL object
// (detachPendingPaths) and then return them upon replay (mergePendingPaths).
PendingPathsMap detachPendingPaths() { return std::move(fPendingPaths); }
- void mergePendingPaths(PendingPathsMap&& paths) {
+ void mergePendingPaths(const PendingPathsMap& paths) {
+#ifdef SK_DEBUG
// Ensure there are no duplicate opList IDs between the incoming path map and ours.
- SkDEBUGCODE(for (const auto& it : paths) SkASSERT(!fPendingPaths.count(it.first)));
- fPendingPaths.insert(std::make_move_iterator(paths.begin()),
- std::make_move_iterator(paths.end()));
+ // This should always be true since opList IDs are globally unique and these are coming
+ // from different DDL recordings.
+ for (const auto& it : paths) {
+ SkASSERT(!fPendingPaths.count(it.first));
+ }
+#endif
+
+ fPendingPaths.insert(paths.begin(), paths.end());
}
// GrPathRenderer overrides.
@@ -101,7 +84,7 @@ private:
// fFlushingPaths holds the GrCCPerOpListPaths objects that are currently being flushed.
// (It will only contain elements when fFlushing is true.)
- SkSTArray<4, std::unique_ptr<GrCCPerOpListPaths>> fFlushingPaths;
+ SkSTArray<4, sk_sp<GrCCPerOpListPaths>> fFlushingPaths;
SkDEBUGCODE(bool fFlushing = false);
const bool fDrawCachablePaths;