1 /*
2  * Copyright 2016 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 GrRenderTargetProxy_DEFINED
9 #define GrRenderTargetProxy_DEFINED
10 
11 #include "include/private/GrTypesPriv.h"
12 #include "src/core/SkArenaAlloc.h"
13 #include "src/gpu/GrCaps.h"
14 #include "src/gpu/GrNativeRect.h"
15 #include "src/gpu/GrSubRunAllocator.h"
16 #include "src/gpu/GrSurfaceProxy.h"
17 #include "src/gpu/GrSwizzle.h"
18 
19 class GrResourceProvider;
20 
21 // GrArenas matches the lifetime of a single frame. It is created and held on the
22 // GrSurfaceFillContext's RenderTargetProxy with the first call to get an arena. Each GrOpsTask
23 // takes a ref on it to keep the arenas alive. When the first GrOpsTask's onExecute() is
24 // completed, the arena ref on the GrSurfaceFillContext's RenderTargetProxy is nulled out so that
25 // any new GrOpsTasks will create and ref a new set of arenas.
26 class GrArenas : public SkNVRefCnt<GrArenas> {
27 public:
arenaAlloc()28     SkArenaAlloc* arenaAlloc() {
29         SkDEBUGCODE(if (fIsFlushed) SK_ABORT("Using a flushed arena");)
30         return &fArenaAlloc;
31     }
flush()32     void flush() {
33         SkDEBUGCODE(fIsFlushed = true;)
34     }
subRunAlloc()35     GrSubRunAllocator* subRunAlloc() { return &fSubRunAllocator; }
36 
37 private:
38     SkArenaAlloc fArenaAlloc{1024};
39     // An allocator specifically designed to minimize the overhead of sub runs. It provides a
40     // different dtor semantics than SkArenaAlloc.
41     GrSubRunAllocator fSubRunAllocator{1024};
42     SkDEBUGCODE(bool fIsFlushed = false;)
43 };
44 
45 // This class delays the acquisition of RenderTargets until they are actually
46 // required
47 // Beware: the uniqueID of the RenderTargetProxy will usually be different than
48 // the uniqueID of the RenderTarget it represents!
49 class GrRenderTargetProxy : virtual public GrSurfaceProxy {
50 public:
asRenderTargetProxy()51     GrRenderTargetProxy* asRenderTargetProxy() override { return this; }
asRenderTargetProxy()52     const GrRenderTargetProxy* asRenderTargetProxy() const override { return this; }
53 
54     // Actually instantiate the backing rendertarget, if necessary.
55     bool instantiate(GrResourceProvider*) override;
56 
57     // Returns true if this proxy either has a stencil attachment already, or if we can attach one
58     // during flush. Wrapped render targets without stencil will return false, since we are unable
59     // to modify their attachments.
60     bool canUseStencil(const GrCaps& caps) const;
61 
62     /*
63      * Indicate that a draw to this proxy requires stencil.
64      */
setNeedsStencil()65     void setNeedsStencil() { fNeedsStencil = true; }
66 
needsStencil()67     int needsStencil() const { return fNeedsStencil; }
68 
69     /**
70      * Returns the number of samples/pixel in the color buffer (One if non-MSAA).
71      */
numSamples()72     int numSamples() const { return fSampleCnt; }
73 
74     int maxWindowRectangles(const GrCaps& caps) const;
75 
glRTFBOIDIs0()76     bool glRTFBOIDIs0() const { return fSurfaceFlags & GrInternalSurfaceFlags::kGLRTFBOIDIs0; }
77 
wrapsVkSecondaryCB()78     bool wrapsVkSecondaryCB() const { return fWrapsVkSecondaryCB == WrapsVkSecondaryCB::kYes; }
79 
supportsVkInputAttachment()80     bool supportsVkInputAttachment() const {
81         return fSurfaceFlags & GrInternalSurfaceFlags::kVkRTSupportsInputAttachment;
82     }
83 
markMSAADirty(SkIRect dirtyRect)84     void markMSAADirty(SkIRect dirtyRect) {
85         SkASSERT(SkIRect::MakeSize(this->backingStoreDimensions()).contains(dirtyRect));
86         SkASSERT(this->requiresManualMSAAResolve());
87         fMSAADirtyRect.join(dirtyRect);
88     }
markMSAAResolved()89     void markMSAAResolved() {
90         SkASSERT(this->requiresManualMSAAResolve());
91         fMSAADirtyRect.setEmpty();
92     }
isMSAADirty()93     bool isMSAADirty() const {
94         SkASSERT(fMSAADirtyRect.isEmpty() || this->requiresManualMSAAResolve());
95         return this->requiresManualMSAAResolve() && !fMSAADirtyRect.isEmpty();
96     }
msaaDirtyRect()97     const SkIRect& msaaDirtyRect() const {
98         SkASSERT(this->requiresManualMSAAResolve());
99         return fMSAADirtyRect;
100     }
101 
102     // TODO: move this to a priv class!
103     bool refsWrappedObjects() const;
104 
arenas()105     sk_sp<GrArenas> arenas() {
106         if (fArenas == nullptr) {
107             fArenas = sk_make_sp<GrArenas>();
108         }
109         return fArenas;
110     }
111 
clearArenas()112     void clearArenas() {
113         if (fArenas != nullptr) {
114             fArenas->flush();
115         }
116         fArenas = nullptr;
117     }
118 
119 protected:
120     friend class GrProxyProvider;  // for ctors
121     friend class GrRenderTargetProxyPriv;
122 
123     // Deferred version
124     GrRenderTargetProxy(const GrCaps&,
125                         const GrBackendFormat&,
126                         SkISize,
127                         int sampleCount,
128                         SkBackingFit,
129                         SkBudgeted,
130                         GrProtected,
131                         GrInternalSurfaceFlags,
132                         UseAllocator);
133 
134     enum class WrapsVkSecondaryCB : bool { kNo = false, kYes = true };
135 
136     // Lazy-callback version
137     // There are two main use cases for lazily-instantiated proxies:
138     //   basic knowledge - width, height, config, samples, origin are known
139     //   minimal knowledge - only config is known.
140     //
141     // The basic knowledge version is used for DDL where we know the type of proxy we are going to
142     // use, but we don't have access to the GPU yet to instantiate it.
143     //
144     // The minimal knowledge version is used for CCPR where we are generating an atlas but we do not
145     // know the final size until flush time.
146     GrRenderTargetProxy(LazyInstantiateCallback&&,
147                         const GrBackendFormat&,
148                         SkISize,
149                         int sampleCount,
150                         SkBackingFit,
151                         SkBudgeted,
152                         GrProtected,
153                         GrInternalSurfaceFlags,
154                         UseAllocator,
155                         WrapsVkSecondaryCB);
156 
157     // Wrapped version
158     GrRenderTargetProxy(sk_sp<GrSurface>,
159                         UseAllocator,
160                         WrapsVkSecondaryCB = WrapsVkSecondaryCB::kNo);
161 
162     sk_sp<GrSurface> createSurface(GrResourceProvider*) const override;
163 
164 private:
165     size_t onUninstantiatedGpuMemorySize() const override;
166     SkDEBUGCODE(void onValidateSurface(const GrSurface*) override;)
167 
168             LazySurfaceDesc callbackDesc() const override;
169 
170     // WARNING: Be careful when adding or removing fields here. ASAN is likely to trigger warnings
171     // when instantiating GrTextureRenderTargetProxy. The std::function in GrSurfaceProxy makes
172     // each class in the diamond require 16 byte alignment. Clang appears to layout the fields for
173     // each class to achieve the necessary alignment. However, ASAN checks the alignment of 'this'
174     // in the constructors, and always looks for the full 16 byte alignment, even if the fields in
175     // that particular class don't require it. Changing the size of this object can move the start
176     // address of other types, leading to this problem.
177     int8_t             fSampleCnt;
178     int8_t             fNeedsStencil = false;
179     WrapsVkSecondaryCB fWrapsVkSecondaryCB;
180     SkIRect            fMSAADirtyRect = SkIRect::MakeEmpty();
181     sk_sp<GrArenas>    fArenas{nullptr};
182 
183     // This is to fix issue in large comment above. Without the padding we can end up with the
184     // GrTextureProxy starting 8 byte aligned by not 16. This happens when the RT ends at bytes 1-8.
185     // Note: with the virtual inheritance an 8 byte pointer is at the start of GrRenderTargetProxy.
186     //
187     // In the current world we end the RT proxy at 12 bytes. Technically any padding between 0-4
188     // will work, but we use 4 to be more explicit about getting it to 16 byte alignment.
189     char               fDummyPadding[4];
190 
191     using INHERITED = GrSurfaceProxy;
192 };
193 
194 #endif
195