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