Part 2 of removing PlatformString.h, remove PlatformString.h
[WebKit-https.git] / Source / WebCore / platform / graphics / blackberry / LayerFilterRenderer.cpp
1 /*
2  * Copyright (C) 2012 Research In Motion Limited. All rights reserved.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18
19 #include "config.h"
20
21 #if USE(ACCELERATED_COMPOSITING) && ENABLE(CSS_FILTERS)
22
23 #include "LayerFilterRenderer.h"
24
25 #include "FilterOperation.h"
26 #include "LayerCompositingThread.h"
27 #include "LayerRenderer.h"
28 #include "NotImplemented.h"
29 #include "TextureCacheCompositingThread.h"
30
31 #include <BlackBerryPlatformGraphics.h>
32 #include <BlackBerryPlatformLog.h>
33 #include <Vector.h>
34
35 #include <cstring>
36 #include <limits>
37 #include <wtf/text/WTFString.h>
38
39 namespace WebCore {
40
41 static int operationTypeToProgramID(const FilterOperation::OperationType& t)
42 {
43     switch (t) {
44     case FilterOperation::GRAYSCALE:
45         return LayerData::CSSFilterShaderGrayscale;
46     case FilterOperation::SEPIA:
47         return LayerData::CSSFilterShaderSepia;
48     case FilterOperation::SATURATE:
49         return LayerData::CSSFilterShaderSaturate;
50     case FilterOperation::HUE_ROTATE:
51         return LayerData::CSSFilterShaderHueRotate;
52     case FilterOperation::INVERT:
53         return LayerData::CSSFilterShaderInvert;
54     case FilterOperation::OPACITY:
55         return LayerData::CSSFilterShaderOpacity;
56     case FilterOperation::BRIGHTNESS:
57         return LayerData::CSSFilterShaderBrightness;
58     case FilterOperation::CONTRAST:
59         return LayerData::CSSFilterShaderContrast;
60     case FilterOperation::BLUR:
61         return LayerData::CSSFilterShaderBlurY;
62     case FilterOperation::DROP_SHADOW:
63         return LayerData::CSSFilterShaderShadow;
64 #if ENABLE(CSS_SHADERS)
65     case FilterOperation::CUSTOM:
66         return LayerData::CSSFilterShaderCustom;
67 #endif
68     default:
69         ASSERT_NOT_REACHED();
70         return -1;
71     }
72 }
73
74 Uniform::Uniform(int c_location)
75     : m_location(c_location)
76 {
77 }
78
79 void Uniform1f::apply()
80 {
81     glUniform1f(location(), m_val);
82 }
83
84 PassRefPtr<Uniform> Uniform1f::create(int location, float val)
85 {
86     return adoptRef(new Uniform1f(location, val));
87 }
88
89 Uniform1f::Uniform1f(int c_location, float c_val)
90     : Uniform(c_location)
91     , m_val(c_val)
92 {
93 }
94
95 void Uniform1i::apply()
96 {
97     glUniform1i(location(), m_val);
98 }
99
100 PassRefPtr<Uniform> Uniform1i::create(int location, int val)
101 {
102     return adoptRef(new Uniform1i(location, val));
103 }
104
105 Uniform1i::Uniform1i(int c_location, int c_val)
106     : Uniform(c_location)
107     , m_val(c_val)
108 {
109 }
110
111 void Uniform2f::apply()
112 {
113     glUniform2f(location(), m_val[0], m_val[1]);
114 }
115
116 PassRefPtr<Uniform> Uniform2f::create(int location, float val0, float val1)
117 {
118     return adoptRef(new Uniform2f(location, val0, val1));
119 }
120
121 Uniform2f::Uniform2f(int c_location, float c_val0, float c_val1)
122     : Uniform(c_location)
123 {
124     m_val[0] = c_val0;
125     m_val[1] = c_val1;
126 }
127
128 void Uniform3f::apply()
129 {
130     glUniform3f(location(), m_val[0], m_val[1], m_val[2]);
131 }
132
133 PassRefPtr<Uniform> Uniform3f::create(int location, float val0, float val1, float val2)
134 {
135     return adoptRef(new Uniform3f(location, val0, val1, val2));
136 }
137
138 Uniform3f::Uniform3f(int c_location, float c_val0, float c_val1, float c_val2)
139     : Uniform(c_location)
140 {
141     m_val[0] = c_val0;
142     m_val[1] = c_val1;
143     m_val[2] = c_val2;
144 }
145
146 void Uniform4f::apply()
147 {
148     glUniform4f(location(), m_val[0], m_val[1], m_val[2], m_val[3]);
149 }
150
151 PassRefPtr<Uniform> Uniform4f::create(int location, float val0, float val1, float val2, float val3)
152 {
153     return adoptRef(new Uniform4f(location, val0, val1, val2, val3));
154 }
155
156 Uniform4f::Uniform4f(int c_location, float c_val0, float c_val1, float c_val2, float c_val3)
157     : Uniform(c_location)
158 {
159     m_val[0] = c_val0;
160     m_val[1] = c_val1;
161     m_val[2] = c_val2;
162     m_val[3] = c_val3;
163 }
164
165 void Matrix4fv::apply()
166 {
167     glUniformMatrix4fv(location(), m_size, m_transpose, m_array);
168 }
169
170 PassRefPtr<Parameter> Matrix4fv::create(GLint location, GLsizei size, GLboolean transpose, GLfloat* array)
171 {
172     return adoptRef(new Matrix4fv(location, size, transpose, array));
173 }
174
175 Matrix4fv::Matrix4fv(GLint clocation, GLsizei size, GLboolean transpose, GLfloat* array)
176     : Uniform(clocation)
177     , m_size(size)
178     , m_transpose(transpose)
179     , m_array(0)
180 {
181     m_array = new GLfloat[size * 4 * 4];
182     std::memcpy(m_array, array, size * 4 * 4 * sizeof(GLfloat));
183 }
184
185 Matrix4fv::~Matrix4fv()
186 {
187     delete[] m_array;
188 }
189
190 void Buffer::apply()
191 {
192     glBindBuffer(m_buffer, m_object);
193 }
194
195 void Buffer::restoreState()
196 {
197     glBindBuffer(m_buffer, 0);
198 }
199
200 PassRefPtr<Parameter> Buffer::create(GLenum buffer, GLuint object)
201 {
202     return adoptRef(new Buffer(buffer, object));
203 }
204
205 Buffer::Buffer(GLenum buffer, GLuint object)
206     : Parameter()
207     , m_buffer(buffer)
208     , m_object(object)
209 {
210 }
211
212 void VertexAttribf::apply()
213 {
214     glVertexAttribPointer(m_location, m_size, GL_FLOAT, false, m_bytesPerVertex, reinterpret_cast<GLvoid*>(static_cast<intptr_t>(m_offset)));
215     glEnableVertexAttribArray(m_location);
216 }
217
218 void VertexAttribf::restoreState()
219 {
220     glDisableVertexAttribArray(m_location);
221 }
222
223 PassRefPtr<Parameter> VertexAttribf::create(int location, int size, int bytesPerVertex, int offset)
224 {
225     return adoptRef(new VertexAttribf(location, size, bytesPerVertex, offset));
226 }
227
228
229 VertexAttribf::VertexAttribf(int location, int size, int bytesPerVertex, int offset)
230     : Parameter()
231     , m_location(location)
232     , m_size(size)
233     , m_bytesPerVertex(bytesPerVertex)
234     , m_offset(offset)
235 {
236 }
237
238 PassRefPtr<LayerFilterRendererAction> LayerFilterRendererAction::create(int programId)
239 {
240     return adoptRef(new LayerFilterRendererAction(programId));
241 }
242
243 LayerFilterRendererAction::LayerFilterRendererAction(int c_programId)
244     : m_programId(c_programId)
245     , m_customId(-1)
246     , m_pushSnapshot(false)
247     , m_popSnapshot(false)
248     , m_drawingMode(DrawTriangleFanArrays)
249 {
250 }
251
252 void LayerFilterRendererAction::useActionOn(LayerFilterRenderer* renderer)
253 {
254     ASSERT(m_programId != -1);
255     if (m_programId == -1) {
256         glUseProgram(renderer->m_cssFilterProgramObject[LayerData::CSSFilterShaderPassthrough]);
257         return;
258     }
259     glUseProgram(renderer->m_cssFilterProgramObject[m_programId]);
260     for (unsigned i = 0; i < m_parameters.size(); ++i)
261         m_parameters[i]->apply();
262 }
263
264 void LayerFilterRendererAction::restoreState()
265 {
266     for (unsigned i = 0; i < m_parameters.size(); ++i)
267         m_parameters[i]->restoreState();
268 }
269
270 PassOwnPtr<LayerFilterRenderer> LayerFilterRenderer::create(const int& positionLocation, const int& texCoordLocation)
271 {
272     return adoptPtr(new LayerFilterRenderer(positionLocation, texCoordLocation));
273 }
274
275 LayerFilterRenderer::LayerFilterRenderer(const int& positionLocation, const int& texCoordLocation)
276     : m_positionLocation(positionLocation)
277     , m_texCoordLocation(texCoordLocation)
278 {
279     // If you ever move this stuff, please make sure that
280     // everything in this constructor is called BEFORE actionsForOperations.
281
282     for (int i = 0; i < LayerData::NumberOfCSSFilterShaders; ++i)
283         m_cssFilterProgramObject[i] = 0;
284
285     if (!(m_enabled = initializeSharedGLObjects()))
286         BlackBerry::Platform::logAlways(BlackBerry::Platform::LogLevelWarn, "CSS Filters are not enabled due to failed initialization.");
287 }
288
289 // Binds the given attribute name to a common location across all programs
290 // used by the compositor. This allows the code to bind the attributes only once
291 // even when switching between programs.
292 //
293 // This is an extension of LayerRenderer::bindCommonAttribLocation and the locations
294 // will match those of LayerRenderer. See LayerFilterRenderer::LayerFilterRenderer()
295 void LayerFilterRenderer::bindCommonAttribLocation(int location, const char* attribName)
296 {
297     for (int i = 0; i < LayerData::NumberOfCSSFilterShaders; ++i)
298         glBindAttribLocation(m_cssFilterProgramObject[i], location, attribName);
299 }
300
301 bool LayerFilterRenderer::initializeSharedGLObjects()
302 {
303     // See also TextureMapperShaderManager.cpp
304
305     char vertexShaderString[] =
306         "attribute vec4 a_position;   \n"
307         "attribute vec2 a_texCoord;   \n"
308         "varying vec2 v_texCoord;     \n"
309         "void main()                  \n"
310         "{                            \n"
311         "  gl_Position = a_position;  \n"
312         "  v_texCoord = a_texCoord;   \n"
313         "}                            \n";
314
315 #define STANDARD_FILTER(x...) \
316         "precision mediump float; \n"\
317         "\n"\
318         "varying mediump vec2 v_texCoord;\n"\
319         "uniform lowp sampler2D s_texture;\n"\
320         "uniform highp float u_amount;\n"\
321         #x\
322         "void main(void)\n { gl_FragColor = shade(texture2D(s_texture, v_texCoord)); }"
323
324 #define OFFSET_FILTER(x...) \
325         "precision mediump float; \n"\
326         "\n"\
327         "varying mediump vec2 v_texCoord;\n"\
328         "uniform lowp sampler2D s_texture;\n"\
329         "uniform highp float u_amount;\n"\
330         "uniform mediump vec2 u_offset;\n"\
331         #x\
332         "void main(void)\n { gl_FragColor = shade(texture2D(s_texture, v_texCoord - u_offset)); }"
333
334 #define BLUR_FILTER(x...) \
335         "precision highp float; \n"\
336         "\n"\
337         "varying mediump vec2 v_texCoord;\n"\
338         "uniform lowp sampler2D s_texture;\n"\
339         "uniform highp float u_amount;\n"\
340         "uniform highp float u_blurSize;\n"\
341         "const float pi = 3.1415927;\n"\
342         #x\
343         "void main(void)\n"\
344         "{\n"\
345         "vec3 incr;\n"\
346         "incr.x = 1.0 / (sqrt(2.0 * pi) * u_amount);\n"\
347         "incr.y = exp(-0.5 / (u_amount * u_amount));\n"\
348         "incr.z = incr.y * incr.y;\n"\
349         "\n"\
350         "vec4 avg = vec4(0.0, 0.0, 0.0, 0.0);\n"\
351         "float coefficientSum = 0.0;\n"\
352         "\n"\
353         "avg += texture2D(s_texture, v_texCoord.xy) * incr.x;\n"\
354         "coefficientSum += incr.x;\n"\
355         "incr.xy *= incr.yz;\n"\
356         "\n"\
357         "for (float i = 1.0; i <= numBlurPixelsPerSide; i++) {\n"\
358         "    avg += texture2D(s_texture, v_texCoord.xy - i * u_blurSize * blurMultiplyVec) * incr.x;\n"\
359         "    avg += texture2D(s_texture, v_texCoord.xy + i * u_blurSize * blurMultiplyVec) * incr.x;\n"\
360         "    coefficientSum += 2.0 * incr.x;\n"\
361         "    incr.xy *= incr.yz;\n"\
362         "}\n"\
363         "\n"\
364         "gl_FragColor = avg / coefficientSum;\n"\
365         "}"
366
367     const char* shaderStrs[LayerData::NumberOfCSSFilterShaders];
368
369     shaderStrs[LayerData::CSSFilterShaderGrayscale] = STANDARD_FILTER(
370         lowp vec4 shade(lowp vec4 color)
371         {
372             lowp float amount = 1.0 - u_amount;
373             return vec4((0.2126 + 0.7874 * amount) * color.r + (0.7152 - 0.7152 * amount) * color.g + (0.0722 - 0.0722 * amount) * color.b,
374                         (0.2126 - 0.2126 * amount) * color.r + (0.7152 + 0.2848 * amount) * color.g + (0.0722 - 0.0722 * amount) * color.b,
375                         (0.2126 - 0.2126 * amount) * color.r + (0.7152 - 0.7152 * amount) * color.g + (0.0722 + 0.9278 * amount) * color.b,
376                         color.a);
377         }
378     );
379
380     shaderStrs[LayerData::CSSFilterShaderSepia] = STANDARD_FILTER(
381         lowp vec4 shade(lowp vec4 color)
382         {
383             lowp float amount = 1.0 - u_amount;
384             return vec4((0.393 + 0.607 * amount) * color.r + (0.769 - 0.769 * amount) * color.g + (0.189 - 0.189 * amount) * color.b,
385                         (0.349 - 0.349 * amount) * color.r + (0.686 + 0.314 * amount) * color.g + (0.168 - 0.168 * amount) * color.b,
386                         (0.272 - 0.272 * amount) * color.r + (0.534 - 0.534 * amount) * color.g + (0.131 + 0.869 * amount) * color.b,
387                         color.a);
388          }
389     );
390
391     shaderStrs[LayerData::CSSFilterShaderSaturate] = STANDARD_FILTER(
392         lowp vec4 shade(lowp vec4 color)
393         {
394             return vec4((0.213 + 0.787 * u_amount) * color.r + (0.715 - 0.715 * u_amount) * color.g + (0.072 - 0.072 * u_amount) * color.b,
395                         (0.213 - 0.213 * u_amount) * color.r + (0.715 + 0.285 * u_amount) * color.g + (0.072 - 0.072 * u_amount) * color.b,
396                         (0.213 - 0.213 * u_amount) * color.r + (0.715 - 0.715 * u_amount) * color.g + (0.072 + 0.928 * u_amount) * color.b,
397                         color.a);
398         }
399     );
400
401     shaderStrs[LayerData::CSSFilterShaderHueRotate] = STANDARD_FILTER(
402         lowp vec4 shade(lowp vec4 color)
403         {
404             highp float pi = 3.14159265358979323846;
405             highp float c = cos(u_amount * pi / 180.0);
406             highp float s = sin(u_amount * pi / 180.0);
407             return vec4(color.r * (0.213 + c * 0.787 - s * 0.213) + color.g * (0.715 - c * 0.715 - s * 0.715) + color.b * (0.072 - c * 0.072 + s * 0.928),
408                         color.r * (0.213 - c * 0.213 + s * 0.143) + color.g * (0.715 + c * 0.285 + s * 0.140) + color.b * (0.072 - c * 0.072 - s * 0.283),
409                         color.r * (0.213 - c * 0.213 - s * 0.787) +  color.g * (0.715 - c * 0.715 + s * 0.715) + color.b * (0.072 + c * 0.928 + s * 0.072),
410                         color.a);
411         }
412     );
413
414     shaderStrs[LayerData::CSSFilterShaderInvert] = STANDARD_FILTER(
415         lowp float invert(lowp float n) { return (1.0 - n) * u_amount + n * (1.0 - u_amount); }
416         lowp vec4 shade(lowp vec4 color)
417         {
418             return vec4(invert(color.r), invert(color.g), invert(color.b), color.a);
419         }
420     );
421
422     shaderStrs[LayerData::CSSFilterShaderBrightness] = STANDARD_FILTER(
423         lowp vec4 shade(lowp vec4 color)
424         {
425             return vec4(color.rgb * (1.0 + u_amount), color.a);
426         }
427     );
428
429     shaderStrs[LayerData::CSSFilterShaderContrast] = STANDARD_FILTER(
430         lowp float contrast(lowp float n) { return (n - 0.5) * u_amount + 0.5; }
431         lowp vec4 shade(lowp vec4 color)
432         {
433             return vec4(contrast(color.r), contrast(color.g), contrast(color.b), color.a);
434         }
435     );
436
437     shaderStrs[LayerData::CSSFilterShaderOpacity] = STANDARD_FILTER(
438         lowp vec4 shade(lowp vec4 color)
439         {
440             return vec4(color.r, color.g, color.b, color.a * u_amount);
441         }
442     );
443
444     shaderStrs[LayerData::CSSFilterShaderBlurX] = BLUR_FILTER(
445         const float numBlurPixelsPerSide = 2.0;
446         const vec2  blurMultiplyVec      = vec2(1.0, 0.0);
447     );
448
449     shaderStrs[LayerData::CSSFilterShaderBlurY] = BLUR_FILTER(
450         const float numBlurPixelsPerSide = 2.0;
451         const vec2  blurMultiplyVec      = vec2(0.0, 1.0);
452     );
453
454     shaderStrs[LayerData::CSSFilterShaderShadow] = OFFSET_FILTER(
455         uniform lowp vec3 u_color;
456         lowp vec4 shade(lowp vec4 color)
457         {
458             if (color.a > 0.5)
459                 return vec4(u_color.r, u_color.g, u_color.b, color.a);
460             return color;
461         }
462     );
463
464     shaderStrs[LayerData::CSSFilterShaderPassthrough] = STANDARD_FILTER(
465         lowp vec4 shade(lowp vec4 color)
466         {
467             return color;
468         }
469     );
470
471     for (int i = 0; i < LayerData::NumberOfCSSFilterShaders; i++) {
472         m_cssFilterProgramObject[i] = LayerRenderer::loadShaderProgram(vertexShaderString, shaderStrs[i]);
473         if (!m_cssFilterProgramObject[i]) {
474             BlackBerry::Platform::logAlways(BlackBerry::Platform::LogLevelWarn, "Could not load CSS Filter Shader %i", i);
475             return false;
476         }
477     }
478
479     // Set ATTRIB locations - these will be the same as the programs in LayerRenderer.cpp
480     bindCommonAttribLocation(m_positionLocation, "a_position");
481     bindCommonAttribLocation(m_texCoordLocation, "a_texCoord");
482
483     // Re-link to take effect
484     for (int i = 0; i < LayerData::NumberOfCSSFilterShaders; ++i)
485         glLinkProgram(m_cssFilterProgramObject[i]);
486
487     // Get UNIFORM locations
488     for (int i = 0; i < LayerData::NumberOfCSSFilterShaders; ++i)
489         m_amountLocation[i] = glGetUniformLocation(m_cssFilterProgramObject[i], "u_amount");
490
491     m_blurAmountLocation[0] = glGetUniformLocation(m_cssFilterProgramObject[LayerData::CSSFilterShaderBlurY], "u_blurSize");
492     m_blurAmountLocation[1] = glGetUniformLocation(m_cssFilterProgramObject[LayerData::CSSFilterShaderBlurX], "u_blurSize");
493
494     m_shadowColorLocation = glGetUniformLocation(m_cssFilterProgramObject[LayerData::CSSFilterShaderShadow], "u_color");
495     m_offsetLocation = glGetUniformLocation(m_cssFilterProgramObject[LayerData::CSSFilterShaderShadow], "u_offset");
496
497     return true;
498 }
499
500 void LayerFilterRenderer::ping(LayerRendererSurface* surface)
501 {
502     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture->textureId(), 0);
503     glBindTexture(GL_TEXTURE_2D, surface->texture()->textureId());
504 }
505
506 void LayerFilterRenderer::pong(LayerRendererSurface* surface)
507 {
508     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, surface->texture()->textureId(), 0);
509     glBindTexture(GL_TEXTURE_2D, m_texture->textureId());
510 }
511
512 void LayerFilterRenderer::pushSnapshot(LayerRendererSurface* surface, int sourceId)
513 {
514     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_snapshotTexture->textureId(), 0);
515
516     glBindTexture(GL_TEXTURE_2D, sourceId);
517     glClear(GL_COLOR_BUFFER_BIT); // to transparency
518
519     glViewport(0, 0, surface->size().width(), surface->size().height());
520
521     glUseProgram(m_cssFilterProgramObject[LayerData::CSSFilterShaderPassthrough]);
522     glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
523 }
524
525 void LayerFilterRenderer::popSnapshot()
526 {
527     // The name is slightly misleading.
528     // This DRAWS the previous texture using the current LayerFilterRendererAction, then sets the texture
529     // to the snapshot texture. Next time glDrawArrays is called, the snapshot will be drawn.
530
531     glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
532     glBindTexture(GL_TEXTURE_2D, m_snapshotTexture->textureId());
533 }
534
535 Vector<RefPtr<LayerFilterRendererAction> > LayerFilterRenderer::actionsForOperations(LayerRendererSurface* surface, const Vector<RefPtr<FilterOperation> >& ops)
536 {
537     Vector<RefPtr<LayerFilterRendererAction> > ret;
538     for (unsigned int i = 0; i < ops.size(); ++i) {
539         const FilterOperation& operation = *ops[i].get();
540         if (operation.getOperationType() == FilterOperation::BLUR && static_cast<const BlurFilterOperation&>(operation).stdDeviation().value() < 0.1)
541             continue;
542
543         int programId = operationTypeToProgramID(operation.getOperationType());
544         ret.append(LayerFilterRendererAction::create(programId));
545
546         switch (operation.getOperationType()) {
547         case FilterOperation::GRAYSCALE:
548         case FilterOperation::SEPIA:
549         case FilterOperation::SATURATE:
550         case FilterOperation::HUE_ROTATE:
551             ret.last()->appendParameter(Uniform1f::create(m_amountLocation[programId]
552                 , static_cast<const BasicColorMatrixFilterOperation&>(operation).amount()));
553             break;
554         case FilterOperation::INVERT:
555         case FilterOperation::BRIGHTNESS:
556         case FilterOperation::CONTRAST:
557         case FilterOperation::OPACITY:
558             ret.last()->appendParameter(Uniform1f::create(m_amountLocation[programId]
559                 , static_cast<const BasicComponentTransferFilterOperation&>(operation).amount()));
560             break;
561         case FilterOperation::BLUR:
562             {
563             // Blur is a two-step process:
564             //     1. blur X
565             //     2. blur Y
566             // This way we can have 2n time instead of n^2 time)
567
568             double amount = static_cast<const BlurFilterOperation&>(operation).stdDeviation().value();
569
570             // BLUR Y:
571             ret.last()->appendParameter(Uniform1f::create(m_amountLocation[LayerData::CSSFilterShaderBlurY], amount));
572             ret.last()->appendParameter(Uniform1f::create(m_blurAmountLocation[0]
573                 , 1.0f / float(surface->size().height())));
574
575             // BLUR X:
576             ret.append(LayerFilterRendererAction::create(LayerData::CSSFilterShaderBlurX));
577             ret.last()->appendParameter(Uniform1f::create(m_amountLocation[LayerData::CSSFilterShaderBlurX], amount));
578             ret.last()->appendParameter(Uniform1f::create(m_blurAmountLocation[1]
579                 , 1.0f / float(surface->size().width())));
580
581             }
582             break;
583         case FilterOperation::DROP_SHADOW:
584             {
585             // Shadow is a four-step process:
586             //     1. capture snapshot
587             //        turn into a solid offset mask
588             //     2. blur X
589             //     3. blur Y
590             //     4. repaint original on top of mask
591             const DropShadowFilterOperation& dsfo = static_cast<const DropShadowFilterOperation&>(operation);
592             ret.last()->setPushSnapshot();
593             ret.last()->appendParameter(Uniform2f::create(m_offsetLocation
594                 , float(dsfo.x()) / float(surface->size().width())
595                 , float(dsfo.y()) / float(surface->size().height())));
596             ret.last()->appendParameter(Uniform3f::create(m_shadowColorLocation
597                 , float(dsfo.color().red()) / 255.0f
598                 , float(dsfo.color().green()) / 255.0f
599                 , float(dsfo.color().blue()) / 255.0f));
600
601             // BLUR Y
602             ret.append(LayerFilterRendererAction::create(LayerData::CSSFilterShaderBlurY));
603             ret.last()->appendParameter(Uniform1f::create(m_amountLocation[LayerData::CSSFilterShaderBlurY]
604                 , dsfo.stdDeviation()));
605             ret.last()->appendParameter(Uniform1f::create(m_blurAmountLocation[0]
606                 , 1.0f / float(surface->size().height())));
607
608             // BLUR X
609             ret.append(LayerFilterRendererAction::create(LayerData::CSSFilterShaderBlurX));
610             ret.last()->appendParameter(Uniform1f::create(m_amountLocation[LayerData::CSSFilterShaderBlurX]
611                 , dsfo.stdDeviation()));
612             ret.last()->appendParameter(Uniform1f::create(m_blurAmountLocation[1]
613                 , 1.0f / float(surface->size().width())));
614
615             // Repaint original image
616             ret.append(LayerFilterRendererAction::create(LayerData::CSSFilterShaderPassthrough));
617             ret.last()->setPopSnapshot();
618             }
619             break;
620         default:
621             ASSERT_NOT_REACHED();
622             break;
623         }
624     }
625
626     if (ret.size() % 2) // We need an even number of actions. See ping-pong note in applyLayerFilters().
627         ret.append(LayerFilterRendererAction::create(LayerData::CSSFilterShaderPassthrough));
628
629     return ret;
630 }
631
632 static float texcoords[4 * 2] = { 0, 0,  0, 1,  1, 1,  1, 0 };
633
634 void LayerFilterRenderer::applyActions(unsigned& fbo, LayerCompositingThread* layer, Vector<RefPtr<LayerFilterRendererAction> > actions)
635 {
636     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
637     ASSERT(!(actions.size() % 2)); // See ping-ponging note below.
638
639     if (!m_enabled)
640         return;
641
642     if (!layer->filters().size())
643         return;
644
645     if (!m_texture)
646         m_texture = textureCacheCompositingThread()->createTexture();
647
648     bool requireSnapshot = false;
649     for (unsigned i = 0; i < actions.size(); ++i) {
650         if (actions[i]->shouldPushSnapshot())
651             requireSnapshot = true;
652     }
653
654     if (!m_snapshotTexture && requireSnapshot)
655         m_snapshotTexture = textureCacheCompositingThread()->createTexture();
656
657     LayerRendererSurface* surface = layer->layerRendererSurface();
658
659     glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, &layer->getTransformedBounds() );
660     glVertexAttribPointer(m_texCoordLocation, 2, GL_FLOAT, GL_FALSE, 0, texcoords);
661
662     m_texture->protect(surface->texture()->size());
663     if (requireSnapshot)
664         m_snapshotTexture->protect(surface->texture()->size());
665
666     if (!fbo)
667         glGenFramebuffers(1, &fbo);
668
669     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
670
671     for (unsigned int i = 0; i < actions.size(); ++i) {
672         // NOTE ABOUT PING-PONGING
673         // =======================
674         // Under OpenGL ES 2.0, we cannot use the fbo we are writting to as a texture, so we need to play ping-pong:
675         //  1) Draw parent surface to our texture with effect.
676         //  2) Draw our surface to parent texture with effect.
677         //  3) Repeat.
678         // Because we eventually have to end on the parent texture, we need an even number of actions.
679         // actionsForOperations takes care of that.
680
681         if (actions[i]->shouldPushSnapshot())
682             pushSnapshot(surface, (!(i % 2) ? surface->texture()->textureId() : m_texture->textureId()));
683
684         if (!(i % 2))
685             ping(surface); // Set framebuffer to ours, and texture to parent
686         else
687             pong(surface); // Set texture to parent, and framebuffer to us
688
689         glClear(GL_COLOR_BUFFER_BIT); // to transparency
690         glViewport(0, 0, surface->size().width(), surface->size().height());
691
692         actions[i]->useActionOn(this);
693
694         if (actions[i]->shouldPopSnapshot())
695             popSnapshot();
696
697         switch (actions[i]->drawingMode()) {
698         case LayerFilterRendererAction::DrawTriangleFanArrays:
699             glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
700             break;
701         case LayerFilterRendererAction::DrawTriangleElementsUShort0:
702             glDrawElements(GL_TRIANGLES, actions[i]->drawingModeParameter(), GL_UNSIGNED_SHORT, reinterpret_cast<GLvoid*>(static_cast<intptr_t>(0)));
703             break;
704         case LayerFilterRendererAction::NumberOfDrawingModes:
705             ASSERT_NOT_REACHED();
706             break;
707         }
708
709         actions[i]->restoreState();
710
711         glVertexAttribPointer(m_positionLocation, 2, GL_FLOAT, GL_FALSE, 0, &layer->getTransformedBounds() );
712         glEnableVertexAttribArray(m_positionLocation);
713         glVertexAttribPointer(m_texCoordLocation, 2, GL_FLOAT, GL_FALSE, 0, texcoords);
714         glEnableVertexAttribArray(m_texCoordLocation);
715     }
716
717     m_texture->unprotect();
718     if (requireSnapshot)
719         m_snapshotTexture->unprotect();
720     glBindTexture(GL_TEXTURE_2D, 0);
721
722     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
723 }
724
725 } // namespace WebCore
726
727 #endif // USE(ACCELERATED_COMPOSITING) && USE(CSS_FILTERS)