• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
3  * Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved.
4  * Copyright (C) 2012 Company 100, Inc. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above
11  *    copyright notice, this list of conditions and the following
12  *    disclaimer.
13  * 2. Redistributions in binary form must reproduce the above
14  *    copyright notice, this list of conditions and the following
15  *    disclaimer in the documentation and/or other materials
16  *    provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
23  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
27  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
28  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include "config.h"
33 #include "platform/graphics/filters/custom/CustomFilterRenderer.h"
34 
35 #include "platform/graphics/GraphicsContext3D.h"
36 #include "platform/graphics/filters/custom/CustomFilterArrayParameter.h"
37 #include "platform/graphics/filters/custom/CustomFilterCompiledProgram.h"
38 #include "platform/graphics/filters/custom/CustomFilterMesh.h"
39 #include "platform/graphics/filters/custom/CustomFilterNumberParameter.h"
40 #include "platform/graphics/filters/custom/CustomFilterParameter.h"
41 #include "platform/graphics/filters/custom/CustomFilterTransformParameter.h"
42 #include "platform/transforms/TransformationMatrix.h"
43 
44 namespace WebCore {
45 
orthogonalProjectionMatrix(TransformationMatrix & matrix,float left,float right,float bottom,float top)46 static void orthogonalProjectionMatrix(TransformationMatrix& matrix, float left, float right, float bottom, float top)
47 {
48     ASSERT(matrix.isIdentity());
49 
50     float deltaX = right - left;
51     float deltaY = top - bottom;
52     if (!deltaX || !deltaY)
53         return;
54     matrix.setM11(2.0f / deltaX);
55     matrix.setM41(-(right + left) / deltaX);
56     matrix.setM22(2.0f / deltaY);
57     matrix.setM42(-(top + bottom) / deltaY);
58 
59     // Use big enough near/far values, so that simple rotations of rather large objects will not
60     // get clipped. 10000 should cover most of the screen resolutions.
61     const float farValue = 10000;
62     const float nearValue = -10000;
63     matrix.setM33(-2.0f / (farValue - nearValue));
64     matrix.setM43(- (farValue + nearValue) / (farValue - nearValue));
65     matrix.setM44(1.0f);
66 }
67 
create(PassRefPtr<GraphicsContext3D> context,CustomFilterProgramType programType,const CustomFilterParameterList & parameters,unsigned meshRows,unsigned meshColumns,CustomFilterMeshType meshType)68 PassRefPtr<CustomFilterRenderer> CustomFilterRenderer::create(PassRefPtr<GraphicsContext3D> context, CustomFilterProgramType programType, const CustomFilterParameterList& parameters,
69     unsigned meshRows, unsigned meshColumns, CustomFilterMeshType meshType)
70 {
71     return adoptRef(new CustomFilterRenderer(context, programType, parameters, meshRows, meshColumns, meshType));
72 }
73 
CustomFilterRenderer(PassRefPtr<GraphicsContext3D> context,CustomFilterProgramType programType,const CustomFilterParameterList & parameters,unsigned meshRows,unsigned meshColumns,CustomFilterMeshType meshType)74 CustomFilterRenderer::CustomFilterRenderer(PassRefPtr<GraphicsContext3D> context, CustomFilterProgramType programType, const CustomFilterParameterList& parameters,
75     unsigned meshRows, unsigned meshColumns, CustomFilterMeshType meshType)
76     : m_context(context)
77     , m_programType(programType)
78     , m_parameters(parameters)
79     , m_meshRows(meshRows)
80     , m_meshColumns(meshColumns)
81     , m_meshType(meshType)
82 {
83 }
84 
~CustomFilterRenderer()85 CustomFilterRenderer::~CustomFilterRenderer()
86 {
87 }
88 
premultipliedAlpha() const89 bool CustomFilterRenderer::premultipliedAlpha() const
90 {
91     return m_programType == ProgramTypeBlendsElementTexture;
92 }
93 
programNeedsInputTexture() const94 bool CustomFilterRenderer::programNeedsInputTexture() const
95 {
96     ASSERT(m_compiledProgram.get());
97     return m_compiledProgram->samplerLocation() != -1;
98 }
99 
draw(Platform3DObject inputTexture,const IntSize & size)100 void CustomFilterRenderer::draw(Platform3DObject inputTexture, const IntSize& size)
101 {
102     // FIXME: We would need something like CustomFilterRendererState that will contain the size and other parameters in the future. We should pass that to bindProgramBuffers instead of storing it.
103     // https://bugs.webkit.org/show_bug.cgi?id=100107
104     m_contextSize = size;
105 
106     bindProgramAndBuffers(inputTexture);
107     m_context->drawElements(GL_TRIANGLES, m_mesh->indicesCount(), GL_UNSIGNED_SHORT, 0);
108     unbindVertexAttributes();
109 }
110 
setCompiledProgram(PassRefPtr<CustomFilterCompiledProgram> compiledProgram)111 void CustomFilterRenderer::setCompiledProgram(PassRefPtr<CustomFilterCompiledProgram> compiledProgram)
112 {
113     m_compiledProgram = compiledProgram;
114 }
115 
prepareForDrawing()116 bool CustomFilterRenderer::prepareForDrawing()
117 {
118     m_context->makeContextCurrent();
119     if (!m_compiledProgram || !m_compiledProgram->isInitialized())
120         return false;
121     initializeMeshIfNeeded();
122     return true;
123 }
124 
initializeMeshIfNeeded()125 void CustomFilterRenderer::initializeMeshIfNeeded()
126 {
127     if (m_mesh.get())
128         return;
129 
130     // FIXME: Sharing the mesh would just save the time needed to upload it to the GPU, so I assume we could
131     // benchmark that for performance.
132     // https://bugs.webkit.org/show_bug.cgi?id=88429
133     m_mesh = CustomFilterMesh::create(m_context.get(), m_meshColumns, m_meshRows, FloatRect(0, 0, 1, 1), m_meshType);
134 }
135 
bindVertexAttribute(int attributeLocation,unsigned size,unsigned offset)136 void CustomFilterRenderer::bindVertexAttribute(int attributeLocation, unsigned size, unsigned offset)
137 {
138     if (attributeLocation != -1) {
139         m_context->vertexAttribPointer(attributeLocation, size, GL_FLOAT, false, m_mesh->bytesPerVertex(), offset);
140         m_context->enableVertexAttribArray(attributeLocation);
141     }
142 }
143 
unbindVertexAttribute(int attributeLocation)144 void CustomFilterRenderer::unbindVertexAttribute(int attributeLocation)
145 {
146     if (attributeLocation != -1)
147         m_context->disableVertexAttribArray(attributeLocation);
148 }
149 
bindProgramArrayParameters(int uniformLocation,CustomFilterArrayParameter * arrayParameter)150 void CustomFilterRenderer::bindProgramArrayParameters(int uniformLocation, CustomFilterArrayParameter* arrayParameter)
151 {
152     unsigned parameterSize = arrayParameter->size();
153     Vector<GC3Dfloat> floatVector;
154 
155     for (unsigned i = 0; i < parameterSize; ++i)
156         floatVector.append(arrayParameter->valueAt(i));
157 
158     m_context->uniform1fv(uniformLocation, parameterSize, floatVector.data());
159 }
160 
bindProgramNumberParameters(int uniformLocation,CustomFilterNumberParameter * numberParameter)161 void CustomFilterRenderer::bindProgramNumberParameters(int uniformLocation, CustomFilterNumberParameter* numberParameter)
162 {
163     switch (numberParameter->size()) {
164     case 1:
165         m_context->uniform1f(uniformLocation, numberParameter->valueAt(0));
166         break;
167     case 2:
168         m_context->uniform2f(uniformLocation, numberParameter->valueAt(0), numberParameter->valueAt(1));
169         break;
170     case 3:
171         m_context->uniform3f(uniformLocation, numberParameter->valueAt(0), numberParameter->valueAt(1), numberParameter->valueAt(2));
172         break;
173     case 4:
174         m_context->uniform4f(uniformLocation, numberParameter->valueAt(0), numberParameter->valueAt(1), numberParameter->valueAt(2), numberParameter->valueAt(3));
175         break;
176     default:
177         ASSERT_NOT_REACHED();
178     }
179 }
180 
bindProgramTransformParameter(int uniformLocation,CustomFilterTransformParameter * transformParameter)181 void CustomFilterRenderer::bindProgramTransformParameter(int uniformLocation, CustomFilterTransformParameter* transformParameter)
182 {
183     TransformationMatrix matrix;
184     if (m_contextSize.width() && m_contextSize.height()) {
185         // The viewport is a box with the size of 1 unit, so we are scaling up here to make sure that translations happen using real pixel
186         // units. At the end we scale back down in order to map it back to the original box. Note that transforms come in reverse order, because it is
187         // supposed to multiply to the left of the coordinates of the vertices.
188         // Note that the origin (0, 0) of the viewport is in the middle of the context, so there's no need to change the origin of the transform
189         // in order to rotate around the middle of mesh.
190         matrix.scale3d(1.0 / m_contextSize.width(), 1.0 / m_contextSize.height(), 1);
191         transformParameter->applyTransform(matrix, m_contextSize);
192         matrix.scale3d(m_contextSize.width(), m_contextSize.height(), 1);
193     }
194     float glMatrix[16];
195     matrix.toColumnMajorFloatArray(glMatrix);
196     m_context->uniformMatrix4fv(uniformLocation, 1, false, &glMatrix[0]);
197 }
198 
bindProgramParameters()199 void CustomFilterRenderer::bindProgramParameters()
200 {
201     // FIXME: Find a way to reset uniforms that are not specified in CSS. This is needed to avoid using values
202     // set by other previous rendered filters.
203     // https://bugs.webkit.org/show_bug.cgi?id=76440
204 
205     size_t parametersSize = m_parameters.size();
206     for (size_t i = 0; i < parametersSize; ++i) {
207         CustomFilterParameter* parameter = m_parameters.at(i).get();
208         int uniformLocation = m_compiledProgram->uniformLocationByName(parameter->name());
209         if (uniformLocation == -1)
210             continue;
211         switch (parameter->parameterType()) {
212         case CustomFilterParameter::Array:
213             bindProgramArrayParameters(uniformLocation, static_cast<CustomFilterArrayParameter*>(parameter));
214             break;
215         case CustomFilterParameter::Number:
216             bindProgramNumberParameters(uniformLocation, static_cast<CustomFilterNumberParameter*>(parameter));
217             break;
218         case CustomFilterParameter::Transform:
219             bindProgramTransformParameter(uniformLocation, static_cast<CustomFilterTransformParameter*>(parameter));
220             break;
221         }
222     }
223 }
224 
bindProgramAndBuffers(Platform3DObject inputTexture)225 void CustomFilterRenderer::bindProgramAndBuffers(Platform3DObject inputTexture)
226 {
227     ASSERT(m_compiledProgram->isInitialized());
228 
229     m_context->useProgram(m_compiledProgram->program());
230 
231     if (programNeedsInputTexture()) {
232         // We should be binding the DOM element texture sampler only if the author is using the CSS mix function.
233         ASSERT(m_programType == ProgramTypeBlendsElementTexture);
234         ASSERT(m_compiledProgram->samplerLocation() != -1);
235 
236         m_context->activeTexture(GL_TEXTURE0);
237         m_context->uniform1i(m_compiledProgram->samplerLocation(), 0);
238         m_context->bindTexture(GL_TEXTURE_2D, inputTexture);
239         m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
240         m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
241         m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
242         m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
243     }
244 
245     if (m_compiledProgram->projectionMatrixLocation() != -1) {
246         TransformationMatrix projectionMatrix;
247         orthogonalProjectionMatrix(projectionMatrix, -0.5, 0.5, -0.5, 0.5);
248         float glProjectionMatrix[16];
249         projectionMatrix.toColumnMajorFloatArray(glProjectionMatrix);
250         m_context->uniformMatrix4fv(m_compiledProgram->projectionMatrixLocation(), 1, false, &glProjectionMatrix[0]);
251     }
252 
253     ASSERT(m_meshColumns);
254     ASSERT(m_meshRows);
255 
256     if (m_compiledProgram->meshSizeLocation() != -1)
257         m_context->uniform2f(m_compiledProgram->meshSizeLocation(), m_meshColumns, m_meshRows);
258 
259     if (m_compiledProgram->tileSizeLocation() != -1)
260         m_context->uniform2f(m_compiledProgram->tileSizeLocation(), 1.0 / m_meshColumns, 1.0 / m_meshRows);
261 
262     if (m_compiledProgram->meshBoxLocation() != -1) {
263         // FIXME: This will change when filter margins will be implemented,
264         // see https://bugs.webkit.org/show_bug.cgi?id=71400
265         m_context->uniform4f(m_compiledProgram->meshBoxLocation(), -0.5, -0.5, 1.0, 1.0);
266     }
267 
268     if (m_compiledProgram->samplerSizeLocation() != -1)
269         m_context->uniform2f(m_compiledProgram->samplerSizeLocation(), m_contextSize.width(), m_contextSize.height());
270 
271     m_context->bindBuffer(GL_ARRAY_BUFFER, m_mesh->verticesBufferObject());
272     m_context->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_mesh->elementsBufferObject());
273 
274     bindVertexAttribute(m_compiledProgram->positionAttribLocation(), PositionAttribSize, PositionAttribOffset);
275     bindVertexAttribute(m_compiledProgram->texAttribLocation(), TexAttribSize, TexAttribOffset);
276     bindVertexAttribute(m_compiledProgram->meshAttribLocation(), MeshAttribSize, MeshAttribOffset);
277     if (m_meshType == MeshTypeDetached)
278         bindVertexAttribute(m_compiledProgram->triangleAttribLocation(), TriangleAttribSize, TriangleAttribOffset);
279 
280     bindProgramParameters();
281 }
282 
unbindVertexAttributes()283 void CustomFilterRenderer::unbindVertexAttributes()
284 {
285     unbindVertexAttribute(m_compiledProgram->positionAttribLocation());
286     unbindVertexAttribute(m_compiledProgram->texAttribLocation());
287     unbindVertexAttribute(m_compiledProgram->meshAttribLocation());
288     if (m_meshType == MeshTypeDetached)
289         unbindVertexAttribute(m_compiledProgram->triangleAttribLocation());
290 }
291 
292 } // namespace WebCore
293