--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -109,16 +109,19 @@ WebGLContextOptions::WebGLContextOptions
}
/*static*/ const uint32_t WebGLContext::kMinMaxColorAttachments = 4;
/*static*/ const uint32_t WebGLContext::kMinMaxDrawBuffers = 4;
WebGLContext::WebGLContext()
: WebGLContextUnchecked(nullptr)
+ , mMaxPerfWarnings(gfxPrefs::WebGLMaxPerfWarnings())
+ , mNumPerfWarnings(0)
+ , mMaxAcceptableFBStatusInvals(gfxPrefs::WebGLMaxAcceptableFBStatusInvals())
, mBufferFetchingIsVerified(false)
, mBufferFetchingHasPerVertex(false)
, mMaxFetchedVertices(0)
, mMaxFetchedInstances(0)
, mLayerIsMirror(false)
, mBypassShaderValidation(false)
, mEmptyTFO(0)
, mContextLossHandler(this)
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -326,16 +326,20 @@ class WebGLContext
BROWSER_DEFAULT_WEBGL = 0x9244,
UNMASKED_VENDOR_WEBGL = 0x9245,
UNMASKED_RENDERER_WEBGL = 0x9246
};
static const uint32_t kMinMaxColorAttachments;
static const uint32_t kMinMaxDrawBuffers;
+ const uint32_t mMaxPerfWarnings;
+ mutable uint64_t mNumPerfWarnings;
+ const uint32_t mMaxAcceptableFBStatusInvals;
+
public:
WebGLContext();
protected:
virtual ~WebGLContext();
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
@@ -1930,16 +1934,20 @@ protected:
int mDrawCallsSinceLastFlush;
int mAlreadyGeneratedWarnings;
int mMaxWarnings;
bool mAlreadyWarnedAboutFakeVertexAttrib0;
bool ShouldGenerateWarnings() const;
+ bool ShouldGeneratePerfWarnings() const {
+ return mNumPerfWarnings < mMaxPerfWarnings;
+ }
+
uint64_t mLastUseIndex;
bool mNeedsFakeNoAlpha;
bool mNeedsFakeNoDepth;
bool mNeedsFakeNoStencil;
bool mNeedsEmulatedLoneDepthStencil;
const bool mAllowFBInvalidation;
@@ -2022,16 +2030,18 @@ protected:
ForceDiscreteGPUHelperCGL mForceDiscreteGPUHelper;
#endif
public:
// console logging helpers
void GenerateWarning(const char* fmt, ...);
void GenerateWarning(const char* fmt, va_list ap);
+ void GeneratePerfWarning(const char* fmt, ...) const;
+
public:
UniquePtr<webgl::FormatUsageAuthority> mFormatUsage;
virtual UniquePtr<webgl::FormatUsageAuthority>
CreateFormatUsage(gl::GLContext* gl) const = 0;
const decltype(mBound2DTextures)* TexListForElemType(GLenum elemType) const;
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -343,44 +343,46 @@ WebGLContext::DeleteFramebuffer(WebGLFra
BindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER,
static_cast<WebGLFramebuffer*>(nullptr));
}
}
void
WebGLContext::DeleteRenderbuffer(WebGLRenderbuffer* rbuf)
{
- if (!ValidateDeleteObject("deleteRenderbuffer", rbuf))
+ const char funcName[] = "deleteRenderbuffer";
+ if (!ValidateDeleteObject(funcName, rbuf))
return;
if (mBoundDrawFramebuffer)
- mBoundDrawFramebuffer->DetachRenderbuffer(rbuf);
+ mBoundDrawFramebuffer->DetachRenderbuffer(funcName, rbuf);
if (mBoundReadFramebuffer)
- mBoundReadFramebuffer->DetachRenderbuffer(rbuf);
-
- rbuf->InvalidateStatusOfAttachedFBs();
+ mBoundReadFramebuffer->DetachRenderbuffer(funcName, rbuf);
+
+ rbuf->InvalidateStatusOfAttachedFBs(funcName);
if (mBoundRenderbuffer == rbuf)
BindRenderbuffer(LOCAL_GL_RENDERBUFFER, nullptr);
rbuf->RequestDelete();
}
void
WebGLContext::DeleteTexture(WebGLTexture* tex)
{
- if (!ValidateDeleteObject("deleteTexture", tex))
+ const char funcName[] = "deleteTexture";
+ if (!ValidateDeleteObject(funcName, tex))
return;
if (mBoundDrawFramebuffer)
- mBoundDrawFramebuffer->DetachTexture(tex);
+ mBoundDrawFramebuffer->DetachTexture(funcName, tex);
if (mBoundReadFramebuffer)
- mBoundReadFramebuffer->DetachTexture(tex);
+ mBoundReadFramebuffer->DetachTexture(funcName, tex);
GLuint activeTexture = mActiveTexture;
for (int32_t i = 0; i < mGLMaxTextureUnits; i++) {
if (mBound2DTextures[i] == tex ||
mBoundCubeMapTextures[i] == tex ||
mBound3DTextures[i] == tex ||
mBound2DArrayTextures[i] == tex)
{
--- a/dom/canvas/WebGLContextUtils.cpp
+++ b/dom/canvas/WebGLContextUtils.cpp
@@ -85,17 +85,17 @@ WebGLContext::GenerateWarning(const char
}
dom::AutoJSAPI api;
if (!api.Init(mCanvasElement->OwnerDoc()->GetScopeObject())) {
return;
}
JSContext* cx = api.cx();
- JS_ReportWarningASCII(cx, "WebGL: %s", buf);
+ JS_ReportWarningASCII(cx, "WebGL warning: %s", buf);
if (!ShouldGenerateWarnings()) {
JS_ReportWarningASCII(cx,
"WebGL: No further warnings will be reported for"
" this WebGL context."
" (already reported %d warnings)",
mAlreadyGeneratedWarnings);
}
}
@@ -105,16 +105,53 @@ WebGLContext::ShouldGenerateWarnings() c
{
if (mMaxWarnings == -1)
return true;
return mAlreadyGeneratedWarnings < mMaxWarnings;
}
void
+WebGLContext::GeneratePerfWarning(const char* fmt, ...) const
+{
+ if (!ShouldGeneratePerfWarnings())
+ return;
+
+ if (!mCanvasElement)
+ return;
+
+ dom::AutoJSAPI api;
+ if (!api.Init(mCanvasElement->OwnerDoc()->GetScopeObject()))
+ return;
+ JSContext* cx = api.cx();
+
+ ////
+
+ va_list ap;
+ va_start(ap, fmt);
+
+ char buf[1024];
+ PR_vsnprintf(buf, 1024, fmt, ap);
+
+ va_end(ap);
+
+ ////
+
+ JS_ReportWarningASCII(cx, "WebGL perf warning: %s", buf);
+ mNumPerfWarnings++;
+
+ if (!ShouldGeneratePerfWarnings()) {
+ JS_ReportWarningASCII(cx,
+ "WebGL: After reporting %u, no further perf warnings will"
+ " be reported for this WebGL context.",
+ uint32_t(mNumPerfWarnings));
+ }
+}
+
+void
WebGLContext::SynthesizeGLError(GLenum err)
{
/* ES2 section 2.5 "GL Errors" states that implementations can have
* multiple 'flags', as errors might be caught in different parts of
* a distributed implementation.
* We're signing up as a distributed implementation here, with
* separate flags for WebGL and the underlying GLContext.
*/
--- a/dom/canvas/WebGLFramebuffer.cpp
+++ b/dom/canvas/WebGLFramebuffer.cpp
@@ -42,17 +42,18 @@ WebGLFBAttachPoint::~WebGLFBAttachPoint(
MOZ_ASSERT(mFB, "Should have been Init'd.");
MOZ_ASSERT(!mRenderbufferPtr);
MOZ_ASSERT(!mTexturePtr);
}
void
WebGLFBAttachPoint::Unlink()
{
- Clear();
+ const char funcName[] = "WebGLFramebuffer::GC";
+ Clear(funcName);
}
bool
WebGLFBAttachPoint::IsDeleteRequested() const
{
return Texture() ? Texture()->IsDeleteRequested()
: Renderbuffer() ? Renderbuffer()->IsDeleteRequested()
: false;
@@ -109,51 +110,51 @@ WebGLFBAttachPoint::IsReadableFloat() co
auto format = formatUsage->format;
if (!format->IsColorFormat())
return false;
return format->componentType == webgl::ComponentType::Float;
}
void
-WebGLFBAttachPoint::Clear()
+WebGLFBAttachPoint::Clear(const char* funcName)
{
if (mRenderbufferPtr) {
MOZ_ASSERT(!mTexturePtr);
mRenderbufferPtr->UnmarkAttachment(*this);
} else if (mTexturePtr) {
mTexturePtr->ImageInfoAt(mTexImageTarget, mTexImageLevel).RemoveAttachPoint(this);
}
mTexturePtr = nullptr;
mRenderbufferPtr = nullptr;
- OnBackingStoreRespecified();
+ OnBackingStoreRespecified(funcName);
}
void
-WebGLFBAttachPoint::SetTexImage(WebGLTexture* tex, TexImageTarget target, GLint level,
- GLint layer)
+WebGLFBAttachPoint::SetTexImage(const char* funcName, WebGLTexture* tex,
+ TexImageTarget target, GLint level, GLint layer)
{
- Clear();
+ Clear(funcName);
mTexturePtr = tex;
mTexImageTarget = target;
mTexImageLevel = level;
mTexImageLayer = layer;
if (mTexturePtr) {
mTexturePtr->ImageInfoAt(mTexImageTarget, mTexImageLevel).AddAttachPoint(this);
}
}
void
-WebGLFBAttachPoint::SetRenderbuffer(WebGLRenderbuffer* rb)
+WebGLFBAttachPoint::SetRenderbuffer(const char* funcName, WebGLRenderbuffer* rb)
{
- Clear();
+ Clear(funcName);
mRenderbufferPtr = rb;
if (mRenderbufferPtr) {
mRenderbufferPtr->MarkAttachment(*this);
}
}
@@ -221,19 +222,19 @@ WebGLFBAttachPoint::Size(uint32_t* const
MOZ_ASSERT(Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel).IsDefined());
const auto& imageInfo = Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel);
*out_width = imageInfo.mWidth;
*out_height = imageInfo.mHeight;
}
void
-WebGLFBAttachPoint::OnBackingStoreRespecified() const
+WebGLFBAttachPoint::OnBackingStoreRespecified(const char* funcName) const
{
- mFB->InvalidateFramebufferStatus();
+ mFB->InvalidateFramebufferStatus(funcName);
}
void
WebGLFBAttachPoint::AttachmentName(nsCString* out) const
{
switch (mAttachmentPoint) {
case LOCAL_GL_DEPTH_ATTACHMENT:
out->AssignLiteral("DEPTH_ATTACHMENT");
@@ -606,16 +607,17 @@ WebGLFBAttachPoint::GetParameter(const c
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// WebGLFramebuffer
WebGLFramebuffer::WebGLFramebuffer(WebGLContext* webgl, GLuint fbo)
: WebGLRefCountedObject(webgl)
, mGLName(fbo)
+ , mNumFBStatusInvals(0)
#ifdef ANDROID
, mIsFB(false)
#endif
, mDepthAttachment(this, LOCAL_GL_DEPTH_ATTACHMENT)
, mStencilAttachment(this, LOCAL_GL_STENCIL_ATTACHMENT)
, mDepthStencilAttachment(this, LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
{
mContext->mFramebuffers.insertBack(this);
@@ -628,24 +630,26 @@ WebGLFramebuffer::WebGLFramebuffer(WebGL
mColorDrawBuffers.push_back(&mColorAttachments[0]);
mColorReadBuffer = &mColorAttachments[0];
}
void
WebGLFramebuffer::Delete()
{
- InvalidateFramebufferStatus();
+ const char funcName[] = "WebGLFramebuffer::Delete";
+
+ InvalidateFramebufferStatus(funcName);
- mDepthAttachment.Clear();
- mStencilAttachment.Clear();
- mDepthStencilAttachment.Clear();
+ mDepthAttachment.Clear(funcName);
+ mStencilAttachment.Clear(funcName);
+ mDepthStencilAttachment.Clear(funcName);
for (auto& cur : mColorAttachments) {
- cur.Clear();
+ cur.Clear(funcName);
}
mContext->MakeContextCurrent();
mContext->gl->fDeleteFramebuffers(1, &mGLName);
LinkedListElement<WebGLFramebuffer>::removeFrom(mContext->mFramebuffers);
#ifdef ANDROID
@@ -696,33 +700,33 @@ WebGLFramebuffer::GetAttachPoint(GLenum
X(mStencilAttachment); \
X(mDepthStencilAttachment); \
\
for (auto& cur : mColorAttachments) { \
X(cur); \
}
void
-WebGLFramebuffer::DetachTexture(const WebGLTexture* tex)
+WebGLFramebuffer::DetachTexture(const char* funcName, const WebGLTexture* tex)
{
const auto fnDetach = [&](WebGLFBAttachPoint& attach) {
if (attach.Texture() == tex) {
- attach.Clear();
+ attach.Clear(funcName);
}
};
FOR_EACH_ATTACHMENT(fnDetach)
}
void
-WebGLFramebuffer::DetachRenderbuffer(const WebGLRenderbuffer* rb)
+WebGLFramebuffer::DetachRenderbuffer(const char* funcName, const WebGLRenderbuffer* rb)
{
const auto fnDetach = [&](WebGLFBAttachPoint& attach) {
if (attach.Renderbuffer() == rb) {
- attach.Clear();
+ attach.Clear(funcName);
}
};
FOR_EACH_ATTACHMENT(fnDetach)
}
////////////////////////////////////////////////////////////////////////////////
// Completeness
@@ -1123,16 +1127,31 @@ WebGLFramebuffer::ResolvedData::Resolved
if (!fnCommon(attach))
return;
readSet.insert(WebGLFBAttachPoint::Ordered(attach));
}
}
void
+WebGLFramebuffer::InvalidateFramebufferStatus(const char* funcName)
+{
+ if (mResolvedCompleteData) {
+ mNumFBStatusInvals++;
+ if (mNumFBStatusInvals > mContext->mMaxAcceptableFBStatusInvals) {
+ mContext->GeneratePerfWarning("%s: FB was invalidated after being complete %u"
+ " times.",
+ funcName, uint32_t(mNumFBStatusInvals));
+ }
+ }
+
+ mResolvedCompleteData = nullptr;
+}
+
+void
WebGLFramebuffer::RefreshResolvedData()
{
if (mResolvedCompleteData) {
mResolvedCompleteData.reset(new ResolvedData(*this));
}
}
////////////////////////////////////////////////////////////////////////////////
@@ -1341,23 +1360,23 @@ WebGLFramebuffer::FramebufferRenderbuffe
// `rb`
if (rb && !mContext->ValidateObject("framebufferRenderbuffer: rb", *rb))
return;
// End of validation.
if (mContext->IsWebGL2() && attachEnum == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
- mDepthAttachment.SetRenderbuffer(rb);
- mStencilAttachment.SetRenderbuffer(rb);
+ mDepthAttachment.SetRenderbuffer(funcName, rb);
+ mStencilAttachment.SetRenderbuffer(funcName, rb);
} else {
- attach->SetRenderbuffer(rb);
+ attach->SetRenderbuffer(funcName, rb);
}
- InvalidateFramebufferStatus();
+ InvalidateFramebufferStatus(funcName);
}
void
WebGLFramebuffer::FramebufferTexture2D(const char* funcName, GLenum attachEnum,
GLenum texImageTarget, WebGLTexture* tex,
GLint level)
{
MOZ_ASSERT(mContext->mBoundDrawFramebuffer == this ||
@@ -1429,23 +1448,23 @@ WebGLFramebuffer::FramebufferTexture2D(c
}
} else if (level != 0) {
return mContext->ErrorInvalidValue("%s: `level` must be 0.", funcName);
}
// End of validation.
if (mContext->IsWebGL2() && attachEnum == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
- mDepthAttachment.SetTexImage(tex, texImageTarget, level);
- mStencilAttachment.SetTexImage(tex, texImageTarget, level);
+ mDepthAttachment.SetTexImage(funcName, tex, texImageTarget, level);
+ mStencilAttachment.SetTexImage(funcName, tex, texImageTarget, level);
} else {
- attach->SetTexImage(tex, texImageTarget, level);
+ attach->SetTexImage(funcName, tex, texImageTarget, level);
}
- InvalidateFramebufferStatus();
+ InvalidateFramebufferStatus(funcName);
}
void
WebGLFramebuffer::FramebufferTextureLayer(const char* funcName, GLenum attachEnum,
WebGLTexture* tex, GLint level, GLint layer)
{
MOZ_ASSERT(mContext->mBoundDrawFramebuffer == this ||
mContext->mBoundReadFramebuffer == this);
@@ -1513,23 +1532,23 @@ WebGLFramebuffer::FramebufferTextureLaye
funcName);
return;
}
}
// End of validation.
if (mContext->IsWebGL2() && attachEnum == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
- mDepthAttachment.SetTexImage(tex, texImageTarget, level, layer);
- mStencilAttachment.SetTexImage(tex, texImageTarget, level, layer);
+ mDepthAttachment.SetTexImage(funcName, tex, texImageTarget, level, layer);
+ mStencilAttachment.SetTexImage(funcName, tex, texImageTarget, level, layer);
} else {
- attach->SetTexImage(tex, texImageTarget, level, layer);
+ attach->SetTexImage(funcName, tex, texImageTarget, level, layer);
}
- InvalidateFramebufferStatus();
+ InvalidateFramebufferStatus(funcName);
}
JS::Value
WebGLFramebuffer::GetAttachmentParameter(const char* funcName, JSContext* cx,
GLenum target, GLenum attachEnum, GLenum pname,
ErrorResult* const out_error)
{
const auto maybeAttach = GetAttachPoint(attachEnum);
--- a/dom/canvas/WebGLFramebuffer.h
+++ b/dom/canvas/WebGLFramebuffer.h
@@ -61,21 +61,21 @@ public:
bool IsDeleteRequested() const;
const webgl::FormatUsageInfo* Format() const;
uint32_t Samples() const;
bool HasAlpha() const;
bool IsReadableFloat() const;
- void Clear();
+ void Clear(const char* funcName);
- void SetTexImage(WebGLTexture* tex, TexImageTarget target, GLint level,
- GLint layer = 0);
- void SetRenderbuffer(WebGLRenderbuffer* rb);
+ void SetTexImage(const char* funcName, WebGLTexture* tex, TexImageTarget target,
+ GLint level, GLint layer = 0);
+ void SetRenderbuffer(const char* funcName, WebGLRenderbuffer* rb);
WebGLTexture* Texture() const { return mTexturePtr; }
WebGLRenderbuffer* Renderbuffer() const { return mRenderbufferPtr; }
TexImageTarget ImageTarget() const {
return mTexImageTarget;
}
GLint Layer() const {
@@ -95,17 +95,17 @@ public:
bool IsComplete(WebGLContext* webgl, nsCString* const out_info) const;
void Resolve(gl::GLContext* gl) const;
JS::Value GetParameter(const char* funcName, WebGLContext* webgl, JSContext* cx,
GLenum target, GLenum attachment, GLenum pname,
ErrorResult* const out_error) const;
- void OnBackingStoreRespecified() const;
+ void OnBackingStoreRespecified(const char* funcName) const;
bool IsEquivalentForFeedback(const WebGLFBAttachPoint& other) const {
if (!IsDefined() || !other.IsDefined())
return false;
#define _(X) X == other.X
return ( _(mRenderbufferPtr) &&
_(mTexturePtr) &&
@@ -149,16 +149,19 @@ class WebGLFramebuffer final
{
friend class WebGLContext;
public:
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(WebGLFramebuffer)
const GLuint mGLName;
+private:
+ uint64_t mNumFBStatusInvals;
+
protected:
#ifdef ANDROID
// Bug 1140459: Some drivers (including our test slaves!) don't
// give reasonable answers for IsRenderbuffer, maybe others.
// This shows up on Android 2.3 emulator.
//
// So we track the `is a Framebuffer` state ourselves.
bool mIsFB;
@@ -225,18 +228,18 @@ protected:
Maybe<WebGLFBAttachPoint*> GetAttachPoint(GLenum attachment); // Fallible
Maybe<WebGLFBAttachPoint*> GetColorAttachPoint(GLenum attachment); // Fallible
void ResolveAttachments() const;
void RefreshDrawBuffers() const;
void RefreshReadBuffer() const;
bool ResolveAttachmentData(const char* funcName) const;
public:
- void DetachTexture(const WebGLTexture* tex);
- void DetachRenderbuffer(const WebGLRenderbuffer* rb);
+ void DetachTexture(const char* funcName, const WebGLTexture* tex);
+ void DetachRenderbuffer(const char* funcName, const WebGLRenderbuffer* rb);
bool ValidateAndInitAttachments(const char* funcName);
bool ValidateClearBufferType(const char* funcName, GLenum buffer, uint32_t drawBuffer,
GLenum funcType) const;
bool ValidateForRead(const char* info,
const webgl::FormatUsageInfo** const out_format,
uint32_t* const out_width, uint32_t* const out_height);
@@ -253,21 +256,17 @@ public:
GETTER(ResolvedCompleteData)
#undef GETTER
////////////////
// Invalidation
bool IsResolvedComplete() const { return bool(mResolvedCompleteData); }
-
- void InvalidateFramebufferStatus() {
- mResolvedCompleteData = nullptr;
- }
-
+ void InvalidateFramebufferStatus(const char* funcName);
void RefreshResolvedData();
////////////////
// WebGL funcs
FBStatus CheckFramebufferStatus(const char* funcName);
void FramebufferRenderbuffer(const char* funcName, GLenum attachment, GLenum rbtarget,
WebGLRenderbuffer* rb);
--- a/dom/canvas/WebGLFramebufferAttachable.cpp
+++ b/dom/canvas/WebGLFramebufferAttachable.cpp
@@ -26,18 +26,18 @@ WebGLFramebufferAttachable::UnmarkAttach
MOZ_ASSERT(false, "Is not attached to FB");
return;
}
mAttachmentPoints.RemoveElementAt(i);
}
void
-WebGLFramebufferAttachable::InvalidateStatusOfAttachedFBs() const
+WebGLFramebufferAttachable::InvalidateStatusOfAttachedFBs(const char* funcName) const
{
const size_t count = mAttachmentPoints.Length();
for (size_t i = 0; i < count; ++i) {
MOZ_ASSERT(mAttachmentPoints[i]->mFB);
- mAttachmentPoints[i]->mFB->InvalidateFramebufferStatus();
+ mAttachmentPoints[i]->mFB->InvalidateFramebufferStatus(funcName);
}
}
} // namespace mozilla
--- a/dom/canvas/WebGLFramebufferAttachable.h
+++ b/dom/canvas/WebGLFramebufferAttachable.h
@@ -14,14 +14,14 @@ class WebGLFBAttachPoint;
class WebGLFramebufferAttachable
{
nsTArray<const WebGLFBAttachPoint*> mAttachmentPoints;
public:
// Track FBO/Attachment combinations
void MarkAttachment(const WebGLFBAttachPoint& attachment);
void UnmarkAttachment(const WebGLFBAttachPoint& attachment);
- void InvalidateStatusOfAttachedFBs() const;
+ void InvalidateStatusOfAttachedFBs(const char* funcName) const;
};
} // namespace mozilla
#endif // !WEBGLFRAMEBUFFERATTACHABLE_H_
--- a/dom/canvas/WebGLRenderbuffer.cpp
+++ b/dom/canvas/WebGLRenderbuffer.cpp
@@ -219,17 +219,17 @@ WebGLRenderbuffer::RenderbufferStorage(c
}
mSamples = samples;
mFormat = usage;
mWidth = width;
mHeight = height;
mImageDataStatus = WebGLImageDataStatus::UninitializedImageData;
- InvalidateStatusOfAttachedFBs();
+ InvalidateStatusOfAttachedFBs(funcName);
}
void
WebGLRenderbuffer::DoFramebufferRenderbuffer(FBTarget target, GLenum attachment) const
{
gl::GLContext* gl = mContext->gl;
if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
--- a/dom/canvas/WebGLTexture.cpp
+++ b/dom/canvas/WebGLTexture.cpp
@@ -28,48 +28,46 @@ namespace mozilla {
template <typename T>
static inline T&
Mutable(const T& x)
{
return const_cast<T&>(x);
}
void
-WebGLTexture::ImageInfo::Clear()
+WebGLTexture::ImageInfo::Clear(const char* funcName)
{
if (!IsDefined())
return;
- OnRespecify();
+ OnRespecify(funcName);
Mutable(mFormat) = LOCAL_GL_NONE;
Mutable(mWidth) = 0;
Mutable(mHeight) = 0;
Mutable(mDepth) = 0;
MOZ_ASSERT(!IsDefined());
}
-WebGLTexture::ImageInfo&
-WebGLTexture::ImageInfo::operator =(const ImageInfo& a)
+void
+WebGLTexture::ImageInfo::Set(const char* funcName, const ImageInfo& a)
{
MOZ_ASSERT(a.IsDefined());
Mutable(mFormat) = a.mFormat;
Mutable(mWidth) = a.mWidth;
Mutable(mHeight) = a.mHeight;
Mutable(mDepth) = a.mDepth;
mIsDataInitialized = a.mIsDataInitialized;
// But *don't* transfer mAttachPoints!
MOZ_ASSERT(a.mAttachPoints.empty());
- OnRespecify();
-
- return *this;
+ OnRespecify(funcName);
}
bool
WebGLTexture::ImageInfo::IsPowerOfTwo() const
{
return mozilla::IsPowerOfTwo(mWidth) &&
mozilla::IsPowerOfTwo(mHeight) &&
mozilla::IsPowerOfTwo(mDepth);
@@ -86,20 +84,20 @@ WebGLTexture::ImageInfo::AddAttachPoint(
void
WebGLTexture::ImageInfo::RemoveAttachPoint(WebGLFBAttachPoint* attachPoint)
{
DebugOnly<size_t> numElemsErased = mAttachPoints.erase(attachPoint);
MOZ_ASSERT_IF(IsDefined(), numElemsErased == 1);
}
void
-WebGLTexture::ImageInfo::OnRespecify() const
+WebGLTexture::ImageInfo::OnRespecify(const char* funcName) const
{
for (auto cur : mAttachPoints) {
- cur->OnBackingStoreRespecified();
+ cur->OnBackingStoreRespecified(funcName);
}
}
size_t
WebGLTexture::ImageInfo::MemoryUsage() const
{
if (!IsDefined())
return 0;
@@ -144,18 +142,19 @@ WebGLTexture::WebGLTexture(WebGLContext*
, mResolved_Swizzle(nullptr)
{
mContext->mTextures.insertBack(this);
}
void
WebGLTexture::Delete()
{
+ const char funcName[] = "WebGLTexture::Delete";
for (auto& cur : mImageInfoArr) {
- cur.Clear();
+ cur.Clear(funcName);
}
mContext->MakeContextCurrent();
mContext->gl->fDeleteTextures(1, &mGLName);
LinkedListElement<WebGLTexture>::removeFrom(mContext->mTextures);
}
@@ -168,28 +167,30 @@ WebGLTexture::MemoryUsage() const
size_t accum = 0;
for (const auto& cur : mImageInfoArr) {
accum += cur.MemoryUsage();
}
return accum;
}
void
-WebGLTexture::SetImageInfo(ImageInfo* target, const ImageInfo& newInfo)
+WebGLTexture::SetImageInfo(const char* funcName, ImageInfo* target,
+ const ImageInfo& newInfo)
{
- *target = newInfo;
+ target->Set(funcName, newInfo);
InvalidateResolveCache();
}
void
-WebGLTexture::SetImageInfosAtLevel(uint32_t level, const ImageInfo& newInfo)
+WebGLTexture::SetImageInfosAtLevel(const char* funcName, uint32_t level,
+ const ImageInfo& newInfo)
{
for (uint8_t i = 0; i < mFaceCount; i++) {
- ImageInfoAtFace(i, level) = newInfo;
+ ImageInfoAtFace(i, level).Set(funcName, newInfo);
}
InvalidateResolveCache();
}
bool
WebGLTexture::IsMipmapComplete(const char* funcName, uint32_t texUnit,
bool* const out_initFailed)
@@ -768,17 +769,18 @@ WebGLTexture::ClampLevelBaseAndMax()
// `[level_base, levels-1]`, where `levels` is the parameter passed to
// TexStorage* for the texture object."
mBaseMipmapLevel = Clamp<uint32_t>(mBaseMipmapLevel, 0, mImmutableLevelCount - 1);
mMaxMipmapLevel = Clamp<uint32_t>(mMaxMipmapLevel, mBaseMipmapLevel,
mImmutableLevelCount - 1);
}
void
-WebGLTexture::PopulateMipChain(uint32_t firstLevel, uint32_t lastLevel)
+WebGLTexture::PopulateMipChain(const char* funcName, uint32_t firstLevel,
+ uint32_t lastLevel)
{
const ImageInfo& baseImageInfo = ImageInfoAtFace(0, firstLevel);
MOZ_ASSERT(baseImageInfo.IsDefined());
uint32_t refWidth = baseImageInfo.mWidth;
uint32_t refHeight = baseImageInfo.mHeight;
uint32_t refDepth = baseImageInfo.mDepth;
if (!refWidth || !refHeight || !refDepth)
@@ -799,17 +801,17 @@ WebGLTexture::PopulateMipChain(uint32_t
refHeight = std::max(uint32_t(1), refHeight / 2);
if (mTarget == LOCAL_GL_TEXTURE_3D) { // But not TEXTURE_2D_ARRAY!
refDepth = std::max(uint32_t(1), refDepth / 2);
}
const ImageInfo cur(baseImageInfo.mFormat, refWidth, refHeight, refDepth,
baseImageInfo.IsDataInitialized());
- SetImageInfosAtLevel(level, cur);
+ SetImageInfosAtLevel(funcName, level, cur);
}
}
//////////////////////////////////////////////////////////////////////////////////////////
// GL calls
bool
WebGLTexture::BindTexture(TexTarget texTarget)
@@ -849,50 +851,53 @@ WebGLTexture::BindTexture(TexTarget texT
return true;
}
void
WebGLTexture::GenerateMipmap(TexTarget texTarget)
{
+ const char funcName[] = "generateMipmap";
// GLES 3.0.4 p160:
// "Mipmap generation replaces texel array levels level base + 1 through q with arrays
// derived from the level base array, regardless of their previous contents. All
// other mipmap arrays, including the level base array, are left unchanged by this
// computation."
const ImageInfo& baseImageInfo = BaseImageInfo();
if (!baseImageInfo.IsDefined()) {
- mContext->ErrorInvalidOperation("generateMipmap: The base level of the texture is"
- " not defined.");
+ mContext->ErrorInvalidOperation("%s: The base level of the texture is not"
+ " defined.",
+ funcName);
return;
}
if (IsCubeMap() && !IsCubeComplete()) {
- mContext->ErrorInvalidOperation("generateMipmap: Cube maps must be \"cube"
- " complete\".");
+ mContext->ErrorInvalidOperation("%s: Cube maps must be \"cube complete\".",
+ funcName);
return;
}
if (!mContext->IsWebGL2() && !baseImageInfo.IsPowerOfTwo()) {
- mContext->ErrorInvalidOperation("generateMipmap: The base level of the texture"
- " does not have power-of-two dimensions.");
+ mContext->ErrorInvalidOperation("%s: The base level of the texture does not have"
+ " power-of-two dimensions.",
+ funcName);
return;
}
auto format = baseImageInfo.mFormat->format;
if (format->compression) {
- mContext->ErrorInvalidOperation("generateMipmap: Texture data at base level is"
- " compressed.");
+ mContext->ErrorInvalidOperation("%s: Texture data at base level is compressed.",
+ funcName);
return;
}
if (format->d) {
- mContext->ErrorInvalidOperation("generateMipmap: Depth textures are not"
- " supported.");
+ mContext->ErrorInvalidOperation("%s: Depth textures are not supported.",
+ funcName);
return;
}
// OpenGL ES 3.0.4 p160:
// If the level base array was not specified with an unsized internal format from
// table 3.3 or a sized internal format that is both color-renderable and
// texture-filterable according to table 3.13, an INVALID_OPERATION error
// is generated.
@@ -905,19 +910,20 @@ WebGLTexture::GenerateMipmap(TexTarget t
// Non-color-renderable formats from Table 3.3.
canGenerateMipmap = true;
break;
default:
break;
}
if (!canGenerateMipmap) {
- mContext->ErrorInvalidOperation("generateMipmap: Texture at base level is not unsized"
+ mContext->ErrorInvalidOperation("%s: Texture at base level is not unsized"
" internal format or is not"
- " color-renderable or texture-filterable.");
+ " color-renderable or texture-filterable.",
+ funcName);
return;
}
// Done with validation. Do the operation.
mContext->MakeContextCurrent();
gl::GLContext* gl = mContext->gl;
@@ -935,17 +941,17 @@ WebGLTexture::GenerateMipmap(TexTarget t
} else {
gl->fGenerateMipmap(texTarget.get());
}
// Record the results.
// Note that we don't use MaxEffectiveMipmapLevel() here, since that returns
// mBaseMipmapLevel if the min filter doesn't require mipmaps.
const uint32_t maxLevel = mBaseMipmapLevel + baseImageInfo.PossibleMipmapLevels() - 1;
- PopulateMipChain(mBaseMipmapLevel, maxLevel);
+ PopulateMipChain(funcName, mBaseMipmapLevel, maxLevel);
}
JS::Value
WebGLTexture::GetTexParameter(TexTarget texTarget, GLenum pname)
{
mContext->MakeContextCurrent();
GLint i = 0;
--- a/dom/canvas/WebGLTexture.h
+++ b/dom/canvas/WebGLTexture.h
@@ -100,27 +100,29 @@ public:
// numLevels(16k) = log2(16k) + 1 = 14 + 1 = 15
// numLevels(1M) = log2(1M) + 1 = 19.9 + 1 ~= 21
// Or we can just max this out to 31, which is the number of unsigned bits in GLsizei.
static const uint8_t kMaxLevelCount = 31;
// And in turn, it needs these forwards:
protected:
// We need to forward these.
- void SetImageInfo(ImageInfo* target, const ImageInfo& newInfo);
- void SetImageInfosAtLevel(uint32_t level, const ImageInfo& newInfo);
+ void SetImageInfo(const char* funcName, ImageInfo* target, const ImageInfo& newInfo);
+ void SetImageInfosAtLevel(const char* funcName, uint32_t level,
+ const ImageInfo& newInfo);
public:
// We store information about the various images that are part of this
// texture. (cubemap faces, mipmap levels)
class ImageInfo
{
- friend void WebGLTexture::SetImageInfo(ImageInfo* target,
+ friend void WebGLTexture::SetImageInfo(const char* funcName, ImageInfo* target,
const ImageInfo& newInfo);
- friend void WebGLTexture::SetImageInfosAtLevel(uint32_t level,
+ friend void WebGLTexture::SetImageInfosAtLevel(const char* funcName,
+ uint32_t level,
const ImageInfo& newInfo);
public:
static const ImageInfo kUndefined;
// This is the "effective internal format" of the texture, an official
// OpenGL spec concept, see OpenGL ES 3.0.3 spec, section 3.8.3, page
// 126 and below.
@@ -150,39 +152,38 @@ public:
, mWidth(width)
, mHeight(height)
, mDepth(depth)
, mIsDataInitialized(isDataInitialized)
{
MOZ_ASSERT(mFormat);
}
- void Clear();
+ void Clear(const char* funcName);
~ImageInfo() {
- if (!IsDefined())
- Clear();
+ MOZ_ASSERT(!mAttachPoints.size());
}
protected:
- ImageInfo& operator =(const ImageInfo& a);
+ void Set(const char* funcName, const ImageInfo& a);
public:
uint32_t PossibleMipmapLevels() const {
// GLES 3.0.4, 3.8 - Mipmapping: `floor(log2(largest_of_dims)) + 1`
const uint32_t largest = std::max(std::max(mWidth, mHeight), mDepth);
MOZ_ASSERT(largest != 0);
return FloorLog2Size(largest) + 1;
}
bool IsPowerOfTwo() const;
void AddAttachPoint(WebGLFBAttachPoint* attachPoint);
void RemoveAttachPoint(WebGLFBAttachPoint* attachPoint);
- void OnRespecify() const;
+ void OnRespecify(const char* funcName) const;
size_t MemoryUsage() const;
bool IsDefined() const {
if (mFormat == LOCAL_GL_NONE) {
MOZ_ASSERT(!mWidth && !mHeight && !mDepth);
return false;
}
@@ -284,17 +285,17 @@ public:
GLint xOffset, GLint yOffset, GLint zOffset, GLint x, GLint y,
GLsizei width, GLsizei height);
////////////////////////////////////
protected:
void ClampLevelBaseAndMax();
- void PopulateMipChain(uint32_t baseLevel, uint32_t maxLevel);
+ void PopulateMipChain(const char* funcName, uint32_t baseLevel, uint32_t maxLevel);
bool MaxEffectiveMipmapLevel(uint32_t texUnit, uint32_t* const out) const;
static uint8_t FaceForTarget(TexImageTarget texImageTarget) {
GLenum rawTexImageTarget = texImageTarget.get();
switch (rawTexImageTarget) {
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
@@ -325,21 +326,21 @@ public:
auto face = FaceForTarget(texImageTarget);
return ImageInfoAtFace(face, level);
}
const ImageInfo& ImageInfoAt(TexImageTarget texImageTarget, GLint level) const {
return const_cast<WebGLTexture*>(this)->ImageInfoAt(texImageTarget, level);
}
- void SetImageInfoAt(TexImageTarget texImageTarget, GLint level,
+ void SetImageInfoAt(const char* funcName, TexImageTarget texImageTarget, GLint level,
const ImageInfo& val)
{
ImageInfo* target = &ImageInfoAt(texImageTarget, level);
- SetImageInfo(target, val);
+ SetImageInfo(funcName, target, val);
}
const ImageInfo& BaseImageInfo() const {
if (mBaseMipmapLevel >= kMaxLevelCount)
return ImageInfo::kUndefined;
return ImageInfoAtFace(0, mBaseMipmapLevel);
}
--- a/dom/canvas/WebGLTextureUpload.cpp
+++ b/dom/canvas/WebGLTextureUpload.cpp
@@ -1180,19 +1180,19 @@ WebGLTexture::TexStorage(const char* fun
}
////////////////////////////////////
// Update our specification data.
const bool isDataInitialized = false;
const WebGLTexture::ImageInfo newInfo(dstUsage, width, height, depth,
isDataInitialized);
- SetImageInfosAtLevel(0, newInfo);
+ SetImageInfosAtLevel(funcName, 0, newInfo);
- PopulateMipChain(0, levels-1);
+ PopulateMipChain(funcName, 0, levels-1);
mImmutable = true;
mImmutableLevelCount = levels;
}
////////////////////////////////////////
// Tex(Sub)Image
@@ -1312,17 +1312,17 @@ WebGLTexture::TexImage(const char* funcN
driverUnpackInfo->unpackFormat, driverUnpackInfo->unpackType);
MOZ_ASSERT(false, "Unexpected GL error.");
return;
}
////////////////////////////////////
// Update our specification data.
- SetImageInfo(imageInfo, newImageInfo);
+ SetImageInfo(funcName, imageInfo, newImageInfo);
}
void
WebGLTexture::TexSubImage(const char* funcName, TexImageTarget target, GLint level,
GLint xOffset, GLint yOffset, GLint zOffset,
const webgl::PackingInfo& pi, const webgl::TexUnpackBlob* blob)
{
////////////////////////////////////
@@ -1518,17 +1518,17 @@ WebGLTexture::CompressedTexImage(const c
}
////////////////////////////////////
// Update our specification data.
const bool isDataInitialized = true;
const ImageInfo newImageInfo(usage, blob->mWidth, blob->mHeight, blob->mDepth,
isDataInitialized);
- SetImageInfo(imageInfo, newImageInfo);
+ SetImageInfo(funcName, imageInfo, newImageInfo);
}
static inline bool
IsSubImageBlockAligned(const webgl::CompressedFormatInfo* compression,
const WebGLTexture::ImageInfo* imageInfo, GLint xOffset,
GLint yOffset, uint32_t width, uint32_t height)
{
if (xOffset % compression->blockWidth != 0 ||
@@ -2165,17 +2165,17 @@ WebGLTexture::CopyTexImage2D(TexImageTar
return;
}
////////////////////////////////////
// Update our specification data.
const bool isDataInitialized = true;
const ImageInfo newImageInfo(dstUsage, width, height, depth, isDataInitialized);
- SetImageInfo(imageInfo, newImageInfo);
+ SetImageInfo(funcName, imageInfo, newImageInfo);
}
void
WebGLTexture::CopyTexSubImage(const char* funcName, TexImageTarget target, GLint level,
GLint xOffset, GLint yOffset, GLint zOffset, GLint x,
GLint y, GLsizei rawWidth, GLsizei rawHeight)
{
uint32_t width, height, depth;
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -611,16 +611,19 @@ private:
DECL_GFX_PREF(Live, "webgl.max-warnings-per-context", WebGLMaxWarningsPerContext, uint32_t, 32);
DECL_GFX_PREF(Live, "webgl.min_capability_mode", WebGLMinCapabilityMode, bool, false);
DECL_GFX_PREF(Live, "webgl.msaa-force", WebGLForceMSAA, bool, false);
DECL_GFX_PREF(Live, "webgl.prefer-16bpp", WebGLPrefer16bpp, bool, false);
DECL_GFX_PREF(Live, "webgl.restore-context-when-visible", WebGLRestoreWhenVisible, bool, true);
DECL_GFX_PREF(Live, "webgl.allow-immediate-queries", WebGLImmediateQueries, bool, false);
DECL_GFX_PREF(Live, "webgl.allow-fb-invalidation", WebGLFBInvalidation, bool, false);
+ DECL_GFX_PREF(Live, "webgl.max-perf-warnings", WebGLMaxPerfWarnings, int32_t, 0);
+ DECL_GFX_PREF(Live, "webgl.max-acceptable-fb-status-invals", WebGLMaxAcceptableFBStatusInvals, int32_t, 0);
+
DECL_GFX_PREF(Live, "webgl.webgl2-compat-mode", WebGL2CompatMode, bool, false);
// WARNING:
// Please make sure that you've added your new preference to the list above in alphabetical order.
// Please do not just append it to the end of the list.
public:
// Manage the singleton:
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -4502,16 +4502,19 @@ pref("webgl.max-warnings-per-context", 3
pref("webgl.enable-draft-extensions", false);
pref("webgl.enable-privileged-extensions", false);
pref("webgl.bypass-shader-validation", false);
pref("webgl.disable-fail-if-major-performance-caveat", false);
pref("webgl.disable-DOM-blit-uploads", false);
pref("webgl.allow-fb-invalidation", false);
pref("webgl.webgl2-compat-mode", false);
+pref("webgl.max-perf-warnings", 0);
+pref("webgl.max-acceptable-fb-status-invals", 0);
+
pref("webgl.enable-webgl2", true);
#ifdef RELEASE_OR_BETA
// Keep this disabled on Release and Beta for now. (see bug 1171228)
pref("webgl.enable-debug-renderer-info", false);
#else
pref("webgl.enable-debug-renderer-info", true);
#endif