From 29e52f13f632c701bd33d802701f5ff29a567eea Mon Sep 17 00:00:00 2001 From: Robert Phillips Date: Thu, 3 Nov 2016 10:19:14 -0400 Subject: [PATCH] Centralize computation of GrRenderTarget & GrTexture VRAM consumption GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=4310 Change-Id: I676749ecf1e489f825799b619a15a45fc7dcd219 Reviewed-on: https://skia-review.googlesource.com/4310 Reviewed-by: Brian Salomon Commit-Queue: Robert Phillips --- include/gpu/GrRenderTarget.h | 2 ++ include/gpu/GrTexture.h | 2 ++ include/private/GrSurfaceProxy.h | 13 ++++++------- src/gpu/GrRenderTarget.cpp | 14 +++++++++++++- src/gpu/GrRenderTargetProxy.cpp | 11 +++-------- src/gpu/GrTexture.cpp | 18 +++++++++++------- src/gpu/GrTextureProxy.cpp | 20 ++++++-------------- src/gpu/gl/GrGLRenderTarget.cpp | 17 +++-------------- src/gpu/gl/GrGLRenderTarget.h | 9 ++++----- src/gpu/vk/GrVkRenderTarget.cpp | 6 ------ src/gpu/vk/GrVkRenderTarget.h | 8 ++------ 11 files changed, 52 insertions(+), 68 deletions(-) diff --git a/include/gpu/GrRenderTarget.h b/include/gpu/GrRenderTarget.h index dcbe8ea974..ad96229dc7 100644 --- a/include/gpu/GrRenderTarget.h +++ b/include/gpu/GrRenderTarget.h @@ -119,6 +119,8 @@ public: return (GrRenderTargetOpList*) this->getLastOpList(); } + static size_t ComputeSize(const GrSurfaceDesc& desc, int colorValuesPerPixel); + protected: enum class Flags { kNone = 0, diff --git a/include/gpu/GrTexture.h b/include/gpu/GrTexture.h index 211f1937da..c86496c3cf 100644 --- a/include/gpu/GrTexture.h +++ b/include/gpu/GrTexture.h @@ -45,6 +45,8 @@ public: inline GrTexturePriv texturePriv(); inline const GrTexturePriv texturePriv() const; + static size_t ComputeSize(const GrSurfaceDesc&, bool hasMipMaps); + protected: GrTexture(GrGpu*, const GrSurfaceDesc&, GrSLType, bool wasMipMapDataProvided); diff --git a/include/private/GrSurfaceProxy.h b/include/private/GrSurfaceProxy.h index 37669fee19..e748853cfd 100644 --- a/include/private/GrSurfaceProxy.h +++ b/include/private/GrSurfaceProxy.h @@ -120,10 +120,6 @@ public: * @return the amount of GPU memory used in bytes */ size_t gpuMemorySize() const { - if (fTarget) { - return fTarget->gpuMemorySize(); - } - if (kInvalidGpuMemorySize == fGpuMemorySize) { fGpuMemorySize = this->onGpuMemorySize(); SkASSERT(kInvalidGpuMemorySize != fGpuMemorySize); @@ -154,15 +150,17 @@ protected: const uint32_t fUniqueID; // set from the backing resource for wrapped resources static const size_t kInvalidGpuMemorySize = ~static_cast(0); + SkDEBUGCODE(size_t getRawGpuMemorySize_debugOnly() const { return fGpuMemorySize; }) + +private: + virtual size_t onGpuMemorySize() const = 0; + // This entry is lazily evaluated so, when the proxy wraps a resource, the resource // will be called but, when the proxy is deferred, it will compute the answer itself. // If the proxy computes its own answer that answer is checked (in debug mode) in // the instantiation method. mutable size_t fGpuMemorySize; -private: - virtual size_t onGpuMemorySize() const = 0; - // The last opList that wrote to or is currently going to write to this surface // The opList can be closed (e.g., no render target context is currently bound // to this renderTarget). @@ -171,6 +169,7 @@ private: // and the opList of a destination surface to which this one is being drawn or copied. GrOpList* fLastOpList; + typedef GrIORefProxy INHERITED; }; diff --git a/src/gpu/GrRenderTarget.cpp b/src/gpu/GrRenderTarget.cpp index e7782cc852..2828866435 100644 --- a/src/gpu/GrRenderTarget.cpp +++ b/src/gpu/GrRenderTarget.cpp @@ -84,12 +84,23 @@ void GrRenderTarget::onAbandon() { INHERITED::onAbandon(); } +size_t GrRenderTarget::ComputeSize(const GrSurfaceDesc& desc, int colorValuesPerPixel) { + SkASSERT(kUnknown_GrPixelConfig != desc.fConfig); + SkASSERT(!GrPixelConfigIsCompressed(desc.fConfig)); + size_t colorBytes = GrBytesPerPixel(desc.fConfig); + SkASSERT(colorBytes > 0); + + size_t rtSize = colorValuesPerPixel * desc.fWidth * desc.fHeight * colorBytes; + SkASSERT(rtSize <= WorstCaseSize(desc)); + return rtSize; +} + /////////////////////////////////////////////////////////////////////////////// bool GrRenderTargetPriv::attachStencilAttachment(GrStencilAttachment* stencil) { if (!stencil && !fRenderTarget->fStencilAttachment) { // No need to do any work since we currently don't have a stencil attachment and - // we're not acctually adding one. + // we're not actually adding one. return true; } fRenderTarget->fStencilAttachment = stencil; @@ -122,3 +133,4 @@ int GrRenderTargetPriv::maxWindowRectangles() const { return (this->flags() & Flags::kWindowRectsSupport) ? fRenderTarget->getGpu()->caps()->maxWindowRectangles() : 0; } + diff --git a/src/gpu/GrRenderTargetProxy.cpp b/src/gpu/GrRenderTargetProxy.cpp index d965e6b629..ac8f5edb76 100644 --- a/src/gpu/GrRenderTargetProxy.cpp +++ b/src/gpu/GrRenderTargetProxy.cpp @@ -54,8 +54,8 @@ GrRenderTarget* GrRenderTargetProxy::instantiate(GrTextureProvider* texProvider) } #ifdef SK_DEBUG - if (kInvalidGpuMemorySize != fGpuMemorySize) { - SkASSERT(fTarget->gpuMemorySize() <= fGpuMemorySize); + if (kInvalidGpuMemorySize != this->getRawGpuMemorySize_debugOnly()) { + SkASSERT(fTarget->gpuMemorySize() <= this->getRawGpuMemorySize_debugOnly()); } #endif @@ -81,13 +81,8 @@ size_t GrRenderTargetProxy::onGpuMemorySize() const { return fTarget->gpuMemorySize(); } - SkASSERT(kUnknown_GrPixelConfig != fDesc.fConfig); - SkASSERT(!GrPixelConfigIsCompressed(fDesc.fConfig)); - size_t colorBytes = GrBytesPerPixel(fDesc.fConfig); - SkASSERT(colorBytes > 0); - // TODO: do we have enough information to improve this worst case estimate? - return (fDesc.fSampleCnt + 1) * fDesc.fWidth * fDesc.fHeight * colorBytes; + return GrRenderTarget::ComputeSize(fDesc, fDesc.fSampleCnt+1); } sk_sp GrRenderTargetProxy::Make(const GrCaps& caps, diff --git a/src/gpu/GrTexture.cpp b/src/gpu/GrTexture.cpp index bb1a6bb081..91036bc156 100644 --- a/src/gpu/GrTexture.cpp +++ b/src/gpu/GrTexture.cpp @@ -35,27 +35,31 @@ void GrTexture::dirtyMipMaps(bool mipMapsDirty) { } } -size_t GrTexture::onGpuMemorySize() const { +size_t GrTexture::ComputeSize(const GrSurfaceDesc& desc, bool hasMipMaps) { size_t textureSize; - if (GrPixelConfigIsCompressed(fDesc.fConfig)) { - textureSize = GrCompressedFormatDataSize(fDesc.fConfig, fDesc.fWidth, fDesc.fHeight); + if (GrPixelConfigIsCompressed(desc.fConfig)) { + textureSize = GrCompressedFormatDataSize(desc.fConfig, desc.fWidth, desc.fHeight); } else { - textureSize = (size_t) fDesc.fWidth * fDesc.fHeight * GrBytesPerPixel(fDesc.fConfig); + textureSize = (size_t) desc.fWidth * desc.fHeight * GrBytesPerPixel(desc.fConfig); } - if (this->texturePriv().hasMipMaps()) { + if (hasMipMaps) { // We don't have to worry about the mipmaps being a different size than // we'd expect because we never change fDesc.fWidth/fHeight. textureSize += textureSize/3; } - SkASSERT(!SkToBool(fDesc.fFlags & kRenderTarget_GrSurfaceFlag)); - SkASSERT(textureSize <= WorstCaseSize(fDesc)); + SkASSERT(!SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag)); + SkASSERT(textureSize <= WorstCaseSize(desc)); return textureSize; } +size_t GrTexture::onGpuMemorySize() const { + return ComputeSize(fDesc, this->texturePriv().hasMipMaps()); +} + void GrTexture::validateDesc() const { if (this->asRenderTarget()) { // This texture has a render target diff --git a/src/gpu/GrTextureProxy.cpp b/src/gpu/GrTextureProxy.cpp index 9aae7057c4..d60bf90ba4 100644 --- a/src/gpu/GrTextureProxy.cpp +++ b/src/gpu/GrTextureProxy.cpp @@ -31,8 +31,8 @@ GrTexture* GrTextureProxy::instantiate(GrTextureProvider* texProvider) { } #ifdef SK_DEBUG - if (kInvalidGpuMemorySize != fGpuMemorySize) { - SkASSERT(fTarget->gpuMemorySize() <= fGpuMemorySize); + if (kInvalidGpuMemorySize != this->getRawGpuMemorySize_debugOnly()) { + SkASSERT(fTarget->gpuMemorySize() <= this->getRawGpuMemorySize_debugOnly()); } #endif @@ -40,21 +40,13 @@ GrTexture* GrTextureProxy::instantiate(GrTextureProvider* texProvider) { } size_t GrTextureProxy::onGpuMemorySize() const { - size_t textureSize; - - if (GrPixelConfigIsCompressed(fDesc.fConfig)) { - textureSize = GrCompressedFormatDataSize(fDesc.fConfig, fDesc.fWidth, fDesc.fHeight); - } else { - textureSize = (size_t) fDesc.fWidth * fDesc.fHeight * GrBytesPerPixel(fDesc.fConfig); + if (fTarget) { + return fTarget->gpuMemorySize(); } + static const bool kHasMipMaps = true; // TODO: add tracking of mipmap state to improve the estimate - textureSize += textureSize/3; - - SkASSERT(!SkToBool(fDesc.fFlags & kRenderTarget_GrSurfaceFlag)); - SkASSERT(textureSize <= GrSurface::WorstCaseSize(fDesc)); - - return textureSize; + return GrTexture::ComputeSize(fDesc, kHasMipMaps); } sk_sp GrTextureProxy::Make(GrTextureProvider* texProvider, diff --git a/src/gpu/gl/GrGLRenderTarget.cpp b/src/gpu/gl/GrGLRenderTarget.cpp index 65366bd380..2f92e0a82d 100644 --- a/src/gpu/gl/GrGLRenderTarget.cpp +++ b/src/gpu/gl/GrGLRenderTarget.cpp @@ -59,9 +59,7 @@ void GrGLRenderTarget::init(const GrSurfaceDesc& desc, const IDDesc& idDesc) { fViewport.fWidth = desc.fWidth; fViewport.fHeight = desc.fHeight; - fGpuMemorySize = this->totalSamples() * this->totalBytesPerSample(); - - SkASSERT(fGpuMemorySize <= WorstCaseSize(desc)); + fNumSamplesOwnedPerPixel = this->totalSamples(); } sk_sp GrGLRenderTarget::MakeWrapped(GrGLGpu* gpu, @@ -84,7 +82,7 @@ sk_sp GrGLRenderTarget::MakeWrapped(GrGLGpu* gpu, } size_t GrGLRenderTarget::onGpuMemorySize() const { - return fGpuMemorySize; + return GrRenderTarget::ComputeSize(fDesc, fNumSamplesOwnedPerPixel); } bool GrGLRenderTarget::completeStencilAttachment() { @@ -185,7 +183,7 @@ void GrGLRenderTarget::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) // Log any renderbuffer's contribution to memory. We only do this if we own the renderbuffer // (have a fMSColorRenderbufferID). if (fMSColorRenderbufferID) { - size_t size = this->msaaSamples() * this->totalBytesPerSample(); + size_t size = GrRenderTarget::ComputeSize(fDesc, this->msaaSamples()); // Due to this resource having both a texture and a renderbuffer component, dump as // skia/gpu_resources/resource_#/renderbuffer @@ -206,15 +204,6 @@ void GrGLRenderTarget::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) } } -size_t GrGLRenderTarget::totalBytesPerSample() const { - SkASSERT(kUnknown_GrPixelConfig != fDesc.fConfig); - SkASSERT(!GrPixelConfigIsCompressed(fDesc.fConfig)); - size_t colorBytes = GrBytesPerPixel(fDesc.fConfig); - SkASSERT(colorBytes > 0); - - return fDesc.fWidth * fDesc.fHeight * colorBytes; -} - int GrGLRenderTarget::msaaSamples() const { if (fTexFBOID == kUnresolvableFBOID || fTexFBOID != fRTFBOID) { // If the render target's FBO is external (fTexFBOID == kUnresolvableFBOID), or if we own diff --git a/src/gpu/gl/GrGLRenderTarget.h b/src/gpu/gl/GrGLRenderTarget.h index 08dd88d523..fc18e30437 100644 --- a/src/gpu/gl/GrGLRenderTarget.h +++ b/src/gpu/gl/GrGLRenderTarget.h @@ -89,8 +89,6 @@ private: GrGLGpu* getGLGpu() const; bool completeStencilAttachment() override; - // The total size of the resource (including all pixels) for a single sample. - size_t totalBytesPerSample() const; int msaaSamples() const; // The number total number of samples, including both MSAA and resolve texture samples. int totalSamples() const; @@ -106,9 +104,10 @@ private: // we want the rendering to be at top left (GL has origin in bottom left) GrGLIRect fViewport; - // onGpuMemorySize() needs to know the VRAM footprint of the FBO(s). However, abandon and - // release zero out the IDs and the cache needs to know the size even after those actions. - size_t fGpuMemorySize; + // The RenderTarget needs to be able to report its VRAM footprint even after abandon and + // release have potentially zeroed out the IDs (e.g., so the cache can reset itself). Since + // the IDs are just required for the computation in totalSamples we cache that result here. + int fNumSamplesOwnedPerPixel; typedef GrRenderTarget INHERITED; }; diff --git a/src/gpu/vk/GrVkRenderTarget.cpp b/src/gpu/vk/GrVkRenderTarget.cpp index e2f0019d9c..278c939c22 100644 --- a/src/gpu/vk/GrVkRenderTarget.cpp +++ b/src/gpu/vk/GrVkRenderTarget.cpp @@ -39,8 +39,6 @@ GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu, , fFramebuffer(nullptr) , fCachedSimpleRenderPass(nullptr) { SkASSERT(desc.fSampleCnt); - // The plus 1 is to account for the resolve texture. - fColorValuesPerPixel = desc.fSampleCnt + 1; // TODO: this still correct? this->createFramebuffer(gpu); this->registerWithCache(budgeted); } @@ -64,8 +62,6 @@ GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu, , fFramebuffer(nullptr) , fCachedSimpleRenderPass(nullptr) { SkASSERT(desc.fSampleCnt); - // The plus 1 is to account for the resolve texture. - fColorValuesPerPixel = desc.fSampleCnt + 1; // TODO: this still correct? this->createFramebuffer(gpu); } @@ -86,7 +82,6 @@ GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu, , fFramebuffer(nullptr) , fCachedSimpleRenderPass(nullptr) { SkASSERT(!desc.fSampleCnt); - fColorValuesPerPixel = 1; this->createFramebuffer(gpu); this->registerWithCache(budgeted); } @@ -107,7 +102,6 @@ GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu, , fFramebuffer(nullptr) , fCachedSimpleRenderPass(nullptr) { SkASSERT(!desc.fSampleCnt); - fColorValuesPerPixel = 1; this->createFramebuffer(gpu); } diff --git a/src/gpu/vk/GrVkRenderTarget.h b/src/gpu/vk/GrVkRenderTarget.h index 0855a6d020..2e2f60a5fd 100644 --- a/src/gpu/vk/GrVkRenderTarget.h +++ b/src/gpu/vk/GrVkRenderTarget.h @@ -99,11 +99,8 @@ protected: // This accounts for the texture's memory and any MSAA renderbuffer's memory. size_t onGpuMemorySize() const override { - SkASSERT(kUnknown_GrPixelConfig != fDesc.fConfig); - SkASSERT(!GrPixelConfigIsCompressed(fDesc.fConfig)); - size_t colorBytes = GrBytesPerPixel(fDesc.fConfig); - SkASSERT(colorBytes > 0); - return fColorValuesPerPixel * fDesc.fWidth * fDesc.fHeight * colorBytes; + // The plus 1 is to account for the resolve texture. + return GrRenderTarget::ComputeSize(fDesc, fDesc.fSampleCnt+1); // TODO: this still correct? } void createFramebuffer(GrVkGpu* gpu); @@ -138,7 +135,6 @@ private: void abandonInternalObjects(); const GrVkFramebuffer* fFramebuffer; - int fColorValuesPerPixel; // This is a cached pointer to a simple render pass. The render target should unref it // once it is done with it. -- 2.34.1