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