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 "include/core/SkRefCnt.h" 12 #include "include/private/SkSemaphore.h" 13 #include "src/core/SkAutoPixmapStorage.h" 14 #include "src/core/SkMakeUnique.h" 15 16 #include "src/gpu/GrOpFlushState.h" 17 #include "src/gpu/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: GrDeferredProxyUploader()43 GrDeferredProxyUploader() : fScheduledUpload(false), fWaited(false) {} 44 ~GrDeferredProxyUploader()45 virtual ~GrDeferredProxyUploader() { 46 // In normal usage (i.e., through GrTDeferredProxyUploader) this will be redundant 47 this->wait(); 48 } 49 scheduleUpload(GrOpFlushState * flushState,GrTextureProxy * proxy)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 signalAndFreeData()72 void signalAndFreeData() { 73 this->freeData(); 74 fPixelsReady.signal(); 75 } 76 getPixels()77 SkAutoPixmapStorage* getPixels() { return &fPixels; } 78 79 protected: wait()80 void wait() { 81 if (!fWaited) { 82 fPixelsReady.wait(); 83 fWaited = true; 84 } 85 } 86 87 private: freeData()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> GrTDeferredProxyUploader(Args &&...args)100 GrTDeferredProxyUploader(Args&&... args) 101 : fData(skstd::make_unique<T>(std::forward<Args>(args)...)) { 102 } 103 ~GrTDeferredProxyUploader()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 data()111 T& data() { return *fData; } 112 113 private: freeData()114 void freeData() override { 115 fData.reset(); 116 } 117 118 std::unique_ptr<T> fData; 119 }; 120 121 #endif 122