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