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