Bumping gaia.json for 2 gaia revision(s) a=gaia-bump
[gecko.git] / dom / canvas / WebGLProgram.cpp
bloba945f4f9324094ed5da9588742e276fd38fb1ea7
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "WebGLContext.h"
7 #include "WebGLShader.h"
8 #include "WebGLProgram.h"
9 #include "mozilla/dom/WebGLRenderingContextBinding.h"
10 #include "GLContext.h"
12 #include "MurmurHash3.h"
14 using namespace mozilla;
16 /** Takes an ASCII string like "foo[i]", turns it into "foo" and returns "[i]" in bracketPart
18 * \param string input/output: the string to split, becomes the string without the bracket part
19 * \param bracketPart output: gets the bracket part.
21 * Notice that if there are multiple brackets like "foo[i].bar[j]", only the last bracket is split.
23 static bool SplitLastSquareBracket(nsACString& string, nsCString& bracketPart)
25 MOZ_ASSERT(bracketPart.IsEmpty(), "SplitLastSquareBracket must be called with empty bracketPart string");
27 if (string.IsEmpty())
28 return false;
30 char *string_start = string.BeginWriting();
31 char *s = string_start + string.Length() - 1;
33 if (*s != ']')
34 return false;
36 while (*s != '[' && s != string_start)
37 s--;
39 if (*s != '[')
40 return false;
42 bracketPart.Assign(s);
43 *s = 0;
44 string.EndWriting();
45 string.SetLength(s - string_start);
46 return true;
49 JSObject*
50 WebGLProgram::WrapObject(JSContext *cx) {
51 return dom::WebGLProgramBinding::Wrap(cx, this);
54 WebGLProgram::WebGLProgram(WebGLContext *context)
55 : WebGLContextBoundObject(context)
56 , mLinkStatus(false)
57 , mGeneration(0)
58 , mIdentifierMap(new CStringMap)
59 , mIdentifierReverseMap(new CStringMap)
60 , mUniformInfoMap(new CStringToUniformInfoMap)
61 , mAttribMaxNameLength(0)
63 SetIsDOMBinding();
64 mContext->MakeContextCurrent();
65 mGLName = mContext->gl->fCreateProgram();
66 mContext->mPrograms.insertBack(this);
69 void
70 WebGLProgram::Delete() {
71 DetachShaders();
72 mContext->MakeContextCurrent();
73 mContext->gl->fDeleteProgram(mGLName);
74 LinkedListElement<WebGLProgram>::removeFrom(mContext->mPrograms);
77 bool
78 WebGLProgram::AttachShader(WebGLShader *shader) {
79 if (ContainsShader(shader))
80 return false;
81 mAttachedShaders.AppendElement(shader);
83 mContext->MakeContextCurrent();
84 mContext->gl->fAttachShader(GLName(), shader->GLName());
86 return true;
89 bool
90 WebGLProgram::DetachShader(WebGLShader *shader) {
91 if (!mAttachedShaders.RemoveElement(shader))
92 return false;
94 mContext->MakeContextCurrent();
95 mContext->gl->fDetachShader(GLName(), shader->GLName());
97 return true;
100 bool
101 WebGLProgram::HasAttachedShaderOfType(GLenum shaderType) {
102 for (uint32_t i = 0; i < mAttachedShaders.Length(); ++i) {
103 if (mAttachedShaders[i] && mAttachedShaders[i]->ShaderType() == shaderType) {
104 return true;
107 return false;
110 bool
111 WebGLProgram::HasBadShaderAttached() {
112 for (uint32_t i = 0; i < mAttachedShaders.Length(); ++i) {
113 if (mAttachedShaders[i] && !mAttachedShaders[i]->CompileStatus()) {
114 return true;
117 return false;
120 size_t
121 WebGLProgram::UpperBoundNumSamplerUniforms() {
122 size_t numSamplerUniforms = 0;
123 for (size_t i = 0; i < mAttachedShaders.Length(); ++i) {
124 const WebGLShader *shader = mAttachedShaders[i];
125 if (!shader)
126 continue;
127 for (size_t j = 0; j < shader->mUniformInfos.Length(); ++j) {
128 WebGLUniformInfo u = shader->mUniformInfos[j];
129 if (u.type == SH_SAMPLER_2D ||
130 u.type == SH_SAMPLER_CUBE)
132 numSamplerUniforms += u.arraySize;
136 return numSamplerUniforms;
139 void
140 WebGLProgram::MapIdentifier(const nsACString& name, nsCString *mappedName) {
141 MOZ_ASSERT(mIdentifierMap);
143 nsCString mutableName(name);
144 nsCString bracketPart;
145 bool hadBracketPart = SplitLastSquareBracket(mutableName, bracketPart);
146 if (hadBracketPart)
147 mutableName.AppendLiteral("[0]");
149 if (mIdentifierMap->Get(mutableName, mappedName)) {
150 if (hadBracketPart) {
151 nsCString mappedBracketPart;
152 bool mappedHadBracketPart = SplitLastSquareBracket(*mappedName, mappedBracketPart);
153 if (mappedHadBracketPart)
154 mappedName->Append(bracketPart);
156 return;
159 // not found? We might be in the situation we have a uniform array name and the GL's glGetActiveUniform
160 // returned its name without [0], as is allowed by desktop GL but not in ES. Let's then try with [0].
161 mutableName.AppendLiteral("[0]");
162 if (mIdentifierMap->Get(mutableName, mappedName))
163 return;
165 // not found? return name unchanged. This case happens e.g. on bad user input, or when
166 // we're not using identifier mapping, or if we didn't store an identifier in the map because
167 // e.g. its mapping is trivial (as happens for short identifiers)
168 mappedName->Assign(name);
171 void
172 WebGLProgram::ReverseMapIdentifier(const nsACString& name, nsCString *reverseMappedName) {
173 MOZ_ASSERT(mIdentifierReverseMap);
175 nsCString mutableName(name);
176 nsCString bracketPart;
177 bool hadBracketPart = SplitLastSquareBracket(mutableName, bracketPart);
178 if (hadBracketPart)
179 mutableName.AppendLiteral("[0]");
181 if (mIdentifierReverseMap->Get(mutableName, reverseMappedName)) {
182 if (hadBracketPart) {
183 nsCString reverseMappedBracketPart;
184 bool reverseMappedHadBracketPart = SplitLastSquareBracket(*reverseMappedName, reverseMappedBracketPart);
185 if (reverseMappedHadBracketPart)
186 reverseMappedName->Append(bracketPart);
188 return;
191 // not found? We might be in the situation we have a uniform array name and the GL's glGetActiveUniform
192 // returned its name without [0], as is allowed by desktop GL but not in ES. Let's then try with [0].
193 mutableName.AppendLiteral("[0]");
194 if (mIdentifierReverseMap->Get(mutableName, reverseMappedName))
195 return;
197 // not found? return name unchanged. This case happens e.g. on bad user input, or when
198 // we're not using identifier mapping, or if we didn't store an identifier in the map because
199 // e.g. its mapping is trivial (as happens for short identifiers)
200 reverseMappedName->Assign(name);
203 WebGLUniformInfo
204 WebGLProgram::GetUniformInfoForMappedIdentifier(const nsACString& name) {
205 MOZ_ASSERT(mUniformInfoMap);
207 nsCString mutableName(name);
208 nsCString bracketPart;
209 bool hadBracketPart = SplitLastSquareBracket(mutableName, bracketPart);
210 // if there is a bracket, we're either an array or an entry in an array.
211 if (hadBracketPart)
212 mutableName.AppendLiteral("[0]");
214 WebGLUniformInfo info;
215 mUniformInfoMap->Get(mutableName, &info);
216 // we don't check if that Get failed, as if it did, it left info with default values
218 return info;
221 /* static */ uint64_t
222 WebGLProgram::IdentifierHashFunction(const char *ident, size_t size)
224 uint64_t outhash[2];
225 // NB: we use the x86 function everywhere, even though it's suboptimal perf
226 // on x64. They return different results; not sure if that's a requirement.
227 MurmurHash3_x86_128(ident, size, 0, &outhash[0]);
228 return outhash[0];
231 /* static */ void
232 WebGLProgram::HashMapIdentifier(const nsACString& name, nsCString *hashedName)
234 uint64_t hash = IdentifierHashFunction(name.BeginReading(), name.Length());
235 hashedName->Truncate();
236 // This MUST MATCH angle/src/compiler/translator/HashNames.h HASHED_NAME_PREFIX
237 hashedName->AppendPrintf("webgl_%llx", hash);
240 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLProgram, mAttachedShaders)
242 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLProgram, AddRef)
243 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLProgram, Release)