Add onMemoryDump to GrContext

Adds an entry point to GrContext to allow enumeration and tracing of GPU resources
via the newly added SkTraceMemoryDump.

Plan is for Chrome to call this on each of its GrContexts.

Dumps both the total size of GPU resources, as well as the total purgeable size.

BUG=526261

Review URL: https://codereview.chromium.org/1313743002
This commit is contained in:
ericrk 2015-09-15 14:16:10 -07:00 committed by Commit bot
parent eb00eaba0c
commit 0a5fa484fd
20 changed files with 217 additions and 18 deletions

View File

@ -336,6 +336,7 @@
'<(skia_src_path)/gpu/gl/GrGLStencilAttachment.h',
'<(skia_src_path)/gpu/gl/GrGLTexture.cpp',
'<(skia_src_path)/gpu/gl/GrGLTexture.h',
'<(skia_src_path)/gpu/gl/GrGLTextureRenderTarget.cpp',
'<(skia_src_path)/gpu/gl/GrGLTextureRenderTarget.h',
'<(skia_src_path)/gpu/gl/GrGLUtil.cpp',
'<(skia_src_path)/gpu/gl/GrGLUtil.h',

View File

@ -43,6 +43,7 @@ class GrTextureParams;
class GrVertexBuffer;
class GrStrokeInfo;
class GrSoftwarePathRenderer;
class SkTraceMemoryDump;
class SK_API GrContext : public SkRefCnt {
public:
@ -358,6 +359,9 @@ public:
to an array of 3 entries */
void setTextContextAtlasSizes_ForTesting(const GrBatchAtlasConfig* configs);
/** Enumerates all cached GPU resources and dumps their memory to traceMemoryDump. */
void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const;
private:
GrGpu* fGpu;
const GrCaps* fCaps;

View File

@ -15,6 +15,7 @@
class GrContext;
class GrGpu;
class GrResourceCache;
class SkTraceMemoryDump;
/**
* Base class for GrGpuResource. Handles the various types of refs we need. Separated out as a base
@ -138,7 +139,7 @@ private:
*/
class SK_API GrGpuResource : public GrIORef<GrGpuResource> {
public:
enum LifeCycle {
/**
@ -252,6 +253,13 @@ public:
*/
void abandon();
/**
* Dumps memory usage information for this GrGpuResource to traceMemoryDump.
* Typically, subclasses should not need to override this, and should only
* need to override setMemoryBacking.
**/
virtual void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const;
protected:
// This must be called by every GrGpuObject. It should be called once the object is fully
// initialized (i.e. not in a base class constructor).
@ -288,6 +296,12 @@ protected:
**/
void setScratchKey(const GrScratchKey& scratchKey);
/**
* Allows subclasses to add additional backing information to the SkTraceMemoryDump. Called by
* onMemoryDump. The default implementation adds no backing information.
**/
virtual void setMemoryBacking(SkTraceMemoryDump*, const SkString&) const {}
private:
/**
* Frees the object in the underlying 3D API. Called by CacheAccess.

View File

@ -105,7 +105,7 @@ void GrContext::DrawingMgr::flush() {
}
}
GrDrawContext* GrContext::DrawingMgr::drawContext(const SkSurfaceProps* surfaceProps) {
GrDrawContext* GrContext::DrawingMgr::drawContext(const SkSurfaceProps* surfaceProps) {
if (this->abandoned()) {
return nullptr;
}
@ -119,7 +119,7 @@ GrDrawContext* GrContext::DrawingMgr::drawContext(const SkSurfaceProps* surfaceP
}
// For now, everyone gets a faux creation ref
return SkRef(fDrawContext[props.pixelGeometry()][props.isUseDeviceIndependentFonts()]);
return SkRef(fDrawContext[props.pixelGeometry()][props.isUseDeviceIndependentFonts()]);
}
////////////////////////////////////////////////////////////////////////////////
@ -759,3 +759,8 @@ void GrContext::setResourceCacheLimits(int maxTextures, size_t maxTextureBytes)
fResourceCache->setLimits(maxTextures, maxTextureBytes);
}
//////////////////////////////////////////////////////////////////////////////
void GrContext::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
fResourceCache->dumpMemoryStatistics(traceMemoryDump);
}

View File

@ -11,6 +11,7 @@
#include "GrResourceCache.h"
#include "GrGpu.h"
#include "GrGpuResourcePriv.h"
#include "SkTraceMemoryDump.h"
static inline GrResourceCache* get_resource_cache(GrGpu* gpu) {
SkASSERT(gpu);
@ -52,6 +53,23 @@ void GrGpuResource::abandon() {
fGpuMemorySize = 0;
}
void GrGpuResource::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
// Dump resource as "skia/gpu_resources/resource_#".
SkString dumpName("skia/gpu_resources/resource_");
dumpName.appendS32(this->getUniqueID());
traceMemoryDump->dumpNumericValue(dumpName.c_str(), "size", "bytes", this->gpuMemorySize());
if (this->isPurgeable()) {
traceMemoryDump->dumpNumericValue(dumpName.c_str(), "purgeable_size", "bytes",
this->gpuMemorySize());
}
// Call setMemoryBacking to allow sub-classes with implementation specific backings (such as GL
// objects) to provide additional information.
this->setMemoryBacking(traceMemoryDump, dumpName);
}
const SkData* GrGpuResource::setCustomData(const SkData* data) {
SkSafeRef(data);
fData.reset(data);

View File

@ -616,6 +616,15 @@ void GrResourceCache::notifyFlushOccurred() {
}
}
void GrResourceCache::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
for (int i = 0; i < fNonpurgeableResources.count(); ++i) {
fNonpurgeableResources[i]->dumpMemoryStatistics(traceMemoryDump);
}
for (int i = 0; i < fPurgeableQueue.count(); ++i) {
fPurgeableQueue.at(i)->dumpMemoryStatistics(traceMemoryDump);
}
}
#ifdef SK_DEBUG
void GrResourceCache::validate() const {
// Reduce the frequency of validations for large resource counts.

View File

@ -22,6 +22,7 @@
class GrCaps;
class SkString;
class SkTraceMemoryDump;
/**
* Manages the lifetime of all GrGpuResource instances.
@ -178,7 +179,7 @@ public:
fOverBudgetCB = overBudgetCB;
fOverBudgetData = data;
}
void notifyFlushOccurred();
#if GR_GPU_STATS
@ -188,6 +189,9 @@ public:
// This function is for unit testing and is only defined in test tools.
void changeTimestamp(uint32_t newTimestamp);
// Enumerates all cached resources and dumps their details to traceMemoryDump.
void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const;
private:
///////////////////////////////////////////////////////////////////////////
/// @name Methods accessible via ResourceAccess

View File

@ -7,6 +7,7 @@
#include "GrGLIndexBuffer.h"
#include "GrGLGpu.h"
#include "SkTraceMemoryDump.h"
GrGLIndexBuffer::GrGLIndexBuffer(GrGLGpu* gpu, const Desc& desc)
: INHERITED(gpu, desc.fSizeInBytes, desc.fDynamic, 0 == desc.fID)
@ -48,3 +49,11 @@ bool GrGLIndexBuffer::onUpdateData(const void* src, size_t srcSizeInBytes) {
return false;
}
}
void GrGLIndexBuffer::setMemoryBacking(SkTraceMemoryDump* traceMemoryDump,
const SkString& dumpName) const {
SkString buffer_id;
buffer_id.appendU32(this->bufferID());
traceMemoryDump->setMemoryBacking(dumpName.c_str(), "gl_buffer",
buffer_id.c_str());
}

View File

@ -33,6 +33,8 @@ public:
protected:
void onAbandon() override;
void onRelease() override;
void setMemoryBacking(SkTraceMemoryDump* traceMemoryDump,
const SkString& dumpName) const override;
private:
void* onMap() override;

View File

@ -10,6 +10,7 @@
#include "GrRenderTargetPriv.h"
#include "GrGLGpu.h"
#include "GrGLUtil.h"
#include "SkTraceMemoryDump.h"
#define GPUGL static_cast<GrGLGpu*>(this->getGpu())
#define GL_CALL(X) GR_GL_CALL(GPUGL->glInterface(), X)
@ -43,20 +44,7 @@ void GrGLRenderTarget::init(const GrSurfaceDesc& desc, const IDDesc& idDesc) {
fViewport.fWidth = desc.fWidth;
fViewport.fHeight = desc.fHeight;
// We own one color value for each MSAA sample.
int colorValuesPerPixel = SkTMax(1, fDesc.fSampleCnt);
if (fTexFBOID != kUnresolvableFBOID && fTexFBOID != fRTFBOID) {
// If we own the resolve buffer then that is one more sample per pixel.
colorValuesPerPixel += 1;
} else if (fTexFBOID != 0) {
// For auto-resolving FBOs, the MSAA buffer is free.
colorValuesPerPixel = 1;
}
SkASSERT(kUnknown_GrPixelConfig != fDesc.fConfig);
SkASSERT(!GrPixelConfigIsCompressed(fDesc.fConfig));
size_t colorBytes = GrBytesPerPixel(fDesc.fConfig);
SkASSERT(colorBytes > 0);
fGpuMemorySize = colorValuesPerPixel * fDesc.fWidth * fDesc.fHeight * colorBytes;
fGpuMemorySize = this->totalSamples() * this->totalBytesPerSample();
SkASSERT(fGpuMemorySize <= WorseCaseSize(desc));
}
@ -160,3 +148,62 @@ GrGLGpu* GrGLRenderTarget::getGLGpu() const {
return static_cast<GrGLGpu*>(this->getGpu());
}
void GrGLRenderTarget::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
// Don't log the backing texture's contribution to the memory size. This will be handled by the
// texture object.
// 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();
// Due to this resource having both a texture and a renderbuffer component, dump as
// skia/gpu_resources/resource_#/renderbuffer
SkString dumpName("skia/gpu_resources/resource_");
dumpName.appendS32(this->getUniqueID());
dumpName.append("/renderbuffer");
traceMemoryDump->dumpNumericValue(dumpName.c_str(), "size", "bytes", size);
if (this->isPurgeable()) {
traceMemoryDump->dumpNumericValue(dumpName.c_str(), "purgeable_size", "bytes", size);
}
SkString renderbuffer_id;
renderbuffer_id.appendU32(fMSColorRenderbufferID);
traceMemoryDump->setMemoryBacking(dumpName.c_str(), "gl_renderbuffer",
renderbuffer_id.c_str());
}
}
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
// the render target's FBO (fTexFBOID == fRTFBOID) then we use the provided sample count.
return SkTMax(1, fDesc.fSampleCnt);
}
// When fTexFBOID == fRTFBOID, we either are not using MSAA, or MSAA is auto resolving, so use
// 0 for the sample count.
return 0;
}
int GrGLRenderTarget::totalSamples() const {
int total_samples = this->msaaSamples();
if (fTexFBOID != kUnresolvableFBOID) {
// If we own the resolve buffer then that is one more sample per pixel.
total_samples += 1;
}
return total_samples;
}

View File

@ -66,6 +66,10 @@ public:
return kCached_LifeCycle == fRTLifecycle || kUncached_LifeCycle == fRTLifecycle;
}
// GrGLRenderTarget overrides dumpMemoryStatistics so it can log its texture and renderbuffer
// components seperately.
void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const override;
protected:
// The public constructor registers this object with the cache. However, only the most derived
// class should register with the cache. This constructor does not do the registration and
@ -89,6 +93,12 @@ 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;
GrGLuint fRTFBOID;
GrGLuint fTexFBOID;
GrGLuint fMSColorRenderbufferID;

View File

@ -8,6 +8,7 @@
#include "GrGLStencilAttachment.h"
#include "GrGLGpu.h"
#include "SkTraceMemoryDump.h"
size_t GrGLStencilAttachment::onGpuMemorySize() const {
uint64_t size = this->width();
@ -33,3 +34,11 @@ void GrGLStencilAttachment::onAbandon() {
INHERITED::onAbandon();
}
void GrGLStencilAttachment::setMemoryBacking(SkTraceMemoryDump* traceMemoryDump,
const SkString& dumpName) const {
SkString renderbuffer_id;
renderbuffer_id.appendU32(this->renderbufferID());
traceMemoryDump->setMemoryBacking(dumpName.c_str(), "gl_renderbuffer",
renderbuffer_id.c_str());
}

View File

@ -50,6 +50,8 @@ protected:
// overrides of GrResource
void onRelease() override;
void onAbandon() override;
void setMemoryBacking(SkTraceMemoryDump* traceMemoryDump,
const SkString& dumpName) const override;
private:
size_t onGpuMemorySize() const override;

View File

@ -7,6 +7,7 @@
#include "GrGLTexture.h"
#include "GrGLGpu.h"
#include "SkTraceMemoryDump.h"
#define GPUGL static_cast<GrGLGpu*>(this->getGpu())
#define GL_CALL(X) GR_GL_CALL(GPUGL->glInterface(), X)
@ -51,3 +52,11 @@ void GrGLTexture::onAbandon() {
GrBackendObject GrGLTexture::getTextureHandle() const {
return static_cast<GrBackendObject>(this->textureID());
}
void GrGLTexture::setMemoryBacking(SkTraceMemoryDump* traceMemoryDump,
const SkString& dumpName) const {
SkString texture_id;
texture_id.appendU32(this->textureID());
traceMemoryDump->setMemoryBacking(dumpName.c_str(), "gl_texture",
texture_id.c_str());
}

View File

@ -63,6 +63,8 @@ protected:
void onAbandon() override;
void onRelease() override;
void setMemoryBacking(SkTraceMemoryDump* traceMemoryDump,
const SkString& dumpName) const override;
private:
TexParams fTexParams;

View File

@ -0,0 +1,39 @@
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "GrGLTextureRenderTarget.h"
#include "SkTraceMemoryDump.h"
// GrGLTextureRenderTarget must dump both of its superclasses.
void GrGLTextureRenderTarget::dumpMemoryStatistics(
SkTraceMemoryDump* traceMemoryDump) const {
GrGLRenderTarget::dumpMemoryStatistics(traceMemoryDump);
// Also dump the GrGLTexture's memory. Due to this resource having both a
// texture and a
// renderbuffer component, dump as skia/gpu_resources/resource_#/texture
SkString dumpName("skia/gpu_resources/resource_");
dumpName.appendS32(this->getUniqueID());
dumpName.append("/texture");
// Use the texture's gpuMemorySize, not our own, which includes the
// renderbuffer as well.
size_t size = GrGLTexture::gpuMemorySize();
traceMemoryDump->dumpNumericValue(dumpName.c_str(), "size", "bytes", size);
if (this->isPurgeable()) {
traceMemoryDump->dumpNumericValue(dumpName.c_str(), "purgeable_size",
"bytes", size);
}
SkString texture_id;
texture_id.appendU32(this->textureID());
traceMemoryDump->setMemoryBacking(dumpName.c_str(), "gl_texture",
texture_id.c_str());
}

View File

@ -9,6 +9,7 @@
#ifndef GrGLTextureRenderTarget_DEFINED
#define GrGLTextureRenderTarget_DEFINED
#include "GrGLGpu.h"
#include "GrGLTexture.h"
#include "GrGLRenderTarget.h"
@ -34,6 +35,8 @@ public:
this->registerWithCache();
}
void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const override;
protected:
void onAbandon() override {
GrGLRenderTarget::onAbandon();

View File

@ -7,6 +7,7 @@
#include "GrGLVertexBuffer.h"
#include "GrGLGpu.h"
#include "SkTraceMemoryDump.h"
GrGLVertexBuffer::GrGLVertexBuffer(GrGLGpu* gpu, const Desc& desc)
: INHERITED(gpu, desc.fSizeInBytes, desc.fDynamic, 0 == desc.fID)
@ -48,3 +49,11 @@ bool GrGLVertexBuffer::onUpdateData(const void* src, size_t srcSizeInBytes) {
return false;
}
}
void GrGLVertexBuffer::setMemoryBacking(SkTraceMemoryDump* traceMemoryDump,
const SkString& dumpName) const {
SkString buffer_id;
buffer_id.appendU32(this->bufferID());
traceMemoryDump->setMemoryBacking(dumpName.c_str(), "gl_buffer",
buffer_id.c_str());
}

View File

@ -33,6 +33,8 @@ public:
protected:
void onAbandon() override;
void onRelease() override;
void setMemoryBacking(SkTraceMemoryDump* traceMemoryDump,
const SkString& dumpName) const override;
private:
void* onMap() override;

View File

@ -674,6 +674,7 @@ SRCS = ['include/private/SkChecksum.h',
'src/gpu/gl/GrGLRenderTarget.cpp',
'src/gpu/gl/GrGLStencilAttachment.cpp',
'src/gpu/gl/GrGLTexture.cpp',
'src/gpu/gl/GrGLTextureRenderTarget.cpp'
'src/gpu/gl/GrGLUtil.cpp',
'src/gpu/gl/GrGLVertexArray.cpp',
'src/gpu/gl/GrGLVertexBuffer.cpp',