diff options
author | 2017-09-29 09:22:17 -0400 | |
---|---|---|
committer | 2017-09-29 13:48:54 +0000 | |
commit | fdd2cb52b781dd68f515a1eb9fe6d054a0ebc226 (patch) | |
tree | be3eb525ce37c3df6c4150ed1e210632b3ec7b13 /src/gpu/GrDeferredProxyUploader.h | |
parent | 5fdee443e750b16dabfe3b1aa61b77207660457a (diff) |
Revert "Revert "Revert "Revert "Make threaded proxy generation MDB-friendly, and defer instantiation""""
This reverts commit 9f8d4d36b514ffe3cc3a4a48900e3dc1fecb2a96.
Bug: skia:
Change-Id: I8d7c1df24d8b13b94404f3d9ba69a1ab55ee00c0
Reviewed-on: https://skia-review.googlesource.com/52920
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
Diffstat (limited to 'src/gpu/GrDeferredProxyUploader.h')
-rw-r--r-- | src/gpu/GrDeferredProxyUploader.h | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/src/gpu/GrDeferredProxyUploader.h b/src/gpu/GrDeferredProxyUploader.h new file mode 100644 index 0000000000..b9c18857b8 --- /dev/null +++ b/src/gpu/GrDeferredProxyUploader.h @@ -0,0 +1,120 @@ +/* + * 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() { + // In normal usage (i.e., through GrTDeferredProxyUploader) this will be redundant + this->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->wait(); + // 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() { + this->freeData(); + fPixelsReady.signal(); + } + + SkAutoPixmapStorage* getPixels() { return &fPixels; } + +protected: + void wait() { + if (!fWaited) { + fPixelsReady.wait(); + fWaited = true; + } + } + +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)...)) { + } + + ~GrTDeferredProxyUploader() override { + // We need to wait here, so that we don't free fData before the worker thread is done + // with it. (This happens if the proxy is deleted early due to a full clear or failure + // of an op list to instantiate). + this->wait(); + } + + T& data() { return *fData; } + +private: + void freeData() override { + fData.reset(); + } + + std::unique_ptr<T> fData; +}; + +#endif |