Brian Osman | 5d03474 | 2017-09-11 13:38:55 -0400 | [diff] [blame] | 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 GrPrepareCallback_DEFINED |
| 9 | #define GrPrepareCallback_DEFINED |
| 10 | |
| 11 | #include "SkAutoPixmapStorage.h" |
| 12 | #include "SkRefCnt.h" |
| 13 | #include "SkSemaphore.h" |
| 14 | |
| 15 | #include "GrOpFlushState.h" |
| 16 | |
| 17 | class GrTextureProxy; |
| 18 | |
| 19 | /** |
| 20 | * An instance of any class derived from GrPrepareCallback can be passed to |
| 21 | * GrOpList::addPrepareCallback. At flush time, all callbacks (on op lists being flushed) will be |
| 22 | * invoked (via operator()). Note that the callback receives the GrOpFlushState, so it can trigger |
| 23 | * ASAP uploads (similar to an Op's onPrepare). |
| 24 | * |
| 25 | * All callbacks are invoked at the beginning of flush, before prepare is called. |
| 26 | */ |
| 27 | class GrPrepareCallback : SkNoncopyable { |
| 28 | public: |
| 29 | virtual ~GrPrepareCallback() {} |
| 30 | virtual void operator()(GrOpFlushState*) = 0; |
| 31 | }; |
| 32 | |
| 33 | /** |
| 34 | * GrMaskUploaderPrepareCallback assists with threaded generation of mask textures. Currently used |
| 35 | * by both software clip masks, and the software path renderer. The calling code typically needs |
| 36 | * to store some additional data (T) for use on the worker thread. That payload is accessed by the |
| 37 | * worker thread to populate the mask in fPixels (using GrSWMaskHelper). This callback's operator() |
| 38 | * handles scheduling the texture upload at flush time. |
| 39 | */ |
| 40 | template <typename T> |
| 41 | class GrMaskUploaderPrepareCallback : public GrPrepareCallback { |
| 42 | public: |
| 43 | template <typename... Args> |
| 44 | GrMaskUploaderPrepareCallback(sk_sp<GrTextureProxy> proxy, Args&&... args) |
| 45 | : fProxy(std::move(proxy)) |
| 46 | , fWaited(false) |
| 47 | , fData(std::forward<Args>(args)...) {} |
| 48 | |
| 49 | ~GrMaskUploaderPrepareCallback() override { |
| 50 | if (!fWaited) { |
| 51 | // This can happen if our owning op list fails to instantiate (so it never prepares) |
| 52 | fPixelsReady.wait(); |
| 53 | } |
| 54 | } |
| 55 | |
| 56 | void operator()(GrOpFlushState* flushState) override { |
| 57 | auto uploadMask = [this](GrDrawOp::WritePixelsFn& writePixelsFn) { |
| 58 | this->fPixelsReady.wait(); |
| 59 | this->fWaited = true; |
| 60 | // If the worker thread was unable to allocate pixels, this check will fail, and we'll |
| 61 | // end up drawing with an uninitialized mask texture, but at least we won't crash. |
| 62 | if (this->fPixels.addr()) { |
| 63 | writePixelsFn(this->fProxy.get(), 0, 0, |
| 64 | this->fPixels.width(), this->fPixels.height(), |
| 65 | kAlpha_8_GrPixelConfig, |
| 66 | this->fPixels.addr(), this->fPixels.rowBytes()); |
| 67 | // Free this memory immediately, so it can be recycled. This avoids memory pressure |
| 68 | // when there is a large amount of threaded work still running during flush. |
| 69 | this->fPixels.reset(); |
| 70 | } |
| 71 | }; |
| 72 | flushState->addASAPUpload(std::move(uploadMask)); |
| 73 | } |
| 74 | |
| 75 | SkAutoPixmapStorage* getPixels() { return &fPixels; } |
| 76 | SkSemaphore* getSemaphore() { return &fPixelsReady; } |
| 77 | T& data() { return fData; } |
| 78 | |
| 79 | private: |
| 80 | sk_sp<GrTextureProxy> fProxy; |
| 81 | SkAutoPixmapStorage fPixels; |
| 82 | SkSemaphore fPixelsReady; |
| 83 | bool fWaited; |
| 84 | |
| 85 | T fData; |
| 86 | }; |
| 87 | |
| 88 | #endif |