Add pre-Flush callback to GrDrawingManager (take 2)
This will allow internal systems (e.g., fonts & path renderers) to create pre-flush atlases.
Depends on: https://skia-review.googlesource.com/c/8988/ (Allow GrSurfaceProxy-derived classes to use flags when instantiating)
Change-Id: I7ffc1b69defda625b6d4311e96776de4cf2abb87
Reviewed-on: https://skia-review.googlesource.com/9903
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index c0d63a3..bcb93b3 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -711,6 +711,11 @@
surfaceProps);
}
+void GrContextPriv::addPreFlushCallbackObject(sk_sp<GrPreFlushCallbackObject> preFlushCBObject) {
+ fContext->fDrawingManager->addPreFlushCallbackObject(std::move(preFlushCBObject));
+}
+
+
static inline GrPixelConfig GrPixelConfigFallback(GrPixelConfig config) {
switch (config) {
case kAlpha_8_GrPixelConfig:
diff --git a/src/gpu/GrContextPriv.h b/src/gpu/GrContextPriv.h
index c70381f..3357636 100644
--- a/src/gpu/GrContextPriv.h
+++ b/src/gpu/GrContextPriv.h
@@ -13,6 +13,7 @@
class GrSemaphore;
class GrSurfaceProxy;
+class GrPreFlushCallbackObject;
/** Class that adds methods to GrContext that are only intended for use internal to Skia.
This class is purely a privileged window into GrContext. It should never have additional
@@ -58,9 +59,15 @@
bool disableGpuYUVConversion() const { return fContext->fDisableGpuYUVConversion; }
+ /*
+ * A ref will be taken on the preFlushCallbackObject which will be removed when the
+ * context is destroyed.
+ */
+ void addPreFlushCallbackObject(sk_sp<GrPreFlushCallbackObject>);
+
private:
explicit GrContextPriv(GrContext* context) : fContext(context) {}
- GrContextPriv(const GrContextPriv&) {} // unimpl
+ GrContextPriv(const GrContextPriv&); // unimpl
GrContextPriv& operator=(const GrContextPriv&); // unimpl
// No taking addresses of this type.
diff --git a/src/gpu/GrDrawingManager.cpp b/src/gpu/GrDrawingManager.cpp
index d670e16..449cae6 100644
--- a/src/gpu/GrDrawingManager.cpp
+++ b/src/gpu/GrDrawingManager.cpp
@@ -75,10 +75,53 @@
}
fFlushing = true;
bool flushed = false;
+
+ for (int i = 0; i < fOpLists.count(); ++i) {
+ // Semi-usually the GrOpLists are already closed at this point, but sometimes Ganesh
+ // needs to flush mid-draw. In that case, the SkGpuDevice's GrOpLists won't be closed
+ // but need to be flushed anyway. Closing such GrOpLists here will mean new
+ // GrOpLists will be created to replace them if the SkGpuDevice(s) write to them again.
+ fOpLists[i]->makeClosed();
+ }
+
SkDEBUGCODE(bool result =)
SkTTopoSort<GrOpList, GrOpList::TopoSortTraits>(&fOpLists);
SkASSERT(result);
+ GrPreFlushResourceProvider preFlushProvider(this);
+
+ if (fPreFlushCBObjects.count()) {
+ // MDB TODO: pre-MDB '1' is the correct pre-allocated size. Post-MDB it will need
+ // to be larger.
+ SkAutoSTArray<1, uint32_t> opListIds(fOpLists.count());
+ for (int i = 0; i < fOpLists.count(); ++i) {
+ opListIds[i] = fOpLists[i]->uniqueID();
+ }
+
+ SkSTArray<1, sk_sp<GrRenderTargetContext>> renderTargetContexts;
+ for (int i = 0; i < fPreFlushCBObjects.count(); ++i) {
+ fPreFlushCBObjects[i]->preFlush(&preFlushProvider,
+ opListIds.get(), opListIds.count(),
+ &renderTargetContexts);
+ if (!renderTargetContexts.count()) {
+ continue; // This is fine. No atlases of this type are required for this flush
+ }
+
+ for (int j = 0; j < renderTargetContexts.count(); ++j) {
+ GrRenderTargetOpList* opList = renderTargetContexts[j]->getOpList();
+ if (!opList) {
+ continue; // Odd - but not a big deal
+ }
+ SkDEBUGCODE(opList->validateTargetsSingleRenderTarget());
+ opList->prepareOps(&fFlushState);
+ if (!opList->executeOps(&fFlushState)) {
+ continue; // This is bad
+ }
+ }
+ renderTargetContexts.reset();
+ }
+ }
+
for (int i = 0; i < fOpLists.count(); ++i) {
fOpLists[i]->prepareOps(&fFlushState);
}
@@ -145,6 +188,10 @@
}
}
+void GrDrawingManager::addPreFlushCallbackObject(sk_sp<GrPreFlushCallbackObject> preFlushCBObject) {
+ fPreFlushCBObjects.push_back(preFlushCBObject);
+}
+
GrRenderTargetOpList* GrDrawingManager::newOpList(GrRenderTargetProxy* rtp) {
SkASSERT(fContext);
diff --git a/src/gpu/GrDrawingManager.h b/src/gpu/GrDrawingManager.h
index 061e878..d914b03 100644
--- a/src/gpu/GrDrawingManager.h
+++ b/src/gpu/GrDrawingManager.h
@@ -11,9 +11,10 @@
#include "GrOpFlushState.h"
#include "GrPathRenderer.h"
#include "GrPathRendererChain.h"
+#include "GrPreFlushResourceProvider.h"
#include "GrRenderTargetOpList.h"
#include "GrResourceCache.h"
-#include "SkTDArray.h"
+#include "SkTArray.h"
#include "text/GrAtlasTextContext.h"
class GrContext;
@@ -67,6 +68,8 @@
void prepareSurfaceForExternalIO(GrSurface*);
+ void addPreFlushCallbackObject(sk_sp<GrPreFlushCallbackObject> preFlushCBObject);
+
private:
GrDrawingManager(GrContext* context,
const GrRenderTargetOpList::Options& optionsForOpLists,
@@ -92,6 +95,7 @@
void internalFlush(GrResourceCache::FlushType);
friend class GrContext; // for access to: ctor, abandon, reset & flush
+ friend class GrPreFlushResourceProvider; // this is just a shallow wrapper around this class
static const int kNumPixelGeometries = 5; // The different pixel geometries
static const int kNumDFTOptions = 2; // DFT or no DFT
@@ -115,6 +119,8 @@
bool fFlushing;
bool fIsImmediateMode;
+
+ SkTArray<sk_sp<GrPreFlushCallbackObject>> fPreFlushCBObjects;
};
#endif
diff --git a/src/gpu/GrPreFlushResourceProvider.cpp b/src/gpu/GrPreFlushResourceProvider.cpp
new file mode 100644
index 0000000..e907f39
--- /dev/null
+++ b/src/gpu/GrPreFlushResourceProvider.cpp
@@ -0,0 +1,65 @@
+/*
+ * 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 "GrPreFlushResourceProvider.h"
+
+#include "GrDrawingManager.h"
+#include "GrSurfaceProxy.h"
+
+sk_sp<GrRenderTargetContext> GrPreFlushResourceProvider::makeRenderTargetContext(
+ const GrSurfaceDesc& desc,
+ sk_sp<SkColorSpace> colorSpace,
+ const SkSurfaceProps* props) {
+ GrSurfaceDesc tmpDesc = desc;
+ tmpDesc.fFlags |= kRenderTarget_GrSurfaceFlag;
+
+ // Because this is being allocated at the start of a flush we must ensure the proxy
+ // will, when instantiated, have no pending IO.
+ // TODO: fold the kNoPendingIO_Flag into GrSurfaceFlags?
+ sk_sp<GrSurfaceProxy> proxy = GrSurfaceProxy::MakeDeferred(
+ fDrawingMgr->getContext()->resourceProvider(),
+ tmpDesc,
+ SkBackingFit::kExact,
+ SkBudgeted::kYes,
+ GrResourceProvider::kNoPendingIO_Flag);
+ if (!proxy->asRenderTargetProxy()) {
+ return nullptr;
+ }
+
+ sk_sp<GrRenderTargetOpList> opList(new GrRenderTargetOpList(
+ proxy->asRenderTargetProxy(),
+ fDrawingMgr->fContext->getGpu(),
+ fDrawingMgr->fContext->resourceProvider(),
+ fDrawingMgr->fContext->getAuditTrail(),
+ fDrawingMgr->fOptionsForOpLists));
+ proxy->setLastOpList(opList.get());
+
+ return fDrawingMgr->makeRenderTargetContext(std::move(proxy),
+ std::move(colorSpace),
+ props);
+}
+
+// TODO: we only need this entry point as long as we have to pre-allocate the atlas.
+// Remove it ASAP.
+sk_sp<GrRenderTargetContext> GrPreFlushResourceProvider::makeRenderTargetContext(
+ sk_sp<GrSurfaceProxy> proxy,
+ sk_sp<SkColorSpace> colorSpace,
+ const SkSurfaceProps* props) {
+
+ sk_sp<GrRenderTargetOpList> opList(new GrRenderTargetOpList(
+ proxy->asRenderTargetProxy(),
+ fDrawingMgr->fContext->getGpu(),
+ fDrawingMgr->fContext->resourceProvider(),
+ fDrawingMgr->fContext->getAuditTrail(),
+ fDrawingMgr->fOptionsForOpLists));
+ proxy->setLastOpList(opList.get());
+
+ return fDrawingMgr->makeRenderTargetContext(std::move(proxy),
+ std::move(colorSpace),
+ props);
+}
+
diff --git a/src/gpu/GrPreFlushResourceProvider.h b/src/gpu/GrPreFlushResourceProvider.h
new file mode 100644
index 0000000..86a299a
--- /dev/null
+++ b/src/gpu/GrPreFlushResourceProvider.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrPreFlushResourceProvider_DEFINED
+#define GrPreFlushResourceProvider_DEFINED
+
+#include "GrTypes.h"
+#include "GrNonAtomicRef.h"
+
+// These two are just for GrPreFlushCallbackObject
+#include "SkRefCnt.h"
+#include "SkTDArray.h"
+
+class GrDrawingManager;
+class GrOpList;
+class GrPreFlushResourceProvider;
+class GrRenderTargetOpList;
+class GrRenderTargetContext;
+class GrSurfaceProxy;
+
+class SkColorSpace;
+class SkSurfaceProps;
+
+/*
+ * This is the base class from which all per-flush callback objects must be derived. It
+ * provides the "preFlush" interface.
+ */
+class GrPreFlushCallbackObject : public GrNonAtomicRef<GrPreFlushCallbackObject> {
+public:
+ virtual ~GrPreFlushCallbackObject() { }
+
+ /*
+ * The preFlush callback allows subsystems (e.g., text, path renderers) to create atlases
+ * for a specific flush. All the GrOpList IDs required for the flush are passed into the
+ * callback. The callback should return the render target contexts used to render the atlases
+ * in 'results'.
+ */
+ virtual void preFlush(GrPreFlushResourceProvider*,
+ const uint32_t* opListIDs, int numOpListIDs,
+ SkTArray<sk_sp<GrRenderTargetContext>>* results) = 0;
+
+private:
+ typedef SkRefCnt INHERITED;
+};
+
+/*
+ * This class is a shallow wrapper around the drawing manager. It is passed into the
+ * preFlush callbacks and is intended to limit the functionality available to them.
+ * It should never have additional data members or virtual methods.
+ */
+class GrPreFlushResourceProvider {
+public:
+ sk_sp<GrRenderTargetContext> makeRenderTargetContext(const GrSurfaceDesc& desc,
+ sk_sp<SkColorSpace> colorSpace,
+ const SkSurfaceProps* props);
+
+ // TODO: we only need this entry point as long as we have to pre-allocate the atlas.
+ // Remove it ASAP.
+ sk_sp<GrRenderTargetContext> makeRenderTargetContext(sk_sp<GrSurfaceProxy> proxy,
+ sk_sp<SkColorSpace> colorSpace,
+ const SkSurfaceProps* props);
+
+private:
+ explicit GrPreFlushResourceProvider(GrDrawingManager* drawingMgr) : fDrawingMgr(drawingMgr) {}
+ GrPreFlushResourceProvider(const GrPreFlushResourceProvider&); // unimpl
+ GrPreFlushResourceProvider& operator=(const GrPreFlushResourceProvider&); // unimpl
+
+ GrDrawingManager* fDrawingMgr;
+
+ friend class GrDrawingManager; // to construct this type.
+};
+
+#endif
diff --git a/src/gpu/GrRenderTargetOpList.cpp b/src/gpu/GrRenderTargetOpList.cpp
index 1c98353..8d47fff 100644
--- a/src/gpu/GrRenderTargetOpList.cpp
+++ b/src/gpu/GrRenderTargetOpList.cpp
@@ -70,14 +70,25 @@
}
}
}
+
+void GrRenderTargetOpList::validateTargetsSingleRenderTarget() const {
+ GrRenderTarget* rt = nullptr;
+ for (int i = 0; i < fRecordedOps.count(); ++i) {
+ if (!fRecordedOps[i].fOp) {
+ continue; // combined forward
+ }
+
+ if (!rt) {
+ rt = fRecordedOps[i].fRenderTarget.get();
+ } else {
+ SkASSERT(fRecordedOps[i].fRenderTarget.get() == rt);
+ }
+ }
+}
#endif
void GrRenderTargetOpList::prepareOps(GrOpFlushState* flushState) {
- // Semi-usually the GrOpLists are already closed at this point, but sometimes Ganesh
- // needs to flush mid-draw. In that case, the SkGpuDevice's GrOpLists won't be closed
- // but need to be flushed anyway. Closing such GrOpLists here will mean new
- // GrOpLists will be created to replace them if the SkGpuDevice(s) write to them again.
- this->makeClosed();
+ // MDB TODO: add SkASSERT(this->isClosed());
// Loop over the ops that haven't yet been prepared.
for (int i = 0; i < fRecordedOps.count(); ++i) {
diff --git a/src/gpu/GrRenderTargetOpList.h b/src/gpu/GrRenderTargetOpList.h
index f4458b5..ab744f3 100644
--- a/src/gpu/GrRenderTargetOpList.h
+++ b/src/gpu/GrRenderTargetOpList.h
@@ -102,6 +102,8 @@
SkDEBUGCODE(void dump() const override;)
+ SkDEBUGCODE(void validateTargetsSingleRenderTarget() const;)
+
private:
friend class GrRenderTargetContextPriv; // for clearStencilClip and stencil clip state.
diff --git a/src/gpu/GrTextureOpList.cpp b/src/gpu/GrTextureOpList.cpp
index d70daa2..d396b2a 100644
--- a/src/gpu/GrTextureOpList.cpp
+++ b/src/gpu/GrTextureOpList.cpp
@@ -45,11 +45,7 @@
#endif
void GrTextureOpList::prepareOps(GrOpFlushState* flushState) {
- // Semi-usually the GrOpLists are already closed at this point, but sometimes Ganesh
- // needs to flush mid-draw. In that case, the SkGpuDevice's GrOpLists won't be closed
- // but need to be flushed anyway. Closing such GrOpLists here will mean new
- // GrOpLists will be created to replace them if the SkGpuDevice(s) write to them again.
- this->makeClosed();
+ // MDB TODO: add SkASSERT(this->isClosed());
// Loop over the ops that haven't yet generated their geometry
for (int i = 0; i < fRecordedOps.count(); ++i) {
diff --git a/src/gpu/ops/GrTestMeshDrawOp.h b/src/gpu/ops/GrTestMeshDrawOp.h
index d78d3e9..039f88d 100644
--- a/src/gpu/ops/GrTestMeshDrawOp.h
+++ b/src/gpu/ops/GrTestMeshDrawOp.h
@@ -19,7 +19,7 @@
*/
class GrTestMeshDrawOp : public GrMeshDrawOp {
public:
- virtual const char* name() const override = 0;
+ const char* name() const override = 0;
protected:
GrTestMeshDrawOp(uint32_t classID, const SkRect& bounds, GrColor color)