From a2379a555b26ca4623216e9bc0b7b26308c67f02 Mon Sep 17 00:00:00 2001 From: Walter Litwinczyk Date: Thu, 18 Sep 2014 16:14:22 -0700 Subject: [PATCH] Bug 1063053 - Add stronger types to WebGL texture code for better debug/compile time checking. r=jgilbert,kamidphish --- dom/canvas/WebGLBindableName.cpp | 27 --- dom/canvas/WebGLBindableName.h | 32 +++- dom/canvas/WebGLBuffer.cpp | 2 +- dom/canvas/WebGLBuffer.h | 2 +- dom/canvas/WebGLContext.cpp | 6 +- dom/canvas/WebGLContext.h | 59 ++++--- dom/canvas/WebGLContextGL.cpp | 249 ++++++++++++++++------------ dom/canvas/WebGLContextUtils.cpp | 8 +- dom/canvas/WebGLContextUtils.h | 3 +- dom/canvas/WebGLContextValidate.cpp | 38 ++--- dom/canvas/WebGLFramebuffer.cpp | 32 ++-- dom/canvas/WebGLFramebuffer.h | 13 +- dom/canvas/WebGLRenderbuffer.cpp | 2 +- dom/canvas/WebGLRenderbuffer.h | 2 +- dom/canvas/WebGLSampler.h | 2 +- dom/canvas/WebGLStrongTypes.h | 152 +++++++++++++++++ dom/canvas/WebGLTexture.cpp | 57 +++---- dom/canvas/WebGLTexture.h | 35 ++-- dom/canvas/WebGLTransformFeedback.h | 2 +- dom/canvas/WebGLVertexArray.cpp | 2 +- dom/canvas/WebGLVertexArray.h | 2 +- dom/canvas/moz.build | 1 - 22 files changed, 454 insertions(+), 274 deletions(-) delete mode 100644 dom/canvas/WebGLBindableName.cpp create mode 100644 dom/canvas/WebGLStrongTypes.h diff --git a/dom/canvas/WebGLBindableName.cpp b/dom/canvas/WebGLBindableName.cpp deleted file mode 100644 index 3a361bd7d43..00000000000 --- a/dom/canvas/WebGLBindableName.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "WebGLBindableName.h" -#include "GLConsts.h" -#include "mozilla/Assertions.h" - -using namespace mozilla; - -WebGLBindableName::WebGLBindableName() - : mGLName(LOCAL_GL_NONE) - , mTarget(LOCAL_GL_NONE) -{ } - -void -WebGLBindableName::BindTo(GLenum target) -{ - MOZ_ASSERT(target != LOCAL_GL_NONE, "Can't bind to GL_NONE."); - MOZ_ASSERT(mTarget == LOCAL_GL_NONE || mTarget == target, "Rebinding is illegal."); - - bool targetChanged = (target != mTarget); - mTarget = target; - if (targetChanged) - OnTargetChanged(); -} diff --git a/dom/canvas/WebGLBindableName.h b/dom/canvas/WebGLBindableName.h index 73261ba7431..bb1319cb046 100644 --- a/dom/canvas/WebGLBindableName.h +++ b/dom/canvas/WebGLBindableName.h @@ -8,19 +8,41 @@ #include "WebGLTypes.h" +#include "GLDefs.h" +#include "mozilla/TypeTraits.h" +#include "mozilla/Assertions.h" + namespace mozilla { /** Represents a GL name that can be bound to a target. */ +template class WebGLBindableName { public: - WebGLBindableName(); - void BindTo(GLenum target); - bool HasEverBeenBound() const { return mTarget != 0; } + WebGLBindableName() + : mGLName(0) + , mTarget(LOCAL_GL_NONE) + { } + + void BindTo(T target) + { + MOZ_ASSERT(target != LOCAL_GL_NONE, "Can't bind to GL_NONE."); + MOZ_ASSERT(!HasEverBeenBound() || mTarget == target, "Rebinding is illegal."); + + bool targetChanged = (target != mTarget); + mTarget = target; + if (targetChanged) + OnTargetChanged(); + } + + bool HasEverBeenBound() const { return mTarget != LOCAL_GL_NONE; } GLuint GLName() const { return mGLName; } - GLenum Target() const { return mTarget; } + T Target() const { + MOZ_ASSERT(HasEverBeenBound()); + return mTarget; + } protected: @@ -28,7 +50,7 @@ protected: virtual void OnTargetChanged() {} GLuint mGLName; - GLenum mTarget; + T mTarget; }; } // namespace mozilla diff --git a/dom/canvas/WebGLBuffer.cpp b/dom/canvas/WebGLBuffer.cpp index 061404d0d48..9ed81e9b755 100644 --- a/dom/canvas/WebGLBuffer.cpp +++ b/dom/canvas/WebGLBuffer.cpp @@ -13,7 +13,7 @@ using namespace mozilla; WebGLBuffer::WebGLBuffer(WebGLContext *context) - : WebGLBindableName() + : WebGLBindableName() , WebGLContextBoundObject(context) , mByteLength(0) { diff --git a/dom/canvas/WebGLBuffer.h b/dom/canvas/WebGLBuffer.h index ebf391fa93a..3373b8a767e 100644 --- a/dom/canvas/WebGLBuffer.h +++ b/dom/canvas/WebGLBuffer.h @@ -20,7 +20,7 @@ class WebGLElementArrayCache; class WebGLBuffer MOZ_FINAL : public nsWrapperCache - , public WebGLBindableName + , public WebGLBindableName , public WebGLRefCountedObject , public LinkedListElement , public WebGLContextBoundObject diff --git a/dom/canvas/WebGLContext.cpp b/dom/canvas/WebGLContext.cpp index f5fe169415f..2328053f40e 100644 --- a/dom/canvas/WebGLContext.cpp +++ b/dom/canvas/WebGLContext.cpp @@ -1746,7 +1746,7 @@ WebGLContext::DidRefresh() } } -bool WebGLContext::TexImageFromVideoElement(GLenum texImageTarget, GLint level, +bool WebGLContext::TexImageFromVideoElement(const TexImageTarget texImageTarget, GLint level, GLenum internalformat, GLenum format, GLenum type, mozilla::dom::Element& elt) { @@ -1793,9 +1793,9 @@ bool WebGLContext::TexImageFromVideoElement(GLenum texImageTarget, GLint level, info.Height() == srcImage->GetSize().height; if (!dimensionsMatch) { // we need to allocation - gl->fTexImage2D(texImageTarget, level, internalformat, srcImage->GetSize().width, srcImage->GetSize().height, 0, format, type, nullptr); + gl->fTexImage2D(texImageTarget.get(), level, internalformat, srcImage->GetSize().width, srcImage->GetSize().height, 0, format, type, nullptr); } - bool ok = gl->BlitHelper()->BlitImageToTexture(srcImage.get(), srcImage->GetSize(), tex->GLName(), texImageTarget, mPixelStoreFlipY); + bool ok = gl->BlitHelper()->BlitImageToTexture(srcImage.get(), srcImage->GetSize(), tex->GLName(), texImageTarget.get(), mPixelStoreFlipY); if (ok) { tex->SetImageInfo(texImageTarget, level, srcImage->GetSize().width, srcImage->GetSize().height, format, type, WebGLImageDataStatus::InitializedImageData); tex->Bind(TexImageTargetToTexTarget(texImageTarget)); diff --git a/dom/canvas/WebGLContext.h b/dom/canvas/WebGLContext.h index 563652ea977..15e4be21325 100644 --- a/dom/canvas/WebGLContext.h +++ b/dom/canvas/WebGLContext.h @@ -17,6 +17,7 @@ #include "WebGLActiveInfo.h" #include "WebGLObjectModel.h" #include "WebGLRenderbuffer.h" +#include "WebGLStrongTypes.h" #include #include "nsTArray.h" @@ -123,7 +124,7 @@ struct WebGLContextOptions { }; // From WebGLContextUtils -GLenum TexImageTargetToTexTarget(GLenum texImageTarget); +TexTarget TexImageTargetToTexTarget(TexImageTarget texImageTarget); class WebGLContext : public nsIDOMWebGLRenderingContext, @@ -224,8 +225,7 @@ public: void DummyFramebufferOperation(const char *info); - WebGLTexture* activeBoundTextureForTarget(GLenum texTarget) const { - MOZ_ASSERT(texTarget == LOCAL_GL_TEXTURE_2D || texTarget == LOCAL_GL_TEXTURE_CUBE_MAP); + WebGLTexture* activeBoundTextureForTarget(const TexTarget texTarget) const { return texTarget == LOCAL_GL_TEXTURE_2D ? mBound2DTextures[mActiveTexture] : mBoundCubeMapTextures[mActiveTexture]; } @@ -234,8 +234,8 @@ public: * GL_TEXTURE_2D, GL_TEXTURE_CUBE_MAP_[POSITIVE|NEGATIVE]_[X|Y|Z], and * not the actual texture binding target: GL_TEXTURE_2D or GL_TEXTURE_CUBE_MAP. */ - WebGLTexture* activeBoundTextureForTexImageTarget(GLenum texImgTarget) const { - const GLenum texTarget = TexImageTargetToTexTarget(texImgTarget); + WebGLTexture* activeBoundTextureForTexImageTarget(const TexImageTarget texImgTarget) const { + const TexTarget texTarget = TexImageTargetToTexTarget(texImgTarget); return activeBoundTextureForTarget(texTarget); } @@ -465,21 +465,24 @@ public: dom::ImageData* pixels, ErrorResult& rv); // Allow whatever element types the bindings are willing to pass // us in TexImage2D - bool TexImageFromVideoElement(GLenum texImageTarget, GLint level, + bool TexImageFromVideoElement(TexImageTarget texImageTarget, GLint level, GLenum internalformat, GLenum format, GLenum type, mozilla::dom::Element& image); template - void TexImage2D(GLenum texImageTarget, GLint level, + void TexImage2D(GLenum rawTexImgTarget, GLint level, GLenum internalformat, GLenum format, GLenum type, ElementType& elt, ErrorResult& rv) { if (IsContextLost()) return; - const GLenum target = TexImageTargetToTexTarget(texImageTarget); - if (target == LOCAL_GL_NONE) - return ErrorInvalidEnumInfo("texImage2D: target", target); + auto dims = 2; + + if (!ValidateTexImageTarget(dims, rawTexImgTarget, WebGLTexImageFunc::TexImage)) + return ErrorInvalidEnumInfo("texSubImage2D: target", rawTexImgTarget); + + const TexImageTarget texImageTarget(rawTexImgTarget); if (!ValidateTexImageFormatAndType(format, type, WebGLTexImageFunc::TexImage)) return; @@ -491,7 +494,7 @@ public: if (level > maxLevel) return ErrorInvalidValue("texImage2D: level %d is too large, max is %d", level, maxLevel); - WebGLTexture* tex = activeBoundTextureForTarget(target); + WebGLTexture* tex = activeBoundTextureForTexImageTarget(texImageTarget); if (!tex) return ErrorInvalidOperation("no texture is bound to this target"); @@ -536,16 +539,17 @@ public: // Allow whatever element types the bindings are willing to pass // us in TexSubImage2D template - void TexSubImage2D(GLenum texImageTarget, GLint level, + void TexSubImage2D(GLenum rawTexImageTarget, GLint level, GLint xoffset, GLint yoffset, GLenum format, GLenum type, ElementType& elt, ErrorResult& rv) { if (IsContextLost()) return; - const GLenum target = TexImageTargetToTexTarget(texImageTarget); - if (target == LOCAL_GL_NONE) - return ErrorInvalidEnumInfo("texSubImage2D: target", texImageTarget); + if (!ValidateTexImageTarget(2, rawTexImageTarget, WebGLTexImageFunc::TexSubImage)) + return ErrorInvalidEnumInfo("texSubImage2D: target", rawTexImageTarget); + + const TexImageTarget texImageTarget(rawTexImageTarget); if (!ValidateTexImageFormatAndType(format, type, WebGLTexImageFunc::TexImage)) return; @@ -1088,7 +1092,7 @@ protected: bool ValidateGLSLString(const nsAString& string, const char *info); bool ValidateCopyTexImage(GLenum format, WebGLTexImageFunc func); - bool ValidateTexImage(GLuint dims, GLenum target, + bool ValidateTexImage(GLuint dims, TexImageTarget texImageTarget, GLint level, GLint internalFormat, GLint xoffset, GLint yoffset, GLint zoffset, GLint width, GLint height, GLint depth, @@ -1098,7 +1102,7 @@ protected: bool ValidateTexImageFormat(GLenum format, WebGLTexImageFunc func); bool ValidateTexImageType(GLenum type, WebGLTexImageFunc func); bool ValidateTexImageFormatAndType(GLenum format, GLenum type, WebGLTexImageFunc func); - bool ValidateTexImageSize(GLenum target, GLint level, + bool ValidateTexImageSize(TexImageTarget target, GLint level, GLint width, GLint height, GLint depth, WebGLTexImageFunc func); bool ValidateTexSubImageSize(GLint x, GLint y, GLint z, @@ -1106,7 +1110,7 @@ protected: GLsizei baseWidth, GLsizei baseHeight, GLsizei baseDepth, WebGLTexImageFunc func); - bool ValidateCompTexImageSize(GLenum target, GLint level, GLenum format, + bool ValidateCompTexImageSize(GLint level, GLenum format, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLsizei levelWidth, GLsizei levelHeight, @@ -1124,13 +1128,13 @@ protected: void MakeContextCurrent() const; // helpers - void TexImage2D_base(GLenum target, GLint level, GLenum internalformat, + void TexImage2D_base(TexImageTarget target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei srcStrideOrZero, GLint border, GLenum format, GLenum type, void *data, uint32_t byteLength, int jsArrayType, WebGLTexelFormat srcFormat, bool srcPremultiplied); - void TexSubImage2D_base(GLenum target, GLint level, + void TexSubImage2D_base(TexImageTarget target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLsizei srcStrideOrZero, GLenum format, GLenum type, @@ -1168,7 +1172,7 @@ protected: RefPtr& imageOut, WebGLTexelFormat *format); - void CopyTexSubImage2D_base(GLenum target, + void CopyTexSubImage2D_base(TexImageTarget texImageTarget, GLint level, GLenum internalformat, GLint xoffset, @@ -1200,17 +1204,12 @@ private: bool ValidateObjectAssumeNonNull(const char* info, ObjectType *aObject); protected: - int32_t MaxTextureSizeForTarget(GLenum target) const { - MOZ_ASSERT(target == LOCAL_GL_TEXTURE_2D || - (target >= LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X && - target <= LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z), - "Invalid target enum"); + int32_t MaxTextureSizeForTarget(TexTarget target) const { return (target == LOCAL_GL_TEXTURE_2D) ? mGLMaxTextureSize : mGLMaxCubeMapTextureSize; } - int32_t MaxTextureLevelForTexImageTarget(GLenum texImageTarget) const { - const GLenum target = TexImageTargetToTexTarget(texImageTarget); - MOZ_ASSERT(target == LOCAL_GL_TEXTURE_2D || target == LOCAL_GL_TEXTURE_CUBE_MAP); + int32_t MaxTextureLevelForTexImageTarget(TexImageTarget texImageTarget) const { + const TexTarget target = TexImageTargetToTexTarget(texImageTarget); return (target == LOCAL_GL_TEXTURE_2D) ? mGLMaxTextureSizeLog2 : mGLMaxCubeMapTextureSizeLog2; } @@ -1222,7 +1221,7 @@ protected: GLenum usage); /** like glTexImage2D but if the call may change the texture size, checks any GL error generated * by this glTexImage2D call and returns it */ - GLenum CheckedTexImage2D(GLenum target, + GLenum CheckedTexImage2D(TexImageTarget texImageTarget, GLint level, GLenum internalFormat, GLsizei width, diff --git a/dom/canvas/WebGLContextGL.cpp b/dom/canvas/WebGLContextGL.cpp index beb417fa9ce..98d219de456 100644 --- a/dom/canvas/WebGLContextGL.cpp +++ b/dom/canvas/WebGLContextGL.cpp @@ -215,7 +215,7 @@ WebGLContext::BindRenderbuffer(GLenum target, WebGLRenderbuffer *wrb) } void -WebGLContext::BindTexture(GLenum target, WebGLTexture *newTex) +WebGLContext::BindTexture(GLenum rawTarget, WebGLTexture *newTex) { if (IsContextLost()) return; @@ -223,18 +223,10 @@ WebGLContext::BindTexture(GLenum target, WebGLTexture *newTex) if (!ValidateObjectAllowDeletedOrNull("bindTexture", newTex)) return; - if (newTex) { - // silently ignore a deleted texture - if (newTex->IsDeleted()) - return; - - if (newTex->Target() != LOCAL_GL_NONE && newTex->Target() != target) - return ErrorInvalidOperation("bindTexture: this texture has already been bound to a different target"); - } - + // Need to check rawTarget first before comparing against newTex->Target() as + // newTex->Target() returns a TexTarget, which will assert on invalid value. WebGLRefPtr* currentTexPtr = nullptr; - - switch (target) { + switch (rawTarget) { case LOCAL_GL_TEXTURE_2D: currentTexPtr = &mBound2DTextures[mActiveTexture]; break; @@ -242,9 +234,20 @@ WebGLContext::BindTexture(GLenum target, WebGLTexture *newTex) currentTexPtr = &mBoundCubeMapTextures[mActiveTexture]; break; default: - return ErrorInvalidEnumInfo("bindTexture: target", target); + return ErrorInvalidEnumInfo("bindTexture: target", rawTarget); } + if (newTex) { + // silently ignore a deleted texture + if (newTex->IsDeleted()) + return; + + if (newTex->HasEverBeenBound() && newTex->Target() != rawTarget) + return ErrorInvalidOperation("bindTexture: this texture has already been bound to a different target"); + } + + const TexTarget target(rawTarget); + WebGLTextureFakeBlackStatus currentTexFakeBlackStatus = WebGLTextureFakeBlackStatus::NotNeeded; if (*currentTexPtr) { currentTexFakeBlackStatus = (*currentTexPtr)->ResolvedFakeBlackStatus(); @@ -265,7 +268,7 @@ WebGLContext::BindTexture(GLenum target, WebGLTexture *newTex) if (newTex) newTex->Bind(target); else - gl->fBindTexture(target, 0 /* == texturename */); + gl->fBindTexture(target.get(), 0 /* == texturename */); } void WebGLContext::BlendEquation(GLenum mode) @@ -349,7 +352,7 @@ WebGLContext::CheckFramebufferStatus(GLenum target) } void -WebGLContext::CopyTexSubImage2D_base(GLenum target, +WebGLContext::CopyTexSubImage2D_base(TexImageTarget texImageTarget, GLint level, GLenum internalformat, GLint xoffset, @@ -369,7 +372,7 @@ WebGLContext::CopyTexSubImage2D_base(GLenum target, // TODO: This changes with color_buffer_float. Reassess when the // patch lands. - if (!ValidateTexImage(2, target, level, internalformat, + if (!ValidateTexImage(2, texImageTarget, level, internalformat, xoffset, yoffset, 0, width, height, 0, 0, internalformat, LOCAL_GL_UNSIGNED_BYTE, @@ -386,16 +389,16 @@ WebGLContext::CopyTexSubImage2D_base(GLenum target, MakeContextCurrent(); - WebGLTexture *tex = activeBoundTextureForTexImageTarget(target); + WebGLTexture *tex = activeBoundTextureForTexImageTarget(texImageTarget); if (!tex) return ErrorInvalidOperation("%s: no texture is bound to this target"); if (CanvasUtils::CheckSaneSubrectSize(x, y, width, height, framebufferWidth, framebufferHeight)) { if (sub) - gl->fCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); + gl->fCopyTexSubImage2D(texImageTarget.get(), level, xoffset, yoffset, x, y, width, height); else - gl->fCopyTexImage2D(target, level, internalformat, x, y, width, height, 0); + gl->fCopyTexImage2D(texImageTarget.get(), level, internalformat, x, y, width, height, 0); } else { // the rect doesn't fit in the framebuffer @@ -429,10 +432,10 @@ WebGLContext::CopyTexSubImage2D_base(GLenum target, // now initialize the texture as black if (sub) - gl->fTexSubImage2D(target, level, 0, 0, width, height, + gl->fTexSubImage2D(texImageTarget.get(), level, 0, 0, width, height, internalformat, LOCAL_GL_UNSIGNED_BYTE, tempZeroData); else - gl->fTexImage2D(target, level, internalformat, width, height, + gl->fTexImage2D(texImageTarget.get(), level, internalformat, width, height, 0, internalformat, LOCAL_GL_UNSIGNED_BYTE, tempZeroData); free(tempZeroData); @@ -456,12 +459,12 @@ WebGLContext::CopyTexSubImage2D_base(GLenum target, GLsizei actual_height = actual_y_plus_height - actual_y; GLint actual_yoffset = yoffset + actual_y - y; - gl->fCopyTexSubImage2D(target, level, actual_xoffset, actual_yoffset, actual_x, actual_y, actual_width, actual_height); + gl->fCopyTexSubImage2D(texImageTarget.get(), level, actual_xoffset, actual_yoffset, actual_x, actual_y, actual_width, actual_height); } } void -WebGLContext::CopyTexImage2D(GLenum target, +WebGLContext::CopyTexImage2D(GLenum rawTexImgTarget, GLint level, GLenum internalformat, GLint x, @@ -478,7 +481,10 @@ WebGLContext::CopyTexImage2D(GLenum target, const GLenum format = internalformat; // WebGL/ES Format const GLenum type = LOCAL_GL_UNSIGNED_BYTE; // WebGL/ES Format - if (!ValidateTexImage(2, target, level, format, + if (!ValidateTexImageTarget(2, rawTexImgTarget, WebGLTexImageFunc::CopyTexImage)) + return; + + if (!ValidateTexImage(2, rawTexImgTarget, level, format, 0, 0, 0, width, height, 0, border, format, type, @@ -493,11 +499,13 @@ WebGLContext::CopyTexImage2D(GLenum target, if (!mBoundFramebuffer) ClearBackbufferIfNeeded(); + const TexImageTarget texImageTarget(rawTexImgTarget); + // check if the memory size of this texture may change with this call bool sizeMayChange = true; - WebGLTexture* tex = activeBoundTextureForTexImageTarget(target); - if (tex->HasImageInfoAt(target, level)) { - const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(target, level); + WebGLTexture* tex = activeBoundTextureForTexImageTarget(texImageTarget); + if (tex->HasImageInfoAt(texImageTarget, level)) { + const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(texImageTarget, level); sizeMayChange = width != imageInfo.Width() || height != imageInfo.Height() || @@ -508,7 +516,7 @@ WebGLContext::CopyTexImage2D(GLenum target, if (sizeMayChange) GetAndFlushUnderlyingGLErrors(); - CopyTexSubImage2D_base(target, level, format, 0, 0, x, y, width, height, false); + CopyTexSubImage2D_base(texImageTarget, level, format, 0, 0, x, y, width, height, false); if (sizeMayChange) { GLenum error = GetAndFlushUnderlyingGLErrors(); @@ -518,12 +526,12 @@ WebGLContext::CopyTexImage2D(GLenum target, } } - tex->SetImageInfo(target, level, width, height, format, type, + tex->SetImageInfo(texImageTarget, level, width, height, format, type, WebGLImageDataStatus::InitializedImageData); } void -WebGLContext::CopyTexSubImage2D(GLenum target, +WebGLContext::CopyTexSubImage2D(GLenum rawTexImgTarget, GLint level, GLint xoffset, GLint yoffset, @@ -535,7 +543,7 @@ WebGLContext::CopyTexSubImage2D(GLenum target, if (IsContextLost()) return; - switch (target) { + switch (rawTexImgTarget) { case LOCAL_GL_TEXTURE_2D: case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X: case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X: @@ -545,13 +553,15 @@ WebGLContext::CopyTexSubImage2D(GLenum target, case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: break; default: - return ErrorInvalidEnumInfo("copyTexSubImage2D: target", target); + return ErrorInvalidEnumInfo("copyTexSubImage2D: target", rawTexImgTarget); } + const TexImageTarget texImageTarget(rawTexImgTarget); + if (level < 0) return ErrorInvalidValue("copyTexSubImage2D: level may not be negative"); - GLsizei maxTextureSize = MaxTextureSizeForTarget(target); + GLsizei maxTextureSize = MaxTextureSizeForTarget(TexImageTargetToTexTarget(texImageTarget)); if (!(maxTextureSize >> level)) return ErrorInvalidValue("copyTexSubImage2D: 2^level exceeds maximum texture size"); @@ -561,14 +571,14 @@ WebGLContext::CopyTexSubImage2D(GLenum target, if (xoffset < 0 || yoffset < 0) return ErrorInvalidValue("copyTexSubImage2D: xoffset and yoffset may not be negative"); - WebGLTexture *tex = activeBoundTextureForTexImageTarget(target); + WebGLTexture *tex = activeBoundTextureForTexImageTarget(texImageTarget); if (!tex) return ErrorInvalidOperation("copyTexSubImage2D: no texture bound to this target"); - if (!tex->HasImageInfoAt(target, level)) + if (!tex->HasImageInfoAt(texImageTarget, level)) return ErrorInvalidOperation("copyTexSubImage2D: no texture image previously defined for this level and face"); - const WebGLTexture::ImageInfo &imageInfo = tex->ImageInfoAt(target, level); + const WebGLTexture::ImageInfo &imageInfo = tex->ImageInfoAt(texImageTarget, level); GLsizei texWidth = imageInfo.Width(); GLsizei texHeight = imageInfo.Height(); @@ -582,10 +592,10 @@ WebGLContext::CopyTexSubImage2D(GLenum target, ClearBackbufferIfNeeded(); if (imageInfo.HasUninitializedImageData()) { - tex->DoDeferredImageInitialization(target, level); + tex->DoDeferredImageInitialization(texImageTarget, level); } - return CopyTexSubImage2D_base(target, level, imageInfo.WebGLFormat(), xoffset, yoffset, x, y, width, height, true); + return CopyTexSubImage2D_base(texImageTarget, level, imageInfo.WebGLFormat(), xoffset, yoffset, x, y, width, height, true); } @@ -692,11 +702,11 @@ WebGLContext::DeleteTexture(WebGLTexture *tex) GLuint activeTexture = mActiveTexture; for (int32_t i = 0; i < mGLMaxTextureUnits; i++) { - if ((tex->Target() == LOCAL_GL_TEXTURE_2D && mBound2DTextures[i] == tex) || - (tex->Target() == LOCAL_GL_TEXTURE_CUBE_MAP && mBoundCubeMapTextures[i] == tex)) + if ((mBound2DTextures[i] == tex && tex->Target() == LOCAL_GL_TEXTURE_2D) || + (mBoundCubeMapTextures[i] == tex && tex->Target() == LOCAL_GL_TEXTURE_CUBE_MAP)) { ActiveTexture(LOCAL_GL_TEXTURE0 + i); - BindTexture(tex->Target(), static_cast(nullptr)); + BindTexture(tex->Target().get(), static_cast(nullptr)); } } ActiveTexture(LOCAL_GL_TEXTURE0 + activeTexture); @@ -801,7 +811,14 @@ WebGLContext::FramebufferTexture2D(GLenum target, if (!mBoundFramebuffer) return ErrorInvalidOperation("framebufferRenderbuffer: cannot modify framebuffer 0"); - return mBoundFramebuffer->FramebufferTexture2D(target, attachment, textarget, tobj, level); + if (textarget != LOCAL_GL_TEXTURE_2D && + (textarget < LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X || + textarget > LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)) + { + return ErrorInvalidEnumInfo("framebufferTexture2D: invalid texture target", textarget); + } + + return mBoundFramebuffer->FramebufferTexture2D(target, attachment, TexImageTarget(textarget), tobj, level); } void @@ -857,21 +874,24 @@ WebGLContext::GetActiveAttrib(WebGLProgram *prog, uint32_t index) } void -WebGLContext::GenerateMipmap(GLenum target) +WebGLContext::GenerateMipmap(GLenum rawTarget) { if (IsContextLost()) return; - if (!ValidateTextureTargetEnum(target, "generateMipmap")) + if (!ValidateTextureTargetEnum(rawTarget, "generateMipmap")) return; + const TexTarget target(rawTarget); + WebGLTexture *tex = activeBoundTextureForTarget(target); if (!tex) return ErrorInvalidOperation("generateMipmap: No texture is bound to this target."); - GLenum imageTarget = (target == LOCAL_GL_TEXTURE_2D) ? LOCAL_GL_TEXTURE_2D - : LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X; + const TexImageTarget imageTarget = (target == LOCAL_GL_TEXTURE_2D) + ? LOCAL_GL_TEXTURE_2D + : LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X; if (!tex->HasImageInfoAt(imageTarget, 0)) { return ErrorInvalidOperation("generateMipmap: Level zero of texture is not defined."); @@ -905,11 +925,11 @@ WebGLContext::GenerateMipmap(GLenum target) // overhead so we do it unconditionally. // // note that the choice of GL_NEAREST_MIPMAP_NEAREST really matters. See Chromium bug 101105. - gl->fTexParameteri(target, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST_MIPMAP_NEAREST); - gl->fGenerateMipmap(target); - gl->fTexParameteri(target, LOCAL_GL_TEXTURE_MIN_FILTER, tex->MinFilter()); + gl->fTexParameteri(target.get(), LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST_MIPMAP_NEAREST); + gl->fGenerateMipmap(target.get()); + gl->fTexParameteri(target.get(), LOCAL_GL_TEXTURE_MIN_FILTER, tex->MinFilter()); } else { - gl->fGenerateMipmap(target); + gl->fGenerateMipmap(target.get()); } } @@ -1173,10 +1193,10 @@ WebGLContext::GetFramebufferAttachmentParameter(JSContext* cx, return WebGLObjectAsJSValue(cx, fba.Texture(), rv); case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL: - return JS::Int32Value(fba.TexImageLevel()); + return JS::Int32Value(fba.MipLevel()); case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: { - GLenum face = fba.TexImageTarget(); + GLenum face = fba.ImageTarget().get(); if (face == LOCAL_GL_TEXTURE_2D) face = 0; return JS::Int32Value(face); @@ -1199,8 +1219,8 @@ WebGLContext::GetFramebufferAttachmentParameter(JSContext* cx, return JS::NumberValue(uint32_t(LOCAL_GL_NONE)); uint32_t ret = LOCAL_GL_NONE; - GLenum type = fba.Texture()->ImageInfoAt(fba.TexImageTarget(), - fba.TexImageLevel()).WebGLType(); + GLenum type = fba.Texture()->ImageInfoAt(fba.ImageTarget(), + fba.MipLevel()).WebGLType(); switch (type) { case LOCAL_GL_UNSIGNED_BYTE: case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4: @@ -1445,7 +1465,7 @@ WebGLContext::GetProgramInfoLog(WebGLProgram *prog, nsACString& retval) // here we have to support all pnames with both int and float params. // See this discussion: // https://www.khronos.org/webgl/public-mailing-list/archives/1008/msg00014.html -void WebGLContext::TexParameter_base(GLenum target, GLenum pname, +void WebGLContext::TexParameter_base(GLenum rawTarget, GLenum pname, GLint *intParamPtr, GLfloat *floatParamPtr) { @@ -1457,10 +1477,12 @@ void WebGLContext::TexParameter_base(GLenum target, GLenum pname, GLint intParam = intParamPtr ? *intParamPtr : GLint(*floatParamPtr); GLfloat floatParam = floatParamPtr ? *floatParamPtr : GLfloat(*intParamPtr); - if (!ValidateTextureTargetEnum(target, "texParameter: target")) + if (!ValidateTextureTargetEnum(rawTarget, "texParameter: target")) return; - WebGLTexture *tex = activeBoundTextureForTarget(target); + const TexTarget texTarget = TexTarget(rawTarget); + + WebGLTexture *tex = activeBoundTextureForTarget(texTarget); if (!tex) return ErrorInvalidOperation("texParameter: no texture is bound to this target"); @@ -1546,22 +1568,24 @@ void WebGLContext::TexParameter_base(GLenum target, GLenum pname, MakeContextCurrent(); if (intParamPtr) - gl->fTexParameteri(target, pname, intParam); + gl->fTexParameteri(texTarget.get(), pname, intParam); else - gl->fTexParameterf(target, pname, floatParam); + gl->fTexParameterf(texTarget.get(), pname, floatParam); } JS::Value -WebGLContext::GetTexParameter(GLenum target, GLenum pname) +WebGLContext::GetTexParameter(GLenum rawTarget, GLenum pname) { if (IsContextLost()) return JS::NullValue(); MakeContextCurrent(); - if (!ValidateTextureTargetEnum(target, "getTexParameter: target")) + if (!ValidateTextureTargetEnum(rawTarget, "getTexParameter: target")) return JS::NullValue(); + const TexTarget target(rawTarget); + if (!activeBoundTextureForTarget(target)) { ErrorInvalidOperation("getTexParameter: no texture bound"); return JS::NullValue(); @@ -1574,13 +1598,13 @@ WebGLContext::GetTexParameter(GLenum target, GLenum pname) case LOCAL_GL_TEXTURE_WRAP_T: { GLint i = 0; - gl->fGetTexParameteriv(target, pname, &i); + gl->fGetTexParameteriv(target.get(), pname, &i); return JS::NumberValue(uint32_t(i)); } case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT: if (IsExtensionEnabled(WebGLExtensionID::EXT_texture_filter_anisotropic)) { GLfloat f = 0.f; - gl->fGetTexParameterfv(target, pname, &f); + gl->fGetTexParameterfv(target.get(), pname, &f); return JS::DoubleValue(f); } @@ -3275,7 +3299,7 @@ WebGLContext::CompileShader(WebGLShader *shader) } void -WebGLContext::CompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, +WebGLContext::CompressedTexImage2D(GLenum rawTexImgTarget, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, const ArrayBufferView& view) { @@ -3284,7 +3308,10 @@ WebGLContext::CompressedTexImage2D(GLenum target, GLint level, GLenum internalfo const WebGLTexImageFunc func = WebGLTexImageFunc::CompTexImage; - if (!ValidateTexImage(2, target, level, internalformat, + if (!ValidateTexImageTarget(2, rawTexImgTarget, WebGLTexImageFunc::CompTexImage)) + return; + + if (!ValidateTexImage(2, rawTexImgTarget, level, internalformat, 0, 0, 0, width, height, 0, border, internalformat, LOCAL_GL_UNSIGNED_BYTE, func)) @@ -3295,26 +3322,27 @@ WebGLContext::CompressedTexImage2D(GLenum target, GLint level, GLenum internalfo view.ComputeLengthAndData(); uint32_t byteLength = view.Length(); - if (!ValidateCompTexImageDataSize(target, internalformat, width, height, byteLength, func)) { + if (!ValidateCompTexImageDataSize(level, internalformat, width, height, byteLength, func)) { return; } - if (!ValidateCompTexImageSize(target, level, internalformat, 0, 0, - width, height, width, height, func)) + if (!ValidateCompTexImageSize(level, internalformat, 0, 0, width, height, width, height, func)) { return; } + const TexImageTarget texImageTarget(rawTexImgTarget); + MakeContextCurrent(); - gl->fCompressedTexImage2D(target, level, internalformat, width, height, border, byteLength, view.Data()); - WebGLTexture* tex = activeBoundTextureForTexImageTarget(target); + gl->fCompressedTexImage2D(texImageTarget.get(), level, internalformat, width, height, border, byteLength, view.Data()); + WebGLTexture* tex = activeBoundTextureForTexImageTarget(texImageTarget); MOZ_ASSERT(tex); - tex->SetImageInfo(target, level, width, height, internalformat, LOCAL_GL_UNSIGNED_BYTE, + tex->SetImageInfo(texImageTarget, level, width, height, internalformat, LOCAL_GL_UNSIGNED_BYTE, WebGLImageDataStatus::InitializedImageData); } void -WebGLContext::CompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, +WebGLContext::CompressedTexSubImage2D(GLenum rawTexImgTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, const ArrayBufferView& view) { @@ -3323,7 +3351,10 @@ WebGLContext::CompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, const WebGLTexImageFunc func = WebGLTexImageFunc::CompTexSubImage; - if (!ValidateTexImage(2, target, + if (!ValidateTexImageTarget(2, rawTexImgTarget, WebGLTexImageFunc::CompTexSubImage)) + return; + + if (!ValidateTexImage(2, rawTexImgTarget, level, format, xoffset, yoffset, 0, width, height, 0, @@ -3333,17 +3364,19 @@ WebGLContext::CompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, return; } - WebGLTexture *tex = activeBoundTextureForTexImageTarget(target); + const TexImageTarget texImageTarget(rawTexImgTarget); + + WebGLTexture *tex = activeBoundTextureForTexImageTarget(texImageTarget); MOZ_ASSERT(tex); - WebGLTexture::ImageInfo& levelInfo = tex->ImageInfoAt(target, level); + WebGLTexture::ImageInfo& levelInfo = tex->ImageInfoAt(texImageTarget, level); view.ComputeLengthAndData(); uint32_t byteLength = view.Length(); - if (!ValidateCompTexImageDataSize(target, format, width, height, byteLength, func)) + if (!ValidateCompTexImageDataSize(level, format, width, height, byteLength, func)) return; - if (!ValidateCompTexImageSize(target, level, format, + if (!ValidateCompTexImageSize(level, format, xoffset, yoffset, width, height, levelInfo.Width(), levelInfo.Height(), @@ -3353,10 +3386,10 @@ WebGLContext::CompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, } if (levelInfo.HasUninitializedImageData()) - tex->DoDeferredImageInitialization(target, level); + tex->DoDeferredImageInitialization(texImageTarget, level); MakeContextCurrent(); - gl->fCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, byteLength, view.Data()); + gl->fCompressedTexSubImage2D(texImageTarget.get(), level, xoffset, yoffset, width, height, format, byteLength, view.Data()); } JS::Value @@ -3543,7 +3576,7 @@ WebGLContext::GetShaderTranslatedSource(WebGLShader *shader, nsAString& retval) retval.Assign(shader->TranslatedSource()); } -GLenum WebGLContext::CheckedTexImage2D(GLenum target, +GLenum WebGLContext::CheckedTexImage2D(TexImageTarget texImageTarget, GLint level, GLenum internalFormat, GLsizei width, @@ -3554,13 +3587,13 @@ GLenum WebGLContext::CheckedTexImage2D(GLenum target, const GLvoid *data) { MOZ_ASSERT(internalFormat == format); - WebGLTexture *tex = activeBoundTextureForTexImageTarget(target); + WebGLTexture *tex = activeBoundTextureForTexImageTarget(texImageTarget); MOZ_ASSERT(tex != nullptr, "no texture bound"); bool sizeMayChange = true; - if (tex->HasImageInfoAt(target, level)) { - const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(target, level); + if (tex->HasImageInfoAt(texImageTarget, level)) { + const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(texImageTarget, level); sizeMayChange = width != imageInfo.Width() || height != imageInfo.Height() || format != imageInfo.WebGLFormat() || @@ -3577,7 +3610,7 @@ GLenum WebGLContext::CheckedTexImage2D(GLenum target, GetAndFlushUnderlyingGLErrors(); } - gl->fTexImage2D(target, level, driverInternalFormat, width, height, border, driverFormat, driverType, data); + gl->fTexImage2D(texImageTarget.get(), level, driverInternalFormat, width, height, border, driverFormat, driverType, data); GLenum error = LOCAL_GL_NO_ERROR; if (sizeMayChange) { @@ -3588,7 +3621,7 @@ GLenum WebGLContext::CheckedTexImage2D(GLenum target, } void -WebGLContext::TexImage2D_base(GLenum target, GLint level, GLenum internalformat, +WebGLContext::TexImage2D_base(TexImageTarget texImageTarget, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei srcStrideOrZero, GLint border, GLenum format, GLenum type, @@ -3598,7 +3631,7 @@ WebGLContext::TexImage2D_base(GLenum target, GLint level, GLenum internalformat, { const WebGLTexImageFunc func = WebGLTexImageFunc::TexImage; - if (!ValidateTexImage(2, target, level, internalformat, + if (!ValidateTexImage(2, texImageTarget, level, internalformat, 0, 0, 0, width, height, 0, border, format, type, func)) @@ -3641,7 +3674,7 @@ WebGLContext::TexImage2D_base(GLenum target, GLint level, GLenum internalformat, return ErrorInvalidOperation("texImage2D: not enough data for operation (need %d, have %d)", bytesNeeded, byteLength); - WebGLTexture *tex = activeBoundTextureForTexImageTarget(target); + WebGLTexture *tex = activeBoundTextureForTexImageTarget(texImageTarget); if (!tex) return ErrorInvalidOperation("texImage2D: no texture is bound to this target"); @@ -3680,7 +3713,7 @@ WebGLContext::TexImage2D_base(GLenum target, GLint level, GLenum internalformat, imageInfoStatusIfSuccess = WebGLImageDataStatus::InitializedImageData; } - GLenum error = CheckedTexImage2D(target, level, internalformat, width, + GLenum error = CheckedTexImage2D(texImageTarget, level, internalformat, width, height, border, format, type, pixels); if (error) { @@ -3693,11 +3726,11 @@ WebGLContext::TexImage2D_base(GLenum target, GLint level, GLenum internalformat, // have NoImageData at this point. MOZ_ASSERT(imageInfoStatusIfSuccess != WebGLImageDataStatus::NoImageData); - tex->SetImageInfo(target, level, width, height, format, type, imageInfoStatusIfSuccess); + tex->SetImageInfo(texImageTarget, level, width, height, format, type, imageInfoStatusIfSuccess); } void -WebGLContext::TexImage2D(GLenum target, GLint level, +WebGLContext::TexImage2D(GLenum rawTarget, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const Nullable &pixels, ErrorResult& rv) @@ -3721,13 +3754,16 @@ WebGLContext::TexImage2D(GLenum target, GLint level, jsArrayType = int(JS_GetArrayBufferViewType(view.Obj())); } - return TexImage2D_base(target, level, internalformat, width, height, 0, border, format, type, + if (!ValidateTexImageTarget(2, rawTarget, WebGLTexImageFunc::TexImage)) + return; + + return TexImage2D_base(rawTarget, level, internalformat, width, height, 0, border, format, type, data, length, jsArrayType, WebGLTexelFormat::Auto, false); } void -WebGLContext::TexImage2D(GLenum target, GLint level, +WebGLContext::TexImage2D(GLenum rawTarget, GLint level, GLenum internalformat, GLenum format, GLenum type, ImageData* pixels, ErrorResult& rv) { @@ -3744,15 +3780,21 @@ WebGLContext::TexImage2D(GLenum target, GLint level, MOZ_ASSERT(inited); arr.ComputeLengthAndData(); - return TexImage2D_base(target, level, internalformat, pixels->Width(), + void* pixelData = arr.Data(); + const uint32_t pixelDataLength = arr.Length(); + + if (!ValidateTexImageTarget(2, rawTarget, WebGLTexImageFunc::TexImage)) + return; + + return TexImage2D_base(rawTarget, level, internalformat, pixels->Width(), pixels->Height(), 4*pixels->Width(), 0, - format, type, arr.Data(), arr.Length(), -1, + format, type, pixelData, pixelDataLength, -1, WebGLTexelFormat::RGBA8, false); } void -WebGLContext::TexSubImage2D_base(GLenum target, GLint level, +WebGLContext::TexSubImage2D_base(TexImageTarget texImageTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLsizei srcStrideOrZero, GLenum format, GLenum type, @@ -3762,7 +3804,7 @@ WebGLContext::TexSubImage2D_base(GLenum target, GLint level, { const WebGLTexImageFunc func = WebGLTexImageFunc::TexSubImage; - if (!ValidateTexImage(2, target, level, format, + if (!ValidateTexImage(2, texImageTarget, level, format, xoffset, yoffset, 0, width, height, 0, 0, format, type, func)) @@ -3797,11 +3839,11 @@ WebGLContext::TexSubImage2D_base(GLenum target, GLint level, if (byteLength < bytesNeeded) return ErrorInvalidOperation("texSubImage2D: not enough data for operation (need %d, have %d)", bytesNeeded, byteLength); - WebGLTexture *tex = activeBoundTextureForTexImageTarget(target); - const WebGLTexture::ImageInfo &imageInfo = tex->ImageInfoAt(target, level); + WebGLTexture *tex = activeBoundTextureForTexImageTarget(texImageTarget); + const WebGLTexture::ImageInfo &imageInfo = tex->ImageInfoAt(texImageTarget, level); if (imageInfo.HasUninitializedImageData()) - tex->DoDeferredImageInitialization(target, level); + tex->DoDeferredImageInitialization(texImageTarget, level); MakeContextCurrent(); @@ -3835,11 +3877,11 @@ WebGLContext::TexSubImage2D_base(GLenum target, GLint level, GLenum driverFormat = LOCAL_GL_NONE; DriverFormatsFromFormatAndType(gl, format, type, &driverInternalFormat, &driverFormat); - gl->fTexSubImage2D(target, level, xoffset, yoffset, width, height, driverFormat, driverType, pixels); + gl->fTexSubImage2D(texImageTarget.get(), level, xoffset, yoffset, width, height, driverFormat, driverType, pixels); } void -WebGLContext::TexSubImage2D(GLenum target, GLint level, +WebGLContext::TexSubImage2D(GLenum rawTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, @@ -3855,7 +3897,10 @@ WebGLContext::TexSubImage2D(GLenum target, GLint level, const ArrayBufferView& view = pixels.Value(); view.ComputeLengthAndData(); - return TexSubImage2D_base(target, level, xoffset, yoffset, + if (!ValidateTexImageTarget(2, rawTarget, WebGLTexImageFunc::TexSubImage)) + return; + + return TexSubImage2D_base(rawTarget, level, xoffset, yoffset, width, height, 0, format, type, view.Data(), view.Length(), JS_GetArrayBufferViewType(view.Obj()), diff --git a/dom/canvas/WebGLContextUtils.cpp b/dom/canvas/WebGLContextUtils.cpp index 5eee4affa0b..f32d606d914 100644 --- a/dom/canvas/WebGLContextUtils.cpp +++ b/dom/canvas/WebGLContextUtils.cpp @@ -56,10 +56,10 @@ FormatHasAlpha(GLenum webGLFormat) webGLFormat == LOCAL_GL_SRGB_ALPHA; } -GLenum -TexImageTargetToTexTarget(GLenum texImageTarget) +TexTarget +TexImageTargetToTexTarget(TexImageTarget texImageTarget) { - switch (texImageTarget) { + switch (texImageTarget.get()) { case LOCAL_GL_TEXTURE_2D: return LOCAL_GL_TEXTURE_2D; case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X: @@ -70,6 +70,8 @@ TexImageTargetToTexTarget(GLenum texImageTarget) case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: return LOCAL_GL_TEXTURE_CUBE_MAP; default: + MOZ_ASSERT(false, "Bad texture conversion"); + // Should be caught by the constructor for TexTarget return LOCAL_GL_NONE; } } diff --git a/dom/canvas/WebGLContextUtils.h b/dom/canvas/WebGLContextUtils.h index bfb3e2b2c6b..202a7858557 100644 --- a/dom/canvas/WebGLContextUtils.h +++ b/dom/canvas/WebGLContextUtils.h @@ -7,6 +7,7 @@ #define WEBGLCONTEXTUTILS_H_ #include "WebGLContext.h" +#include "WebGLStrongTypes.h" #include "mozilla/Assertions.h" #include "mozilla/dom/BindingUtils.h" @@ -31,7 +32,7 @@ GLenum DriverTypeFromType(gl::GLContext* gl, GLenum webGLType); // the currently bound texture is appropriate for this texImageTarget. // // Returns GL_NONE if passed an invalid texture image target -GLenum TexImageTargetToTexTarget(GLenum texImageTarget); +TexTarget TexImageTargetToTexTarget(TexImageTarget texImageTarget); struct GLComponents { diff --git a/dom/canvas/WebGLContextValidate.cpp b/dom/canvas/WebGLContextValidate.cpp index 4004c0f55a6..559a0595e1f 100644 --- a/dom/canvas/WebGLContextValidate.cpp +++ b/dom/canvas/WebGLContextValidate.cpp @@ -149,10 +149,10 @@ IsSubFunc(WebGLTexImageFunc func) * returns true is target is a texture cube map target. */ static bool -IsTexImageCubemapTarget(GLenum target) +IsTexImageCubemapTarget(GLenum texImageTarget) { - return (target >= LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X && - target <= LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z); + return (texImageTarget >= LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X && + texImageTarget <= LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z); } /* @@ -712,7 +712,7 @@ WebGLContext::ValidateTexImageType(GLenum type, WebGLTexImageFunc func) */ // TODO: WebGL 2 bool -WebGLContext::ValidateCompTexImageSize(GLenum target, GLint level, GLenum format, +WebGLContext::ValidateCompTexImageSize(GLint level, GLenum format, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLsizei levelWidth, GLsizei levelHeight, @@ -884,7 +884,7 @@ WebGLContext::ValidateCompTexImageDataSize(GLint level, GLenum format, * Target and level must have been validated before calling. */ bool -WebGLContext::ValidateTexImageSize(GLenum target, GLint level, +WebGLContext::ValidateTexImageSize(TexImageTarget texImageTarget, GLint level, GLint width, GLint height, GLint depth, WebGLTexImageFunc func) { @@ -903,8 +903,8 @@ WebGLContext::ValidateTexImageSize(GLenum target, GLint level, if (level > 31) level = 31; - const GLuint maxTexImageSize = MaxTextureSizeForTarget(target) >> level; - const bool isCubemapTarget = IsTexImageCubemapTarget(target); + const GLuint maxTexImageSize = MaxTextureSizeForTarget(TexImageTargetToTexTarget(texImageTarget)) >> level; + const bool isCubemapTarget = IsTexImageCubemapTarget(texImageTarget.get()); const bool isSub = IsSubFunc(func); if (!isSub && isCubemapTarget && (width != height)) { @@ -918,7 +918,7 @@ WebGLContext::ValidateTexImageSize(GLenum target, GLint level, return false; } - if (target == LOCAL_GL_TEXTURE_2D || isCubemapTarget) + if (texImageTarget == LOCAL_GL_TEXTURE_2D || isCubemapTarget) { /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification * "If wt and ht are the specified image width and height, @@ -978,7 +978,7 @@ WebGLContext::ValidateTexImageSize(GLenum target, GLint level, } // TODO: WebGL 2 - if (target == LOCAL_GL_TEXTURE_3D) { + if (texImageTarget == LOCAL_GL_TEXTURE_3D) { if (depth < 0) { ErrorInvalidValue("%s: depth must be >= 0", InfoFrom(func)); return false; @@ -1308,7 +1308,7 @@ WebGLContext::ValidateCopyTexImage(GLenum format, WebGLTexImageFunc func) */ // TODO: Texture dims is here for future expansion in WebGL 2.0 bool -WebGLContext::ValidateTexImage(GLuint dims, GLenum target, +WebGLContext::ValidateTexImage(GLuint dims, TexImageTarget texImageTarget, GLint level, GLint internalFormat, GLint xoffset, GLint yoffset, GLint zoffset, GLint width, GLint height, GLint depth, @@ -1317,10 +1317,6 @@ WebGLContext::ValidateTexImage(GLuint dims, GLenum target, { const char* info = InfoFrom(func); - /* Check target */ - if (!ValidateTexImageTarget(dims, target, func)) - return false; - /* Check level */ if (level < 0) { ErrorInvalidValue("%s: level must be >= 0", info); @@ -1357,7 +1353,7 @@ WebGLContext::ValidateTexImage(GLuint dims, GLenum target, } /* Check texture image size */ - if (!ValidateTexImageSize(target, level, width, height, 0, func)) + if (!ValidateTexImageSize(texImageTarget, level, width, height, 0, func)) return false; /* 5.14.8 Texture objects - WebGL Spec. @@ -1365,21 +1361,21 @@ WebGLContext::ValidateTexImage(GLuint dims, GLenum target, * WebGLTexture bound (see above), an INVALID_OPERATION error * is generated." */ - WebGLTexture* tex = activeBoundTextureForTexImageTarget(target); + WebGLTexture* tex = activeBoundTextureForTexImageTarget(texImageTarget); if (!tex) { ErrorInvalidOperation("%s: no texture is bound to target %s", - info, WebGLContext::EnumName(target)); + info, WebGLContext::EnumName(texImageTarget.get())); return false; } if (IsSubFunc(func)) { - if (!tex->HasImageInfoAt(target, level)) { + if (!tex->HasImageInfoAt(texImageTarget, level)) { ErrorInvalidOperation("%s: no texture image previously defined for target %s at level %d", - info, WebGLContext::EnumName(target), level); + info, WebGLContext::EnumName(texImageTarget.get()), level); return false; } - const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(target, level); + const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(texImageTarget, level); if (!ValidateTexSubImageSize(xoffset, yoffset, zoffset, width, height, depth, imageInfo.Width(), imageInfo.Height(), 0, @@ -1401,7 +1397,7 @@ WebGLContext::ValidateTexImage(GLuint dims, GLenum target, } /* Additional checks for depth textures */ - if (target != LOCAL_GL_TEXTURE_2D && + if (texImageTarget != LOCAL_GL_TEXTURE_2D && (format == LOCAL_GL_DEPTH_COMPONENT || format == LOCAL_GL_DEPTH_STENCIL)) { diff --git a/dom/canvas/WebGLFramebuffer.cpp b/dom/canvas/WebGLFramebuffer.cpp index 98dae837e7a..c1d2e1e39d5 100644 --- a/dom/canvas/WebGLFramebuffer.cpp +++ b/dom/canvas/WebGLFramebuffer.cpp @@ -24,7 +24,7 @@ WebGLFramebuffer::WrapObject(JSContext* cx) } WebGLFramebuffer::WebGLFramebuffer(WebGLContext* context) - : WebGLBindableName() + : WebGLBindableName() , WebGLContextBoundObject(context) , mStatus(0) , mDepthAttachment(LOCAL_GL_DEPTH_ATTACHMENT) @@ -42,6 +42,7 @@ WebGLFramebuffer::WebGLFramebuffer(WebGLContext* context) WebGLFramebuffer::Attachment::Attachment(GLenum aAttachmentPoint) : mAttachmentPoint(aAttachmentPoint) + , mTexImageTarget(LOCAL_GL_NONE) , mNeedsFinalize(false) {} @@ -84,9 +85,9 @@ WebGLFramebuffer::GetFormatForAttachment(const WebGLFramebuffer::Attachment& att if (attachment.Texture()) { const WebGLTexture& tex = *attachment.Texture(); - MOZ_ASSERT(tex.HasImageInfoAt(tex.Target(), 0)); + MOZ_ASSERT(tex.HasImageInfoAt(attachment.ImageTarget(), 0)); - const WebGLTexture::ImageInfo& imgInfo = tex.ImageInfoAt(tex.Target(), 0); + const WebGLTexture::ImageInfo& imgInfo = tex.ImageInfoAt(attachment.ImageTarget(), 0); return imgInfo.WebGLFormat(); } @@ -130,7 +131,7 @@ WebGLFramebuffer::Attachment::IsReadableFloat() const } void -WebGLFramebuffer::Attachment::SetTexImage(WebGLTexture* tex, GLenum target, GLint level) +WebGLFramebuffer::Attachment::SetTexImage(WebGLTexture* tex, TexImageTarget target, GLint level) { mTexturePtr = tex; mRenderbufferPtr = nullptr; @@ -395,14 +396,18 @@ WebGLFramebuffer::Attachment::FinalizeAttachment(GLContext* gl, GLenum attachmen if (Texture()) { MOZ_ASSERT(gl == Texture()->Context()->gl); + const GLenum imageTarget = ImageTarget().get(); + const GLint mipLevel = MipLevel(); + const GLuint glName = Texture()->GLName(); + if (attachmentLoc == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) { gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT, - TexImageTarget(), Texture()->GLName(), TexImageLevel()); + imageTarget, glName, mipLevel); gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT, - TexImageTarget(), Texture()->GLName(), TexImageLevel()); + imageTarget, glName, mipLevel); } else { gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, attachmentLoc, - TexImageTarget(), Texture()->GLName(), TexImageLevel()); + imageTarget, glName, mipLevel); } return; } @@ -500,7 +505,7 @@ WebGLFramebuffer::FramebufferRenderbuffer(GLenum target, void WebGLFramebuffer::FramebufferTexture2D(GLenum target, GLenum attachment, - GLenum textarget, + TexImageTarget texImageTarget, WebGLTexture* wtex, GLint level) { @@ -512,16 +517,9 @@ WebGLFramebuffer::FramebufferTexture2D(GLenum target, if (target != LOCAL_GL_FRAMEBUFFER) return mContext->ErrorInvalidEnumInfo("framebufferTexture2D: target", target); - if (textarget != LOCAL_GL_TEXTURE_2D && - (textarget < LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X || - textarget > LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)) - { - return mContext->ErrorInvalidEnumInfo("framebufferTexture2D: invalid texture target", textarget); - } - if (wtex) { bool isTexture2D = wtex->Target() == LOCAL_GL_TEXTURE_2D; - bool isTexTarget2D = textarget == LOCAL_GL_TEXTURE_2D; + bool isTexTarget2D = texImageTarget == LOCAL_GL_TEXTURE_2D; if (isTexture2D != isTexTarget2D) { return mContext->ErrorInvalidOperation("framebufferTexture2D: mismatched texture and texture target"); } @@ -555,7 +553,7 @@ WebGLFramebuffer::FramebufferTexture2D(GLenum target, if (wtex) wtex->AttachTo(this, attachment); - a->SetTexImage(wtex, textarget, level); + a->SetTexImage(wtex, texImageTarget, level); } WebGLFramebuffer::Attachment* diff --git a/dom/canvas/WebGLFramebuffer.h b/dom/canvas/WebGLFramebuffer.h index 946e14cdece..c291ee5e92f 100644 --- a/dom/canvas/WebGLFramebuffer.h +++ b/dom/canvas/WebGLFramebuffer.h @@ -8,6 +8,7 @@ #include "WebGLBindableName.h" #include "WebGLObjectModel.h" +#include "WebGLStrongTypes.h" #include "nsWrapperCache.h" @@ -24,7 +25,7 @@ namespace gl { class WebGLFramebuffer MOZ_FINAL : public nsWrapperCache - , public WebGLBindableName + , public WebGLBindableName , public WebGLRefCountedObject , public LinkedListElement , public WebGLContextBoundObject @@ -41,7 +42,7 @@ public: WebGLRefPtr mTexturePtr; WebGLRefPtr mRenderbufferPtr; GLenum mAttachmentPoint; - GLenum mTexImageTarget; + TexImageTarget mTexImageTarget; GLint mTexImageLevel; mutable bool mNeedsFinalize; @@ -57,7 +58,7 @@ public: bool HasAlpha() const; bool IsReadableFloat() const; - void SetTexImage(WebGLTexture* tex, GLenum target, GLint level); + void SetTexImage(WebGLTexture* tex, TexImageTarget target, GLint level); void SetRenderbuffer(WebGLRenderbuffer* rb); const WebGLTexture* Texture() const { @@ -72,10 +73,10 @@ public: WebGLRenderbuffer* Renderbuffer() { return mRenderbufferPtr; } - GLenum TexImageTarget() const { + TexImageTarget ImageTarget() const { return mTexImageTarget; } - GLint TexImageLevel() const { + GLint MipLevel() const { return mTexImageLevel; } @@ -101,7 +102,7 @@ public: void FramebufferTexture2D(GLenum target, GLenum attachment, - GLenum textarget, + TexImageTarget texImageTarget, WebGLTexture* wtex, GLint level); diff --git a/dom/canvas/WebGLRenderbuffer.cpp b/dom/canvas/WebGLRenderbuffer.cpp index 48dca59a9ee..0ad5e45f8e2 100644 --- a/dom/canvas/WebGLRenderbuffer.cpp +++ b/dom/canvas/WebGLRenderbuffer.cpp @@ -43,7 +43,7 @@ WebGLRenderbuffer::WrapObject(JSContext *cx) { } WebGLRenderbuffer::WebGLRenderbuffer(WebGLContext *context) - : WebGLBindableName() + : WebGLBindableName() , WebGLContextBoundObject(context) , mPrimaryRB(0) , mSecondaryRB(0) diff --git a/dom/canvas/WebGLRenderbuffer.h b/dom/canvas/WebGLRenderbuffer.h index 46aabe2ebec..40a251a0ba5 100644 --- a/dom/canvas/WebGLRenderbuffer.h +++ b/dom/canvas/WebGLRenderbuffer.h @@ -18,7 +18,7 @@ namespace mozilla { class WebGLRenderbuffer MOZ_FINAL : public nsWrapperCache - , public WebGLBindableName + , public WebGLBindableName , public WebGLRefCountedObject , public LinkedListElement , public WebGLRectangleObject diff --git a/dom/canvas/WebGLSampler.h b/dom/canvas/WebGLSampler.h index fe17e2d4d04..d3d6a9b37f2 100644 --- a/dom/canvas/WebGLSampler.h +++ b/dom/canvas/WebGLSampler.h @@ -16,7 +16,7 @@ namespace mozilla { class WebGLSampler MOZ_FINAL - : public WebGLBindableName + : public WebGLBindableName , public nsWrapperCache , public WebGLRefCountedObject , public LinkedListElement diff --git a/dom/canvas/WebGLStrongTypes.h b/dom/canvas/WebGLStrongTypes.h new file mode 100644 index 00000000000..483269966f6 --- /dev/null +++ b/dom/canvas/WebGLStrongTypes.h @@ -0,0 +1,152 @@ + +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef WEBGLSTRONGTYPES_H_ +#define WEBGLSTRONGTYPES_H_ + +#include "GLDefs.h" +#include "mozilla/Assertions.h" +#include "mozilla/ArrayUtils.h" + +// Usage: +// =========== +// +// To create a new type from a set of GLenums do the following: +// +// STRONG_GLENUM_BEGIN(TypeName) +// Enum1, +// Enum2, +// ... +// STRONG_GLENUM_END() +// +// where TypeName is the name you want to give the type. Now simply use TypeName +// instead of GLenum. +// +// ~~~~~~~~~~~~~~~~ +// Important Notes: +// ~~~~~~~~~~~~~~~~ +// +// Boolean operators (==, !=) are provided in an effort to prevent some mistakes +// when using constants. For example we want to make sure that GL_ENUM_X is +// a valid value for the type in code like: +// +// if (myNewType == LOCAL_GL_SOME_ENUM) +// ... +// +// The operators will assert that LOCAL_GL_SOME_ENUM is a value that myNewType +// can have. +// +// ---- +// +// A get() method is provided to allow access to the underlying GLenum. This +// method should ideally only be called when passing parameters to the gl->fXXXX +// functions, and be used very minimally everywhere else. +// +// Definitely XXX - DO NOT DO - XXX: +// +// if (myNewType.get() == LOCAL_GL_SOME_ENUM) +// ... +// +// As that undermines the debug checks that were implemented in the ==, and != +// operators. If you see code like this it should be treated with suspicion. +// +// Background: +// =========== +// +// This macro is the first step in an effort to make the WebGL code safer. +// Many of the different functions take GLenum as their parameter which leads +// to bugs because of subtle differences in the enums purpose. For example there +// are two types of 'texture targets'. One is the texture binding locations: +// +// GL_TEXTURE_2D +// GL_TEXTURE_CUBE_MAP +// +// Yet, this is not the same as texture image targets: +// +// GL_TEXTURE_2D +// GL_TEXTURE_CUBE_MAP_POSITIVE_X +// GL_TEXTURE_CUBE_MAP_NEGATIVE_X +// GL_TEXTURE_CUBE_MAP_POSITIVE_Y +// ... +// +// This subtle distinction has already led to many bugs in the texture code +// because of invalid assumptions about what type goes where. The macro below +// is an attempt at fixing this by providing a small wrapper around GLenum that +// validates its values. +// +#ifdef DEBUG + +template +static bool +IsValueInArr(GLenum value, const GLenum (&arr)[N]) +{ + for (size_t i = 0; i < N; ++i) { + if (value == arr[i]) + return true; + } + + return false; +} + +#endif + +#define STRONG_GLENUM_BEGIN(NAME) \ + class NAME { \ + private: \ + GLenum mValue; \ + public: \ + MOZ_CONSTEXPR NAME(const NAME& other) \ + : mValue(other.mValue) { } \ + \ + bool operator==(const NAME& other) const { \ + return mValue == other.mValue; \ + } \ + \ + bool operator!=(const NAME& other) const { \ + return mValue != other.mValue; \ + } \ + \ + GLenum get() const { \ + MOZ_ASSERT(mValue != LOCAL_GL_NONE); \ + return mValue; \ + } \ + \ + NAME(GLenum val) \ + : mValue(val) \ + { \ + const GLenum validValues[] = { + +#define STRONG_GLENUM_END() \ + }; \ + (void)validValues; \ + MOZ_ASSERT(IsValueInArr(mValue, validValues)); \ + } \ + }; + +/****************************************************************************** + * Add your types after this comment + *****************************************************************************/ + +STRONG_GLENUM_BEGIN(TexImageTarget) + LOCAL_GL_NONE, + LOCAL_GL_TEXTURE_2D, + LOCAL_GL_TEXTURE_3D, + LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X, + LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X, + LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y, + LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, + LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z, + LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, +STRONG_GLENUM_END() + +STRONG_GLENUM_BEGIN(TexTarget) + LOCAL_GL_NONE, + LOCAL_GL_TEXTURE_2D, + LOCAL_GL_TEXTURE_3D, + LOCAL_GL_TEXTURE_CUBE_MAP, +STRONG_GLENUM_END() + +#endif diff --git a/dom/canvas/WebGLTexture.cpp b/dom/canvas/WebGLTexture.cpp index 8f0aeae14d4..88ccda38492 100644 --- a/dom/canvas/WebGLTexture.cpp +++ b/dom/canvas/WebGLTexture.cpp @@ -23,7 +23,7 @@ WebGLTexture::WrapObject(JSContext *cx) { } WebGLTexture::WebGLTexture(WebGLContext *context) - : WebGLBindableName() + : WebGLBindableName() , WebGLContextBoundObject(context) , mMinFilter(LOCAL_GL_NEAREST_MIPMAP_LINEAR) , mMagFilter(LOCAL_GL_LINEAR) @@ -76,7 +76,7 @@ WebGLTexture::MemoryUsage() const { } bool -WebGLTexture::DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(GLenum texImageTarget) const { +WebGLTexture::DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(TexImageTarget texImageTarget) const { if (mHaveGeneratedMipmap) return true; @@ -103,15 +103,15 @@ WebGLTexture::DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(GLenum texImag } void -WebGLTexture::Bind(GLenum aTarget) { +WebGLTexture::Bind(TexTarget aTexTarget) { // this function should only be called by bindTexture(). // it assumes that the GL context is already current. bool firstTimeThisTextureIsBound = !HasEverBeenBound(); if (firstTimeThisTextureIsBound) { - BindTo(aTarget); - } else if (aTarget != Target()) { + BindTo(aTexTarget); + } else if (aTexTarget != Target()) { mContext->ErrorInvalidOperation("bindTexture: this texture has already been bound to a different target"); // very important to return here before modifying texture state! This was the place when I lost a whole day figuring // very strange 'invalid write' crashes. @@ -119,12 +119,11 @@ WebGLTexture::Bind(GLenum aTarget) { } GLuint name = GLName(); - GLenum target = Target(); - mContext->gl->fBindTexture(target, name); + mContext->gl->fBindTexture(aTexTarget.get(), name); if (firstTimeThisTextureIsBound) { - mFacesCount = (mTarget == LOCAL_GL_TEXTURE_2D) ? 1 : 6; + mFacesCount = (aTexTarget == LOCAL_GL_TEXTURE_2D) ? 1 : 6; EnsureMaxLevelWithCustomImagesAtLeast(0); SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown); @@ -132,12 +131,12 @@ WebGLTexture::Bind(GLenum aTarget) { // present in GLES 2, but is present in GL and it seems as if for cube maps // we need to set it to GL_CLAMP_TO_EDGE to get the expected GLES behavior. if (mTarget == LOCAL_GL_TEXTURE_CUBE_MAP && !mContext->gl->IsGLES()) - mContext->gl->fTexParameteri(mTarget, LOCAL_GL_TEXTURE_WRAP_R, LOCAL_GL_CLAMP_TO_EDGE); + mContext->gl->fTexParameteri(aTexTarget.get(), LOCAL_GL_TEXTURE_WRAP_R, LOCAL_GL_CLAMP_TO_EDGE); } } void -WebGLTexture::SetImageInfo(GLenum aTexImageTarget, GLint aLevel, +WebGLTexture::SetImageInfo(TexImageTarget aTexImageTarget, GLint aLevel, GLsizei aWidth, GLsizei aHeight, GLenum aFormat, GLenum aType, WebGLImageDataStatus aStatus) { @@ -227,13 +226,11 @@ WebGLTexture::IsCubeComplete() const { return AreAllLevel0ImageInfosEqual(); } -static GLenum +static TexImageTarget GLCubeMapFaceById(int id) { - GLenum result = LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + id; - MOZ_ASSERT(result >= LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X && - result <= LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z); - return result; + // Correctness is checked by the constructor for TexImageTarget + return TexImageTarget(LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + id); } bool @@ -241,7 +238,7 @@ WebGLTexture::IsMipmapCubeComplete() const { if (!IsCubeComplete()) // in particular, this checks that this is a cube map return false; for (int i = 0; i < 6; i++) { - GLenum face = GLCubeMapFaceById(i); + const TexImageTarget face = GLCubeMapFaceById(i); if (!DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(face)) return false; } @@ -279,7 +276,7 @@ WebGLTexture::ResolvedFakeBlackStatus() { ("%s is a 2D texture, with a minification filter requiring a mipmap, " "and is not mipmap complete (as defined in section 3.7.10).", msg_rendering_as_black); mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture; - } else if (!ImageInfoAt(mTarget, 0).IsPowerOfTwo()) { + } else if (!ImageInfoBase().IsPowerOfTwo()) { mContext->GenerateWarning ("%s is a 2D texture, with a minification filter requiring a mipmap, " "and either its width or height is not a power of two.", msg_rendering_as_black); @@ -288,12 +285,12 @@ WebGLTexture::ResolvedFakeBlackStatus() { } else // no mipmap required { - if (!ImageInfoAt(mTarget, 0).IsPositive()) { + if (!ImageInfoBase().IsPositive()) { mContext->GenerateWarning ("%s is a 2D texture and its width or height is equal to zero.", msg_rendering_as_black); mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture; - } else if (!AreBothWrapModesClampToEdge() && !ImageInfoAt(mTarget, 0).IsPowerOfTwo()) { + } else if (!AreBothWrapModesClampToEdge() && !ImageInfoBase().IsPowerOfTwo()) { mContext->GenerateWarning ("%s is a 2D texture, with a minification filter not requiring a mipmap, " "with its width or height not a power of two, and with a wrap mode " @@ -411,9 +408,9 @@ WebGLTexture::ResolvedFakeBlackStatus() { // glTexImage2D is able to upload data to images. for (size_t level = 0; level <= mMaxLevelWithCustomImages; ++level) { for (size_t face = 0; face < mFacesCount; ++face) { - GLenum imageTarget = mTarget == LOCAL_GL_TEXTURE_2D - ? LOCAL_GL_TEXTURE_2D - : LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + face; + TexImageTarget imageTarget = mTarget == LOCAL_GL_TEXTURE_2D + ? LOCAL_GL_TEXTURE_2D + : LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + face; const ImageInfo& imageInfo = ImageInfoAt(imageTarget, level); if (imageInfo.mImageDataStatus == WebGLImageDataStatus::UninitializedImageData) { DoDeferredImageInitialization(imageTarget, level); @@ -461,7 +458,7 @@ ClearByMask(WebGLContext* context, GLbitfield mask) // `mask` from glClear. static bool ClearWithTempFB(WebGLContext* context, GLuint tex, - GLenum texImageTarget, GLint level, + TexImageTarget texImageTarget, GLint level, GLenum baseInternalFormat, GLsizei width, GLsizei height) { @@ -485,22 +482,22 @@ ClearWithTempFB(WebGLContext* context, GLuint tex, case LOCAL_GL_BGRA: mask = LOCAL_GL_COLOR_BUFFER_BIT; gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, - texImageTarget, tex, level); + texImageTarget.get(), tex, level); break; case LOCAL_GL_DEPTH_COMPONENT: mask = LOCAL_GL_DEPTH_BUFFER_BIT; gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT, - texImageTarget, tex, level); + texImageTarget.get(), tex, level); break; case LOCAL_GL_DEPTH_STENCIL: mask = LOCAL_GL_DEPTH_BUFFER_BIT | LOCAL_GL_STENCIL_BUFFER_BIT; gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT, - texImageTarget, tex, level); + texImageTarget.get(), tex, level); gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT, - texImageTarget, tex, level); + texImageTarget.get(), tex, level); break; default: @@ -537,7 +534,7 @@ ClearWithTempFB(WebGLContext* context, GLuint tex, void -WebGLTexture::DoDeferredImageInitialization(GLenum imageTarget, GLint level) +WebGLTexture::DoDeferredImageInitialization(TexImageTarget imageTarget, GLint level) { const ImageInfo& imageInfo = ImageInfoAt(imageTarget, level); MOZ_ASSERT(imageInfo.mImageDataStatus == WebGLImageDataStatus::UninitializedImageData); @@ -558,7 +555,7 @@ WebGLTexture::DoDeferredImageInitialization(GLenum imageTarget, GLint level) } // That didn't work. Try uploading zeros then. - gl::ScopedBindTexture autoBindTex(mContext->gl, GLName(), mTarget); + gl::ScopedBindTexture autoBindTex(mContext->gl, GLName(), mTarget.get()); uint32_t texelsize = WebGLTexelConversions::TexelBytesForFormat(texelformat); CheckedUint32 checked_byteLength @@ -578,7 +575,7 @@ WebGLTexture::DoDeferredImageInitialization(GLenum imageTarget, GLint level) DriverFormatsFromFormatAndType(gl, format, type, &driverInternalFormat, &driverFormat); mContext->GetAndFlushUnderlyingGLErrors(); - gl->fTexImage2D(imageTarget, level, driverInternalFormat, + gl->fTexImage2D(imageTarget.get(), level, driverInternalFormat, imageInfo.mWidth, imageInfo.mHeight, 0, driverFormat, driverType, zeros); diff --git a/dom/canvas/WebGLTexture.h b/dom/canvas/WebGLTexture.h index dcbbc1330ec..a9f598609cb 100644 --- a/dom/canvas/WebGLTexture.h +++ b/dom/canvas/WebGLTexture.h @@ -9,6 +9,7 @@ #include "WebGLBindableName.h" #include "WebGLFramebufferAttachable.h" #include "WebGLObjectModel.h" +#include "WebGLStrongTypes.h" #include "nsWrapperCache.h" @@ -28,7 +29,7 @@ inline bool is_pot_assuming_nonnegative(GLsizei x) // WrapObject calls in GetParameter and GetFramebufferAttachmentParameter. class WebGLTexture MOZ_FINAL : public nsWrapperCache - , public WebGLBindableName + , public WebGLBindableName , public WebGLRefCountedObject , public LinkedListElement , public WebGLContextBoundObject @@ -129,13 +130,11 @@ public: }; private: - static size_t FaceForTarget(GLenum target) { - // Call this out explicitly: - MOZ_ASSERT(target != LOCAL_GL_TEXTURE_CUBE_MAP); - MOZ_ASSERT(target == LOCAL_GL_TEXTURE_2D || - (target >= LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X && - target <= LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)); - return target == LOCAL_GL_TEXTURE_2D ? 0 : target - LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X; + static size_t FaceForTarget(TexImageTarget texImageTarget) { + if (texImageTarget == LOCAL_GL_TEXTURE_2D) + return 0; + + return texImageTarget.get() - LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X; } ImageInfo& ImageInfoAtFace(size_t face, GLint level) { @@ -152,20 +151,16 @@ private: } public: - ImageInfo& ImageInfoAt(GLenum imageTarget, GLint level) { - MOZ_ASSERT(imageTarget); - + ImageInfo& ImageInfoAt(TexImageTarget imageTarget, GLint level) { size_t face = FaceForTarget(imageTarget); return ImageInfoAtFace(face, level); } - const ImageInfo& ImageInfoAt(GLenum imageTarget, GLint level) const { + const ImageInfo& ImageInfoAt(TexImageTarget imageTarget, GLint level) const { return const_cast(this)->ImageInfoAt(imageTarget, level); } - bool HasImageInfoAt(GLenum imageTarget, GLint level) const { - MOZ_ASSERT(imageTarget); - + bool HasImageInfoAt(TexImageTarget imageTarget, GLint level) const { size_t face = FaceForTarget(imageTarget); CheckedUint32 checked_index = CheckedUint32(level) * mFacesCount + face; return checked_index.isValid() && @@ -183,7 +178,7 @@ public: int64_t MemoryUsage() const; - void SetImageDataStatus(GLenum imageTarget, GLint level, WebGLImageDataStatus newStatus) { + void SetImageDataStatus(TexImageTarget imageTarget, GLint level, WebGLImageDataStatus newStatus) { MOZ_ASSERT(HasImageInfoAt(imageTarget, level)); ImageInfo& imageInfo = ImageInfoAt(imageTarget, level); // there is no way to go from having image data to not having any @@ -195,7 +190,7 @@ public: imageInfo.mImageDataStatus = newStatus; } - void DoDeferredImageInitialization(GLenum imageTarget, GLint level); + void DoDeferredImageInitialization(TexImageTarget imageTarget, GLint level); protected: @@ -222,13 +217,13 @@ protected: return mWrapS == LOCAL_GL_CLAMP_TO_EDGE && mWrapT == LOCAL_GL_CLAMP_TO_EDGE; } - bool DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(GLenum texImageTarget) const; + bool DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(TexImageTarget texImageTarget) const; public: - void Bind(GLenum aTarget); + void Bind(TexTarget aTexTarget); - void SetImageInfo(GLenum aTarget, GLint aLevel, + void SetImageInfo(TexImageTarget aTarget, GLint aLevel, GLsizei aWidth, GLsizei aHeight, GLenum aFormat, GLenum aType, WebGLImageDataStatus aStatus); diff --git a/dom/canvas/WebGLTransformFeedback.h b/dom/canvas/WebGLTransformFeedback.h index 4d0df602a5c..17467c56875 100644 --- a/dom/canvas/WebGLTransformFeedback.h +++ b/dom/canvas/WebGLTransformFeedback.h @@ -16,7 +16,7 @@ namespace mozilla { class WebGLTransformFeedback MOZ_FINAL - : public WebGLBindableName + : public WebGLBindableName , public nsWrapperCache , public WebGLRefCountedObject , public LinkedListElement diff --git a/dom/canvas/WebGLVertexArray.cpp b/dom/canvas/WebGLVertexArray.cpp index 67b424b2e50..9b49ad7cb16 100644 --- a/dom/canvas/WebGLVertexArray.cpp +++ b/dom/canvas/WebGLVertexArray.cpp @@ -20,7 +20,7 @@ WebGLVertexArray::WrapObject(JSContext *cx) { } WebGLVertexArray::WebGLVertexArray(WebGLContext* context) - : WebGLBindableName() + : WebGLBindableName() , WebGLContextBoundObject(context) { SetIsDOMBinding(); diff --git a/dom/canvas/WebGLVertexArray.h b/dom/canvas/WebGLVertexArray.h index bd35c00a9d7..6d58c8dd068 100644 --- a/dom/canvas/WebGLVertexArray.h +++ b/dom/canvas/WebGLVertexArray.h @@ -21,7 +21,7 @@ class WebGLVertexArrayFake; class WebGLVertexArray : public nsWrapperCache - , public WebGLBindableName + , public WebGLBindableName , public WebGLRefCountedObject , public LinkedListElement , public WebGLContextBoundObject diff --git a/dom/canvas/moz.build b/dom/canvas/moz.build index 8f8edc6e9d7..f0819efc0a3 100644 --- a/dom/canvas/moz.build +++ b/dom/canvas/moz.build @@ -53,7 +53,6 @@ UNIFIED_SOURCES += [ 'WebGL2ContextUniforms.cpp', 'WebGL2ContextVAOs.cpp', 'WebGLActiveInfo.cpp', - 'WebGLBindableName.cpp', 'WebGLBuffer.cpp', 'WebGLContext.cpp', 'WebGLContextAsyncQueries.cpp',