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 33namespace WebCore { 34 35typedef size_t ANGLEGetInfoType; 36 37inline static ANGLEGetInfoType getValidationResultValue(const ShHandle compiler, ShShaderInfo shaderInfo) 38{ 39 ANGLEGetInfoType value = 0; 40 ShGetInfo(compiler, shaderInfo, &value); 41 return value; 42} 43 44static 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 137ANGLEPlatformBridge::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 148ANGLEPlatformBridge::~ANGLEPlatformBridge() 149{ 150 cleanupCompilers(); 151} 152 153void 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 165void 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 173bool 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