Home | History | Annotate | Download | only in gpu
      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 
     43 namespace WebCore {
     44 
     45 // static
     46 void 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
     60 void 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
     81 unsigned 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
    101 unsigned 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 
    124 Shader::Shader(GraphicsContext3D* context, unsigned program)
    125     : m_context(context)
    126     , m_program(program)
    127 {
    128 }
    129 
    130 Shader::~Shader()
    131 {
    132     m_context->deleteProgram(m_program);
    133 }
    134 
    135 // static
    136 String 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
    192 String 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