Revert "Make threaded proxy generation MDB-friendly, and defer instantiation"

This reverts commit 742f3d02a1.

Reason for revert: Aaah!

Original change's description:
> Make threaded proxy generation MDB-friendly, and defer instantiation
> 
> Replaces GrPrepareCallback with GrDeferredProxyUploader, stored directly
> on GrTextureProxy. Op lists now store a list of referenced proxies that
> are being generated by worker threads. At flush time, iterate over those
> proxies, and invoke their uploader.
> 
> Lifetime of the uploader object is now tied to the proxy, but the ASAP
> upload function will free the proxy's uploader, if it's called.
> 
> Bug: skia:
> Change-Id: Ieb2c6a805d19990012839a8e103c3ca5b8d3dfc6
> Reviewed-on: https://skia-review.googlesource.com/49904
> Commit-Queue: Brian Osman <brianosman@google.com>
> Reviewed-by: Robert Phillips <robertphillips@google.com>

TBR=egdaniel@google.com,robertphillips@google.com,brianosman@google.com

Change-Id: I8f76a67044dc4159f903097d8b1ef19ffb48c730
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: skia:
Reviewed-on: https://skia-review.googlesource.com/52760
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
This commit is contained in:
Brian Osman 2017-09-28 15:14:28 +00:00 committed by Skia Commit-Bot
parent 742f3d02a1
commit 837c6c7c0c
11 changed files with 130 additions and 188 deletions

View File

