blob: af8161d163ecf94b0f1f5f638977f88625dbcc9c [file] [log] [blame]
Brian Osman5d034742017-09-11 13:38:55 -04001/*
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
17class 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 */
27class GrPrepareCallback : SkNoncopyable {
28public:
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 */
40template <typename T>
41class GrMaskUploaderPrepareCallback : public GrPrepareCallback {
42public:
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
79private:
80 sk_sp<GrTextureProxy> fProxy;
81 SkAutoPixmapStorage fPixels;
82 SkSemaphore fPixelsReady;
83 bool fWaited;
84
85 T fData;
86};
87
88#endif