From 25bc6850db2d881cdc197f2ae878841d6f86b5ce Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Fri, 11 Oct 2013 09:16:43 -0400 Subject: [PATCH] Bug 922810 - Part 6: Clean up and optimize fake black textures implementation - r=jgilbert --- content/canvas/src/WebGLContext.cpp | 14 +-- content/canvas/src/WebGLContext.h | 24 +++- content/canvas/src/WebGLContextGL.cpp | 161 +++++++++++++++----------- 3 files changed, 119 insertions(+), 80 deletions(-) diff --git a/content/canvas/src/WebGLContext.cpp b/content/canvas/src/WebGLContext.cpp index a2dd1a3d8c39..575d9faf7a53 100644 --- a/content/canvas/src/WebGLContext.cpp +++ b/content/canvas/src/WebGLContext.cpp @@ -121,8 +121,7 @@ WebGLContext::WebGLContext() mShaderValidation = true; - mBlackTexturesAreInitialized = false; - mFakeBlackStatus = WebGLContextFakeBlackStatus::Unknown; + mFakeBlackStatus = WebGLContextFakeBlackStatus::NotNeeded; mVertexAttrib0Vector[0] = 0; mVertexAttrib0Vector[1] = 0; @@ -264,13 +263,10 @@ WebGLContext::DestroyResourcesAndContext() while (!mQueries.isEmpty()) mQueries.getLast()->DeleteOnce(); - if (mBlackTexturesAreInitialized) { - gl->fDeleteTextures(1, &mBlackOpaqueTexture2D); - gl->fDeleteTextures(1, &mBlackOpaqueTextureCubeMap); - gl->fDeleteTextures(1, &mBlackTransparentTexture2D); - gl->fDeleteTextures(1, &mBlackTransparentTextureCubeMap); - mBlackTexturesAreInitialized = false; - } + mBlackOpaqueTexture2D = nullptr; + mBlackOpaqueTextureCubeMap = nullptr; + mBlackTransparentTexture2D = nullptr; + mBlackTransparentTextureCubeMap = nullptr; if (mFakeVertexAttrib0BufferObject) { gl->fDeleteBuffers(1, &mFakeVertexAttrib0BufferObject); diff --git a/content/canvas/src/WebGLContext.h b/content/canvas/src/WebGLContext.h index 8d37f708706c..0a30b434dc39 100644 --- a/content/canvas/src/WebGLContext.h +++ b/content/canvas/src/WebGLContext.h @@ -26,6 +26,7 @@ #include "mozilla/LinkedList.h" #include "mozilla/CheckedInt.h" +#include "mozilla/Scoped.h" #ifdef XP_MACOSX #include "ForceDiscreteGPUHelperCGL.h" @@ -1094,8 +1095,27 @@ protected: WebGLContextFakeBlackStatus mFakeBlackStatus; - GLuint mBlackOpaqueTexture2D, mBlackOpaqueTextureCubeMap, mBlackTransparentTexture2D, mBlackTransparentTextureCubeMap; - bool mBlackTexturesAreInitialized; + class FakeBlackTexture + { + gl::GLContext* mGL; + GLuint mGLName; + + public: + FakeBlackTexture(gl::GLContext* gl, GLenum target, GLenum format); + ~FakeBlackTexture(); + GLuint GLName() const { return mGLName; } + }; + + ScopedDeletePtr mBlackOpaqueTexture2D, + mBlackOpaqueTextureCubeMap, + mBlackTransparentTexture2D, + mBlackTransparentTextureCubeMap; + + void BindFakeBlackTexturesHelper( + GLenum target, + const nsTArray >& boundTexturesArray, + ScopedDeletePtr & opaqueTextureScopedPtr, + ScopedDeletePtr & transparentTextureScopedPtr); GLfloat mVertexAttrib0Vector[4]; GLfloat mFakeVertexAttrib0BufferObjectVector[4]; diff --git a/content/canvas/src/WebGLContextGL.cpp b/content/canvas/src/WebGLContextGL.cpp index 064df55fabef..7e3be90129d2 100644 --- a/content/canvas/src/WebGLContextGL.cpp +++ b/content/canvas/src/WebGLContextGL.cpp @@ -52,15 +52,58 @@ using namespace mozilla::gl; static bool BaseTypeAndSizeFromUniformType(GLenum uType, GLenum *baseType, GLint *unitSize); static GLenum InternalFormatForFormatAndType(GLenum format, GLenum type, bool isGLES2); -// -// WebGL API -// - inline const WebGLRectangleObject *WebGLContext::FramebufferRectangleObject() const { return mBoundFramebuffer ? mBoundFramebuffer->RectangleObject() : static_cast(this); } +WebGLContext::FakeBlackTexture::FakeBlackTexture(GLContext *gl, GLenum target, GLenum format) + : mGL(gl) + , mGLName(0) +{ + MOZ_ASSERT(target == LOCAL_GL_TEXTURE_2D || target == LOCAL_GL_TEXTURE_CUBE_MAP); + MOZ_ASSERT(format == LOCAL_GL_RGB || format == LOCAL_GL_RGBA); + + mGL->MakeCurrent(); + GLuint formerBinding = 0; + gl->GetUIntegerv(target == LOCAL_GL_TEXTURE_2D + ? LOCAL_GL_TEXTURE_BINDING_2D + : LOCAL_GL_TEXTURE_BINDING_CUBE_MAP, + &formerBinding); + gl->fGenTextures(1, &mGLName); + gl->fBindTexture(target, mGLName); + + // we allocate our zeros on the heap, and we overallocate (16 bytes instead of 4) + // to minimize the risk of running into a driver bug in texImage2D, as it is + // a bit unusual maybe to create 1x1 textures, and the stack may not have the alignment + // that texImage2D expects. + void* zeros = calloc(1, 16); + if (target == LOCAL_GL_TEXTURE_2D) { + gl->fTexImage2D(target, 0, format, 1, 1, + 0, format, LOCAL_GL_UNSIGNED_BYTE, zeros); + } else { + for (GLuint i = 0; i < 6; ++i) { + gl->fTexImage2D(LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, format, 1, 1, + 0, format, LOCAL_GL_UNSIGNED_BYTE, zeros); + } + } + free(zeros); + + gl->fBindTexture(target, formerBinding); +} + +WebGLContext::FakeBlackTexture::~FakeBlackTexture() +{ + if (mGL) { + mGL->MakeCurrent(); + mGL->fDeleteTextures(1, &mGLName); + } +} + +// +// WebGL API +// + void WebGLContext::ActiveTexture(GLenum texture) { @@ -973,6 +1016,43 @@ WebGLContext::ResolvedFakeBlackStatus() return mFakeBlackStatus; } +void +WebGLContext::BindFakeBlackTexturesHelper( + GLenum target, + const nsTArray > & boundTexturesArray, + ScopedDeletePtr & opaqueTextureScopedPtr, + ScopedDeletePtr & transparentTextureScopedPtr) +{ + for (int32_t i = 0; i < mGLMaxTextureUnits; ++i) { + if (!boundTexturesArray[i]) { + continue; + } + + WebGLTextureFakeBlackStatus s = boundTexturesArray[i]->ResolvedFakeBlackStatus(); + MOZ_ASSERT(s != WebGLTextureFakeBlackStatus::Unknown); + + if (MOZ_LIKELY(s == WebGLTextureFakeBlackStatus::NotNeeded)) { + continue; + } + + bool opaque = s == WebGLTextureFakeBlackStatus::IncompleteTexture; + ScopedDeletePtr& + blackTexturePtr = opaque + ? opaqueTextureScopedPtr + : transparentTextureScopedPtr; + + if (!blackTexturePtr) { + GLenum format = opaque ? LOCAL_GL_RGB : LOCAL_GL_RGBA; + blackTexturePtr + = new FakeBlackTexture(gl, target, format); + } + + gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i); + gl->fBindTexture(target, + blackTexturePtr->GLName()); + } +} + void WebGLContext::BindFakeBlackTextures() { @@ -980,71 +1060,14 @@ WebGLContext::BindFakeBlackTextures() if (MOZ_LIKELY(ResolvedFakeBlackStatus() == WebGLContextFakeBlackStatus::NotNeeded)) return; - if (!mBlackTexturesAreInitialized) { - GLuint bound2DTex = 0; - GLuint boundCubeTex = 0; - gl->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, (GLint*) &bound2DTex); - gl->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_CUBE_MAP, (GLint*) &boundCubeTex); - - const uint8_t black_opaque[] = {0, 0, 0, 255}; - - gl->fGenTextures(1, &mBlackOpaqueTexture2D); - gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mBlackOpaqueTexture2D); - gl->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGBA, 1, 1, - 0, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, black_opaque); - - gl->fGenTextures(1, &mBlackOpaqueTextureCubeMap); - gl->fBindTexture(LOCAL_GL_TEXTURE_CUBE_MAP, mBlackOpaqueTextureCubeMap); - for (GLuint i = 0; i < 6; ++i) { - gl->fTexImage2D(LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, LOCAL_GL_RGBA, 1, 1, - 0, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, black_opaque); - } - - const uint8_t black_transparent[] = {0, 0, 0, 0}; - - gl->fGenTextures(1, &mBlackTransparentTexture2D); - gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mBlackTransparentTexture2D); - gl->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGBA, 1, 1, - 0, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, black_transparent); - - gl->fGenTextures(1, &mBlackTransparentTextureCubeMap); - gl->fBindTexture(LOCAL_GL_TEXTURE_CUBE_MAP, mBlackTransparentTextureCubeMap); - for (GLuint i = 0; i < 6; ++i) { - gl->fTexImage2D(LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, LOCAL_GL_RGBA, 1, 1, - 0, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, black_transparent); - } - // Reset bound textures - gl->fBindTexture(LOCAL_GL_TEXTURE_2D, bound2DTex); - gl->fBindTexture(LOCAL_GL_TEXTURE_CUBE_MAP, boundCubeTex); - - mBlackTexturesAreInitialized = true; - } - - for (int32_t i = 0; i < mGLMaxTextureUnits; ++i) { - WebGLTextureFakeBlackStatus s; - s = mBound2DTextures[i] - ? mBound2DTextures[i]->ResolvedFakeBlackStatus() - : WebGLTextureFakeBlackStatus::NotNeeded; - MOZ_ASSERT(s != WebGLTextureFakeBlackStatus::Unknown); - if (s != WebGLTextureFakeBlackStatus::NotNeeded) { - gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i); - gl->fBindTexture(LOCAL_GL_TEXTURE_2D, - s == WebGLTextureFakeBlackStatus::IncompleteTexture - ? mBlackOpaqueTexture2D - : mBlackTransparentTexture2D); - } - s = mBoundCubeMapTextures[i] - ? mBoundCubeMapTextures[i]->ResolvedFakeBlackStatus() - : WebGLTextureFakeBlackStatus::NotNeeded; - MOZ_ASSERT(s != WebGLTextureFakeBlackStatus::Unknown); - if (s != WebGLTextureFakeBlackStatus::NotNeeded) { - gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i); - gl->fBindTexture(LOCAL_GL_TEXTURE_CUBE_MAP, - s == WebGLTextureFakeBlackStatus::IncompleteTexture - ? mBlackOpaqueTextureCubeMap - : mBlackTransparentTextureCubeMap); - } - } + BindFakeBlackTexturesHelper(LOCAL_GL_TEXTURE_2D, + mBound2DTextures, + mBlackOpaqueTexture2D, + mBlackTransparentTexture2D); + BindFakeBlackTexturesHelper(LOCAL_GL_TEXTURE_CUBE_MAP, + mBoundCubeMapTextures, + mBlackOpaqueTextureCubeMap, + mBlackTransparentTextureCubeMap); } void