1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/canvas/src/WebGLProgram.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,243 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "WebGLContext.h" 1.10 +#include "WebGLShader.h" 1.11 +#include "WebGLProgram.h" 1.12 +#include "mozilla/dom/WebGLRenderingContextBinding.h" 1.13 +#include "GLContext.h" 1.14 + 1.15 +using namespace mozilla; 1.16 + 1.17 +/** Takes an ASCII string like "foo[i]", turns it into "foo" and returns "[i]" in bracketPart 1.18 + * 1.19 + * \param string input/output: the string to split, becomes the string without the bracket part 1.20 + * \param bracketPart output: gets the bracket part. 1.21 + * 1.22 + * Notice that if there are multiple brackets like "foo[i].bar[j]", only the last bracket is split. 1.23 + */ 1.24 +static bool SplitLastSquareBracket(nsACString& string, nsCString& bracketPart) 1.25 +{ 1.26 + MOZ_ASSERT(bracketPart.IsEmpty(), "SplitLastSquareBracket must be called with empty bracketPart string"); 1.27 + 1.28 + if (string.IsEmpty()) 1.29 + return false; 1.30 + 1.31 + char *string_start = string.BeginWriting(); 1.32 + char *s = string_start + string.Length() - 1; 1.33 + 1.34 + if (*s != ']') 1.35 + return false; 1.36 + 1.37 + while (*s != '[' && s != string_start) 1.38 + s--; 1.39 + 1.40 + if (*s != '[') 1.41 + return false; 1.42 + 1.43 + bracketPart.Assign(s); 1.44 + *s = 0; 1.45 + string.EndWriting(); 1.46 + string.SetLength(s - string_start); 1.47 + return true; 1.48 +} 1.49 + 1.50 +JSObject* 1.51 +WebGLProgram::WrapObject(JSContext *cx) { 1.52 + return dom::WebGLProgramBinding::Wrap(cx, this); 1.53 +} 1.54 + 1.55 +WebGLProgram::WebGLProgram(WebGLContext *context) 1.56 + : WebGLContextBoundObject(context) 1.57 + , mLinkStatus(false) 1.58 + , mGeneration(0) 1.59 + , mAttribMaxNameLength(0) 1.60 +{ 1.61 + SetIsDOMBinding(); 1.62 + mContext->MakeContextCurrent(); 1.63 + mGLName = mContext->gl->fCreateProgram(); 1.64 + mContext->mPrograms.insertBack(this); 1.65 +} 1.66 + 1.67 +void 1.68 +WebGLProgram::Delete() { 1.69 + DetachShaders(); 1.70 + mContext->MakeContextCurrent(); 1.71 + mContext->gl->fDeleteProgram(mGLName); 1.72 + LinkedListElement<WebGLProgram>::removeFrom(mContext->mPrograms); 1.73 +} 1.74 + 1.75 +bool 1.76 +WebGLProgram::AttachShader(WebGLShader *shader) { 1.77 + if (ContainsShader(shader)) 1.78 + return false; 1.79 + mAttachedShaders.AppendElement(shader); 1.80 + 1.81 + mContext->MakeContextCurrent(); 1.82 + mContext->gl->fAttachShader(GLName(), shader->GLName()); 1.83 + 1.84 + return true; 1.85 +} 1.86 + 1.87 +bool 1.88 +WebGLProgram::DetachShader(WebGLShader *shader) { 1.89 + if (!mAttachedShaders.RemoveElement(shader)) 1.90 + return false; 1.91 + 1.92 + mContext->MakeContextCurrent(); 1.93 + mContext->gl->fDetachShader(GLName(), shader->GLName()); 1.94 + 1.95 + return true; 1.96 +} 1.97 + 1.98 +bool 1.99 +WebGLProgram::HasAttachedShaderOfType(GLenum shaderType) { 1.100 + for (uint32_t i = 0; i < mAttachedShaders.Length(); ++i) { 1.101 + if (mAttachedShaders[i] && mAttachedShaders[i]->ShaderType() == shaderType) { 1.102 + return true; 1.103 + } 1.104 + } 1.105 + return false; 1.106 +} 1.107 + 1.108 +bool 1.109 +WebGLProgram::HasBadShaderAttached() { 1.110 + for (uint32_t i = 0; i < mAttachedShaders.Length(); ++i) { 1.111 + if (mAttachedShaders[i] && !mAttachedShaders[i]->CompileStatus()) { 1.112 + return true; 1.113 + } 1.114 + } 1.115 + return false; 1.116 +} 1.117 + 1.118 +size_t 1.119 +WebGLProgram::UpperBoundNumSamplerUniforms() { 1.120 + size_t numSamplerUniforms = 0; 1.121 + for (size_t i = 0; i < mAttachedShaders.Length(); ++i) { 1.122 + const WebGLShader *shader = mAttachedShaders[i]; 1.123 + if (!shader) 1.124 + continue; 1.125 + for (size_t j = 0; j < shader->mUniformInfos.Length(); ++j) { 1.126 + WebGLUniformInfo u = shader->mUniformInfos[j]; 1.127 + if (u.type == SH_SAMPLER_2D || 1.128 + u.type == SH_SAMPLER_CUBE) 1.129 + { 1.130 + numSamplerUniforms += u.arraySize; 1.131 + } 1.132 + } 1.133 + } 1.134 + return numSamplerUniforms; 1.135 +} 1.136 + 1.137 +void 1.138 +WebGLProgram::MapIdentifier(const nsACString& name, nsCString *mappedName) { 1.139 + if (!mIdentifierMap) { 1.140 + // if the identifier map doesn't exist yet, build it now 1.141 + mIdentifierMap = new CStringMap; 1.142 + for (size_t i = 0; i < mAttachedShaders.Length(); i++) { 1.143 + for (size_t j = 0; j < mAttachedShaders[i]->mAttributes.Length(); j++) { 1.144 + const WebGLMappedIdentifier& attrib = mAttachedShaders[i]->mAttributes[j]; 1.145 + mIdentifierMap->Put(attrib.original, attrib.mapped); 1.146 + } 1.147 + for (size_t j = 0; j < mAttachedShaders[i]->mUniforms.Length(); j++) { 1.148 + const WebGLMappedIdentifier& uniform = mAttachedShaders[i]->mUniforms[j]; 1.149 + mIdentifierMap->Put(uniform.original, uniform.mapped); 1.150 + } 1.151 + } 1.152 + } 1.153 + 1.154 + nsCString mutableName(name); 1.155 + nsCString bracketPart; 1.156 + bool hadBracketPart = SplitLastSquareBracket(mutableName, bracketPart); 1.157 + if (hadBracketPart) 1.158 + mutableName.AppendLiteral("[0]"); 1.159 + 1.160 + if (mIdentifierMap->Get(mutableName, mappedName)) { 1.161 + if (hadBracketPart) { 1.162 + nsCString mappedBracketPart; 1.163 + bool mappedHadBracketPart = SplitLastSquareBracket(*mappedName, mappedBracketPart); 1.164 + if (mappedHadBracketPart) 1.165 + mappedName->Append(bracketPart); 1.166 + } 1.167 + return; 1.168 + } 1.169 + 1.170 + // not found? We might be in the situation we have a uniform array name and the GL's glGetActiveUniform 1.171 + // returned its name without [0], as is allowed by desktop GL but not in ES. Let's then try with [0]. 1.172 + mutableName.AppendLiteral("[0]"); 1.173 + if (mIdentifierMap->Get(mutableName, mappedName)) 1.174 + return; 1.175 + 1.176 + // not found? return name unchanged. This case happens e.g. on bad user input, or when 1.177 + // we're not using identifier mapping, or if we didn't store an identifier in the map because 1.178 + // e.g. its mapping is trivial (as happens for short identifiers) 1.179 + mappedName->Assign(name); 1.180 +} 1.181 + 1.182 +void 1.183 +WebGLProgram::ReverseMapIdentifier(const nsACString& name, nsCString *reverseMappedName) { 1.184 + if (!mIdentifierReverseMap) { 1.185 + // if the identifier reverse map doesn't exist yet, build it now 1.186 + mIdentifierReverseMap = new CStringMap; 1.187 + for (size_t i = 0; i < mAttachedShaders.Length(); i++) { 1.188 + for (size_t j = 0; j < mAttachedShaders[i]->mAttributes.Length(); j++) { 1.189 + const WebGLMappedIdentifier& attrib = mAttachedShaders[i]->mAttributes[j]; 1.190 + mIdentifierReverseMap->Put(attrib.mapped, attrib.original); 1.191 + } 1.192 + for (size_t j = 0; j < mAttachedShaders[i]->mUniforms.Length(); j++) { 1.193 + const WebGLMappedIdentifier& uniform = mAttachedShaders[i]->mUniforms[j]; 1.194 + mIdentifierReverseMap->Put(uniform.mapped, uniform.original); 1.195 + } 1.196 + } 1.197 + } 1.198 + 1.199 + nsCString mutableName(name); 1.200 + nsCString bracketPart; 1.201 + bool hadBracketPart = SplitLastSquareBracket(mutableName, bracketPart); 1.202 + if (hadBracketPart) 1.203 + mutableName.AppendLiteral("[0]"); 1.204 + 1.205 + if (mIdentifierReverseMap->Get(mutableName, reverseMappedName)) { 1.206 + if (hadBracketPart) { 1.207 + nsCString reverseMappedBracketPart; 1.208 + bool reverseMappedHadBracketPart = SplitLastSquareBracket(*reverseMappedName, reverseMappedBracketPart); 1.209 + if (reverseMappedHadBracketPart) 1.210 + reverseMappedName->Append(bracketPart); 1.211 + } 1.212 + return; 1.213 + } 1.214 + 1.215 + // not found? We might be in the situation we have a uniform array name and the GL's glGetActiveUniform 1.216 + // returned its name without [0], as is allowed by desktop GL but not in ES. Let's then try with [0]. 1.217 + mutableName.AppendLiteral("[0]"); 1.218 + if (mIdentifierReverseMap->Get(mutableName, reverseMappedName)) 1.219 + return; 1.220 + 1.221 + // not found? return name unchanged. This case happens e.g. on bad user input, or when 1.222 + // we're not using identifier mapping, or if we didn't store an identifier in the map because 1.223 + // e.g. its mapping is trivial (as happens for short identifiers) 1.224 + reverseMappedName->Assign(name); 1.225 +} 1.226 + 1.227 +WebGLUniformInfo 1.228 +WebGLProgram::GetUniformInfoForMappedIdentifier(const nsACString& name) { 1.229 + nsCString mutableName(name); 1.230 + nsCString bracketPart; 1.231 + bool hadBracketPart = SplitLastSquareBracket(mutableName, bracketPart); 1.232 + // if there is a bracket, we're either an array or an entry in an array. 1.233 + if (hadBracketPart) 1.234 + mutableName.AppendLiteral("[0]"); 1.235 + 1.236 + WebGLUniformInfo info; 1.237 + mUniformInfoMap->Get(mutableName, &info); 1.238 + // we don't check if that Get failed, as if it did, it left info with default values 1.239 + 1.240 + return info; 1.241 +} 1.242 + 1.243 +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(WebGLProgram, mAttachedShaders) 1.244 + 1.245 +NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLProgram, AddRef) 1.246 +NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLProgram, Release)