1/* 2 * Copyright (c) 2010, Google 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 are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include "config.h" 32 33#if ENABLE(ACCELERATED_2D_CANVAS) 34 35#include "Shader.h" 36 37#include "AffineTransform.h" 38#include "GraphicsContext3D.h" 39 40#include <wtf/text/CString.h> 41#include <wtf/text/StringBuilder.h> 42 43namespace WebCore { 44 45// static 46void Shader::affineTo3x3(const AffineTransform& transform, float mat[9]) 47{ 48 mat[0] = transform.a(); 49 mat[1] = transform.b(); 50 mat[2] = 0.0f; 51 mat[3] = transform.c(); 52 mat[4] = transform.d(); 53 mat[5] = 0.0f; 54 mat[6] = transform.e(); 55 mat[7] = transform.f(); 56 mat[8] = 1.0f; 57} 58 59// static 60void Shader::affineTo4x4(const AffineTransform& transform, float mat[16]) 61{ 62 mat[0] = transform.a(); 63 mat[1] = transform.b(); 64 mat[2] = 0.0f; 65 mat[3] = 0.0f; 66 mat[4] = transform.c(); 67 mat[5] = transform.d(); 68 mat[6] = 0.0f; 69 mat[7] = 0.0f; 70 mat[8] = 0.0f; 71 mat[9] = 0.0f; 72 mat[10] = 1.0f; 73 mat[11] = 0.0f; 74 mat[12] = transform.e(); 75 mat[13] = transform.f(); 76 mat[14] = 0.0f; 77 mat[15] = 1.0f; 78} 79 80// static 81unsigned Shader::loadShader(GraphicsContext3D* context, unsigned type, const String& shaderSource) 82{ 83 unsigned shader = context->createShader(type); 84 if (!shader) 85 return 0; 86 87 context->shaderSource(shader, shaderSource); 88 context->compileShader(shader); 89 int compileStatus = 0; 90 context->getShaderiv(shader, GraphicsContext3D::COMPILE_STATUS, &compileStatus); 91 if (!compileStatus) { 92 String infoLog = context->getShaderInfoLog(shader); 93 LOG_ERROR("%s", infoLog.utf8().data()); 94 context->deleteShader(shader); 95 return 0; 96 } 97 return shader; 98} 99 100// static 101unsigned Shader::loadProgram(GraphicsContext3D* context, const String& vertexShaderSource, const String& fragmentShaderSource) 102{ 103 unsigned vertexShader = loadShader(context, GraphicsContext3D::VERTEX_SHADER, vertexShaderSource); 104 if (!vertexShader) 105 return 0; 106 unsigned fragmentShader = loadShader(context, GraphicsContext3D::FRAGMENT_SHADER, fragmentShaderSource); 107 if (!fragmentShader) 108 return 0; 109 unsigned program = context->createProgram(); 110 if (!program) 111 return 0; 112 context->attachShader(program, vertexShader); 113 context->attachShader(program, fragmentShader); 114 context->linkProgram(program); 115 int linkStatus = 0; 116 context->getProgramiv(program, GraphicsContext3D::LINK_STATUS, &linkStatus); 117 if (!linkStatus) 118 context->deleteProgram(program); 119 context->deleteShader(vertexShader); 120 context->deleteShader(fragmentShader); 121 return program; 122} 123 124Shader::Shader(GraphicsContext3D* context, unsigned program) 125 : m_context(context) 126 , m_program(program) 127{ 128} 129 130Shader::~Shader() 131{ 132 m_context->deleteProgram(m_program); 133} 134 135// static 136String Shader::generateVertex(Shader::VertexType vertexType, Shader::FillType fillType) 137{ 138 StringBuilder builder; 139 switch (vertexType) { 140 case TwoDimensional: 141 builder.append( 142 "uniform mat3 matrix;\n" 143 "attribute vec2 position;\n"); 144 break; 145 case LoopBlinnInterior: 146 builder.append( 147 "uniform mat4 worldViewProjection;\n" 148 "attribute vec2 position;\n"); 149 break; 150 case LoopBlinnExterior: 151 builder.append( 152 "uniform mat4 worldViewProjection;\n" 153 "attribute vec2 position;\n" 154 "attribute vec3 klm;\n" 155 "varying vec3 v_klm;\n"); 156 break; 157 } 158 159 if (fillType == TextureFill) { 160 builder.append( 161 "uniform mat3 texMatrix;\n" 162 "varying vec3 texCoord;\n"); 163 } 164 165 builder.append( 166 "void main() {\n"); 167 168 if (vertexType == TwoDimensional) { 169 builder.append( 170 "gl_Position = vec4(matrix * vec3(position, 1.0), 1.0);\n"); 171 } else { 172 builder.append( 173 "gl_Position = worldViewProjection * vec4(position, 0.0, 1.0);\n"); 174 if (vertexType == LoopBlinnExterior) { 175 builder.append( 176 "v_klm = klm;\n"); 177 } 178 } 179 180 if (fillType == TextureFill) { 181 builder.append( 182 "texCoord = texMatrix * vec3(position, 1.0);\n"); 183 } 184 185 builder.append( 186 "}\n"); 187 188 return builder.toString(); 189} 190 191// static 192String Shader::generateFragment(Shader::VertexType vertexType, Shader::FillType fillType, Shader::AntialiasType antialiasType) 193{ 194 StringBuilder builder; 195 builder.append( 196 "#ifdef GL_ES\n" 197 "precision mediump float;\n" 198 "#endif\n"); 199 200 if (vertexType == LoopBlinnExterior) { 201 if (antialiasType == Antialiased) { 202 builder.append( 203 "#extension GL_OES_standard_derivatives : enable\n"); 204 } 205 builder.append( 206 "varying vec3 v_klm;\n"); 207 } 208 209 switch (fillType) { 210 case SolidFill: 211 builder.append( 212 "uniform vec4 color;\n"); 213 break; 214 case TextureFill: 215 builder.append( 216 "uniform sampler2D sampler;\n" 217 "uniform float globalAlpha;\n" 218 "varying vec3 texCoord;\n"); 219 break; 220 } 221 222 builder.append( 223 "void main() {\n"); 224 225 if (vertexType != LoopBlinnExterior) { 226 builder.append( 227 "float alpha = 1.0;\n"); 228 } else { 229 if (antialiasType == Antialiased) { 230 builder.append( 231 " // Gradients\n" 232 " vec3 px = dFdx(v_klm);\n" 233 " vec3 py = dFdy(v_klm);\n" 234 "\n" 235 " // Chain rule\n" 236 " float k2 = v_klm.x * v_klm.x;\n" 237 " float c = k2 * v_klm.x - v_klm.y * v_klm.z;\n" 238 " float k23 = 3.0 * k2;\n" 239 " float cx = k23 * px.x - v_klm.z * px.y - v_klm.y * px.z;\n" 240 " float cy = k23 * py.x - v_klm.z * py.y - v_klm.y * py.z;\n" 241 "\n" 242 " // Signed distance\n" 243 " float sd = c / sqrt(cx * cx + cy * cy);\n" 244 "\n" 245 " // Linear alpha\n" 246 " // FIXME: figure out why this needs to be\n" 247 " // negated compared to the HLSL version, and also why\n" 248 " // we need an adjustment by +1.0 for it to look good.\n" 249 " // float alpha = clamp(0.5 - sd, 0.0, 1.0);\n" 250 " float alpha = clamp(sd + 0.5, 0.0, 1.0);\n"); 251 } else { 252 builder.append( 253 " float t = v_klm.x * v_klm.x * v_klm.x - v_klm.y * v_klm.z;\n" 254 " float alpha = clamp(sign(t), 0.0, 1.0);\n"); 255 } 256 } 257 258 switch (fillType) { 259 case SolidFill: 260 builder.append( 261 "gl_FragColor = color * alpha;\n"); 262 break; 263 case TextureFill: 264 builder.append( 265 "gl_FragColor = texture2D(sampler, texCoord.xy) * alpha * globalAlpha;\n"); 266 break; 267 } 268 269 builder.append( 270 "}\n"); 271 272 return builder.toString(); 273} 274 275} // namespace WebCore 276 277#endif 278