Add creation-time POD memory pool for GrOps
This CL begins pulling some of the work forward into onPrePrepare.
Change-Id: If049e0662db51b465b8b82aafebeef2323bddfd4
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/249802
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
diff --git a/include/private/GrRecordingContext.h b/include/private/GrRecordingContext.h
index 1f44bee..39d851c 100644
--- a/include/private/GrRecordingContext.h
+++ b/include/private/GrRecordingContext.h
@@ -22,6 +22,7 @@
class GrSurfaceProxy;
class GrTextBlobCache;
class GrTextureContext;
+class SkArenaAlloc;
class GrRecordingContext : public GrImageContext {
public:
@@ -49,6 +50,11 @@
sk_sp<GrOpMemoryPool> refOpMemoryPool();
GrOpMemoryPool* opMemoryPool();
+ SkArenaAlloc* opPODAllocator();
+ // This entry point should only be used for DDL creation where we want the ops' POD lifetime
+ // to match that of the DDL.
+ std::unique_ptr<SkArenaAlloc> detachOpPOD();
+
GrStrikeCache* getGrStrikeCache() { return fStrikeCache.get(); }
GrTextBlobCache* getTextBlobCache();
const GrTextBlobCache* getTextBlobCache() const;
@@ -125,6 +131,7 @@
std::unique_ptr<GrDrawingManager> fDrawingManager;
// All the GrOp-derived classes use this pool.
sk_sp<GrOpMemoryPool> fOpMemoryPool;
+ std::unique_ptr<SkArenaAlloc> fOpPODAllocator;
std::unique_ptr<GrStrikeCache> fStrikeCache;
std::unique_ptr<GrTextBlobCache> fTextBlobCache;
diff --git a/include/private/SkDeferredDisplayList.h b/include/private/SkDeferredDisplayList.h
index e8fc35b..b90995c 100644
--- a/include/private/SkDeferredDisplayList.h
+++ b/include/private/SkDeferredDisplayList.h
@@ -59,7 +59,7 @@
const SkDeferredDisplayListPriv priv() const;
private:
- friend class GrDrawingManager; // for access to 'fRenderTasks' and 'fLazyProxyData'
+ friend class GrDrawingManager; // for access to 'fRenderTasks', 'fLazyProxyData', 'fOpPOD'
friend class SkDeferredDisplayListRecorder; // for access to 'fLazyProxyData'
friend class SkDeferredDisplayListPriv;
@@ -71,6 +71,7 @@
SkTArray<sk_sp<GrRenderTask>> fRenderTasks;
PendingPathsMap fPendingPaths; // This is the path data from CCPR.
+ std::unique_ptr<SkArenaAlloc> fOpPOD;
#endif
sk_sp<LazyProxyData> fLazyProxyData;
};
diff --git a/src/core/SkDeferredDisplayList.cpp b/src/core/SkDeferredDisplayList.cpp
index c89cd99..c718433 100644
--- a/src/core/SkDeferredDisplayList.cpp
+++ b/src/core/SkDeferredDisplayList.cpp
@@ -8,6 +8,7 @@
#include "include/core/SkRefCnt.h"
#include "include/core/SkTypes.h"
#include "include/private/SkDeferredDisplayList.h"
+#include "src/core/SkArenaAlloc.h"
#include <utility>
class SkSurfaceCharacterization;
diff --git a/src/gpu/GrDrawingManager.cpp b/src/gpu/GrDrawingManager.cpp
index 6b2990d..ba89eca 100644
--- a/src/gpu/GrDrawingManager.cpp
+++ b/src/gpu/GrDrawingManager.cpp
@@ -581,6 +581,8 @@
renderTask->prePrepare(fContext);
}
+ ddl->fOpPOD = fContext->priv().detachOpPOD();
+
if (fPathRendererChain) {
if (auto ccpr = fPathRendererChain->getCoverageCountingPathRenderer()) {
ddl->fPendingPaths = ccpr->detachPendingPaths();
diff --git a/src/gpu/GrOpsTask.cpp b/src/gpu/GrOpsTask.cpp
index 63ff79f..4306ad0 100644
--- a/src/gpu/GrOpsTask.cpp
+++ b/src/gpu/GrOpsTask.cpp
@@ -406,7 +406,7 @@
for (const auto& chain : fOpChains) {
if (chain.shouldExecute()) {
- chain.head()->prePrepare(context);
+ chain.head()->prePrepare(context, chain.appliedClip());
}
}
}
diff --git a/src/gpu/GrRecordingContext.cpp b/src/gpu/GrRecordingContext.cpp
index 081b693..58eb8c5 100644
--- a/src/gpu/GrRecordingContext.cpp
+++ b/src/gpu/GrRecordingContext.cpp
@@ -8,6 +8,7 @@
#include "include/private/GrRecordingContext.h"
#include "include/gpu/GrContext.h"
+#include "src/core/SkArenaAlloc.h"
#include "src/gpu/GrAuditTrail.h"
#include "src/gpu/GrCaps.h"
#include "src/gpu/GrDrawingManager.h"
@@ -115,6 +116,9 @@
return fDrawingManager.get();
}
+// This entry point exists bc the GrOpsTask (and SkAtlasTextTarget) take refs on the memory pool.
+// Ostensibly, this is to keep the op's data alive in DDL mode but the back pointer is also
+// used for deletion.
sk_sp<GrOpMemoryPool> GrRecordingContext::refOpMemoryPool() {
if (!fOpMemoryPool) {
// DDL TODO: should the size of the memory pool be decreased in DDL mode? CPU-side memory
@@ -131,6 +135,22 @@
return this->refOpMemoryPool().get();
}
+// Stored in this arena:
+// GrTextureOp's DynamicStateArrays and FixedDynamicState
+SkArenaAlloc* GrRecordingContext::opPODAllocator() {
+ if (!fOpPODAllocator) {
+ // TODO: empirically determine a better number for SkArenaAlloc's firstHeapAllocation param
+ fOpPODAllocator = std::unique_ptr<SkArenaAlloc>(new SkArenaAlloc(sizeof(GrPipeline) * 100));
+ }
+
+ SkASSERT(fOpPODAllocator);
+ return fOpPODAllocator.get();
+}
+
+std::unique_ptr<SkArenaAlloc> GrRecordingContext::detachOpPOD() {
+ return std::move(fOpPODAllocator);
+}
+
GrTextBlobCache* GrRecordingContext::getTextBlobCache() {
return fTextBlobCache.get();
}
@@ -302,6 +322,10 @@
return fContext->refCaps();
}
+std::unique_ptr<SkArenaAlloc> GrRecordingContextPriv::detachOpPOD() {
+ return fContext->detachOpPOD();
+}
+
sk_sp<GrSkSLFPFactoryCache> GrRecordingContextPriv::fpFactoryCache() {
return fContext->fpFactoryCache();
}
diff --git a/src/gpu/GrRecordingContextPriv.h b/src/gpu/GrRecordingContextPriv.h
index 2987778..dfaf914 100644
--- a/src/gpu/GrRecordingContextPriv.h
+++ b/src/gpu/GrRecordingContextPriv.h
@@ -46,6 +46,9 @@
sk_sp<GrOpMemoryPool> refOpMemoryPool();
GrOpMemoryPool* opMemoryPool() { return fContext->opMemoryPool(); }
+ SkArenaAlloc* opPODAllocator() { return fContext->opPODAllocator(); }
+ std::unique_ptr<SkArenaAlloc> detachOpPOD();
+
GrStrikeCache* getGrStrikeCache() { return fContext->getGrStrikeCache(); }
GrTextBlobCache* getTextBlobCache() { return fContext->getTextBlobCache(); }
diff --git a/src/gpu/ops/GrMeshDrawOp.cpp b/src/gpu/ops/GrMeshDrawOp.cpp
index 0ba8e43..77dcf6d 100644
--- a/src/gpu/ops/GrMeshDrawOp.cpp
+++ b/src/gpu/ops/GrMeshDrawOp.cpp
@@ -75,32 +75,37 @@
//////////////////////////////////////////////////////////////////////////////
-GrPipeline::DynamicStateArrays* GrMeshDrawOp::Target::allocDynamicStateArrays(
- int numMeshes, int numPrimitiveProcessorTextures, bool allocScissors) {
- auto result = this->allocator()->make<GrPipeline::DynamicStateArrays>();
+GrPipeline::DynamicStateArrays* GrMeshDrawOp::Target::AllocDynamicStateArrays(
+ SkArenaAlloc* arena, int numMeshes, int numPrimitiveProcessorTextures,
+ bool allocScissors) {
+
+ auto result = arena->make<GrPipeline::DynamicStateArrays>();
+
if (allocScissors) {
- result->fScissorRects = this->allocator()->makeArray<SkIRect>(numMeshes);
+ result->fScissorRects = arena->makeArray<SkIRect>(numMeshes);
}
+
if (numPrimitiveProcessorTextures) {
- result->fPrimitiveProcessorTextures =
- this->allocator()->makeArrayDefault<GrTextureProxy*>(
+ result->fPrimitiveProcessorTextures = arena->makeArrayDefault<GrTextureProxy*>(
numPrimitiveProcessorTextures * numMeshes);
}
+
return result;
}
-GrPipeline::FixedDynamicState* GrMeshDrawOp::Target::makeFixedDynamicState(
- int numPrimProcTextures) {
- const GrAppliedClip* clip = this->appliedClip();
+GrPipeline::FixedDynamicState* GrMeshDrawOp::Target::MakeFixedDynamicState(
+ SkArenaAlloc* arena, const GrAppliedClip* clip, int numPrimProcTextures) {
+
if ((clip && clip->scissorState().enabled()) || numPrimProcTextures) {
const SkIRect& scissor = (clip) ? clip->scissorState().rect() : SkIRect::MakeEmpty();
- auto fixedDynamicState =
- this->allocator()->make<GrPipeline::FixedDynamicState>(scissor);
+
+ auto result = arena->make<GrPipeline::FixedDynamicState>(scissor);
+
if (numPrimProcTextures) {
- fixedDynamicState->fPrimitiveProcessorTextures =
- this->allocator()->makeArrayDefault<GrTextureProxy*>(numPrimProcTextures);
+ result->fPrimitiveProcessorTextures = arena->makeArrayDefault<GrTextureProxy*>(
+ numPrimProcTextures);
}
- return fixedDynamicState;
+ return result;
}
return nullptr;
}
diff --git a/src/gpu/ops/GrMeshDrawOp.h b/src/gpu/ops/GrMeshDrawOp.h
index 6bdb637..91286d1 100644
--- a/src/gpu/ops/GrMeshDrawOp.h
+++ b/src/gpu/ops/GrMeshDrawOp.h
@@ -72,11 +72,13 @@
};
private:
- void onPrePrepare(GrRecordingContext* context) final { this->onPrePrepareDraws(context); }
+ void onPrePrepare(GrRecordingContext* context, const GrAppliedClip* clip) final {
+ this->onPrePrepareDraws(context, clip);
+ }
void onPrepare(GrOpFlushState* state) final;
// Only the GrTextureOp currently overrides this virtual
- virtual void onPrePrepareDraws(GrRecordingContext*) {}
+ virtual void onPrePrepareDraws(GrRecordingContext*, const GrAppliedClip*) {}
virtual void onPrepareDraws(Target*) = 0;
typedef GrDrawOp INHERITED;
@@ -146,11 +148,20 @@
GrMesh* allocMeshes(int n) { return this->allocator()->makeArray<GrMesh>(n); }
- GrPipeline::DynamicStateArrays* allocDynamicStateArrays(int numMeshes,
- int numPrimitiveProcessorTextures,
- bool allocScissors);
+ static GrPipeline::DynamicStateArrays* AllocDynamicStateArrays(SkArenaAlloc*,
+ int numMeshes,
+ int numPrimitiveProcTextures,
+ bool allocScissors);
- GrPipeline::FixedDynamicState* makeFixedDynamicState(int numPrimitiveProcessorTextures);
+ static GrPipeline::FixedDynamicState* MakeFixedDynamicState(SkArenaAlloc*,
+ const GrAppliedClip* clip,
+ int numPrimitiveProcessorTextures);
+
+
+ GrPipeline::FixedDynamicState* makeFixedDynamicState(int numPrimitiveProcessorTextures) {
+ return MakeFixedDynamicState(this->allocator(), this->appliedClip(),
+ numPrimitiveProcessorTextures);
+ }
virtual GrRenderTargetProxy* proxy() const = 0;
@@ -174,7 +185,6 @@
virtual GrDeferredUploadTarget* deferredUploadTarget() = 0;
-private:
virtual SkArenaAlloc* allocator() = 0;
};
diff --git a/src/gpu/ops/GrOp.h b/src/gpu/ops/GrOp.h
index 0ad0a2b..9a250a3 100644
--- a/src/gpu/ops/GrOp.h
+++ b/src/gpu/ops/GrOp.h
@@ -18,6 +18,7 @@
#include <atomic>
#include <new>
+class GrAppliedClip;
class GrCaps;
class GrOpFlushState;
class GrOpsRenderPass;
@@ -158,7 +159,9 @@
* onPrePrepare must be prepared to handle both cases (when onPrePrepare has been called
* ahead of time and when it has not been called).
*/
- void prePrepare(GrRecordingContext* context) { this->onPrePrepare(context); }
+ void prePrepare(GrRecordingContext* context, GrAppliedClip* clip) {
+ this->onPrePrepare(context, clip);
+ }
/**
* Called prior to executing. The op should perform any resource creation or data transfers
@@ -289,7 +292,7 @@
}
// Only GrMeshDrawOp currently overrides this virtual
- virtual void onPrePrepare(GrRecordingContext*) {}
+ virtual void onPrePrepare(GrRecordingContext*, const GrAppliedClip*) {}
virtual void onPrepare(GrOpFlushState*) = 0;
// If this op is chained then chainBounds is the union of the bounds of all ops in the chain.
// Otherwise, this op's bounds.
diff --git a/src/gpu/ops/GrTextureOp.cpp b/src/gpu/ops/GrTextureOp.cpp
index 9da40bd..3cbefea 100644
--- a/src/gpu/ops/GrTextureOp.cpp
+++ b/src/gpu/ops/GrTextureOp.cpp
@@ -427,11 +427,32 @@
}
}
- void onPrePrepareDraws(GrRecordingContext* context) override {
- SkASSERT(!fPrePrepared);
- // Pull forward the tessellation of the quads to here
+ void onPrePrepareDraws(GrRecordingContext* context, const GrAppliedClip* clip) override {
+ TRACE_EVENT0("skia.gpu", TRACE_FUNC);
- //GrOpMemoryPool* pool = context->priv().opMemoryPool();
+ SkDEBUGCODE(this->validate();)
+ SkASSERT(!fPrePrepared);
+
+ int numProxies, numTotalQuads;
+
+ SkArenaAlloc* arena = context->priv().opPODAllocator();
+
+ const VertexSpec vertexSpec = this->characterize(&numProxies, &numTotalQuads);
+ (void) vertexSpec;
+
+ // We'll use a dynamic state array for the GP textures when there are multiple ops.
+ // Otherwise, we use fixed dynamic state to specify the single op's proxy.
+ // Note: these are being allocated in the opPOD arena not the flush state!
+ SkASSERT(!fDynamicStateArrays && !fFixedDynamicState);
+ if (numProxies > 1) {
+ fDynamicStateArrays = Target::AllocDynamicStateArrays(arena, numProxies, 1, false);
+ fFixedDynamicState = Target::MakeFixedDynamicState(arena, clip, 0);
+ } else {
+ fFixedDynamicState = Target::MakeFixedDynamicState(arena, clip, 1);
+ fFixedDynamicState->fPrimitiveProcessorTextures[0] = fProxies[0].fProxy;
+ }
+
+ // Pull forward the tessellation of the quads to here
fPrePrepared = true;
}
@@ -509,12 +530,22 @@
// Otherwise, we use fixed dynamic state to specify the single op's proxy.
GrPipeline::DynamicStateArrays* dynamicStateArrays = nullptr;
GrPipeline::FixedDynamicState* fixedDynamicState;
- if (numProxies > 1) {
- dynamicStateArrays = target->allocDynamicStateArrays(numProxies, 1, false);
- fixedDynamicState = target->makeFixedDynamicState(0);
+
+ if (fPrePrepared) {
+ dynamicStateArrays = fDynamicStateArrays;
+ fixedDynamicState = fFixedDynamicState;
} else {
- fixedDynamicState = target->makeFixedDynamicState(1);
- fixedDynamicState->fPrimitiveProcessorTextures[0] = fProxies[0].fProxy;
+ SkArenaAlloc* arena = target->allocator();
+
+ SkASSERT(!fDynamicStateArrays && !fFixedDynamicState);
+
+ if (numProxies > 1) {
+ dynamicStateArrays = Target::AllocDynamicStateArrays(arena, numProxies, 1, false);
+ fixedDynamicState = Target::MakeFixedDynamicState(arena, target->appliedClip(), 0);
+ } else {
+ fixedDynamicState = Target::MakeFixedDynamicState(arena, target->appliedClip(), 1);
+ fixedDynamicState->fPrimitiveProcessorTextures[0] = fProxies[0].fProxy;
+ }
}
size_t vertexSize = vertexSpec.vertexSize();
@@ -667,6 +698,11 @@
GrQuadBuffer<ColorDomainAndAA> fQuads;
sk_sp<GrColorSpaceXform> fTextureColorSpaceXform;
+ // fDynamicStateArrays and fFixedDynamicState are only filled in when this op has been
+ // prePrepared. In that case they've been allocated in the opPOD arena not in the
+ // FlushState arena.
+ GrPipeline::DynamicStateArrays* fDynamicStateArrays = nullptr;
+ GrPipeline::FixedDynamicState* fFixedDynamicState = nullptr;
unsigned fSaturate : 1;
unsigned fFilter : 2;
unsigned fAAType : 2;
diff --git a/tests/OpChainTest.cpp b/tests/OpChainTest.cpp
index 8a523b1..c662843 100644
--- a/tests/OpChainTest.cpp
+++ b/tests/OpChainTest.cpp
@@ -205,9 +205,9 @@
GrOpFlushState flushState(context->priv().getGpu(),
context->priv().resourceProvider(),
&tracker);
- GrOpsTask opsTask(sk_ref_sp(context->priv().opMemoryPool()),
- sk_ref_sp(proxy->asRenderTargetProxy()),
- context->priv().auditTrail());
+ GrOpsTask opsTask(context->priv().refOpMemoryPool(),
+ sk_ref_sp(proxy->asRenderTargetProxy()),
+ context->priv().auditTrail());
// This assumes the particular values of kRanges.
std::fill_n(result, result_width(), -1);
std::fill_n(validResult, result_width(), -1);