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");
30 char *string_start
= string
.BeginWriting();
31 char *s
= string_start
+ string
.Length() - 1;
36 while (*s
!= '[' && s
!= string_start
)
42 bracketPart
.Assign(s
);
45 string
.SetLength(s
- string_start
);
50 WebGLProgram::WrapObject(JSContext
*cx
) {
51 return dom::WebGLProgramBinding::Wrap(cx
, this);
54 WebGLProgram::WebGLProgram(WebGLContext
*context
)
55 : WebGLContextBoundObject(context
)
58 , mIdentifierMap(new CStringMap
)
59 , mIdentifierReverseMap(new CStringMap
)
60 , mUniformInfoMap(new CStringToUniformInfoMap
)
61 , mAttribMaxNameLength(0)
64 mContext
->MakeContextCurrent();
65 mGLName
= mContext
->gl
->fCreateProgram();
66 mContext
->mPrograms
.insertBack(this);
70 WebGLProgram::Delete() {
72 mContext
->MakeContextCurrent();
73 mContext
->gl
->fDeleteProgram(mGLName
);
74 LinkedListElement
<WebGLProgram
>::removeFrom(mContext
->mPrograms
);
78 WebGLProgram::AttachShader(WebGLShader
*shader
) {
79 if (ContainsShader(shader
))
81 mAttachedShaders
.AppendElement(shader
);
83 mContext
->MakeContextCurrent();
84 mContext
->gl
->fAttachShader(GLName(), shader
->GLName());
90 WebGLProgram::DetachShader(WebGLShader
*shader
) {
91 if (!mAttachedShaders
.RemoveElement(shader
))
94 mContext
->MakeContextCurrent();
95 mContext
->gl
->fDetachShader(GLName(), shader
->GLName());
101 WebGLProgram::HasAttachedShaderOfType(GLenum shaderType
) {
102 for (uint32_t i
= 0; i
< mAttachedShaders
.Length(); ++i
) {
103 if (mAttachedShaders
[i
] && mAttachedShaders
[i
]->ShaderType() == shaderType
) {
111 WebGLProgram::HasBadShaderAttached() {
112 for (uint32_t i
= 0; i
< mAttachedShaders
.Length(); ++i
) {
113 if (mAttachedShaders
[i
] && !mAttachedShaders
[i
]->CompileStatus()) {
121 WebGLProgram::UpperBoundNumSamplerUniforms() {
122 size_t numSamplerUniforms
= 0;
123 for (size_t i
= 0; i
< mAttachedShaders
.Length(); ++i
) {
124 const WebGLShader
*shader
= mAttachedShaders
[i
];
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
;
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
);
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
);
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
))
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
);
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
);
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
);
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
))
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
);
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.
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
221 /* static */ uint64_t
222 WebGLProgram::IdentifierHashFunction(const char *ident
, size_t size
)
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]);
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
)