Bug 638549 - WebGL about:memory - part 1: initial implementation accounting for WebGLContexts and WebGLTextures - r=jrmuizel

This commit is contained in:
Benoit Jacob 2011-07-07 20:01:12 -04:00
parent b056df375e
commit 2dbf369778
3 changed files with 172 additions and 0 deletions

View File

@ -73,6 +73,54 @@ using namespace mozilla;
using namespace mozilla::gl;
using namespace mozilla::layers;
WebGLMemoryReporter* WebGLMemoryReporter::sUniqueInstance = nsnull;
NS_MEMORY_REPORTER_IMPLEMENT(WebGLTextureMemoryUsed,
"webgl-texture-memory",
KIND_OTHER,
UNITS_BYTES,
WebGLMemoryReporter::GetTextureMemoryUsed,
"Memory used by WebGL textures. The OpenGL implementation is free to store these textures in either video memory or main memory.")
NS_MEMORY_REPORTER_IMPLEMENT(WebGLTextureCount,
"webgl-texture-count",
KIND_OTHER,
UNITS_COUNT,
WebGLMemoryReporter::GetTextureCount,
"Number of WebGL textures.")
NS_MEMORY_REPORTER_IMPLEMENT(WebGLContextCount,
"webgl-context-count",
KIND_OTHER,
UNITS_COUNT,
WebGLMemoryReporter::GetContextCount,
"Number of WebGL contexts.")
WebGLMemoryReporter* WebGLMemoryReporter::UniqueInstance()
{
if (!sUniqueInstance) {
sUniqueInstance = new WebGLMemoryReporter;
}
return sUniqueInstance;
}
WebGLMemoryReporter::WebGLMemoryReporter()
: mTextureMemoryUsageReporter(new NS_MEMORY_REPORTER_NAME(WebGLTextureMemoryUsed))
, mTextureCountReporter(new NS_MEMORY_REPORTER_NAME(WebGLTextureCount))
, mContextCountReporter(new NS_MEMORY_REPORTER_NAME(WebGLContextCount))
{
NS_RegisterMemoryReporter(mTextureMemoryUsageReporter);
NS_RegisterMemoryReporter(mTextureCountReporter);
NS_RegisterMemoryReporter(mContextCountReporter);
}
WebGLMemoryReporter::~WebGLMemoryReporter()
{
NS_UnregisterMemoryReporter(mTextureMemoryUsageReporter);
NS_UnregisterMemoryReporter(mTextureCountReporter);
NS_UnregisterMemoryReporter(mContextCountReporter);
}
nsresult NS_NewCanvasRenderingContextWebGL(nsIDOMWebGLRenderingContext** aResult);
nsresult
@ -165,11 +213,14 @@ WebGLContext::WebGLContext()
// See OpenGL ES 2.0.25 spec, 6.2 State Tables, table 6.13
mPixelStorePackAlignment = 4;
mPixelStoreUnpackAlignment = 4;
WebGLMemoryReporter::AddWebGLContext(this);
}
WebGLContext::~WebGLContext()
{
DestroyResourcesAndContext();
WebGLMemoryReporter::RemoveWebGLContext(this);
}
static PLDHashOperator

View File

