Home | History | Annotate | Download | only in gpu
      1 /*
      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  */
     41 class GrDeferredProxyUploader : public SkNoncopyable {
     42 public:
     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 
     56         auto uploadMask = [this, proxy](GrDeferredTextureUploadWritePixelsFn& writePixelsFn) {
     57             this->wait();
     58             GrColorType pixelColorType = SkColorTypeToGrColorType(this->fPixels.info().colorType());
     59             // 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(),
     63                               pixelColorType, this->fPixels.addr(), this->fPixels.rowBytes());
     64             }
     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 
     79 protected:
     80     void wait() {
     81         if (!fWaited) {
     82             fPixelsReady.wait();
     83             fWaited = true;
     84         }
     85     }
     86 
     87 private:
     88     virtual void freeData() {}
     89 
     90     SkAutoPixmapStorage fPixels;
     91     SkSemaphore fPixelsReady;
     92     bool fScheduledUpload;
     93     bool fWaited;
     94 };
     95 
     96 template <typename T>
     97 class GrTDeferredProxyUploader : public GrDeferredProxyUploader {
     98 public:
     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 
    113 private:
    114     void freeData() override {
    115         fData.reset();
    116     }
    117 
    118     std::unique_ptr<T> fData;
    119 };
    120 
    121 #endif
    122