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