@ -72,7 +72,6 @@ skia_gpu_sources = [
"$_src/gpu/GrCoordTransform.h",
"$_src/gpu/GrDefaultGeoProcFactory.cpp",
"$_src/gpu/GrDefaultGeoProcFactory.h",
"$_src/gpu/GrDeferredProxyUploader.h",
"$_src/gpu/GrDistanceFieldGenFromVector.cpp",
"$_src/gpu/GrDistanceFieldGenFromVector.h",
"$_src/gpu/GrDrawingManager.cpp",
@ -128,6 +127,7 @@ skia_gpu_sources = [
"$_src/gpu/GrOnFlushResourceProvider.h",
"$_src/gpu/GrPipeline.cpp",
"$_src/gpu/GrPipeline.h",
"$_src/gpu/GrPrepareCallback.h",
"$_src/gpu/GrPrimitiveProcessor.cpp",
"$_src/gpu/GrPrimitiveProcessor.h",
"$_src/gpu/GrProcessorSet.cpp",

View File

@ -12,7 +12,6 @@
#include "GrSurfaceProxy.h"
class GrCaps;
class GrDeferredProxyUploader;
class GrResourceCache;
class GrResourceProvider;
class GrTextureOpList;
@ -70,7 +69,6 @@ public:
protected:
friend class GrSurfaceProxy; // for ctors
friend class GrTextureProxyPriv;
// Deferred version
GrTextureProxy(const GrSurfaceDesc& srcDesc, SkBackingFit, SkBudgeted,
@ -91,11 +89,6 @@ private:
GrUniqueKey fUniqueKey;
GrResourceCache* fCache; // only set when fUniqueKey is valid
// Only used for proxies whose contents are being prepared on a worker thread. This object
// stores the texture data, allowing the proxy to remain uninstantiated until flush. At that
// point, the proxy is instantiated, and this data is used to perform an ASAP upload.
std::unique_ptr<GrDeferredProxyUploader> fDeferredUploader;
size_t onUninstantiatedGpuMemorySize() const override;
// Methods made available via GrTextureProxy::CacheAccess

View File

@ -9,11 +9,11 @@
#include "GrAppliedClip.h"
#include "GrContextPriv.h"
#include "GrDeferredProxyUploader.h"
#include "GrDrawingManager.h"
#include "GrRenderTargetContextPriv.h"
#include "GrFixedClip.h"
#include "GrGpuResourcePriv.h"
#include "GrPrepareCallback.h"
#include "GrResourceProvider.h"
#include "GrStencilAttachment.h"
#include "GrSWMaskHelper.h"
@ -428,7 +428,7 @@ sk_sp<GrTextureProxy> GrClipStackClip::createAlphaClipMask(GrContext* context,
namespace {
/**
* Payload class for use with GrTDeferredProxyUploader. The clip mask code renders multiple
* Payload class for use with GrMaskUploaderPrepareCallback. The clip mask code renders multiple
* elements, each storing their own AA setting (and already transformed into device space). This
* stores all of the information needed by the worker thread to draw all clip elements (see below,
* in createSoftwareClipMask).
@ -526,8 +526,15 @@ sk_sp<GrTextureProxy> GrClipStackClip::createSoftwareClipMask(
proxy = GrSurfaceProxy::MakeDeferred(context->resourceProvider(), desc,
SkBackingFit::kApprox, SkBudgeted::kYes);
auto uploader = skstd::make_unique<GrTDeferredProxyUploader<ClipMaskData>>(reducedClip);
GrTDeferredProxyUploader<ClipMaskData>* uploaderRaw = uploader.get();
// TODO: I believe the assignUniqueKeyToProxy below used to instantiate the proxy before
// the draw that used the result was being flushed, so the upload was succeeding. With
// assignUniqueKeyToProxy no longer forcing an instantiation it will have to happen
// explicitly elsewhere.
proxy->instantiate(context->resourceProvider());
auto uploader = skstd::make_unique<GrMaskUploaderPrepareCallback<ClipMaskData>>(
proxy, reducedClip);
GrMaskUploaderPrepareCallback<ClipMaskData>* uploaderRaw = uploader.get();
auto drawAndUploadMask = [uploaderRaw, maskSpaceIBounds] {
TRACE_EVENT0("skia", "Threaded SW Clip Mask Render");
GrSWMaskHelper helper(uploaderRaw->getPixels());
@ -538,11 +545,11 @@ sk_sp<GrTextureProxy> GrClipStackClip::createSoftwareClipMask(
} else {
SkDEBUGFAIL("Unable to allocate SW clip mask.");
}
uploaderRaw->signalAndFreeData();
uploaderRaw->getSemaphore()->signal();
};
taskGroup->add(std::move(drawAndUploadMask));
proxy->texPriv().setDeferredUploader(std::move(uploader));
renderTargetContext->getOpList()->addPrepareCallback(std::move(uploader));
} else {
GrSWMaskHelper helper;
if (!helper.init(maskSpaceIBounds)) {

View File

@ -1,108 +0,0 @@
/*
* 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 GrDeferredProxyUploader_DEFINED
#define GrDeferredProxyUploader_DEFINED
#include "SkAutoPixmapStorage.h"
#include "SkMakeUnique.h"
#include "SkRefCnt.h"
#include "SkSemaphore.h"
#include "GrOpFlushState.h"
#include "GrTextureProxyPriv.h"
/**
* GrDeferredProxyUploader assists with threaded generation of textures. Currently used by both
* software clip masks, and the software path renderer. The calling code typically needs to store
* some additional data (T) for use on the worker thread. GrTDeferredProxyUploader allows storing
* such data. The common flow is:
*
* 1) A GrTDeferredProxyUploader is created, with some payload (eg an SkPath to draw).
* The uploader is owned by the proxy that it's going to populate.
* 2) A task is created with a pointer to the uploader. A worker thread executes that task, using
* the payload data to allocate and fill in the fPixels pixmap.
* 3) The worker thread calls signalAndFreeData(), which notifies the main thread that the pixmap
* is ready, and then deletes the payload data (which is no longer needed).
* 4) In parallel to 2-3, on the main thread... Some op is created that refers to the proxy. When
* that op is added to an op list, the op list retains a pointer to the "deferred" proxies.
* 5) At flush time, the op list ensures that the deferred proxies are instantiated, then calls
* scheduleUpload on those proxies, which calls scheduleUpload on the uploader (below).
* 6) scheduleUpload defers the upload even further, by adding an ASAPUpload to the flush.
* 7) When the ASAP upload happens, we wait to make sure that the pixels are marked ready
* (from step #3 on the worker thread). Then we perform the actual upload to the texture.
* Finally, we call resetDeferredUploader, which deletes the uploader object, causing fPixels
* to be freed.
*/
class GrDeferredProxyUploader : public SkNoncopyable {
public:
GrDeferredProxyUploader() : fScheduledUpload(false), fWaited(false) {}
virtual ~GrDeferredProxyUploader() {
if (!fWaited) {
// This can happen if our owning proxy fails to instantiate
fPixelsReady.wait();
}
}
void scheduleUpload(GrOpFlushState* flushState, GrTextureProxy* proxy) {
if (fScheduledUpload) {
// Multiple references to the owning proxy may have caused us to already execute
return;
}
auto uploadMask = [this, proxy](GrDrawOp::WritePixelsFn& writePixelsFn) {
this->fPixelsReady.wait();
this->fWaited = true;
// If the worker thread was unable to allocate pixels, this check will fail, and we'll
// end up drawing with an uninitialized mask texture, but at least we won't crash.
if (this->fPixels.addr()) {
writePixelsFn(proxy, 0, 0, this->fPixels.width(), this->fPixels.height(),
proxy->config(), this->fPixels.addr(), this->fPixels.rowBytes());
}
// Upload has finished, so tell the proxy to release this GrDeferredProxyUploader
proxy->texPriv().resetDeferredUploader();
};
flushState->addASAPUpload(std::move(uploadMask));
fScheduledUpload = true;
}
void signalAndFreeData() {
fPixelsReady.signal();
this->freeData();
}
SkAutoPixmapStorage* getPixels() { return &fPixels; }
private:
virtual void freeData() {}
SkAutoPixmapStorage fPixels;
SkSemaphore fPixelsReady;
bool fScheduledUpload;
bool fWaited;
};
template <typename T>
class GrTDeferredProxyUploader : public GrDeferredProxyUploader {
public:
template <typename... Args>
GrTDeferredProxyUploader(Args&&... args)
: fData(skstd::make_unique<T>(std::forward<Args>(args)...)) {
}
T& data() { return *fData; }
private:
void freeData() override {
fData.reset();
}
std::unique_ptr<T> fData;
};
#endif

View File

@ -195,8 +195,6 @@ GrSemaphoresSubmitted GrDrawingManager::internalFlush(GrSurfaceProxy*,
continue;
}
// Instantiate all deferred proxies (being built on worker threads) so we can upload them
fOpLists[i]->instantiateDeferredProxies(fContext->resourceProvider());
fOpLists[i]->prepare(&fFlushState);
}

View File

@ -8,9 +8,8 @@
#include "GrOpList.h"
#include "GrContext.h"
#include "GrDeferredProxyUploader.h"
#include "GrPrepareCallback.h"
#include "GrSurfaceProxy.h"
#include "GrTextureProxyPriv.h"
#include "SkAtomics.h"
@ -58,19 +57,17 @@ void GrOpList::reset() {
}
fTarget.reset();
fDeferredProxies.reset();
fPrepareCallbacks.reset();
fAuditTrail = nullptr;
}
void GrOpList::instantiateDeferredProxies(GrResourceProvider* resourceProvider) {
for (int i = 0; i < fDeferredProxies.count(); ++i) {
fDeferredProxies[i]->instantiate(resourceProvider);
}
void GrOpList::addPrepareCallback(std::unique_ptr<GrPrepareCallback> callback) {
fPrepareCallbacks.push_back(std::move(callback));
}
void GrOpList::prepare(GrOpFlushState* flushState) {
for (int i = 0; i < fDeferredProxies.count(); ++i) {
fDeferredProxies[i]->texPriv().scheduleUpload(flushState);
for (int i = 0; i < fPrepareCallbacks.count(); ++i) {
(*fPrepareCallbacks[i])(flushState);
}
this->onPrepare(flushState);
@ -103,12 +100,6 @@ void GrOpList::addDependency(GrSurfaceProxy* dependedOn, const GrCaps& caps) {
opList->makeClosed(caps);
}
}
if (GrTextureProxy* textureProxy = dependedOn->asTextureProxy()) {
if (textureProxy->texPriv().isDeferred()) {
fDeferredProxies.push_back(textureProxy);
}
}
}
#ifdef SK_DEBUG

View File

@ -23,6 +23,7 @@
class GrAuditTrail;
class GrCaps;
class GrOpFlushState;
class GrPrepareCallback;
class GrRenderTargetOpList;
class GrResourceAllocator;
class GrResourceProvider;
@ -38,10 +39,8 @@ public:
GrOpList(GrResourceProvider*, GrSurfaceProxy*, GrAuditTrail*);
~GrOpList() override;
// These four methods are invoked at flush time
// These three methods are invoked at flush time
bool instantiate(GrResourceProvider* resourceProvider);
// Instantiates any "threaded" texture proxies that are being prepared elsewhere
void instantiateDeferredProxies(GrResourceProvider* resourceProvider);
void prepare(GrOpFlushState* flushState);
bool execute(GrOpFlushState* flushState) { return this->onExecute(flushState); }
@ -60,6 +59,8 @@ public:
virtual void reset();
void addPrepareCallback(std::unique_ptr<GrPrepareCallback> callback);
// TODO: in an MDB world, where the OpLists don't allocate GPU resources, it seems like
// these could go away
virtual void abandonGpuResources() = 0;
@ -180,8 +181,8 @@ private:
// 'this' GrOpList relies on the output of the GrOpLists in 'fDependencies'
SkSTArray<1, GrOpList*, true> fDependencies;
// List of texture proxies whose contents are being prepared on a worker thread
SkTArray<GrTextureProxy*, true> fDeferredProxies;
// These are used rarely, most clients never produce any
SkTArray<std::unique_ptr<GrPrepareCallback>> fPrepareCallbacks;
typedef SkRefCnt INHERITED;
};

View File

@ -0,0 +1,88 @@
/*
* 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 GrPrepareCallback_DEFINED
#define GrPrepareCallback_DEFINED
#include "SkAutoPixmapStorage.h"
#include "SkRefCnt.h"
#include "SkSemaphore.h"
#include "GrOpFlushState.h"
class GrTextureProxy;
/**
* An instance of any class derived from GrPrepareCallback can be passed to
* GrOpList::addPrepareCallback. At flush time, all callbacks (on op lists being flushed) will be
* invoked (via operator()). Note that the callback receives the GrOpFlushState, so it can trigger
* ASAP uploads (similar to an Op's onPrepare).
*
* All callbacks are invoked at the beginning of flush, before prepare is called.
*/
class GrPrepareCallback : SkNoncopyable {
public:
virtual ~GrPrepareCallback() {}
virtual void operator()(GrOpFlushState*) = 0;
};
/**
* GrMaskUploaderPrepareCallback assists with threaded generation of mask textures. Currently used
* by both software clip masks, and the software path renderer. The calling code typically needs
* to store some additional data (T) for use on the worker thread. That payload is accessed by the
* worker thread to populate the mask in fPixels (using GrSWMaskHelper). This callback's operator()
* handles scheduling the texture upload at flush time.
*/
template <typename T>
class GrMaskUploaderPrepareCallback : public GrPrepareCallback {
public:
template <typename... Args>
GrMaskUploaderPrepareCallback(sk_sp<GrTextureProxy> proxy, Args&&... args)
: fProxy(std::move(proxy))
, fWaited(false)
, fData(std::forward<Args>(args)...) {}
~GrMaskUploaderPrepareCallback() override {
if (!fWaited) {
// This can happen if our owning op list fails to instantiate (so it never prepares)
fPixelsReady.wait();
}
}
void operator()(GrOpFlushState* flushState) override {
auto uploadMask = [this](GrDrawOp::WritePixelsFn& writePixelsFn) {
this->fPixelsReady.wait();
this->fWaited = true;
// If the worker thread was unable to allocate pixels, this check will fail, and we'll
// end up drawing with an uninitialized mask texture, but at least we won't crash.
if (this->fPixels.addr()) {
writePixelsFn(this->fProxy.get(), 0, 0,
this->fPixels.width(), this->fPixels.height(),
kAlpha_8_GrPixelConfig,
this->fPixels.addr(), this->fPixels.rowBytes());
// Free this memory immediately, so it can be recycled. This avoids memory pressure
// when there is a large amount of threaded work still running during flush.
this->fPixels.reset();
}
};
flushState->addASAPUpload(std::move(uploadMask));
}
SkAutoPixmapStorage* getPixels() { return &fPixels; }
SkSemaphore* getSemaphore() { return &fPixelsReady; }
T& data() { return fData; }
private:
sk_sp<GrTextureProxy> fProxy;
SkAutoPixmapStorage fPixels;
SkSemaphore fPixelsReady;
bool fWaited;
T fData;
};
#endif

View File

@ -9,10 +9,10 @@
#include "GrAuditTrail.h"
#include "GrClip.h"
#include "GrContextPriv.h"
#include "GrDeferredProxyUploader.h"
#include "GrGpuResourcePriv.h"
#include "GrOpFlushState.h"
#include "GrOpList.h"
#include "GrPrepareCallback.h"
#include "GrResourceProvider.h"
#include "GrSWMaskHelper.h"
#include "SkMakeUnique.h"
@ -175,7 +175,7 @@ static sk_sp<GrTextureProxy> make_deferred_mask_texture_proxy(GrContext* context
namespace {
/**
* Payload class for use with GrTDeferredProxyUploader. The software path renderer only draws
* Payload class for use with GrMaskUploaderPrepareCallback. The software path renderer only draws
* a single path into the mask texture. This stores all of the information needed by the worker
* thread's call to drawShape (see below, in onDrawPath).
*/
@ -317,9 +317,15 @@ bool GrSoftwarePathRenderer::onDrawPath(const DrawPathArgs& args) {
return false;
}
auto uploader = skstd::make_unique<GrTDeferredProxyUploader<SoftwarePathData>>(
*boundsForMask, *args.fViewMatrix, *args.fShape, aa);
GrTDeferredProxyUploader<SoftwarePathData>* uploaderRaw = uploader.get();
// TODO: I believe the assignUniqueKeyToProxy below used to instantiate the proxy before
// before the draw that used the result was being flushed, so the upload was succeeding.
// With assignUniqueKeyToProxy no longer forcing an instantiation it will have to happen
// explicitly elsewhere.
proxy->instantiate(fResourceProvider);
auto uploader = skstd::make_unique<GrMaskUploaderPrepareCallback<SoftwarePathData>>(
proxy, *boundsForMask, *args.fViewMatrix, *args.fShape, aa);
GrMaskUploaderPrepareCallback<SoftwarePathData>* uploaderRaw = uploader.get();
auto drawAndUploadMask = [uploaderRaw] {
TRACE_EVENT0("skia", "Threaded SW Mask Render");
@ -331,10 +337,10 @@ bool GrSoftwarePathRenderer::onDrawPath(const DrawPathArgs& args) {
} else {
SkDEBUGFAIL("Unable to allocate SW mask.");
}
uploaderRaw->signalAndFreeData();
uploaderRaw->getSemaphore()->signal();
};
taskGroup->add(std::move(drawAndUploadMask));
proxy->texPriv().setDeferredUploader(std::move(uploader));
args.fRenderTargetContext->getOpList()->addPrepareCallback(std::move(uploader));
} else {
GrSWMaskHelper helper;
if (!helper.init(*boundsForMask)) {

View File

@ -6,11 +6,10 @@
*/
#include "GrTextureProxy.h"
#include "GrTextureProxyPriv.h"
#include "GrContext.h"
#include "GrDeferredProxyUploader.h"
#include "GrResourceCache.h"
#include "GrTexturePriv.h"
GrTextureProxy::GrTextureProxy(const GrSurfaceDesc& srcDesc, SkBackingFit fit, SkBudgeted budgeted,
@ -18,8 +17,7 @@ GrTextureProxy::GrTextureProxy(const GrSurfaceDesc& srcDesc, SkBackingFit fit, S
: INHERITED(srcDesc, fit, budgeted, flags)
, fIsMipMapped(false)
, fMipColorMode(SkDestinationSurfaceColorMode::kLegacy)
, fCache(nullptr)
, fDeferredUploader(nullptr) {
, fCache(nullptr) {
SkASSERT(!srcData); // currently handled in Make()
}
@ -27,8 +25,7 @@ GrTextureProxy::GrTextureProxy(sk_sp<GrSurface> surf, GrSurfaceOrigin origin)
: INHERITED(std::move(surf), origin, SkBackingFit::kExact)
, fIsMipMapped(fTarget->asTexture()->texturePriv().hasMipMaps())
, fMipColorMode(fTarget->asTexture()->texturePriv().mipColorMode())
, fCache(nullptr)
, fDeferredUploader(nullptr) {
, fCache(nullptr) {
if (fTarget->getUniqueKey().isValid()) {
fCache = fTarget->asTexture()->getContext()->getResourceCache();
fCache->adoptUniqueKeyFromSurface(this, fTarget);
@ -70,25 +67,6 @@ sk_sp<GrSurface> GrTextureProxy::createSurface(GrResourceProvider* resourceProvi
return surface;
}
void GrTextureProxyPriv::setDeferredUploader(std::unique_ptr<GrDeferredProxyUploader> uploader) {
SkASSERT(!fTextureProxy->fDeferredUploader);
fTextureProxy->fDeferredUploader = std::move(uploader);
}
void GrTextureProxyPriv::scheduleUpload(GrOpFlushState* flushState) {
SkASSERT(fTextureProxy->fDeferredUploader);
// Instantiate might have failed
if (fTextureProxy->fTarget) {
fTextureProxy->fDeferredUploader->scheduleUpload(flushState, fTextureProxy);
}
}
void GrTextureProxyPriv::resetDeferredUploader() {
SkASSERT(fTextureProxy->fDeferredUploader);
fTextureProxy->fDeferredUploader.reset();
}
// This method parallels the highest_filter_mode functions in GrGLTexture & GrVkTexture.
GrSamplerState::Filter GrTextureProxy::highestFilterMode() const {
if (fTarget) {

View File

@ -10,23 +10,11 @@
#include "GrTextureProxy.h"
class GrDeferredProxyUploader;
class GrOpFlushState;
/**
* This class hides the more specialized capabilities of GrTextureProxy.
*/
class GrTextureProxyPriv {
public:
// Attach a deferred uploader to the proxy. Holds data being prepared by a worker thread.
void setDeferredUploader(std::unique_ptr<GrDeferredProxyUploader>);
bool isDeferred() const { return SkToBool(fTextureProxy->fDeferredUploader.get()); }
// For a deferred proxy (one that has a deferred uploader attached), this schedules an ASAP
// upload of that data to the instantiated texture.
void scheduleUpload(GrOpFlushState*);
// Clears any deferred uploader object on the proxy. Used to free the CPU data after the
// contents have been uploaded.
void resetDeferredUploader();
private:
explicit GrTextureProxyPriv(GrTextureProxy* textureProxy) : fTextureProxy(textureProxy) {}