From a5e8e36119b7f9cf9e236f4306b3b5cd64de2467 Mon Sep 17 00:00:00 2001 From: Saurabh Anand Date: Sun, 9 Dec 2012 02:11:02 +0530 Subject: [PATCH] Bug 817785 - Split out WebGLProgram into separate files --- content/canvas/src/WebGLContext.h | 322 +------------------- content/canvas/src/WebGLContextValidate.cpp | 9 +- content/canvas/src/WebGLProgram.cpp | 242 +++++++++++++++ content/canvas/src/WebGLProgram.h | 127 ++++++++ 4 files changed, 377 insertions(+), 323 deletions(-) create mode 100644 content/canvas/src/WebGLProgram.h diff --git a/content/canvas/src/WebGLContext.h b/content/canvas/src/WebGLContext.h index b9c0f6efd94e..2918913edea1 100644 --- a/content/canvas/src/WebGLContext.h +++ b/content/canvas/src/WebGLContext.h @@ -10,12 +10,12 @@ #include "WebGLObjectModel.h" #include "WebGLShader.h" #include "WebGLBuffer.h" +#include "WebGLProgram.h" #include "WebGLRenderbuffer.h" #include "WebGLTexture.h" #include "WebGLVertexAttribData.h" #include "WebGLShaderPrecisionFormat.h" #include -#include #include "nsTArray.h" #include "nsDataHashtable.h" @@ -70,7 +70,6 @@ class nsIPropertyBag; namespace mozilla { -class WebGLProgram; class WebGLFramebuffer; class WebGLUniformLocation; class WebGLMemoryPressureObserver; @@ -1160,325 +1159,6 @@ ToSupports(WebGLContext* context) return static_cast(context); } -/** Takes an ASCII string like "foo[i]", turns it into "foo" and returns "[i]" in bracketPart - * - * \param string input/output: the string to split, becomes the string without the bracket part - * \param bracketPart output: gets the bracket part. - * - * Notice that if there are multiple brackets like "foo[i].bar[j]", only the last bracket is split. - */ -static bool SplitLastSquareBracket(nsACString& string, nsCString& bracketPart) -{ - MOZ_ASSERT(bracketPart.IsEmpty(), "SplitLastSquareBracket must be called with empty bracketPart string"); - - if (string.IsEmpty()) - return false; - - char *string_start = string.BeginWriting(); - char *s = string_start + string.Length() - 1; - - if (*s != ']') - return false; - - while (*s != '[' && s != string_start) - s--; - - if (*s != '[') - return false; - - bracketPart.Assign(s); - *s = 0; - string.EndWriting(); - string.SetLength(s - string_start); - return true; -} - -typedef nsDataHashtable CStringMap; -typedef nsDataHashtable CStringToUniformInfoMap; - -class WebGLProgram MOZ_FINAL - : public nsISupports - , public WebGLRefCountedObject - , public LinkedListElement - , public WebGLContextBoundObject - , public nsWrapperCache -{ -public: - WebGLProgram(WebGLContext *context) - : WebGLContextBoundObject(context) - , mLinkStatus(false) - , mGeneration(0) - , mAttribMaxNameLength(0) - { - SetIsDOMBinding(); - mContext->MakeContextCurrent(); - mGLName = mContext->gl->fCreateProgram(); - mContext->mPrograms.insertBack(this); - } - - ~WebGLProgram() { - DeleteOnce(); - } - - void Delete() { - DetachShaders(); - mContext->MakeContextCurrent(); - mContext->gl->fDeleteProgram(mGLName); - LinkedListElement::removeFrom(mContext->mPrograms); - } - - void DetachShaders() { - mAttachedShaders.Clear(); - } - - WebGLuint GLName() { return mGLName; } - const nsTArray >& AttachedShaders() const { return mAttachedShaders; } - bool LinkStatus() { return mLinkStatus; } - uint32_t Generation() const { return mGeneration.value(); } - void SetLinkStatus(bool val) { mLinkStatus = val; } - - bool ContainsShader(WebGLShader *shader) { - return mAttachedShaders.Contains(shader); - } - - // return true if the shader wasn't already attached - bool AttachShader(WebGLShader *shader) { - if (ContainsShader(shader)) - return false; - mAttachedShaders.AppendElement(shader); - - mContext->MakeContextCurrent(); - mContext->gl->fAttachShader(GLName(), shader->GLName()); - - return true; - } - - // return true if the shader was found and removed - bool DetachShader(WebGLShader *shader) { - if (!mAttachedShaders.RemoveElement(shader)) - return false; - - mContext->MakeContextCurrent(); - mContext->gl->fDetachShader(GLName(), shader->GLName()); - - return true; - } - - bool HasAttachedShaderOfType(GLenum shaderType) { - for (uint32_t i = 0; i < mAttachedShaders.Length(); ++i) { - if (mAttachedShaders[i] && mAttachedShaders[i]->ShaderType() == shaderType) { - return true; - } - } - return false; - } - - bool HasBothShaderTypesAttached() { - return - HasAttachedShaderOfType(LOCAL_GL_VERTEX_SHADER) && - HasAttachedShaderOfType(LOCAL_GL_FRAGMENT_SHADER); - } - - bool HasBadShaderAttached() { - for (uint32_t i = 0; i < mAttachedShaders.Length(); ++i) { - if (mAttachedShaders[i] && !mAttachedShaders[i]->CompileStatus()) { - return true; - } - } - return false; - } - - size_t UpperBoundNumSamplerUniforms() { - size_t numSamplerUniforms = 0; - for (size_t i = 0; i < mAttachedShaders.Length(); ++i) { - const WebGLShader *shader = mAttachedShaders[i]; - if (!shader) - continue; - for (size_t j = 0; j < shader->mUniformInfos.Length(); ++j) { - WebGLUniformInfo u = shader->mUniformInfos[j]; - if (u.type == SH_SAMPLER_2D || - u.type == SH_SAMPLER_CUBE) - { - numSamplerUniforms += u.arraySize; - } - } - } - return numSamplerUniforms; - } - - bool NextGeneration() - { - if (!(mGeneration + 1).isValid()) - return false; // must exit without changing mGeneration - ++mGeneration; - return true; - } - - /* Called only after LinkProgram */ - bool UpdateInfo(); - - /* Getters for cached program info */ - bool IsAttribInUse(unsigned i) const { return mAttribsInUse[i]; } - - /* Maps identifier |name| to the mapped identifier |*mappedName| - * Both are ASCII strings. - */ - void MapIdentifier(const nsACString& name, nsCString *mappedName) { - if (!mIdentifierMap) { - // if the identifier map doesn't exist yet, build it now - mIdentifierMap = new CStringMap; - mIdentifierMap->Init(); - for (size_t i = 0; i < mAttachedShaders.Length(); i++) { - for (size_t j = 0; j < mAttachedShaders[i]->mAttributes.Length(); j++) { - const WebGLMappedIdentifier& attrib = mAttachedShaders[i]->mAttributes[j]; - mIdentifierMap->Put(attrib.original, attrib.mapped); - } - for (size_t j = 0; j < mAttachedShaders[i]->mUniforms.Length(); j++) { - const WebGLMappedIdentifier& uniform = mAttachedShaders[i]->mUniforms[j]; - mIdentifierMap->Put(uniform.original, uniform.mapped); - } - } - } - - nsCString mutableName(name); - nsCString bracketPart; - bool hadBracketPart = SplitLastSquareBracket(mutableName, bracketPart); - if (hadBracketPart) - mutableName.AppendLiteral("[0]"); - - if (mIdentifierMap->Get(mutableName, mappedName)) { - if (hadBracketPart) { - nsCString mappedBracketPart; - bool mappedHadBracketPart = SplitLastSquareBracket(*mappedName, mappedBracketPart); - if (mappedHadBracketPart) - mappedName->Append(bracketPart); - } - return; - } - - // not found? We might be in the situation we have a uniform array name and the GL's glGetActiveUniform - // returned its name without [0], as is allowed by desktop GL but not in ES. Let's then try with [0]. - mutableName.AppendLiteral("[0]"); - if (mIdentifierMap->Get(mutableName, mappedName)) - return; - - // not found? return name unchanged. This case happens e.g. on bad user input, or when - // we're not using identifier mapping, or if we didn't store an identifier in the map because - // e.g. its mapping is trivial (as happens for short identifiers) - mappedName->Assign(name); - } - - /* Un-maps mapped identifier |name| to the original identifier |*reverseMappedName| - * Both are ASCII strings. - */ - void ReverseMapIdentifier(const nsACString& name, nsCString *reverseMappedName) { - if (!mIdentifierReverseMap) { - // if the identifier reverse map doesn't exist yet, build it now - mIdentifierReverseMap = new CStringMap; - mIdentifierReverseMap->Init(); - for (size_t i = 0; i < mAttachedShaders.Length(); i++) { - for (size_t j = 0; j < mAttachedShaders[i]->mAttributes.Length(); j++) { - const WebGLMappedIdentifier& attrib = mAttachedShaders[i]->mAttributes[j]; - mIdentifierReverseMap->Put(attrib.mapped, attrib.original); - } - for (size_t j = 0; j < mAttachedShaders[i]->mUniforms.Length(); j++) { - const WebGLMappedIdentifier& uniform = mAttachedShaders[i]->mUniforms[j]; - mIdentifierReverseMap->Put(uniform.mapped, uniform.original); - } - } - } - - nsCString mutableName(name); - nsCString bracketPart; - bool hadBracketPart = SplitLastSquareBracket(mutableName, bracketPart); - if (hadBracketPart) - mutableName.AppendLiteral("[0]"); - - if (mIdentifierReverseMap->Get(mutableName, reverseMappedName)) { - if (hadBracketPart) { - nsCString reverseMappedBracketPart; - bool reverseMappedHadBracketPart = SplitLastSquareBracket(*reverseMappedName, reverseMappedBracketPart); - if (reverseMappedHadBracketPart) - reverseMappedName->Append(bracketPart); - } - return; - } - - // not found? We might be in the situation we have a uniform array name and the GL's glGetActiveUniform - // returned its name without [0], as is allowed by desktop GL but not in ES. Let's then try with [0]. - mutableName.AppendLiteral("[0]"); - if (mIdentifierReverseMap->Get(mutableName, reverseMappedName)) - return; - - // not found? return name unchanged. This case happens e.g. on bad user input, or when - // we're not using identifier mapping, or if we didn't store an identifier in the map because - // e.g. its mapping is trivial (as happens for short identifiers) - reverseMappedName->Assign(name); - } - - /* Returns the uniform array size (or 1 if the uniform is not an array) of - * the uniform with given mapped identifier. - * - * Note: the input string |name| is the mapped identifier, not the original identifier. - */ - WebGLUniformInfo GetUniformInfoForMappedIdentifier(const nsACString& name) { - if (!mUniformInfoMap) { - // if the identifier-to-array-size map doesn't exist yet, build it now - mUniformInfoMap = new CStringToUniformInfoMap; - mUniformInfoMap->Init(); - for (size_t i = 0; i < mAttachedShaders.Length(); i++) { - for (size_t j = 0; j < mAttachedShaders[i]->mUniforms.Length(); j++) { - const WebGLMappedIdentifier& uniform = mAttachedShaders[i]->mUniforms[j]; - const WebGLUniformInfo& info = mAttachedShaders[i]->mUniformInfos[j]; - mUniformInfoMap->Put(uniform.mapped, info); - } - } - } - - nsCString mutableName(name); - nsCString bracketPart; - bool hadBracketPart = SplitLastSquareBracket(mutableName, bracketPart); - // if there is a bracket, we're either an array or an entry in an array. - if (hadBracketPart) - mutableName.AppendLiteral("[0]"); - - WebGLUniformInfo info; - mUniformInfoMap->Get(mutableName, &info); - // we don't check if that Get failed, as if it did, it left info with default values - - // if there is a bracket and it's not [0], then we're not an array, we're just an entry in an array - if (hadBracketPart && !bracketPart.EqualsLiteral("[0]")) { - info.isArray = false; - info.arraySize = 1; - } - return info; - } - - WebGLContext *GetParentObject() const { - return Context(); - } - - virtual JSObject* WrapObject(JSContext *cx, JSObject *scope, bool *triedToWrap); - - NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(WebGLProgram) - -protected: - - WebGLuint mGLName; - bool mLinkStatus; - // attached shaders of the program object - nsTArray > mAttachedShaders; - CheckedUint32 mGeneration; - - // post-link data - std::vector mAttribsInUse; - nsAutoPtr mIdentifierMap, mIdentifierReverseMap; - nsAutoPtr mUniformInfoMap; - int mAttribMaxNameLength; -}; - - class WebGLFramebufferAttachment { // deleting a texture or renderbuffer immediately detaches it diff --git a/content/canvas/src/WebGLContextValidate.cpp b/content/canvas/src/WebGLContextValidate.cpp index f23dc6a9b119..a03f46eab0f2 100644 --- a/content/canvas/src/WebGLContextValidate.cpp +++ b/content/canvas/src/WebGLContextValidate.cpp @@ -38,8 +38,13 @@ WebGLProgram::UpdateInfo() GLint attribCount; mContext->gl->fGetProgramiv(mGLName, LOCAL_GL_ACTIVE_ATTRIBUTES, &attribCount); - mAttribsInUse.resize(mContext->mGLMaxVertexAttribs); - std::fill(mAttribsInUse.begin(), mAttribsInUse.end(), false); + if (!mAttribsInUse.SetLength(mContext->mGLMaxVertexAttribs)) { + mContext->ErrorOutOfMemory("updateInfo: out of memory to allocate %d attribs", mContext->mGLMaxVertexAttribs); + return false; + } + + for (size_t i = 0; i < mAttribsInUse.Length(); i++) + mAttribsInUse[i] = false; nsAutoArrayPtr nameBuf(new char[mAttribMaxNameLength]); diff --git a/content/canvas/src/WebGLProgram.cpp b/content/canvas/src/WebGLProgram.cpp index 77de0907419b..ce27487d7f57 100644 --- a/content/canvas/src/WebGLProgram.cpp +++ b/content/canvas/src/WebGLProgram.cpp @@ -4,15 +4,257 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "WebGLContext.h" +#include "WebGLProgram.h" #include "mozilla/dom/WebGLRenderingContextBinding.h" using namespace mozilla; +/** Takes an ASCII string like "foo[i]", turns it into "foo" and returns "[i]" in bracketPart + * + * \param string input/output: the string to split, becomes the string without the bracket part + * \param bracketPart output: gets the bracket part. + * + * Notice that if there are multiple brackets like "foo[i].bar[j]", only the last bracket is split. + */ +static bool SplitLastSquareBracket(nsACString& string, nsCString& bracketPart) +{ + MOZ_ASSERT(bracketPart.IsEmpty(), "SplitLastSquareBracket must be called with empty bracketPart string"); + + if (string.IsEmpty()) + return false; + + char *string_start = string.BeginWriting(); + char *s = string_start + string.Length() - 1; + + if (*s != ']') + return false; + + while (*s != '[' && s != string_start) + s--; + + if (*s != '[') + return false; + + bracketPart.Assign(s); + *s = 0; + string.EndWriting(); + string.SetLength(s - string_start); + return true; +} + JSObject* WebGLProgram::WrapObject(JSContext *cx, JSObject *scope, bool *triedToWrap) { return dom::WebGLProgramBinding::Wrap(cx, scope, this, triedToWrap); } +WebGLProgram::WebGLProgram(WebGLContext *context) + : WebGLContextBoundObject(context) + , mLinkStatus(false) + , mGeneration(0) + , mAttribMaxNameLength(0) +{ + SetIsDOMBinding(); + mContext->MakeContextCurrent(); + mGLName = mContext->gl->fCreateProgram(); + mContext->mPrograms.insertBack(this); +} + +void +WebGLProgram::Delete() { + DetachShaders(); + mContext->MakeContextCurrent(); + mContext->gl->fDeleteProgram(mGLName); + LinkedListElement::removeFrom(mContext->mPrograms); +} + +bool +WebGLProgram::AttachShader(WebGLShader *shader) { + if (ContainsShader(shader)) + return false; + mAttachedShaders.AppendElement(shader); + + mContext->MakeContextCurrent(); + mContext->gl->fAttachShader(GLName(), shader->GLName()); + + return true; +} + +bool +WebGLProgram::DetachShader(WebGLShader *shader) { + if (!mAttachedShaders.RemoveElement(shader)) + return false; + + mContext->MakeContextCurrent(); + mContext->gl->fDetachShader(GLName(), shader->GLName()); + + return true; +} + +bool +WebGLProgram::HasAttachedShaderOfType(GLenum shaderType) { + for (uint32_t i = 0; i < mAttachedShaders.Length(); ++i) { + if (mAttachedShaders[i] && mAttachedShaders[i]->ShaderType() == shaderType) { + return true; + } + } + return false; +} + +bool +WebGLProgram::HasBadShaderAttached() { + for (uint32_t i = 0; i < mAttachedShaders.Length(); ++i) { + if (mAttachedShaders[i] && !mAttachedShaders[i]->CompileStatus()) { + return true; + } + } + return false; +} + +size_t +WebGLProgram::UpperBoundNumSamplerUniforms() { + size_t numSamplerUniforms = 0; + for (size_t i = 0; i < mAttachedShaders.Length(); ++i) { + const WebGLShader *shader = mAttachedShaders[i]; + if (!shader) + continue; + for (size_t j = 0; j < shader->mUniformInfos.Length(); ++j) { + WebGLUniformInfo u = shader->mUniformInfos[j]; + if (u.type == SH_SAMPLER_2D || + u.type == SH_SAMPLER_CUBE) + { + numSamplerUniforms += u.arraySize; + } + } + } + return numSamplerUniforms; +} + +void +WebGLProgram::MapIdentifier(const nsACString& name, nsCString *mappedName) { + if (!mIdentifierMap) { + // if the identifier map doesn't exist yet, build it now + mIdentifierMap = new CStringMap; + mIdentifierMap->Init(); + for (size_t i = 0; i < mAttachedShaders.Length(); i++) { + for (size_t j = 0; j < mAttachedShaders[i]->mAttributes.Length(); j++) { + const WebGLMappedIdentifier& attrib = mAttachedShaders[i]->mAttributes[j]; + mIdentifierMap->Put(attrib.original, attrib.mapped); + } + for (size_t j = 0; j < mAttachedShaders[i]->mUniforms.Length(); j++) { + const WebGLMappedIdentifier& uniform = mAttachedShaders[i]->mUniforms[j]; + mIdentifierMap->Put(uniform.original, uniform.mapped); + } + } + } + + nsCString mutableName(name); + nsCString bracketPart; + bool hadBracketPart = SplitLastSquareBracket(mutableName, bracketPart); + if (hadBracketPart) + mutableName.AppendLiteral("[0]"); + + if (mIdentifierMap->Get(mutableName, mappedName)) { + if (hadBracketPart) { + nsCString mappedBracketPart; + bool mappedHadBracketPart = SplitLastSquareBracket(*mappedName, mappedBracketPart); + if (mappedHadBracketPart) + mappedName->Append(bracketPart); + } + return; + } + + // not found? We might be in the situation we have a uniform array name and the GL's glGetActiveUniform + // returned its name without [0], as is allowed by desktop GL but not in ES. Let's then try with [0]. + mutableName.AppendLiteral("[0]"); + if (mIdentifierMap->Get(mutableName, mappedName)) + return; + + // not found? return name unchanged. This case happens e.g. on bad user input, or when + // we're not using identifier mapping, or if we didn't store an identifier in the map because + // e.g. its mapping is trivial (as happens for short identifiers) + mappedName->Assign(name); +} + +void +WebGLProgram::ReverseMapIdentifier(const nsACString& name, nsCString *reverseMappedName) { + if (!mIdentifierReverseMap) { + // if the identifier reverse map doesn't exist yet, build it now + mIdentifierReverseMap = new CStringMap; + mIdentifierReverseMap->Init(); + for (size_t i = 0; i < mAttachedShaders.Length(); i++) { + for (size_t j = 0; j < mAttachedShaders[i]->mAttributes.Length(); j++) { + const WebGLMappedIdentifier& attrib = mAttachedShaders[i]->mAttributes[j]; + mIdentifierReverseMap->Put(attrib.mapped, attrib.original); + } + for (size_t j = 0; j < mAttachedShaders[i]->mUniforms.Length(); j++) { + const WebGLMappedIdentifier& uniform = mAttachedShaders[i]->mUniforms[j]; + mIdentifierReverseMap->Put(uniform.mapped, uniform.original); + } + } + } + + nsCString mutableName(name); + nsCString bracketPart; + bool hadBracketPart = SplitLastSquareBracket(mutableName, bracketPart); + if (hadBracketPart) + mutableName.AppendLiteral("[0]"); + + if (mIdentifierReverseMap->Get(mutableName, reverseMappedName)) { + if (hadBracketPart) { + nsCString reverseMappedBracketPart; + bool reverseMappedHadBracketPart = SplitLastSquareBracket(*reverseMappedName, reverseMappedBracketPart); + if (reverseMappedHadBracketPart) + reverseMappedName->Append(bracketPart); + } + return; + } + + // not found? We might be in the situation we have a uniform array name and the GL's glGetActiveUniform + // returned its name without [0], as is allowed by desktop GL but not in ES. Let's then try with [0]. + mutableName.AppendLiteral("[0]"); + if (mIdentifierReverseMap->Get(mutableName, reverseMappedName)) + return; + + // not found? return name unchanged. This case happens e.g. on bad user input, or when + // we're not using identifier mapping, or if we didn't store an identifier in the map because + // e.g. its mapping is trivial (as happens for short identifiers) + reverseMappedName->Assign(name); +} + +WebGLUniformInfo +WebGLProgram::GetUniformInfoForMappedIdentifier(const nsACString& name) { + if (!mUniformInfoMap) { + // if the identifier-to-array-size map doesn't exist yet, build it now + mUniformInfoMap = new CStringToUniformInfoMap; + mUniformInfoMap->Init(); + for (size_t i = 0; i < mAttachedShaders.Length(); i++) { + for (size_t j = 0; j < mAttachedShaders[i]->mUniforms.Length(); j++) { + const WebGLMappedIdentifier& uniform = mAttachedShaders[i]->mUniforms[j]; + const WebGLUniformInfo& info = mAttachedShaders[i]->mUniformInfos[j]; + mUniformInfoMap->Put(uniform.mapped, info); + } + } + } + + nsCString mutableName(name); + nsCString bracketPart; + bool hadBracketPart = SplitLastSquareBracket(mutableName, bracketPart); + // if there is a bracket, we're either an array or an entry in an array. + if (hadBracketPart) + mutableName.AppendLiteral("[0]"); + + WebGLUniformInfo info; + mUniformInfoMap->Get(mutableName, &info); + // we don't check if that Get failed, as if it did, it left info with default values + + // if there is a bracket and it's not [0], then we're not an array, we're just an entry in an array + if (hadBracketPart && !bracketPart.EqualsLiteral("[0]")) { + info.isArray = false; + info.arraySize = 1; + } + return info; +} + NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(WebGLProgram, mAttachedShaders) NS_IMPL_CYCLE_COLLECTING_ADDREF(WebGLProgram) diff --git a/content/canvas/src/WebGLProgram.h b/content/canvas/src/WebGLProgram.h new file mode 100644 index 000000000000..88b00176c191 --- /dev/null +++ b/content/canvas/src/WebGLProgram.h @@ -0,0 +1,127 @@ +/* -*- 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 WEBGLPROGRAM_H_ +#define WEBGLPROGRAM_H_ + +#include "WebGLObjectModel.h" +#include "WebGLShader.h" + +#include "nsWrapperCache.h" + +#include "mozilla/LinkedList.h" +#include "mozilla/CheckedInt.h" + +namespace mozilla { + +typedef nsDataHashtable CStringMap; +typedef nsDataHashtable CStringToUniformInfoMap; + +class WebGLProgram MOZ_FINAL + : public nsISupports + , public WebGLRefCountedObject + , public LinkedListElement + , public WebGLContextBoundObject + , public nsWrapperCache +{ +public: + WebGLProgram(WebGLContext *context); + + ~WebGLProgram() { + DeleteOnce(); + } + + void Delete(); + + void DetachShaders() { + mAttachedShaders.Clear(); + } + + WebGLuint GLName() { return mGLName; } + const nsTArray >& AttachedShaders() const { return mAttachedShaders; } + bool LinkStatus() { return mLinkStatus; } + uint32_t Generation() const { return mGeneration.value(); } + void SetLinkStatus(bool val) { mLinkStatus = val; } + + bool ContainsShader(WebGLShader *shader) { + return mAttachedShaders.Contains(shader); + } + + // return true if the shader wasn't already attached + bool AttachShader(WebGLShader *shader); + + // return true if the shader was found and removed + bool DetachShader(WebGLShader *shader); + + bool HasAttachedShaderOfType(GLenum shaderType); + + bool HasBothShaderTypesAttached() { + return + HasAttachedShaderOfType(LOCAL_GL_VERTEX_SHADER) && + HasAttachedShaderOfType(LOCAL_GL_FRAGMENT_SHADER); + } + + bool HasBadShaderAttached(); + + size_t UpperBoundNumSamplerUniforms(); + + bool NextGeneration() + { + if (!(mGeneration + 1).isValid()) + return false; // must exit without changing mGeneration + ++mGeneration; + return true; + } + + /* Called only after LinkProgram */ + bool UpdateInfo(); + + /* Getters for cached program info */ + bool IsAttribInUse(unsigned i) const { return mAttribsInUse[i]; } + + /* Maps identifier |name| to the mapped identifier |*mappedName| + * Both are ASCII strings. + */ + void MapIdentifier(const nsACString& name, nsCString *mappedName); + + /* Un-maps mapped identifier |name| to the original identifier |*reverseMappedName| + * Both are ASCII strings. + */ + void ReverseMapIdentifier(const nsACString& name, nsCString *reverseMappedName); + + /* Returns the uniform array size (or 1 if the uniform is not an array) of + * the uniform with given mapped identifier. + * + * Note: the input string |name| is the mapped identifier, not the original identifier. + */ + WebGLUniformInfo GetUniformInfoForMappedIdentifier(const nsACString& name); + + WebGLContext *GetParentObject() const { + return Context(); + } + + virtual JSObject* WrapObject(JSContext *cx, JSObject *scope, bool *triedToWrap); + + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(WebGLProgram) + +protected: + + WebGLuint mGLName; + bool mLinkStatus; + // attached shaders of the program object + nsTArray > mAttachedShaders; + CheckedUint32 mGeneration; + + // post-link data + nsTArray mAttribsInUse; + nsAutoPtr mIdentifierMap, mIdentifierReverseMap; + nsAutoPtr mUniformInfoMap; + int mAttribMaxNameLength; +}; + +} // namespace mozilla + +#endif