Hook into some shader symbol logic following the ANGLE update in r159533.
[WebKit-https.git] / Source / WebCore / platform / graphics / ANGLEWebKitBridge.cpp
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 #if USE(3D_GRAPHICS)
29
30 #include "ANGLEWebKitBridge.h"
31 #include "Logging.h"
32 #include <wtf/StdLibExtras.h>
33
34 namespace WebCore {
35
36 // Temporary typedef to support an incompatible change in the ANGLE API.
37 #if !defined(ANGLE_SH_VERSION) || ANGLE_SH_VERSION < 108
38 typedef int ANGLEGetInfoType;
39 #else
40 typedef size_t ANGLEGetInfoType;
41 #endif
42
43 inline static ANGLEGetInfoType getValidationResultValue(const ShHandle compiler, ShShaderInfo shaderInfo)
44 {
45     ANGLEGetInfoType value = 0;
46     ShGetInfo(compiler, shaderInfo, &value);
47     return value;
48 }
49
50 static bool getSymbolInfo(ShHandle compiler, ShShaderInfo symbolType, Vector<ANGLEShaderSymbol>& symbols)
51 {
52     ShShaderInfo symbolMaxNameLengthType;
53
54     switch (symbolType) {
55     case SH_ACTIVE_ATTRIBUTES:
56         symbolMaxNameLengthType = SH_ACTIVE_ATTRIBUTE_MAX_LENGTH;
57         break;
58     case SH_ACTIVE_UNIFORMS:
59         symbolMaxNameLengthType = SH_ACTIVE_UNIFORM_MAX_LENGTH;
60         break;
61     case SH_VARYINGS:
62         symbolMaxNameLengthType = SH_VARYING_MAX_LENGTH;
63     default:
64         ASSERT_NOT_REACHED();
65         return false;
66     }
67
68     ANGLEGetInfoType numSymbols = getValidationResultValue(compiler, symbolType);
69
70     ANGLEGetInfoType maxNameLength = getValidationResultValue(compiler, symbolMaxNameLengthType);
71     if (maxNameLength <= 1)
72         return false;
73
74     ANGLEGetInfoType maxMappedNameLength = getValidationResultValue(compiler, SH_MAPPED_NAME_MAX_LENGTH);
75     if (maxMappedNameLength <= 1)
76         return false;
77
78     // The maximum allowed symbol name length is 256 characters.
79     Vector<char, 256> nameBuffer(maxNameLength);
80     Vector<char, 256> mappedNameBuffer(maxMappedNameLength);
81     
82     for (ANGLEGetInfoType i = 0; i < numSymbols; ++i) {
83         ANGLEShaderSymbol symbol;
84         ANGLEGetInfoType nameLength = 0;
85         ShPrecisionType precision;
86         int staticUse;
87         switch (symbolType) {
88         case SH_ACTIVE_ATTRIBUTES:
89             symbol.symbolType = SHADER_SYMBOL_TYPE_ATTRIBUTE;
90             ShGetVariableInfo(compiler, symbolType, i, &nameLength, &symbol.size, &symbol.dataType, &precision, &staticUse, nameBuffer.data(), mappedNameBuffer.data());
91             break;
92         case SH_ACTIVE_UNIFORMS:
93             symbol.symbolType = SHADER_SYMBOL_TYPE_UNIFORM;
94             ShGetVariableInfo(compiler, symbolType, i, &nameLength, &symbol.size, &symbol.dataType, &precision, &staticUse, nameBuffer.data(), mappedNameBuffer.data());
95             break;
96         case SH_VARYINGS:
97             symbol.symbolType = SHADER_SYMBOL_TYPE_VARYING;
98             ShGetVariableInfo(compiler, symbolType, i, &nameLength, &symbol.size, &symbol.dataType, &precision, &staticUse, nameBuffer.data(), mappedNameBuffer.data());
99             break;
100         default:
101             ASSERT_NOT_REACHED();
102             return false;
103         }
104         if (!nameLength)
105             return false;
106         
107         // The ShGetActive* calls above are guaranteed to produce null-terminated strings for
108         // nameBuffer and mappedNameBuffer. Also, the character set for symbol names
109         // is a subset of Latin-1 as specified by the OpenGL ES Shading Language, Section 3.1 and
110         // WebGL, Section "Characters Outside the GLSL Source Character Set".
111
112         String name = String(nameBuffer.data());
113         String mappedName = String(mappedNameBuffer.data());
114         LOG(WebGL, "Map shader symbol %s -> %s\n", name.utf8().data(), mappedName.utf8().data());
115         
116         // ANGLE returns array names in the format "array[0]".
117         // The only way to know if a symbol is an array is to check if it ends with "[0]".
118         // We can't check the size because regular symbols and arrays of length 1 both have a size of 1.
119         symbol.isArray = name.endsWith("[0]") && mappedName.endsWith("[0]");
120         if (symbol.isArray) {
121             // Add a symbol for the array name without the "[0]" suffix.
122             name.truncate(name.length() - 3);
123             mappedName.truncate(mappedName.length() - 3);
124         }
125
126         symbol.name = name;
127         symbol.mappedName = mappedName;
128         symbol.precision = precision;
129         symbol.staticUse = staticUse;
130         symbols.append(symbol);
131     
132         if (symbol.isArray) {
133             // Add symbols for each array element.
134             symbol.isArray = false;
135             for (int i = 0; i < symbol.size; i++) {
136                 String arrayBrackets = "[" + String::number(i) + "]";
137                 symbol.name = name + arrayBrackets;
138                 symbol.mappedName = mappedName + arrayBrackets;
139                 symbols.append(symbol);
140             }
141         }
142     }
143     return true;
144 }
145
146 ANGLEWebKitBridge::ANGLEWebKitBridge(ShShaderOutput shaderOutput, ShShaderSpec shaderSpec)
147     : builtCompilers(false)
148     , m_fragmentCompiler(0)
149     , m_vertexCompiler(0)
150     , m_shaderOutput(shaderOutput)
151     , m_shaderSpec(shaderSpec)
152 {
153     // This is a no-op if it's already initialized.
154     ShInitialize();
155 }
156
157 ANGLEWebKitBridge::~ANGLEWebKitBridge()
158 {
159     cleanupCompilers();
160 }
161
162 void ANGLEWebKitBridge::cleanupCompilers()
163 {
164     if (m_fragmentCompiler)
165         ShDestruct(m_fragmentCompiler);
166     m_fragmentCompiler = 0;
167     if (m_vertexCompiler)
168         ShDestruct(m_vertexCompiler);
169     m_vertexCompiler = 0;
170
171     builtCompilers = false;
172 }
173     
174 void ANGLEWebKitBridge::setResources(ShBuiltInResources resources)
175 {
176     // Resources are (possibly) changing - cleanup compilers if we had them already
177     cleanupCompilers();
178     
179     m_resources = resources;
180 }
181
182 bool ANGLEWebKitBridge::compileShaderSource(const char* shaderSource, ANGLEShaderType shaderType, String& translatedShaderSource, String& shaderValidationLog, Vector<ANGLEShaderSymbol>& symbols, int extraCompileOptions)
183 {
184     if (!builtCompilers) {
185         m_fragmentCompiler = ShConstructCompiler(SH_FRAGMENT_SHADER, m_shaderSpec, m_shaderOutput, &m_resources);
186         m_vertexCompiler = ShConstructCompiler(SH_VERTEX_SHADER, m_shaderSpec, m_shaderOutput, &m_resources);
187         if (!m_fragmentCompiler || !m_vertexCompiler) {
188             cleanupCompilers();
189             return false;
190         }
191
192         builtCompilers = true;
193     }
194     
195     ShHandle compiler;
196
197     if (shaderType == SHADER_TYPE_VERTEX)
198         compiler = m_vertexCompiler;
199     else
200         compiler = m_fragmentCompiler;
201
202     const char* const shaderSourceStrings[] = { shaderSource };
203
204     bool validateSuccess = ShCompile(compiler, shaderSourceStrings, 1, SH_OBJECT_CODE | SH_VARIABLES | extraCompileOptions);
205     if (!validateSuccess) {
206         int logSize = getValidationResultValue(compiler, SH_INFO_LOG_LENGTH);
207         if (logSize > 1) {
208             auto logBuffer = std::make_unique<char[]>(logSize);
209             if (logBuffer) {
210                 ShGetInfoLog(compiler, logBuffer.get());
211                 shaderValidationLog = logBuffer.get();
212             }
213         }
214         return false;
215     }
216
217     int translationLength = getValidationResultValue(compiler, SH_OBJECT_CODE_LENGTH);
218     if (translationLength > 1) {
219         auto translationBuffer = std::make_unique<char[]>(translationLength);
220         if (!translationBuffer)
221             return false;
222         ShGetObjectCode(compiler, translationBuffer.get());
223         translatedShaderSource = translationBuffer.get();
224     }
225     
226     if (!getSymbolInfo(compiler, SH_ACTIVE_ATTRIBUTES, symbols))
227         return false;
228     if (!getSymbolInfo(compiler, SH_ACTIVE_UNIFORMS, symbols))
229         return false;
230
231     return true;
232 }
233
234 }
235
236 #endif // USE(3D_GRAPHICS)