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 GrDeferredUpload_DEFINED
9 #define GrDeferredUpload_DEFINED
10 
11 #include <functional>
12 #include "GrTypes.h"
13 #include "GrTypesPriv.h"
14 
15 class GrTextureProxy;
16 
17 /**
18  * A word about deferred uploads and tokens: Ops should usually schedule their uploads to occur at
19  * the beginning of a frame whenever possible. These are called ASAP uploads. Of course, this
20  * requires that there are no draws that have yet to be flushed that rely on the old texture
21  * contents. In that case the ASAP upload would happen prior to the draw and therefore the draw
22  * would read the new (wrong) texture data. When this read-before-write data hazard exists they
23  * should schedule an inline upload.
24  *
25  * Ops, in conjunction with helpers such as GrDrawOpAtlas, use upload tokens to know what the most
26  * recent draw was that referenced a resource (or portion of a resource). Each draw is assigned a
27  * token. A resource (or portion thereof) can be tagged with the most recent reading draw's token.
28  * The deferred uploads target provides a facility for testing whether the draw corresponding to the
29  * token has been flushed. If it has not been flushed then the op must perform an inline upload
30  * instead so that the upload occurs after the draw depending on the old contents and before the
31  * draw depending on the updated contents. When scheduling an inline upload the op provides the
32  * token of the draw that the upload must occur before.
33  */
34 
35 /**
36  * GrDeferredUploadToken is used to sequence the uploads relative to each other and to draws.
37  */
38 class GrDeferredUploadToken {
39 public:
40     static GrDeferredUploadToken AlreadyFlushedToken() { return GrDeferredUploadToken(0); }
41 
42     GrDeferredUploadToken(const GrDeferredUploadToken&) = default;
43     GrDeferredUploadToken& operator=(const GrDeferredUploadToken&) = default;
44 
45     bool operator==(const GrDeferredUploadToken& that) const {
46         return fSequenceNumber == that.fSequenceNumber;
47     }
48     bool operator!=(const GrDeferredUploadToken& that) const { return !(*this == that); }
49     bool operator<(const GrDeferredUploadToken that) const {
50         return fSequenceNumber < that.fSequenceNumber;
51     }
52     bool operator<=(const GrDeferredUploadToken that) const {
53         return fSequenceNumber <= that.fSequenceNumber;
54     }
55     bool operator>(const GrDeferredUploadToken that) const {
56         return fSequenceNumber > that.fSequenceNumber;
57     }
58     bool operator>=(const GrDeferredUploadToken that) const {
59         return fSequenceNumber >= that.fSequenceNumber;
60     }
61 
62     GrDeferredUploadToken& operator++() {
63         ++fSequenceNumber;
64         return *this;
65     }
66     GrDeferredUploadToken operator++(int) {
67         auto old = fSequenceNumber;
68         ++fSequenceNumber;
69         return GrDeferredUploadToken(old);
70     }
71 
72     GrDeferredUploadToken next() const { return GrDeferredUploadToken(fSequenceNumber + 1); }
73 
74     /** Is this token in the [start, end] inclusive interval? */
75     bool inInterval(const GrDeferredUploadToken& start, const GrDeferredUploadToken& end) {
76         return *this >= start && *this <= end;
77     }
78 
79 private:
80     GrDeferredUploadToken() = delete;
81     explicit GrDeferredUploadToken(uint64_t sequenceNumber) : fSequenceNumber(sequenceNumber) {}
82     uint64_t fSequenceNumber;
83 };
84 
85 /*
86  * The GrTokenTracker encapsulates the incrementing and distribution of tokens.
87  */
88 class GrTokenTracker {
89 public:
90     /** Gets the token one beyond the last token that has been flushed. */
91     GrDeferredUploadToken nextTokenToFlush() const { return fLastFlushedToken.next(); }
92 
93     /** Gets the next draw token that will be issued by this target. This can be used by an op
94         to record that the next draw it issues will use a resource (e.g. texture) while preparing
95         that draw. */
96     GrDeferredUploadToken nextDrawToken() const { return fLastIssuedToken.next(); }
97 
98 private:
99     // Only these three classes get to increment the token counters
100     friend class SkInternalAtlasTextContext;
101     friend class GrOpFlushState;
102     friend class TestingUploadTarget;
103 
104     /** Issues the next token for a draw. */
105     GrDeferredUploadToken issueDrawToken() { return ++fLastIssuedToken; }
106 
107     /** Advances the last flushed token by one. */
108     GrDeferredUploadToken flushToken() { return ++fLastFlushedToken; }
109 
110     GrDeferredUploadToken fLastIssuedToken = GrDeferredUploadToken::AlreadyFlushedToken();
111     GrDeferredUploadToken fLastFlushedToken = GrDeferredUploadToken::AlreadyFlushedToken();
112 };
113 
114 /**
115  * Passed to a deferred upload when it is executed, this method allows the deferred upload to
116  * actually write its pixel data into a texture.
117  */
118 using GrDeferredTextureUploadWritePixelsFn =
119         std::function<bool(GrTextureProxy*, int left, int top, int width, int height,
120                            GrColorType colorType, const void* buffer, size_t rowBytes)>;
121 
122 /**
123  * A deferred texture upload is simply a std::function that takes a
124  * GrDeferredTextureUploadWritePixelsFn as a parameter. It is called when it should perform its
125  * upload as the draw/upload sequence is executed.
126  */
127 using GrDeferredTextureUploadFn = std::function<void(GrDeferredTextureUploadWritePixelsFn&)>;
128 
129 /**
130  * An interface for scheduling deferred uploads. It accepts asap and deferred inline uploads.
131  */
132 class GrDeferredUploadTarget {
133 public:
134     virtual ~GrDeferredUploadTarget() {}
135 
136     virtual const GrTokenTracker* tokenTracker() = 0;
137 
138     /** Returns the token of the draw that this upload will occur before. */
139     virtual GrDeferredUploadToken addInlineUpload(GrDeferredTextureUploadFn&&) = 0;
140 
141     /** Returns the token of the draw that this upload will occur before. Since ASAP uploads
142         are done first during a flush, this will be the first token since the most recent
143         flush. */
144     virtual GrDeferredUploadToken addASAPUpload(GrDeferredTextureUploadFn&& upload) = 0;
145 };
146 
147 #endif
148