/* * Copyright 2016 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef GrRenderTargetProxy_DEFINED #define GrRenderTargetProxy_DEFINED #include "include/private/GrTypesPriv.h" #include "src/core/SkArenaAlloc.h" #include "src/gpu/GrCaps.h" #include "src/gpu/GrNativeRect.h" #include "src/gpu/GrSubRunAllocator.h" #include "src/gpu/GrSurfaceProxy.h" #include "src/gpu/GrSwizzle.h" class GrResourceProvider; // GrArenas matches the lifetime of a single frame. It is created and held on the // GrSurfaceFillContext's RenderTargetProxy with the first call to get an arena. Each GrOpsTask // takes a ref on it to keep the arenas alive. When the first GrOpsTask's onExecute() is // completed, the arena ref on the GrSurfaceFillContext's RenderTargetProxy is nulled out so that // any new GrOpsTasks will create and ref a new set of arenas. class GrArenas : public SkNVRefCnt { public: SkArenaAlloc* arenaAlloc() { SkDEBUGCODE(if (fIsFlushed) SK_ABORT("Using a flushed arena");) return &fArenaAlloc; } void flush() { SkDEBUGCODE(fIsFlushed = true;) } GrSubRunAllocator* subRunAlloc() { return &fSubRunAllocator; } private: SkArenaAlloc fArenaAlloc{1024}; // An allocator specifically designed to minimize the overhead of sub runs. It provides a // different dtor semantics than SkArenaAlloc. GrSubRunAllocator fSubRunAllocator{1024}; SkDEBUGCODE(bool fIsFlushed = false;) }; // This class delays the acquisition of RenderTargets until they are actually // required // Beware: the uniqueID of the RenderTargetProxy will usually be different than // the uniqueID of the RenderTarget it represents! class GrRenderTargetProxy : virtual public GrSurfaceProxy { public: GrRenderTargetProxy* asRenderTargetProxy() override { return this; } const GrRenderTargetProxy* asRenderTargetProxy() const override { return this; } // Actually instantiate the backing rendertarget, if necessary. bool instantiate(GrResourceProvider*) override; // Returns true if this proxy either has a stencil attachment already, or if we can attach one // during flush. Wrapped render targets without stencil will return false, since we are unable // to modify their attachments. bool canUseStencil(const GrCaps& caps) const; /* * Indicate that a draw to this proxy requires stencil. */ void setNeedsStencil() { fNeedsStencil = true; } int needsStencil() const { return fNeedsStencil; } /** * Returns the number of samples/pixel in the color buffer (One if non-MSAA). */ int numSamples() const { return fSampleCnt; } int maxWindowRectangles(const GrCaps& caps) const; bool glRTFBOIDIs0() const { return fSurfaceFlags & GrInternalSurfaceFlags::kGLRTFBOIDIs0; } bool wrapsVkSecondaryCB() const { return fWrapsVkSecondaryCB == WrapsVkSecondaryCB::kYes; } bool supportsVkInputAttachment() const { return fSurfaceFlags & GrInternalSurfaceFlags::kVkRTSupportsInputAttachment; } void markMSAADirty(SkIRect dirtyRect) { SkASSERT(SkIRect::MakeSize(this->backingStoreDimensions()).contains(dirtyRect)); SkASSERT(this->requiresManualMSAAResolve()); fMSAADirtyRect.join(dirtyRect); } void markMSAAResolved() { SkASSERT(this->requiresManualMSAAResolve()); fMSAADirtyRect.setEmpty(); } bool isMSAADirty() const { SkASSERT(fMSAADirtyRect.isEmpty() || this->requiresManualMSAAResolve()); return this->requiresManualMSAAResolve() && !fMSAADirtyRect.isEmpty(); } const SkIRect& msaaDirtyRect() const { SkASSERT(this->requiresManualMSAAResolve()); return fMSAADirtyRect; } // TODO: move this to a priv class! bool refsWrappedObjects() const; sk_sp arenas() { if (fArenas == nullptr) { fArenas = sk_make_sp(); } return fArenas; } void clearArenas() { if (fArenas != nullptr) { fArenas->flush(); } fArenas = nullptr; } protected: friend class GrProxyProvider; // for ctors friend class GrRenderTargetProxyPriv; // Deferred version GrRenderTargetProxy(const GrCaps&, const GrBackendFormat&, SkISize, int sampleCount, SkBackingFit, SkBudgeted, GrProtected, GrInternalSurfaceFlags, UseAllocator); enum class WrapsVkSecondaryCB : bool { kNo = false, kYes = true }; // Lazy-callback version // There are two main use cases for lazily-instantiated proxies: // basic knowledge - width, height, config, samples, origin are known // minimal knowledge - only config is known. // // The basic knowledge version is used for DDL where we know the type of proxy we are going to // use, but we don't have access to the GPU yet to instantiate it. // // The minimal knowledge version is used for CCPR where we are generating an atlas but we do not // know the final size until flush time. GrRenderTargetProxy(LazyInstantiateCallback&&, const GrBackendFormat&, SkISize, int sampleCount, SkBackingFit, SkBudgeted, GrProtected, GrInternalSurfaceFlags, UseAllocator, WrapsVkSecondaryCB); // Wrapped version GrRenderTargetProxy(sk_sp, UseAllocator, WrapsVkSecondaryCB = WrapsVkSecondaryCB::kNo); sk_sp createSurface(GrResourceProvider*) const override; private: size_t onUninstantiatedGpuMemorySize() const override; SkDEBUGCODE(void onValidateSurface(const GrSurface*) override;) LazySurfaceDesc callbackDesc() const override; // WARNING: Be careful when adding or removing fields here. ASAN is likely to trigger warnings // when instantiating GrTextureRenderTargetProxy. The std::function in GrSurfaceProxy makes // each class in the diamond require 16 byte alignment. Clang appears to layout the fields for // each class to achieve the necessary alignment. However, ASAN checks the alignment of 'this' // in the constructors, and always looks for the full 16 byte alignment, even if the fields in // that particular class don't require it. Changing the size of this object can move the start // address of other types, leading to this problem. int8_t fSampleCnt; int8_t fNeedsStencil = false; WrapsVkSecondaryCB fWrapsVkSecondaryCB; SkIRect fMSAADirtyRect = SkIRect::MakeEmpty(); sk_sp fArenas{nullptr}; // This is to fix issue in large comment above. Without the padding we can end up with the // GrTextureProxy starting 8 byte aligned by not 16. This happens when the RT ends at bytes 1-8. // Note: with the virtual inheritance an 8 byte pointer is at the start of GrRenderTargetProxy. // // In the current world we end the RT proxy at 12 bytes. Technically any padding between 0-4 // will work, but we use 4 to be more explicit about getting it to 16 byte alignment. char fDummyPadding[4]; using INHERITED = GrSurfaceProxy; }; #endif