blob: 589fa33dc9c3148a41ba241245f88c26861e52a5 [file] [log] [blame]
Brian Osman099fa0f2017-10-02 16:38:32 -04001/*
2 * Copyright 2017 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef GrDeferredProxyUploader_DEFINED
9#define GrDeferredProxyUploader_DEFINED
10
11#include "SkAutoPixmapStorage.h"
12#include "SkMakeUnique.h"
13#include "SkRefCnt.h"
14#include "SkSemaphore.h"
15
16#include "GrOpFlushState.h"
17#include "GrTextureProxyPriv.h"
18
19/**
20 * GrDeferredProxyUploader assists with threaded generation of textures. Currently used by both
21 * software clip masks, and the software path renderer. The calling code typically needs to store
22 * some additional data (T) for use on the worker thread. GrTDeferredProxyUploader allows storing
23 * such data. The common flow is:
24 *
25 * 1) A GrTDeferredProxyUploader is created, with some payload (eg an SkPath to draw).
26 * The uploader is owned by the proxy that it's going to populate.
27 * 2) A task is created with a pointer to the uploader. A worker thread executes that task, using
28 * the payload data to allocate and fill in the fPixels pixmap.
29 * 3) The worker thread calls signalAndFreeData(), which notifies the main thread that the pixmap
30 * is ready, and then deletes the payload data (which is no longer needed).
31 * 4) In parallel to 2-3, on the main thread... Some op is created that refers to the proxy. When
32 * that op is added to an op list, the op list retains a pointer to the "deferred" proxies.
33 * 5) At flush time, the op list ensures that the deferred proxies are instantiated, then calls
34 * scheduleUpload on those proxies, which calls scheduleUpload on the uploader (below).
35 * 6) scheduleUpload defers the upload even further, by adding an ASAPUpload to the flush.
36 * 7) When the ASAP upload happens, we wait to make sure that the pixels are marked ready
37 * (from step #3 on the worker thread). Then we perform the actual upload to the texture.
38 * Finally, we call resetDeferredUploader, which deletes the uploader object, causing fPixels
39 * to be freed.
40 */
41class GrDeferredProxyUploader : public SkNoncopyable {
42public:
43 GrDeferredProxyUploader() : fScheduledUpload(false), fWaited(false) {}
44
45 virtual ~GrDeferredProxyUploader() {
46 // In normal usage (i.e., through GrTDeferredProxyUploader) this will be redundant
47 this->wait();
48 }
49
50 void scheduleUpload(GrOpFlushState* flushState, GrTextureProxy* proxy) {
51 if (fScheduledUpload) {
52 // Multiple references to the owning proxy may have caused us to already execute
53 return;
54 }
55
Brian Salomon943ed792017-10-30 09:37:55 -040056 auto uploadMask = [this, proxy](GrDeferredTextureUploadWritePixelsFn& writePixelsFn) {
Brian Osman099fa0f2017-10-02 16:38:32 -040057 this->wait();
Brian Salomonc320b152018-02-20 14:05:36 -050058 GrColorType pixelColorType = SkColorTypeToGrColorType(this->fPixels.info().colorType());
Brian Osman099fa0f2017-10-02 16:38:32 -040059 // If the worker thread was unable to allocate pixels, this check will fail, and we'll
60 // end up drawing with an uninitialized mask texture, but at least we won't crash.
61 if (this->fPixels.addr()) {
62 writePixelsFn(proxy, 0, 0, this->fPixels.width(), this->fPixels.height(),
Brian Salomonc320b152018-02-20 14:05:36 -050063 pixelColorType, this->fPixels.addr(), this->fPixels.rowBytes());
Brian Osman099fa0f2017-10-02 16:38:32 -040064 }
65 // Upload has finished, so tell the proxy to release this GrDeferredProxyUploader
66 proxy->texPriv().resetDeferredUploader();
67 };
68 flushState->addASAPUpload(std::move(uploadMask));
69 fScheduledUpload = true;
70 }
71
72 void signalAndFreeData() {
73 this->freeData();
74 fPixelsReady.signal();
75 }
76
77 SkAutoPixmapStorage* getPixels() { return &fPixels; }
78
79protected:
80 void wait() {
81 if (!fWaited) {
82 fPixelsReady.wait();
83 fWaited = true;
84 }
85 }
86
87private:
88 virtual void freeData() {}
89
90 SkAutoPixmapStorage fPixels;
91 SkSemaphore fPixelsReady;
92 bool fScheduledUpload;
93 bool fWaited;
94};
95
96template <typename T>
97class GrTDeferredProxyUploader : public GrDeferredProxyUploader {
98public:
99 template <typename... Args>
100 GrTDeferredProxyUploader(Args&&... args)
101 : fData(skstd::make_unique<T>(std::forward<Args>(args)...)) {
102 }
103
104 ~GrTDeferredProxyUploader() override {
105 // We need to wait here, so that we don't free fData before the worker thread is done
106 // with it. (This happens if the proxy is deleted early due to a full clear or failure
107 // of an op list to instantiate).
108 this->wait();
109 }
110
111 T& data() { return *fData; }
112
113private:
114 void freeData() override {
115 fData.reset();
116 }
117
118 std::unique_ptr<T> fData;
119};
120
121#endif