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 SkBackingFit; 30 struct SkISize; 31 namespace skgpu { 32 enum class Budgeted : bool; 33 enum class Protected : 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 GrVkSecondaryCBDrawContext; // for ctors 137 // Deferred version 138 GrRenderTargetProxy(const GrCaps&, 139 const GrBackendFormat&, 140 SkISize, 141 int sampleCount, 142 SkBackingFit, 143 skgpu::Budgeted, 144 skgpu::Protected, 145 GrInternalSurfaceFlags, 146 UseAllocator, 147 std::string_view label); 148 149 enum class WrapsVkSecondaryCB : bool { kNo = false, kYes = true }; 150 151 // Lazy-callback version 152 // There are two main use cases for lazily-instantiated proxies: 153 // basic knowledge - width, height, config, samples, origin are known 154 // minimal knowledge - only config is known. 155 // 156 // The basic knowledge version is used for DDL where we know the type of proxy we are going to 157 // use, but we don't have access to the GPU yet to instantiate it. 158 // 159 // The minimal knowledge version is used for when we are generating an atlas but we do not know 160 // the final size until we have finished adding to it. 161 GrRenderTargetProxy(LazyInstantiateCallback&&, 162 const GrBackendFormat&, 163 SkISize, 164 int sampleCount, 165 SkBackingFit, 166 skgpu::Budgeted, 167 skgpu::Protected, 168 GrInternalSurfaceFlags, 169 UseAllocator, 170 WrapsVkSecondaryCB, 171 std::string_view label); 172 173 // Wrapped version 174 GrRenderTargetProxy(sk_sp<GrSurface>, 175 UseAllocator, 176 WrapsVkSecondaryCB = WrapsVkSecondaryCB::kNo); 177 178 sk_sp<GrSurface> createSurface(GrResourceProvider*) const override; 179 180 private: 181 size_t onUninstantiatedGpuMemorySize() const override; 182 SkDEBUGCODE(void onValidateSurface(const GrSurface*) override;) 183 184 LazySurfaceDesc callbackDesc() const override; 185 186 // WARNING: Be careful when adding or removing fields here. ASAN is likely to trigger warnings 187 // when instantiating GrTextureRenderTargetProxy. The std::function in GrSurfaceProxy makes 188 // each class in the diamond require 16 byte alignment. Clang appears to layout the fields for 189 // each class to achieve the necessary alignment. However, ASAN checks the alignment of 'this' 190 // in the constructors, and always looks for the full 16 byte alignment, even if the fields in 191 // that particular class don't require it. Changing the size of this object can move the start 192 // address of other types, leading to this problem. 193 int8_t fSampleCnt; 194 int8_t fNeedsStencil = false; 195 WrapsVkSecondaryCB fWrapsVkSecondaryCB; 196 SkIRect fMSAADirtyRect = SkIRect::MakeEmpty(); 197 sk_sp<GrArenas> fArenas{nullptr}; 198 199 // This is to fix issue in large comment above. Without the padding we can end up with the 200 // GrTextureProxy starting 8 byte aligned by not 16. This happens when the RT ends at bytes 1-8. 201 // Note: with the virtual inheritance an 8 byte pointer is at the start of GrRenderTargetProxy. 202 // 203 // In the current world we end the RT proxy at 12 bytes. Technically any padding between 0-4 204 // will work, but we use 4 to be more explicit about getting it to 16 byte alignment. 205 char fPadding[4]; 206 207 using INHERITED = GrSurfaceProxy; 208 }; 209 210 #endif 211