@ -56,6 +56,7 @@
#include "nsWeakReference.h"
#include "nsIDOMHTMLElement.h"
#include "nsIJSNativeInitializer.h"
#include "nsIMemoryReporter.h"
#include "GLContextProvider.h"
#include "Layers.h"
@ -320,6 +321,8 @@ class WebGLContext :
public nsICanvasRenderingContextInternal,
public nsSupportsWeakReference
{
friend class WebGLMemoryReporter;
public:
WebGLContext();
virtual ~WebGLContext();
@ -469,6 +472,8 @@ protected:
PRBool ValidateAttribIndex(WebGLuint index, const char *info);
PRBool ValidateStencilParamsForDrawCall();
static PRUint32 GetTexelSize(WebGLenum format, WebGLenum type);
void Invalidate();
void DestroyResourcesAndContext();
@ -909,6 +914,12 @@ protected:
return is_pot_assuming_nonnegative(mWidth) &&
is_pot_assuming_nonnegative(mHeight); // negative sizes should never happen (caught in texImage2D...)
}
PRInt64 MemoryUsage() const {
if (!mIsDefined)
return 0;
PRInt64 texelSize = WebGLContext::GetTexelSize(mFormat, mType);
return PRInt64(mWidth) * PRInt64(mHeight) * texelSize;
}
WebGLsizei mWidth, mHeight;
WebGLenum mFormat, mType;
PRBool mIsDefined;
@ -939,6 +950,22 @@ public:
return target == LOCAL_GL_TEXTURE_2D ? 0 : target - LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X;
}
PRInt64 MemoryUsage() const {
PRInt64 result = 0;
for(size_t face = 0; face < mFacesCount; face++) {
if (mHaveGeneratedMipmap) {
// Each mipmap level is 1/4 the size of the previous level
// 1 + x + x^2 + ... = 1/(1-x)
// for x = 1/4, we get 1/(1-1/4) = 4/3
result += ImageInfoAt(0, face).MemoryUsage() * 4 / 3;
} else {
for(size_t level = 0; level <= mMaxLevelWithCustomImages; level++)
result += ImageInfoAt(level, face).MemoryUsage();
}
}
return result;
}
protected:
WebGLenum mTarget;
@ -2066,6 +2093,72 @@ WebGLContext::CanGetConcreteObject(const char *info,
return GetConcreteObject(info, aInterface, &aConcreteObject, isNull, isDeleted, PR_FALSE);
}
class WebGLMemoryReporter
{
WebGLMemoryReporter();
~WebGLMemoryReporter();
static WebGLMemoryReporter* sUniqueInstance;
// here we store plain pointers, not RefPtrs: we don't want the WebGLMemoryReporter unique instance to keep alive all
// WebGLContexts ever created.
typedef nsTArray<const WebGLContext*> ContextsArrayType;
ContextsArrayType mContexts;
nsIMemoryReporter *mTextureMemoryUsageReporter;
nsIMemoryReporter *mTextureCountReporter;
nsIMemoryReporter *mContextCountReporter;
static WebGLMemoryReporter* UniqueInstance();
static ContextsArrayType & Contexts() { return UniqueInstance()->mContexts; }
public:
static void AddWebGLContext(const WebGLContext* c) {
Contexts().AppendElement(c);
}
static void RemoveWebGLContext(const WebGLContext* c) {
ContextsArrayType & contexts = Contexts();
contexts.RemoveElement(c);
if (contexts.IsEmpty()) {
delete sUniqueInstance;
sUniqueInstance = nsnull;
}
}
static PLDHashOperator TextureMemoryUsageFunction(const PRUint32&, WebGLTexture *aValue, void *aData)
{
PRInt64 *result = (PRInt64*) aData;
*result += aValue->MemoryUsage();
return PL_DHASH_NEXT;
}
static PRInt64 GetTextureMemoryUsed() {
const ContextsArrayType & contexts = Contexts();
PRInt64 result = 0;
for(size_t i = 0; i < contexts.Length(); ++i) {
PRInt64 textureMemoryUsageForThisContext = 0;
contexts[i]->mMapTextures.EnumerateRead(TextureMemoryUsageFunction, &textureMemoryUsageForThisContext);
result += textureMemoryUsageForThisContext;
}
return result;
}
static PRInt64 GetTextureCount() {
const ContextsArrayType & contexts = Contexts();
PRInt64 result = 0;
for(size_t i = 0; i < contexts.Length(); ++i) {
result += contexts[i]->mMapTextures.Count();
}
return result;
}
static PRInt64 GetContextCount() {
return Contexts().Length();
}
};
}
#endif

View File

@ -328,6 +328,34 @@ PRBool WebGLContext::ValidateDrawModeEnum(WebGLenum mode, const char *info)
}
}
PRUint32 WebGLContext::GetTexelSize(WebGLenum format, WebGLenum type)
{
if (type == LOCAL_GL_UNSIGNED_BYTE || type == LOCAL_GL_FLOAT) {
int multiplier = type == LOCAL_GL_FLOAT ? 4 : 1;
switch (format) {
case LOCAL_GL_ALPHA:
case LOCAL_GL_LUMINANCE:
return 1 * multiplier;
case LOCAL_GL_LUMINANCE_ALPHA:
return 2 * multiplier;
case LOCAL_GL_RGB:
return 3 * multiplier;
case LOCAL_GL_RGBA:
return 4 * multiplier;
default:
break;
}
} else if (type == LOCAL_GL_UNSIGNED_SHORT_4_4_4_4 ||
type == LOCAL_GL_UNSIGNED_SHORT_5_5_5_1 ||
type == LOCAL_GL_UNSIGNED_SHORT_5_6_5)
{
return 2;
}
NS_ABORT();
return 0;
}
PRBool WebGLContext::ValidateTexFormatAndType(WebGLenum format, WebGLenum type, int jsArrayType,
PRUint32 *texelSize, const char *info)
{