aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/GrDeferredProxyUploader.h
diff options
context:
space:
mode:
authorGravatar Brian Osman <brianosman@google.com>2017-09-29 09:22:17 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-09-29 13:48:54 +0000
commitfdd2cb52b781dd68f515a1eb9fe6d054a0ebc226 (patch)
treebe3eb525ce37c3df6c4150ed1e210632b3ec7b13 /src/gpu/GrDeferredProxyUploader.h
parent5fdee443e750b16dabfe3b1aa61b77207660457a (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.h120
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