1 /*
2 * Copyright (C) 2010 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "config.h"
27
28 #include "platform/graphics/angle/ANGLEPlatformBridge.h"
29
30 #include "wtf/OwnPtr.h"
31 #include "wtf/PassOwnPtr.h"
32
33 namespace WebCore {
34
35 typedef size_t ANGLEGetInfoType;
36
getValidationResultValue(const ShHandle compiler,ShShaderInfo shaderInfo)37 inline static ANGLEGetInfoType getValidationResultValue(const ShHandle compiler, ShShaderInfo shaderInfo)
38 {
39 ANGLEGetInfoType value = 0;
40 ShGetInfo(compiler, shaderInfo, &value);
41 return value;
42 }
43
getSymbolInfo(ShHandle compiler,ShShaderInfo symbolType,Vector<ANGLEShaderSymbol> & symbols)44 static bool getSymbolInfo(ShHandle compiler, ShShaderInfo symbolType, Vector<ANGLEShaderSymbol>& symbols)
45 {
46 ShShaderInfo symbolMaxNameLengthType;
47
48 switch (symbolType) {
49 case SH_ACTIVE_ATTRIBUTES:
50 symbolMaxNameLengthType = SH_ACTIVE_ATTRIBUTE_MAX_LENGTH;
51 break;
52 case SH_ACTIVE_UNIFORMS:
53 symbolMaxNameLengthType = SH_ACTIVE_UNIFORM_MAX_LENGTH;
54 break;
55 default:
56 ASSERT_NOT_REACHED();
57 return false;
58 }
59
60 ANGLEGetInfoType numSymbols = getValidationResultValue(compiler, symbolType);
61
62 ANGLEGetInfoType maxNameLength = getValidationResultValue(compiler, symbolMaxNameLengthType);
63 if (maxNameLength <= 1)
64 return false;
65
66 ANGLEGetInfoType maxMappedNameLength = getValidationResultValue(compiler, SH_MAPPED_NAME_MAX_LENGTH);
67 if (maxMappedNameLength <= 1)
68 return false;
69
70 // The maximum allowed symbol name length is 256 characters.
71 Vector<char, 256> nameBuffer(maxNameLength);
72 Vector<char, 256> mappedNameBuffer(maxMappedNameLength);
73
74 for (ANGLEGetInfoType i = 0; i < numSymbols; ++i) {
75 ANGLEShaderSymbol symbol;
76 ANGLEGetInfoType nameLength = 0;
77 switch (symbolType) {
78 case SH_ACTIVE_ATTRIBUTES:
79 symbol.symbolType = SHADER_SYMBOL_TYPE_ATTRIBUTE;
80 #if ANGLE_SH_VERSION >= 112
81 ShGetVariableInfo(compiler, symbolType, i, &nameLength, &symbol.size, &symbol.dataType, &symbol.precision, &symbol.staticUse, nameBuffer.data(), mappedNameBuffer.data());
82 #else
83 ShGetVariableInfo(compiler, symbolType, i, &nameLength, &symbol.size, &symbol.dataType, &symbol.precision, nameBuffer.data(), mappedNameBuffer.data());
84 #endif
85 break;
86 case SH_ACTIVE_UNIFORMS:
87 symbol.symbolType = SHADER_SYMBOL_TYPE_UNIFORM;
88 #if ANGLE_SH_VERSION >= 112
89 ShGetVariableInfo(compiler, symbolType, i, &nameLength, &symbol.size, &symbol.dataType, &symbol.precision, &symbol.staticUse, nameBuffer.data(), mappedNameBuffer.data());
90 #else
91 ShGetVariableInfo(compiler, symbolType, i, &nameLength, &symbol.size, &symbol.dataType, &symbol.precision, nameBuffer.data(), mappedNameBuffer.data());
92 #endif
93 break;
94 default:
95 ASSERT_NOT_REACHED();
96 return false;
97 }
98 if (!nameLength)
99 return false;
100
101 // The ShGetActive* calls above are guaranteed to produce null-terminated strings for
102 // nameBuffer and mappedNameBuffer. Also, the character set for symbol names
103 // is a subset of Latin-1 as specified by the OpenGL ES Shading Language, Section 3.1 and
104 // WebGL, Section "Characters Outside the GLSL Source Character Set".
105
106 String name = String(nameBuffer.data());
107 String mappedName = String(mappedNameBuffer.data());
108
109 // ANGLE returns array names in the format "array[0]".
110 // The only way to know if a symbol is an array is to check if it ends with "[0]".
111 // We can't check the size because regular symbols and arrays of length 1 both have a size of 1.
112 symbol.isArray = name.endsWith("[0]") && mappedName.endsWith("[0]");
113 if (symbol.isArray) {
114 // Add a symbol for the array name without the "[0]" suffix.
115 name.truncate(name.length() - 3);
116 mappedName.truncate(mappedName.length() - 3);
117 }
118
119 symbol.name = name;
120 symbol.mappedName = mappedName;
121 symbols.append(symbol);
122
123 if (symbol.isArray) {
124 // Add symbols for each array element.
125 symbol.isArray = false;
126 for (int i = 0; i < symbol.size; i++) {
127 String arrayBrackets = "[" + String::number(i) + "]";
128 symbol.name = name + arrayBrackets;
129 symbol.mappedName = mappedName + arrayBrackets;
130 symbols.append(symbol);
131 }
132 }
133 }
134 return true;
135 }
136
ANGLEPlatformBridge(ShShaderOutput shaderOutput,ShShaderSpec shaderSpec)137 ANGLEPlatformBridge::ANGLEPlatformBridge(ShShaderOutput shaderOutput, ShShaderSpec shaderSpec)
138 : builtCompilers(false)
139 , m_fragmentCompiler(0)
140 , m_vertexCompiler(0)
141 , m_shaderOutput(shaderOutput)
142 , m_shaderSpec(shaderSpec)
143 {
144 // This is a no-op if it's already initialized.
145 ShInitialize();
146 }
147
~ANGLEPlatformBridge()148 ANGLEPlatformBridge::~ANGLEPlatformBridge()
149 {
150 cleanupCompilers();
151 }
152
cleanupCompilers()153 void ANGLEPlatformBridge::cleanupCompilers()
154 {
155 if (m_fragmentCompiler)
156 ShDestruct(m_fragmentCompiler);
157 m_fragmentCompiler = 0;
158 if (m_vertexCompiler)
159 ShDestruct(m_vertexCompiler);
160 m_vertexCompiler = 0;
161
162 builtCompilers = false;
163 }
164
setResources(ShBuiltInResources resources)165 void ANGLEPlatformBridge::setResources(ShBuiltInResources resources)
166 {
167 // Resources are (possibly) changing - cleanup compilers if we had them already
168 cleanupCompilers();
169
170 m_resources = resources;
171 }
172
compileShaderSource(const char * shaderSource,ANGLEShaderType shaderType,String & translatedShaderSource,String & shaderValidationLog,Vector<ANGLEShaderSymbol> & symbols,int extraCompileOptions)173 bool ANGLEPlatformBridge::compileShaderSource(const char* shaderSource, ANGLEShaderType shaderType, String& translatedShaderSource, String& shaderValidationLog, Vector<ANGLEShaderSymbol>& symbols, int extraCompileOptions)
174 {
175 if (!builtCompilers) {
176 m_fragmentCompiler = ShConstructCompiler(SH_FRAGMENT_SHADER, m_shaderSpec, m_shaderOutput, &m_resources);
177 m_vertexCompiler = ShConstructCompiler(SH_VERTEX_SHADER, m_shaderSpec, m_shaderOutput, &m_resources);
178 if (!m_fragmentCompiler || !m_vertexCompiler) {
179 cleanupCompilers();
180 return false;
181 }
182
183 builtCompilers = true;
184 }
185
186 ShHandle compiler;
187
188 if (shaderType == SHADER_TYPE_VERTEX)
189 compiler = m_vertexCompiler;
190 else
191 compiler = m_fragmentCompiler;
192
193 const char* const shaderSourceStrings[] = { shaderSource };
194
195 #if ANGLE_SH_VERSION >= 111
196 bool validateSuccess = ShCompile(compiler, shaderSourceStrings, 1, SH_OBJECT_CODE | SH_VARIABLES | extraCompileOptions);
197 #else
198 bool validateSuccess = ShCompile(compiler, shaderSourceStrings, 1, SH_OBJECT_CODE | SH_ATTRIBUTES_UNIFORMS | extraCompileOptions);
199 #endif
200 if (!validateSuccess) {
201 int logSize = getValidationResultValue(compiler, SH_INFO_LOG_LENGTH);
202 if (logSize > 1) {
203 OwnPtr<char[]> logBuffer = adoptArrayPtr(new char[logSize]);
204 if (logBuffer) {
205 ShGetInfoLog(compiler, logBuffer.get());
206 shaderValidationLog = logBuffer.get();
207 }
208 }
209 return false;
210 }
211
212 int translationLength = getValidationResultValue(compiler, SH_OBJECT_CODE_LENGTH);
213 if (translationLength > 1) {
214 OwnPtr<char[]> translationBuffer = adoptArrayPtr(new char[translationLength]);
215 if (!translationBuffer)
216 return false;
217 ShGetObjectCode(compiler, translationBuffer.get());
218 translatedShaderSource = translationBuffer.get();
219 }
220
221 if (!getSymbolInfo(compiler, SH_ACTIVE_ATTRIBUTES, symbols))
222 return false;
223 if (!getSymbolInfo(compiler, SH_ACTIVE_UNIFORMS, symbols))
224 return false;
225
226 return true;
227 }
228
229 }
230