1/*
2 * Copyright (C) 2012 Adobe Systems Incorporated. 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 *
8 * 1. Redistributions of source code must retain the above
9 *    copyright notice, this list of conditions and the following
10 *    disclaimer.
11 * 2. Redistributions in binary form must reproduce the above
12 *    copyright notice, this list of conditions and the following
13 *    disclaimer in the documentation and/or other materials
14 *    provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
21 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
25 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
26 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include "config.h"
31
32#if ENABLE(CSS_SHADERS) && USE(3D_GRAPHICS)
33#include "CustomFilterCompiledProgram.h"
34
35#include "CustomFilterGlobalContext.h"
36
37namespace WebCore {
38
39CustomFilterCompiledProgram::CustomFilterCompiledProgram(PassRefPtr<GraphicsContext3D> context, const String& validatedVertexShader, const String& validatedFragmentShader, CustomFilterProgramType programType)
40    : m_context(context)
41    , m_program(0)
42    , m_positionAttribLocation(-1)
43    , m_texAttribLocation(-1)
44    , m_meshAttribLocation(-1)
45    , m_triangleAttribLocation(-1)
46    , m_meshBoxLocation(-1)
47    , m_projectionMatrixLocation(-1)
48    , m_tileSizeLocation(-1)
49    , m_meshSizeLocation(-1)
50    , m_samplerLocation(-1)
51    , m_samplerSizeLocation(-1)
52    , m_contentSamplerLocation(-1)
53    , m_isInitialized(false)
54{
55    ASSERT(!validatedVertexShader.isNull() && !validatedFragmentShader.isNull());
56
57    m_context->makeContextCurrent();
58
59    Platform3DObject vertexShader = compileShader(GraphicsContext3D::VERTEX_SHADER, validatedVertexShader);
60    if (!vertexShader)
61        return;
62
63    Platform3DObject fragmentShader = compileShader(GraphicsContext3D::FRAGMENT_SHADER, validatedFragmentShader);
64    if (!fragmentShader) {
65        m_context->deleteShader(vertexShader);
66        return;
67    }
68
69    m_program = linkProgram(vertexShader, fragmentShader);
70
71    m_context->deleteShader(vertexShader);
72    m_context->deleteShader(fragmentShader);
73
74    if (!m_program)
75        return;
76
77    initializeParameterLocations(programType);
78
79    m_isInitialized = true;
80}
81
82Platform3DObject CustomFilterCompiledProgram::compileShader(GC3Denum shaderType, const String& shaderString)
83{
84    ASSERT(!shaderString.isNull());
85
86    Platform3DObject shader = m_context->createShader(shaderType);
87    m_context->shaderSource(shader, shaderString);
88    m_context->compileShader(shader);
89
90    int compiled = 0;
91    m_context->getShaderiv(shader, GraphicsContext3D::COMPILE_STATUS, &compiled);
92    if (!compiled) {
93        // FIXME: This is an invalid shader. Throw some errors.
94        // https://bugs.webkit.org/show_bug.cgi?id=74416
95        m_context->deleteShader(shader);
96        return 0;
97    }
98
99    return shader;
100}
101
102Platform3DObject CustomFilterCompiledProgram::linkProgram(Platform3DObject vertexShader, Platform3DObject fragmentShader)
103{
104    Platform3DObject program = m_context->createProgram();
105    m_context->attachShader(program, vertexShader);
106    m_context->attachShader(program, fragmentShader);
107    m_context->linkProgram(program);
108
109    int linked = 0;
110    m_context->getProgramiv(program, GraphicsContext3D::LINK_STATUS, &linked);
111    if (!linked) {
112        // FIXME: Invalid vertex/fragment shader combination. Throw some errors here.
113        // https://bugs.webkit.org/show_bug.cgi?id=74416
114        m_context->deleteProgram(program);
115        return 0;
116    }
117
118    return program;
119}
120
121void CustomFilterCompiledProgram::initializeParameterLocations(CustomFilterProgramType programType)
122{
123    m_positionAttribLocation = m_context->getAttribLocation(m_program, "a_position");
124    m_texAttribLocation = m_context->getAttribLocation(m_program, "a_texCoord");
125    m_meshAttribLocation = m_context->getAttribLocation(m_program, "a_meshCoord");
126    m_triangleAttribLocation = m_context->getAttribLocation(m_program, "a_triangleCoord");
127    m_meshBoxLocation = m_context->getUniformLocation(m_program, "u_meshBox");
128    m_tileSizeLocation = m_context->getUniformLocation(m_program, "u_tileSize");
129    m_meshSizeLocation = m_context->getUniformLocation(m_program, "u_meshSize");
130    m_projectionMatrixLocation = m_context->getUniformLocation(m_program, "u_projectionMatrix");
131    m_samplerSizeLocation = m_context->getUniformLocation(m_program, "u_textureSize");
132    m_contentSamplerLocation = m_context->getUniformLocation(m_program, "u_contentTexture");
133    if (programType == PROGRAM_TYPE_BLENDS_ELEMENT_TEXTURE) {
134        // When the author uses the CSS mix function in a custom filter, WebKit adds the internal
135        // symbol css_u_texture to the shader code, which references the texture of the element.
136        m_samplerLocation = m_context->getUniformLocation(m_program, "css_u_texture");
137    }
138}
139
140int CustomFilterCompiledProgram::uniformLocationByName(const String& name)
141{
142    ASSERT(m_isInitialized);
143    // FIXME: Improve this by caching the uniform locations.
144    return m_context->getUniformLocation(m_program, name);
145}
146
147CustomFilterCompiledProgram::~CustomFilterCompiledProgram()
148{
149    if (m_program) {
150        m_context->makeContextCurrent();
151        m_context->deleteProgram(m_program);
152    }
153}
154
155} // namespace WebCore
156#endif // ENABLE(CSS_SHADERS) && USE(3D_GRAPHICS)
157