[CSS Shaders] Create constants for vertex attribute sizes and offsets
[WebKit-https.git] / Source / WebCore / platform / graphics / filters / FECustomFilter.cpp
1 /*
2  * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
3  * Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above
10  *    copyright notice, this list of conditions and the following
11  *    disclaimer.
12  * 2. Redistributions in binary form must reproduce the above
13  *    copyright notice, this list of conditions and the following
14  *    disclaimer in the documentation and/or other materials
15  *    provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
22  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
26  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
27  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30
31 #include "config.h"
32
33 #if ENABLE(CSS_SHADERS) && USE(3D_GRAPHICS)
34 #include "FECustomFilter.h"
35
36 #include "CustomFilterArrayParameter.h"
37 #include "CustomFilterCompiledProgram.h"
38 #include "CustomFilterConstants.h"
39 #include "CustomFilterGlobalContext.h"
40 #include "CustomFilterMesh.h"
41 #include "CustomFilterNumberParameter.h"
42 #include "CustomFilterParameter.h"
43 #include "CustomFilterProgram.h"
44 #include "CustomFilterTransformParameter.h"
45 #include "CustomFilterValidatedProgram.h"
46 #include "DrawingBuffer.h"
47 #include "Extensions3D.h"
48 #include "GraphicsContext3D.h"
49 #include "ImageData.h"
50 #include "NotImplemented.h"
51 #include "RenderTreeAsText.h"
52 #include "TextStream.h"
53 #include "TilingData.h"
54 #include "TransformationMatrix.h"
55
56 #include <wtf/Uint8ClampedArray.h>
57
58 namespace WebCore {
59
60 static const int kMaxSampleCount = 4;
61
62 static void orthogonalProjectionMatrix(TransformationMatrix& matrix, float left, float right, float bottom, float top)
63 {
64     ASSERT(matrix.isIdentity());
65     
66     float deltaX = right - left;
67     float deltaY = top - bottom;
68     if (!deltaX || !deltaY)
69         return;
70     matrix.setM11(2.0f / deltaX);
71     matrix.setM41(-(right + left) / deltaX);
72     matrix.setM22(2.0f / deltaY);
73     matrix.setM42(-(top + bottom) / deltaY);
74
75     // Use big enough near/far values, so that simple rotations of rather large objects will not
76     // get clipped. 10000 should cover most of the screen resolutions.
77     const float farValue = 10000;
78     const float nearValue = -10000;
79     matrix.setM33(-2.0f / (farValue - nearValue));
80     matrix.setM43(- (farValue + nearValue) / (farValue - nearValue));
81     matrix.setM44(1.0f);
82 }
83
84 FECustomFilter::FECustomFilter(Filter* filter, CustomFilterGlobalContext* customFilterGlobalContext, PassRefPtr<CustomFilterValidatedProgram> validatedProgram, const CustomFilterParameterList& parameters,
85                                unsigned meshRows, unsigned meshColumns, CustomFilterOperation::MeshBoxType,
86                                CustomFilterOperation::MeshType meshType)
87     : FilterEffect(filter)
88     , m_globalContext(customFilterGlobalContext)
89     , m_validatedProgram(validatedProgram)
90     , m_compiledProgram(0) // Don't compile the program unless we need to paint.
91     , m_inputTexture(0)
92     , m_frameBuffer(0)
93     , m_depthBuffer(0)
94     , m_destTexture(0)
95     , m_triedMultisampleBuffer(false)
96     , m_multisampleFrameBuffer(0)
97     , m_multisampleRenderBuffer(0)
98     , m_multisampleDepthBuffer(0)
99     , m_parameters(parameters)
100     , m_meshRows(meshRows)
101     , m_meshColumns(meshColumns)
102     , m_meshType(meshType)
103 {
104     // An FECustomFilter shouldn't have been created unless the program passed validation.
105     ASSERT(m_validatedProgram->isInitialized());
106 }
107
108 PassRefPtr<FECustomFilter> FECustomFilter::create(Filter* filter, CustomFilterGlobalContext* customFilterGlobalContext, PassRefPtr<CustomFilterValidatedProgram> validatedProgram, const CustomFilterParameterList& parameters,
109                                            unsigned meshRows, unsigned meshColumns, CustomFilterOperation::MeshBoxType meshBoxType,
110                                            CustomFilterOperation::MeshType meshType)
111 {
112     return adoptRef(new FECustomFilter(filter, customFilterGlobalContext, validatedProgram, parameters, meshRows, meshColumns, meshBoxType, meshType));
113 }
114
115 FECustomFilter::~FECustomFilter()
116 {
117     deleteRenderBuffers();
118 }
119
120 void FECustomFilter::deleteRenderBuffers()
121 {
122     if (!m_context)
123         return;
124     m_context->makeContextCurrent();
125     if (m_inputTexture) {
126         m_context->deleteTexture(m_inputTexture);
127         m_inputTexture = 0;
128     }
129     if (m_frameBuffer) {
130         // Make sure to unbind any framebuffer from the context first, otherwise
131         // some platforms might refuse to bind the same buffer id again.
132         m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, 0);
133         m_context->deleteFramebuffer(m_frameBuffer);
134         m_frameBuffer = 0;
135     }
136     if (m_depthBuffer) {
137         m_context->deleteRenderbuffer(m_depthBuffer);
138         m_depthBuffer = 0;
139     }
140     if (m_destTexture) {
141         m_context->deleteTexture(m_destTexture);
142         m_destTexture = 0;
143     }
144     deleteMultisampleRenderBuffers();
145 }
146
147 void FECustomFilter::deleteMultisampleRenderBuffers()
148 {
149     if (m_multisampleFrameBuffer) {
150         // Make sure to unbind any framebuffer from the context first, otherwise
151         // some platforms might refuse to bind the same buffer id again.
152         m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, 0);
153         m_context->deleteFramebuffer(m_multisampleFrameBuffer);
154         m_multisampleFrameBuffer = 0;
155     }
156     if (m_multisampleRenderBuffer) {
157         m_context->deleteRenderbuffer(m_multisampleRenderBuffer);
158         m_multisampleRenderBuffer = 0;
159     }
160     if (m_multisampleDepthBuffer) {
161         m_context->deleteRenderbuffer(m_multisampleDepthBuffer);
162         m_multisampleDepthBuffer = 0;
163     }
164 }
165
166 void FECustomFilter::platformApplySoftware()
167 {
168     if (!applyShader())
169         clearShaderResult();
170 }
171
172 void FECustomFilter::clearShaderResult()
173 {
174     clearResult();
175     Uint8ClampedArray* dstPixelArray = createUnmultipliedImageResult();
176     if (!dstPixelArray)
177         return;
178
179     FilterEffect* in = inputEffect(0);
180     setIsAlphaImage(in->isAlphaImage());
181     IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
182     in->copyUnmultipliedImage(dstPixelArray, effectDrawingRect);
183 }
184
185 void FECustomFilter::drawFilterMesh(Platform3DObject inputTexture)
186 {
187     bool multisample = canUseMultisampleBuffers();
188     m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, multisample ? m_multisampleFrameBuffer : m_frameBuffer);
189     m_context->viewport(0, 0, m_contextSize.width(), m_contextSize.height());
190     
191     m_context->clearColor(0, 0, 0, 0);
192     m_context->clear(GraphicsContext3D::COLOR_BUFFER_BIT | GraphicsContext3D::DEPTH_BUFFER_BIT);
193     
194     bindProgramAndBuffers(inputTexture);
195     m_context->drawElements(GraphicsContext3D::TRIANGLES, m_mesh->indicesCount(), GraphicsContext3D::UNSIGNED_SHORT, 0);
196     unbindVertexAttributes();
197
198     if (multisample)
199         resolveMultisampleBuffer();
200 }
201
202 bool FECustomFilter::prepareForDrawing(CustomFilterDrawType filterDrawType)
203 {
204     if (!m_context && !initializeContext())
205         return false;
206     m_context->makeContextCurrent();
207
208     // If the shader had compiler errors we cannot draw anything.
209     if (!m_compiledProgram->isInitialized())
210         return false;
211     
212     // Only allocate a texture if the program needs one and the caller doesn't allocate one by itself.
213     if ((programNeedsInputTexture() && (filterDrawType == NEEDS_INPUT_TEXTURE) && !ensureInputTexture())
214         || !ensureFrameBuffer())
215         return false;
216     
217     return true;
218 }
219
220 bool FECustomFilter::programNeedsInputTexture() const
221 {
222     ASSERT(m_compiledProgram.get());
223     return m_compiledProgram->samplerLocation() != -1;
224 }
225
226 bool FECustomFilter::applyShader()
227 {
228     Uint8ClampedArray* dstPixelArray = createUnmultipliedImageResult();
229     if (!dstPixelArray)
230         return false;
231
232     if (!prepareForDrawing())
233         return false;
234
235     FilterEffect* in = inputEffect(0);
236     IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
237     IntSize newContextSize(effectDrawingRect.size());
238     if (!resizeContextIfNeeded(newContextSize))
239         return false;
240
241     bool needsInputTexture = programNeedsInputTexture();
242     if (needsInputTexture) {
243         RefPtr<Uint8ClampedArray> srcPixelArray = in->asUnmultipliedImage(effectDrawingRect);
244         uploadInputTexture(srcPixelArray.get());
245     }
246     drawFilterMesh(needsInputTexture ? m_inputTexture : 0);
247
248     ASSERT(static_cast<size_t>(newContextSize.width() * newContextSize.height() * 4) == dstPixelArray->length());
249     m_context->readPixels(0, 0, newContextSize.width(), newContextSize.height(), GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, dstPixelArray->data());
250
251     return true;
252 }
253
254 bool FECustomFilter::initializeContext()
255 {
256     ASSERT(!m_context.get());
257     m_context = m_globalContext->context();
258     if (!m_context)
259         return false;
260     m_context->makeContextCurrent();
261     m_compiledProgram = m_validatedProgram->compiledProgram();
262
263     // FIXME: Sharing the mesh would just save the time needed to upload it to the GPU, so I assume we could
264     // benchmark that for performance.
265     // https://bugs.webkit.org/show_bug.cgi?id=88429
266     m_mesh = CustomFilterMesh::create(m_context.get(), m_meshColumns, m_meshRows, 
267                                       FloatRect(0, 0, 1, 1),
268                                       m_meshType);
269
270     return true;
271 }
272
273 bool FECustomFilter::ensureInputTexture()
274 {
275     if (!m_inputTexture)
276         m_inputTexture = m_context->createTexture();
277     return m_inputTexture;
278 }
279
280 void FECustomFilter::uploadInputTexture(Uint8ClampedArray* srcPixelArray)
281 {
282     m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_inputTexture);
283     m_context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, m_contextSize.width(), m_contextSize.height(), 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, srcPixelArray->data());
284 }
285
286 bool FECustomFilter::ensureFrameBuffer()
287 {
288     if (!m_frameBuffer)
289         m_frameBuffer = m_context->createFramebuffer();
290     if (!m_depthBuffer)
291         m_depthBuffer = m_context->createRenderbuffer();
292     if (!m_destTexture)
293         m_destTexture = m_context->createTexture();
294     return m_frameBuffer && m_depthBuffer && m_destTexture;
295 }
296
297 bool FECustomFilter::createMultisampleBuffer()
298 {
299     ASSERT(!m_triedMultisampleBuffer);
300     m_triedMultisampleBuffer = true;
301
302     Extensions3D* extensions = m_context->getExtensions();
303     if (!extensions
304         || !extensions->maySupportMultisampling()
305         || !extensions->supports("GL_ANGLE_framebuffer_multisample")
306         || !extensions->supports("GL_ANGLE_framebuffer_blit")
307         || !extensions->supports("GL_OES_rgb8_rgba8"))
308         return false;
309
310     extensions->ensureEnabled("GL_ANGLE_framebuffer_blit");
311     extensions->ensureEnabled("GL_ANGLE_framebuffer_multisample");
312     extensions->ensureEnabled("GL_OES_rgb8_rgba8");
313
314     if (!m_multisampleFrameBuffer)
315         m_multisampleFrameBuffer = m_context->createFramebuffer();
316     if (!m_multisampleRenderBuffer)
317         m_multisampleRenderBuffer = m_context->createRenderbuffer();
318     if (!m_multisampleDepthBuffer)
319         m_multisampleDepthBuffer = m_context->createRenderbuffer();
320
321     return true;
322 }
323
324 void FECustomFilter::resolveMultisampleBuffer()
325 {
326     ASSERT(m_triedMultisampleBuffer && m_multisampleFrameBuffer && m_multisampleRenderBuffer && m_multisampleDepthBuffer);
327     m_context->bindFramebuffer(Extensions3D::READ_FRAMEBUFFER, m_multisampleFrameBuffer);
328     m_context->bindFramebuffer(Extensions3D::DRAW_FRAMEBUFFER, m_frameBuffer);
329
330     ASSERT(m_context->getExtensions());
331     m_context->getExtensions()->blitFramebuffer(0, 0, m_contextSize.width(), m_contextSize.height(), 0, 0, m_contextSize.width(), m_contextSize.height(), GraphicsContext3D::COLOR_BUFFER_BIT, GraphicsContext3D::NEAREST);
332
333     m_context->bindFramebuffer(Extensions3D::READ_FRAMEBUFFER, 0);
334     m_context->bindFramebuffer(Extensions3D::DRAW_FRAMEBUFFER, 0);
335     
336     m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_frameBuffer);
337 }
338
339 bool FECustomFilter::canUseMultisampleBuffers() const
340 {
341     return m_triedMultisampleBuffer && m_multisampleFrameBuffer && m_multisampleRenderBuffer && m_multisampleDepthBuffer;
342 }
343
344 bool FECustomFilter::resizeMultisampleBuffers(const IntSize& newContextSize)
345 {
346     if (!m_triedMultisampleBuffer && !createMultisampleBuffer())
347          return false;
348  
349     if (!canUseMultisampleBuffers())
350         return false;
351
352     int maxSupportedSampleCount = 0;
353     m_context->getIntegerv(Extensions3D::MAX_SAMPLES, &maxSupportedSampleCount);
354     int sampleCount = std::min(kMaxSampleCount, maxSupportedSampleCount);
355     if (!sampleCount) {
356         deleteMultisampleRenderBuffers();
357         return false;
358     }
359
360     Extensions3D* extensions = m_context->getExtensions();
361     ASSERT(extensions);
362     
363     m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_multisampleFrameBuffer);
364
365     m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_multisampleRenderBuffer);
366     extensions->renderbufferStorageMultisample(GraphicsContext3D::RENDERBUFFER, sampleCount, Extensions3D::RGBA8_OES, newContextSize.width(), newContextSize.height());
367     m_context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::RENDERBUFFER, m_multisampleRenderBuffer);
368
369     m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_multisampleDepthBuffer);
370     extensions->renderbufferStorageMultisample(GraphicsContext3D::RENDERBUFFER, sampleCount, GraphicsContext3D::DEPTH_COMPONENT16, newContextSize.width(), newContextSize.height());
371     m_context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_multisampleDepthBuffer);
372
373     m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, 0);
374
375     if (m_context->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) {
376         deleteMultisampleRenderBuffers();
377         return false;
378     }
379
380     return true;
381 }
382
383 bool FECustomFilter::resizeContextIfNeeded(const IntSize& newContextSize)
384 {
385     if (newContextSize.isEmpty())
386         return false;
387     if (m_contextSize == newContextSize)
388         return true;
389
390     int maxTextureSize = 0;
391     m_context->getIntegerv(GraphicsContext3D::MAX_TEXTURE_SIZE, &maxTextureSize);
392     if (newContextSize.height() > maxTextureSize || newContextSize.width() > maxTextureSize)
393         return false;
394
395     return resizeContext(newContextSize);
396 }
397
398 bool FECustomFilter::resizeContext(const IntSize& newContextSize)
399 {
400     bool multisample = resizeMultisampleBuffers(newContextSize);
401
402     m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_frameBuffer);
403     m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_destTexture);
404     // We are going to clear the output buffer anyway, so we can safely initialize the destination texture with garbage data.
405 #if PLATFORM(CHROMIUM)
406     // FIXME: GraphicsContext3D::texImage2DDirect is not implemented on Chromium.
407     m_context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, newContextSize.width(), newContextSize.height(), 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, 0);
408 #else
409     m_context->texImage2DDirect(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, newContextSize.width(), newContextSize.height(), 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, 0);
410 #endif
411     m_context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, m_destTexture, 0);
412  
413     // We don't need the depth buffer for the texture framebuffer, if we already
414     // have a multisample buffer.
415     if (!multisample) {
416         m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_depthBuffer);
417         m_context->renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GraphicsContext3D::DEPTH_COMPONENT16, newContextSize.width(), newContextSize.height());
418         m_context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_depthBuffer);
419     }
420
421     if (m_context->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE)
422         return false;
423
424     if (multisample) {
425         // Clear the framebuffer first, otherwise the first blit will fail.
426         m_context->clearColor(0, 0, 0, 0);
427         m_context->clear(GraphicsContext3D::COLOR_BUFFER_BIT);
428     }
429
430     m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, 0);
431     
432     m_contextSize = newContextSize;
433     return true;
434 }
435
436 void FECustomFilter::bindVertexAttribute(int attributeLocation, unsigned size, unsigned offset)
437 {
438     if (attributeLocation != -1) {
439         m_context->vertexAttribPointer(attributeLocation, size, GraphicsContext3D::FLOAT, false, m_mesh->bytesPerVertex(), offset);
440         m_context->enableVertexAttribArray(attributeLocation);
441     }
442 }
443
444 void FECustomFilter::unbindVertexAttribute(int attributeLocation)
445 {
446     if (attributeLocation != -1)
447         m_context->disableVertexAttribArray(attributeLocation);
448 }
449
450 void FECustomFilter::bindProgramArrayParameters(int uniformLocation, CustomFilterArrayParameter* arrayParameter)
451 {
452     unsigned parameterSize = arrayParameter->size();
453     Vector<GC3Dfloat> floatVector;
454
455     for (unsigned i = 0; i < parameterSize; ++i)
456         floatVector.append(arrayParameter->valueAt(i));
457
458     m_context->uniform1fv(uniformLocation, parameterSize, floatVector.data());
459 }
460
461 void FECustomFilter::bindProgramNumberParameters(int uniformLocation, CustomFilterNumberParameter* numberParameter)
462 {
463     switch (numberParameter->size()) {
464     case 1:
465         m_context->uniform1f(uniformLocation, numberParameter->valueAt(0));
466         break;
467     case 2:
468         m_context->uniform2f(uniformLocation, numberParameter->valueAt(0), numberParameter->valueAt(1));
469         break;
470     case 3:
471         m_context->uniform3f(uniformLocation, numberParameter->valueAt(0), numberParameter->valueAt(1), numberParameter->valueAt(2));
472         break;
473     case 4:
474         m_context->uniform4f(uniformLocation, numberParameter->valueAt(0), numberParameter->valueAt(1), numberParameter->valueAt(2), numberParameter->valueAt(3));
475         break;
476     default:
477         ASSERT_NOT_REACHED();
478     }
479 }
480
481 void FECustomFilter::bindProgramTransformParameter(int uniformLocation, CustomFilterTransformParameter* transformParameter)
482 {
483     TransformationMatrix matrix;
484     if (m_contextSize.width() && m_contextSize.height()) {
485         // The viewport is a box with the size of 1 unit, so we are scalling up here to make sure that translations happen using real pixel
486         // 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 
487         // supposed to multiply to the left of the coordinates of the vertices.
488         // 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
489         // in order to rotate around the middle of mesh.
490         matrix.scale3d(1.0 / m_contextSize.width(), 1.0 / m_contextSize.height(), 1);
491         transformParameter->applyTransform(matrix, m_contextSize);
492         matrix.scale3d(m_contextSize.width(), m_contextSize.height(), 1);
493     }
494     float glMatrix[16];
495     matrix.toColumnMajorFloatArray(glMatrix);
496     m_context->uniformMatrix4fv(uniformLocation, 1, false, &glMatrix[0]);
497 }
498
499 void FECustomFilter::bindProgramParameters()
500 {
501     // FIXME: Find a way to reset uniforms that are not specified in CSS. This is needed to avoid using values
502     // set by other previous rendered filters.
503     // https://bugs.webkit.org/show_bug.cgi?id=76440
504     
505     size_t parametersSize = m_parameters.size();
506     for (size_t i = 0; i < parametersSize; ++i) {
507         CustomFilterParameter* parameter = m_parameters.at(i).get();
508         int uniformLocation = m_compiledProgram->uniformLocationByName(parameter->name());
509         if (uniformLocation == -1)
510             continue;
511         switch (parameter->parameterType()) {
512         case CustomFilterParameter::ARRAY:
513             bindProgramArrayParameters(uniformLocation, static_cast<CustomFilterArrayParameter*>(parameter));
514             break;
515         case CustomFilterParameter::NUMBER:
516             bindProgramNumberParameters(uniformLocation, static_cast<CustomFilterNumberParameter*>(parameter));
517             break;
518         case CustomFilterParameter::TRANSFORM:
519             bindProgramTransformParameter(uniformLocation, static_cast<CustomFilterTransformParameter*>(parameter));
520             break;
521         }
522     }
523 }
524
525 void FECustomFilter::bindProgramAndBuffers(Platform3DObject inputTexture)
526 {
527     ASSERT(m_compiledProgram->isInitialized());
528
529     m_context->useProgram(m_compiledProgram->program());
530     
531     if (programNeedsInputTexture()) {
532         // We should be binding the DOM element texture sampler only if the author is using the CSS mix function.
533         ASSERT(m_validatedProgram->programInfo().programType() == PROGRAM_TYPE_BLENDS_ELEMENT_TEXTURE);
534         ASSERT(m_compiledProgram->samplerLocation() != -1);
535
536         m_context->activeTexture(GraphicsContext3D::TEXTURE0);
537         m_context->uniform1i(m_compiledProgram->samplerLocation(), 0);
538         m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, inputTexture);
539         m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR);
540         m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR);
541         m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE);
542         m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE);
543     }
544     
545     if (m_compiledProgram->projectionMatrixLocation() != -1) {
546         TransformationMatrix projectionMatrix; 
547         orthogonalProjectionMatrix(projectionMatrix, -0.5, 0.5, -0.5, 0.5);
548         float glProjectionMatrix[16];
549         projectionMatrix.toColumnMajorFloatArray(glProjectionMatrix);
550         m_context->uniformMatrix4fv(m_compiledProgram->projectionMatrixLocation(), 1, false, &glProjectionMatrix[0]);
551     }
552
553     ASSERT(m_meshColumns);
554     ASSERT(m_meshRows);
555
556     if (m_compiledProgram->meshSizeLocation() != -1)
557         m_context->uniform2f(m_compiledProgram->meshSizeLocation(), m_meshColumns, m_meshRows);
558
559     if (m_compiledProgram->tileSizeLocation() != -1)
560         m_context->uniform2f(m_compiledProgram->tileSizeLocation(), 1.0 / m_meshColumns, 1.0 / m_meshRows);
561
562     if (m_compiledProgram->meshBoxLocation() != -1) {
563         // FIXME: This will change when filter margins will be implemented,
564         // see https://bugs.webkit.org/show_bug.cgi?id=71400
565         m_context->uniform4f(m_compiledProgram->meshBoxLocation(), -0.5, -0.5, 1.0, 1.0);
566     }
567
568     if (m_compiledProgram->samplerSizeLocation() != -1)
569         m_context->uniform2f(m_compiledProgram->samplerSizeLocation(), m_contextSize.width(), m_contextSize.height());
570     
571     m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_mesh->verticesBufferObject());
572     m_context->bindBuffer(GraphicsContext3D::ELEMENT_ARRAY_BUFFER, m_mesh->elementsBufferObject());
573
574     bindVertexAttribute(m_compiledProgram->positionAttribLocation(), PositionAttribSize, PositionAttribOffset);
575     bindVertexAttribute(m_compiledProgram->texAttribLocation(), TexAttribSize, TexAttribOffset);
576     // FIXME: Get rid of the internal tex coord attribute "css_a_texCoord". 
577     // https://bugs.webkit.org/show_bug.cgi?id=94358
578     bindVertexAttribute(m_compiledProgram->internalTexCoordAttribLocation(), TexAttribSize, TexAttribOffset);
579     bindVertexAttribute(m_compiledProgram->meshAttribLocation(), MeshAttribSize, MeshAttribOffset);
580     if (m_meshType == CustomFilterOperation::DETACHED)
581         bindVertexAttribute(m_compiledProgram->triangleAttribLocation(), TriangleAttribSize, TriangleAttribOffset);
582     
583     bindProgramParameters();
584 }
585
586 void FECustomFilter::unbindVertexAttributes()
587 {
588     unbindVertexAttribute(m_compiledProgram->positionAttribLocation());
589     unbindVertexAttribute(m_compiledProgram->texAttribLocation());
590     unbindVertexAttribute(m_compiledProgram->internalTexCoordAttribLocation());
591     unbindVertexAttribute(m_compiledProgram->meshAttribLocation());
592     if (m_meshType == CustomFilterOperation::DETACHED)
593         unbindVertexAttribute(m_compiledProgram->triangleAttribLocation());
594 }
595
596 void FECustomFilter::dump()
597 {
598 }
599
600 TextStream& FECustomFilter::externalRepresentation(TextStream& ts, int indent) const
601 {
602     writeIndent(ts, indent);
603     ts << "[feCustomFilter";
604     FilterEffect::externalRepresentation(ts);
605     ts << "]\n";
606     inputEffect(0)->externalRepresentation(ts, indent + 1);
607     return ts;
608 }
609
610 } // namespace WebCore
611
612 #endif // ENABLE(CSS_SHADERS) && USE(3D_GRAPHICS)