7c9f2ae45eca3823d4492a35f7a29ccf47d53112
[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     default:
62         ASSERT_NOT_REACHED();
63         return false;
64     }
65
66     ANGLEGetInfoType numSymbols = getValidationResultValue(compiler, symbolType);
67
68     ANGLEGetInfoType maxNameLength = getValidationResultValue(compiler, symbolMaxNameLengthType);
69     if (maxNameLength <= 1)
70         return false;
71
72     ANGLEGetInfoType maxMappedNameLength = getValidationResultValue(compiler, SH_MAPPED_NAME_MAX_LENGTH);
73     if (maxMappedNameLength <= 1)
74         return false;
75
76     // The maximum allowed symbol name length is 256 characters.
77     Vector<char, 256> nameBuffer(maxNameLength);
78     Vector<char, 256> mappedNameBuffer(maxMappedNameLength);
79     
80     for (ANGLEGetInfoType i = 0; i < numSymbols; ++i) {
81         ANGLEShaderSymbol symbol;
82         ANGLEGetInfoType nameLength = 0;
83         ShPrecisionType precision;
84         int staticUse;
85         switch (symbolType) {
86         case SH_ACTIVE_ATTRIBUTES:
87             symbol.symbolType = SHADER_SYMBOL_TYPE_ATTRIBUTE;
88             ShGetVariableInfo(compiler, symbolType, i, &nameLength, &symbol.size, &symbol.dataType, &precision, &staticUse, nameBuffer.data(), mappedNameBuffer.data());
89             break;
90         case SH_ACTIVE_UNIFORMS:
91             symbol.symbolType = SHADER_SYMBOL_TYPE_UNIFORM;
92             ShGetVariableInfo(compiler, symbolType, i, &nameLength, &symbol.size, &symbol.dataType, &precision, &staticUse, nameBuffer.data(), mappedNameBuffer.data());
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         LOG(WebGL, "Map shader symbol %s -> %s\n", name.utf8().data(), mappedName.utf8().data());
109         
110         // ANGLE returns array names in the format "array[0]".
111         // The only way to know if a symbol is an array is to check if it ends with "[0]".
112         // We can't check the size because regular symbols and arrays of length 1 both have a size of 1.
113         symbol.isArray = name.endsWith("[0]") && mappedName.endsWith("[0]");
114         if (symbol.isArray) {
115             // Add a symbol for the array name without the "[0]" suffix.
116             name.truncate(name.length() - 3);
117             mappedName.truncate(mappedName.length() - 3);
118         }
119
120         symbol.name = name;
121         symbol.mappedName = mappedName;
122         symbols.append(symbol);
123     
124         if (symbol.isArray) {
125             // Add symbols for each array element.
126             symbol.isArray = false;
127             for (int i = 0; i < symbol.size; i++) {
128                 String arrayBrackets = "[" + String::number(i) + "]";
129                 symbol.name = name + arrayBrackets;
130                 symbol.mappedName = mappedName + arrayBrackets;
131                 symbols.append(symbol);
132             }
133         }
134     }
135     return true;
136 }
137
138 ANGLEWebKitBridge::ANGLEWebKitBridge(ShShaderOutput shaderOutput, ShShaderSpec shaderSpec)
139     : builtCompilers(false)
140     , m_fragmentCompiler(0)
141     , m_vertexCompiler(0)
142     , m_shaderOutput(shaderOutput)
143     , m_shaderSpec(shaderSpec)
144 {
145     // This is a no-op if it's already initialized.
146     ShInitialize();
147 }
148
149 ANGLEWebKitBridge::~ANGLEWebKitBridge()
150 {
151     cleanupCompilers();
152 }
153
154 void ANGLEWebKitBridge::cleanupCompilers()
155 {
156     if (m_fragmentCompiler)
157         ShDestruct(m_fragmentCompiler);
158     m_fragmentCompiler = 0;
159     if (m_vertexCompiler)
160         ShDestruct(m_vertexCompiler);
161     m_vertexCompiler = 0;
162
163     builtCompilers = false;
164 }
165     
166 void ANGLEWebKitBridge::setResources(ShBuiltInResources resources)
167 {
168     // Resources are (possibly) changing - cleanup compilers if we had them already
169     cleanupCompilers();
170     
171     m_resources = resources;
172 }
173
174 bool ANGLEWebKitBridge::compileShaderSource(const char* shaderSource, ANGLEShaderType shaderType, String& translatedShaderSource, String& shaderValidationLog, Vector<ANGLEShaderSymbol>& symbols, int extraCompileOptions)
175 {
176     if (!builtCompilers) {
177         m_fragmentCompiler = ShConstructCompiler(SH_FRAGMENT_SHADER, m_shaderSpec, m_shaderOutput, &m_resources);
178         m_vertexCompiler = ShConstructCompiler(SH_VERTEX_SHADER, m_shaderSpec, m_shaderOutput, &m_resources);
179         if (!m_fragmentCompiler || !m_vertexCompiler) {
180             cleanupCompilers();
181             return false;
182         }
183
184         builtCompilers = true;
185     }
186     
187     ShHandle compiler;
188
189     if (shaderType == SHADER_TYPE_VERTEX)
190         compiler = m_vertexCompiler;
191     else
192         compiler = m_fragmentCompiler;
193
194     const char* const shaderSourceStrings[] = { shaderSource };
195
196     bool validateSuccess = ShCompile(compiler, shaderSourceStrings, 1, SH_OBJECT_CODE | SH_VARIABLES | extraCompileOptions);
197     if (!validateSuccess) {
198         int logSize = getValidationResultValue(compiler, SH_INFO_LOG_LENGTH);
199         if (logSize > 1) {
200             auto logBuffer = std::make_unique<char[]>(logSize);
201             if (logBuffer) {
202                 ShGetInfoLog(compiler, logBuffer.get());
203                 shaderValidationLog = logBuffer.get();
204             }
205         }
206         return false;
207     }
208
209     int translationLength = getValidationResultValue(compiler, SH_OBJECT_CODE_LENGTH);
210     if (translationLength > 1) {
211         auto translationBuffer = std::make_unique<char[]>(translationLength);
212         if (!translationBuffer)
213             return false;
214         ShGetObjectCode(compiler, translationBuffer.get());
215         translatedShaderSource = translationBuffer.get();
216     }
217     
218     if (!getSymbolInfo(compiler, SH_ACTIVE_ATTRIBUTES, symbols))
219         return false;
220     if (!getSymbolInfo(compiler, SH_ACTIVE_UNIFORMS, symbols))
221         return false;
222
223     return true;
224 }
225
226 }
227
228 #endif // USE(3D_GRAPHICS)