1/*
2 * Copyright (C) 2010, 2016 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 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 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#if ENABLE(GRAPHICS_CONTEXT_3D)
29
30#include "ANGLEWebKitBridge.h"
31#include "Logging.h"
32#include <wtf/StdLibExtras.h>
33
34namespace WebCore {
35
36// FIXME: This is awful. Get rid of ANGLEWebKitBridge completely and call the libANGLE API directly to validate shaders.
37
38static void appendSymbol(const sh::ShaderVariable& variable, ANGLEShaderSymbolType symbolType, Vector<std::pair<ANGLEShaderSymbolType, sh::ShaderVariable>>& symbols, const std::string& name, const std::string& mappedName)
39{
40 LOG(WebGL, "Map shader symbol %s -> %s\n", name.c_str(), mappedName.c_str());
41
42 sh::ShaderVariable variableToAppend = variable;
43 variableToAppend.name = name;
44 variableToAppend.mappedName = mappedName;
45 symbols.append(std::make_pair(symbolType, variableToAppend));
46
47 if (variable.isArray()) {
48 for (unsigned i = 0; i < std::max(1u, variable.arraySizes.back()); i++) {
49 std::string arrayBrackets = "[" + std::to_string(i) + "]";
50 std::string arrayName = name + arrayBrackets;
51 std::string arrayMappedName = mappedName + arrayBrackets;
52 LOG(WebGL, "Map shader symbol %s -> %s\n", arrayName.c_str(), arrayMappedName.c_str());
53 variableToAppend.name = arrayName;
54 variableToAppend.mappedName = arrayMappedName;
55 symbols.append(std::make_pair(symbolType, variableToAppend));
56 }
57 }
58}
59
60static void getStructInfo(const sh::ShaderVariable& field, ANGLEShaderSymbolType symbolType, Vector<std::pair<ANGLEShaderSymbolType, sh::ShaderVariable>>& symbols, const std::string& namePrefix, const std::string& mappedNamePrefix)
61{
62 std::string name = namePrefix + '.' + field.name;
63 std::string mappedName = mappedNamePrefix + '.' + field.mappedName;
64
65 if (field.isStruct()) {
66 for (const auto& subfield : field.fields) {
67 // ANGLE restricts the depth of structs, which prevents stack overflow errors in this recursion.
68 getStructInfo(subfield, symbolType, symbols, name, mappedName);
69 }
70 } else
71 appendSymbol(field, symbolType, symbols, name, mappedName);
72}
73
74static void getSymbolInfo(const sh::ShaderVariable& variable, ANGLEShaderSymbolType symbolType, Vector<std::pair<ANGLEShaderSymbolType, sh::ShaderVariable>>& symbols)
75{
76 if (variable.isStruct()) {
77 if (variable.isArray()) {
78 for (unsigned i = 0; i < std::max(1u, variable.arraySizes.back()); i++) {
79 std::string arrayBrackets = "[" + std::to_string(i) + "]";
80 std::string arrayName = variable.name + arrayBrackets;
81 std::string arrayMappedName = variable.mappedName + arrayBrackets;
82 for (const auto& field : variable.fields)
83 getStructInfo(field, symbolType, symbols, arrayName, arrayMappedName);
84 }
85 } else {
86 for (const auto& field : variable.fields)
87 getStructInfo(field, symbolType, symbols, variable.name, variable.mappedName);
88 }
89 } else
90 appendSymbol(variable, symbolType, symbols, variable.name, variable.mappedName);
91}
92
93static bool getSymbolInfo(ShHandle compiler, ANGLEShaderSymbolType symbolType, Vector<std::pair<ANGLEShaderSymbolType, sh::ShaderVariable>>& symbols)
94{
95 switch (symbolType) {
96 case SHADER_SYMBOL_TYPE_UNIFORM: {
97 auto uniforms = sh::GetUniforms(compiler);
98 if (!uniforms)
99 return false;
100 for (const auto& uniform : *uniforms)
101 getSymbolInfo(uniform, symbolType, symbols);
102 break;
103 }
104 case SHADER_SYMBOL_TYPE_VARYING: {
105 auto varyings = sh::GetVaryings(compiler);
106 if (!varyings)
107 return false;
108 for (const auto& varying : *varyings)
109 getSymbolInfo(varying, symbolType, symbols);
110 break;
111 }
112 case SHADER_SYMBOL_TYPE_ATTRIBUTE: {
113 auto attributes = sh::GetAttributes(compiler);
114 if (!attributes)
115 return false;
116 for (const auto& attribute : *attributes)
117 getSymbolInfo(attribute, symbolType, symbols);
118 break;
119 }
120 default:
121 ASSERT_NOT_REACHED();
122 return false;
123 }
124 return true;
125}
126
127ANGLEWebKitBridge::ANGLEWebKitBridge(ShShaderOutput shaderOutput, ShShaderSpec shaderSpec)
128 : builtCompilers(false)
129 , m_fragmentCompiler(0)
130 , m_vertexCompiler(0)
131 , m_shaderOutput(shaderOutput)
132 , m_shaderSpec(shaderSpec)
133{
134 // This is a no-op if it's already initialized.
135 sh::Initialize();
136}
137
138ANGLEWebKitBridge::~ANGLEWebKitBridge()
139{
140 cleanupCompilers();
141}
142
143void ANGLEWebKitBridge::cleanupCompilers()
144{
145 if (m_fragmentCompiler)
146 sh::Destruct(m_fragmentCompiler);
147 m_fragmentCompiler = nullptr;
148 if (m_vertexCompiler)
149 sh::Destruct(m_vertexCompiler);
150 m_vertexCompiler = nullptr;
151
152 builtCompilers = false;
153}
154
155void ANGLEWebKitBridge::setResources(const ShBuiltInResources& resources)
156{
157 // Resources are (possibly) changing - cleanup compilers if we had them already
158 cleanupCompilers();
159
160 m_resources = resources;
161}
162
163bool ANGLEWebKitBridge::compileShaderSource(const char* shaderSource, ANGLEShaderType shaderType, String& translatedShaderSource, String& shaderValidationLog, Vector<std::pair<ANGLEShaderSymbolType, sh::ShaderVariable>>& symbols, uint64_t extraCompileOptions)
164{
165 if (!builtCompilers) {
166 m_fragmentCompiler = sh::ConstructCompiler(GL_FRAGMENT_SHADER, m_shaderSpec, m_shaderOutput, &m_resources);
167 m_vertexCompiler = sh::ConstructCompiler(GL_VERTEX_SHADER, m_shaderSpec, m_shaderOutput, &m_resources);
168 if (!m_fragmentCompiler || !m_vertexCompiler) {
169 cleanupCompilers();
170 return false;
171 }
172
173 builtCompilers = true;
174 }
175
176 ShHandle compiler;
177
178 if (shaderType == SHADER_TYPE_VERTEX)
179 compiler = m_vertexCompiler;
180 else
181 compiler = m_fragmentCompiler;
182
183 const char* const shaderSourceStrings[] = { shaderSource };
184
185 bool validateSuccess = sh::Compile(compiler, shaderSourceStrings, 1, SH_OBJECT_CODE | SH_VARIABLES | extraCompileOptions);
186 if (!validateSuccess) {
187 const std::string& log = sh::GetInfoLog(compiler);
188 if (log.length())
189 shaderValidationLog = log.c_str();
190 return false;
191 }
192
193 const std::string& objectCode = sh::GetObjectCode(compiler);
194 if (objectCode.length())
195 translatedShaderSource = objectCode.c_str();
196
197 if (!getSymbolInfo(compiler, SHADER_SYMBOL_TYPE_ATTRIBUTE, symbols))
198 return false;
199 if (!getSymbolInfo(compiler, SHADER_SYMBOL_TYPE_UNIFORM, symbols))
200 return false;
201 if (!getSymbolInfo(compiler, SHADER_SYMBOL_TYPE_VARYING, symbols))
202 return false;
203
204 return true;
205}
206
207}
208
209#endif // ENABLE(GRAPHICS_CONTEXT_3D)
210