1/*
2 * Copyright (C) 2010, 2011, 2012, 2013 Research In Motion Limited. All rights reserved.
3 * Copyright (C) 2010 Google Inc. 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 are
7 * met:
8 *
9 *     * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *     * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 *     * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32
33#include "config.h"
34
35#if USE(ACCELERATED_COMPOSITING)
36#include "LayerRenderer.h"
37
38#include "LayerCompositingThread.h"
39#include "LayerFilterRenderer.h"
40#include "LayerRendererClient.h"
41#include "TextureCacheCompositingThread.h"
42
43#include <BlackBerryPlatformGraphics.h>
44#include <BlackBerryPlatformLog.h>
45#include <EGL/egl.h>
46#include <limits>
47#include <wtf/text/CString.h>
48#include <wtf/text/WTFString.h>
49
50#define DEBUG_LAYER_ANIMATIONS 0 // Show running animations as green.
51#define DEBUG_CLIPPING 0
52
53using BlackBerry::Platform::Graphics::GLES2Context;
54using BlackBerry::Platform::Graphics::GLES2Program;
55using namespace std;
56
57namespace WebCore {
58
59#ifndef NDEBUG
60#define checkGLError() \
61{ \
62    if (GLenum error = glGetError()) \
63        BlackBerry::Platform::logAlways(BlackBerry::Platform::LogLevelCritical, "%s:%d GL Error: 0x%x ", __FILE__, __LINE__, error); \
64}
65#else
66#define checkGLError()
67#endif
68
69GLuint LayerRenderer::loadShader(GLenum type, const char* shaderSource)
70{
71    GLuint shader = glCreateShader(type);
72    if (!shader)
73        return 0;
74    glShaderSource(shader, 1, &shaderSource, 0);
75    glCompileShader(shader);
76    GLint compiled;
77    glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
78    if (!compiled) {
79        char infoLog[2048];
80        GLsizei length;
81        glGetShaderInfoLog(shader, 2048, &length, infoLog);
82        BlackBerry::Platform::logAlways(BlackBerry::Platform::LogLevelCritical, "Failed to compile shader:\n%s\nlog: %s", shaderSource, infoLog);
83        glDeleteShader(shader);
84        return 0;
85    }
86    return shader;
87}
88
89GLuint LayerRenderer::loadShaderProgram(const char* vertexShaderSource, const char* fragmentShaderSource)
90{
91    GLuint vertexShader;
92    GLuint fragmentShader;
93    GLuint programObject;
94    GLint linked;
95    vertexShader = loadShader(GL_VERTEX_SHADER, vertexShaderSource);
96    if (!vertexShader)
97        return 0;
98    fragmentShader = loadShader(GL_FRAGMENT_SHADER, fragmentShaderSource);
99    if (!fragmentShader) {
100        glDeleteShader(vertexShader);
101        return 0;
102    }
103    programObject = glCreateProgram();
104    if (programObject) {
105        glAttachShader(programObject, vertexShader);
106        glAttachShader(programObject, fragmentShader);
107        glLinkProgram(programObject);
108        glGetProgramiv(programObject, GL_LINK_STATUS, &linked);
109        if (!linked) {
110            glDeleteProgram(programObject);
111            programObject = 0;
112        }
113    }
114    glDeleteShader(vertexShader);
115    glDeleteShader(fragmentShader);
116    return programObject;
117}
118
119TransformationMatrix LayerRenderer::orthoMatrix(float left, float right, float bottom, float top, float nearZ, float farZ)
120{
121    float deltaX = right - left;
122    float deltaY = top - bottom;
123    float deltaZ = farZ - nearZ;
124    TransformationMatrix ortho;
125    if (!deltaX || !deltaY || !deltaZ)
126        return ortho;
127    ortho.setM11(2.0f / deltaX);
128    ortho.setM41(-(right + left) / deltaX);
129    ortho.setM22(2.0f / deltaY);
130    ortho.setM42(-(top + bottom) / deltaY);
131    ortho.setM33(-2.0f / deltaZ);
132    ortho.setM43(-(nearZ + farZ) / deltaZ);
133    return ortho;
134}
135
136static Vector<LayerCompositingThread*> rawPtrVectorFromRefPtrVector(const Vector<RefPtr<LayerCompositingThread> >& sublayers)
137{
138    Vector<LayerCompositingThread*> sublayerList;
139    for (size_t i = 0; i < sublayers.size(); i++)
140        sublayerList.append(sublayers[i].get());
141
142    return sublayerList;
143}
144
145PassOwnPtr<LayerRenderer> LayerRenderer::create(LayerRendererClient* client)
146{
147    return adoptPtr(new LayerRenderer(client));
148}
149
150LayerRenderer::LayerRenderer(LayerRendererClient* client)
151    : m_client(client)
152    , m_scale(1.0)
153    , m_animationTime(-numeric_limits<double>::infinity())
154    , m_fbo(0)
155    , m_currentLayerRendererSurface(0)
156    , m_isRobustnessSupported(false)
157    , m_needsCommit(false)
158    , m_stencilCleared(false)
159{
160    // We're now initializing lazily, so a check if the context can be made current
161    // will have to suffice to determine if hardware compositing is possible.
162    m_hardwareCompositing = makeContextCurrent();
163    if (m_hardwareCompositing) {
164        m_isRobustnessSupported = String(reinterpret_cast<const char*>(::glGetString(GL_EXTENSIONS))).contains("GL_EXT_robustness");
165        if (m_isRobustnessSupported)
166            m_glGetGraphicsResetStatusEXT = reinterpret_cast<PFNGLGETGRAPHICSRESETSTATUSEXTPROC>(eglGetProcAddress("glGetGraphicsResetStatusEXT"));
167    }
168}
169
170LayerRenderer::~LayerRenderer()
171{
172    if (m_hardwareCompositing) {
173        makeContextCurrent();
174        if (m_fbo)
175            glDeleteFramebuffers(1, &m_fbo);
176
177        for (size_t i = 0; i < NumberOfPrograms; ++i)
178            glDeleteProgram(m_programs[i].m_program);
179
180        // Free up all GL textures.
181        while (m_layers.begin() != m_layers.end()) {
182            LayerSet::iterator iter = m_layers.begin();
183            (*iter)->deleteTextures();
184            (*iter)->setLayerRenderer(0);
185            removeLayer(*iter);
186        }
187
188        textureCacheCompositingThread()->clear();
189    }
190}
191
192void LayerRenderer::releaseLayerResources()
193{
194    if (m_hardwareCompositing) {
195        makeContextCurrent();
196        // Free up all GL textures.
197        for (LayerSet::iterator iter = m_layers.begin(); iter != m_layers.end(); ++iter)
198            (*iter)->deleteTextures();
199
200        textureCacheCompositingThread()->clear();
201    }
202}
203
204static inline bool compareLayerW(const LayerCompositingThread* a, const LayerCompositingThread* b)
205{
206    return a->centerW() > b->centerW();
207}
208
209void LayerRenderer::prepareFrame(double animationTime, LayerCompositingThread* rootLayer)
210{
211    if (animationTime != m_animationTime) {
212        m_animationTime = animationTime;
213
214        // Aha, new frame! Reset rendering results.
215        bool wasEmpty = m_lastRenderingResults.isEmpty();
216        m_lastRenderingResults = LayerRenderingResults();
217        m_lastRenderingResults.wasEmpty = wasEmpty;
218    }
219
220    if (!rootLayer)
221        return;
222
223    bool isContextCurrent = makeContextCurrent();
224    prepareFrameRecursive(rootLayer, animationTime, isContextCurrent);
225}
226
227void LayerRenderer::setViewport(const IntRect& targetRect, const IntRect& clipRect, const FloatRect& visibleRect, const IntRect& layoutRect, const IntSize& contentsSize)
228{
229    // These parameters are used to calculate position of fixed position elements
230    m_visibleRect = visibleRect;
231    m_layoutRect = layoutRect;
232    m_contentsSize = contentsSize;
233
234    m_viewport = targetRect;
235    m_scissorRect = clipRect;
236
237    // The clipRect parameter uses render target coordinates, map to normalized device coordinates
238    m_clipRect = clipRect;
239    m_clipRect.intersect(targetRect);
240    m_clipRect = FloatRect(-1 + 2 * (m_clipRect.x() - targetRect.x()) / targetRect.width(),
241        -1 + 2 * (m_clipRect.y() - targetRect.y()) / targetRect.height(),
242        2 * m_clipRect.width() / targetRect.width(),
243        2 * m_clipRect.height() / targetRect.height());
244
245#if DEBUG_CLIPPING
246    printf("LayerRenderer::setViewport() m_visibleRect=(%.2f,%.2f %.2fx%.2f), m_layoutRect=(%d,%d %dx%d), m_contentsSize=(%dx%d), m_viewport=(%d,%d %dx%d), m_scissorRect=(%d,%d %dx%d), m_clipRect=(%.2f,%.2f %.2fx%.2f)\n",
247        m_visibleRect.x(), m_visibleRect.y(), m_visibleRect.width(), m_visibleRect.height(),
248        m_layoutRect.x(), m_layoutRect.y(), m_layoutRect.width(), m_layoutRect.height(),
249        m_contentsSize.width(), m_contentsSize.height(),
250        m_viewport.x(), m_viewport.y(), m_viewport.width(), m_viewport.height(),
251        m_scissorRect.x(), m_scissorRect.y(), m_scissorRect.width(), m_scissorRect.height(),
252        m_clipRect.x(), m_clipRect.y(), m_clipRect.width(), m_clipRect.height());
253    fflush(stdout);
254#endif
255
256    if (!m_hardwareCompositing)
257        return;
258
259    // Okay, we're going to do some drawing.
260    if (!makeContextCurrent())
261        return;
262
263    // Get rid of any bound buffer that might affect the interpretation of our
264    // glVertexAttribPointer calls.
265    glBindBuffer(GL_ARRAY_BUFFER, 0);
266    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
267
268    glActiveTexture(GL_TEXTURE0);
269    glDisable(GL_DEPTH_TEST);
270    glDisable(GL_CULL_FACE);
271    glDisable(GL_STENCIL_TEST);
272
273    // If culling is enabled then we will cull the backface.
274    glCullFace(GL_BACK);
275
276    // The BlackBerry::Platform::GraphicsContext uses OpenGL conventions, so everything is upside down
277    glFrontFace(GL_CW);
278
279    checkGLError();
280
281    glViewport(m_viewport.x(), m_viewport.y(), m_viewport.width(), m_viewport.height());
282
283    glEnable(GL_SCISSOR_TEST);
284#if DEBUG_CLIPPING
285    printf("LayerRenderer::compositeLayers(): clipping to (%d,%d %dx%d)\n", m_scissorRect.x(), m_scissorRect.y(), m_scissorRect.width(), m_scissorRect.height());
286    fflush(stdout);
287#endif
288    glScissor(m_scissorRect.x(), m_scissorRect.y(), m_scissorRect.width(), m_scissorRect.height());
289
290    m_stencilCleared = false;
291}
292
293void LayerRenderer::compositeLayers(const TransformationMatrix& matrix, LayerCompositingThread* rootLayer)
294{
295    ASSERT(m_hardwareCompositing);
296    if (!m_hardwareCompositing)
297        return;
298
299    if (!rootLayer)
300        return;
301
302    // Used to draw scale invariant layers. We assume uniform scale.
303    // The matrix maps to normalized device coordinates, a system that maps the
304    // viewport to the interval -1 to 1.
305    // So it has to scale down by a factor equal to one half the viewport.
306    m_scale = matrix.m11() * m_viewport.width() / 2;
307
308    Vector<RefPtr<LayerCompositingThread> > surfaceLayers;
309    const Vector<RefPtr<LayerCompositingThread> >& sublayers = rootLayer->sublayers();
310    for (size_t i = 0; i < sublayers.size(); i++) {
311        float opacity = 1;
312        FloatRect clipRect(m_clipRect);
313        updateLayersRecursive(sublayers[i].get(), TransformationMatrix(), matrix, surfaceLayers, opacity, clipRect);
314    }
315
316    // Decompose the dirty rect into a set of non-overlaping rectangles
317    // (they need to not overlap so that the blending code doesn't draw any region twice).
318    for (int i = 0; i < LayerRenderingResults::NumberOfDirtyRects; ++i) {
319        BlackBerry::Platform::IntRectRegion region(BlackBerry::Platform::IntRect(m_lastRenderingResults.dirtyRect(i)));
320        m_lastRenderingResults.dirtyRegion = BlackBerry::Platform::IntRectRegion::unionRegions(m_lastRenderingResults.dirtyRegion, region);
321    }
322
323    // If we won't draw anything, don't touch the OpenGL APIs.
324    if (m_lastRenderingResults.isEmpty() && m_lastRenderingResults.wasEmpty)
325        return;
326
327    // Okay, we're going to do some drawing.
328    if (!makeContextCurrent())
329        return;
330
331    // If some layers should be drawn on temporary surfaces, we should do it first.
332    if (!surfaceLayers.isEmpty())
333        drawLayersOnSurfaces(surfaceLayers);
334
335    // Don't render the root layer, the BlackBerry port uses the BackingStore to draw the
336    // root layer.
337    for (size_t i = 0; i < sublayers.size(); i++) {
338        int currentStencilValue = 0;
339        FloatRect clipRect(m_clipRect);
340        compositeLayersRecursive(sublayers[i].get(), currentStencilValue, clipRect);
341    }
342
343    // We need to make sure that all texture resource usage is finished before
344    // unlocking the texture resources, so force a glFinish() in that case.
345    if (m_layersLockingTextureResources.size())
346        glFinish();
347
348    m_client->context()->swapBuffers();
349
350    glDisable(GL_SCISSOR_TEST);
351    glDisable(GL_STENCIL_TEST);
352
353    // PR 147254, the EGL implementation crashes when the last bound texture
354    // was an EGLImage, and you try to bind another texture and the pixmap
355    // backing the EGLImage was deleted in between. Make this easier for the
356    // driver by unbinding early (when the pixmap is hopefully still around).
357    glBindTexture(GL_TEXTURE_2D, 0);
358
359    LayerSet::iterator iter = m_layersLockingTextureResources.begin();
360    for (; iter != m_layersLockingTextureResources.end(); ++iter)
361        (*iter)->releaseTextureResources();
362
363    m_layersLockingTextureResources.clear();
364
365    if (m_needsCommit) {
366        m_needsCommit = false;
367        rootLayer->scheduleCommit();
368    }
369
370    textureCacheCompositingThread()->collectGarbage();
371}
372
373static float texcoords[4 * 2] = { 0, 0,  1, 0,  1, 1,  0, 1 };
374
375void LayerRenderer::compositeBuffer(const TransformationMatrix& transform, const FloatRect& contents, BlackBerry::Platform::Graphics::Buffer* buffer, bool contentsOpaque, float opacity)
376{
377    if (!buffer)
378        return;
379
380    FloatQuad vertices(transform.mapPoint(contents.minXMinYCorner()),
381        transform.mapPoint(contents.minXMaxYCorner()),
382        transform.mapPoint(contents.maxXMaxYCorner()),
383        transform.mapPoint(contents.maxXMinYCorner()));
384
385    if (!vertices.boundingBox().intersects(m_clipRect))
386        return;
387
388    if (!contentsOpaque || opacity < 1.0f) {
389        glEnable(GL_BLEND);
390        glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
391    } else
392        glDisable(GL_BLEND);
393
394    if (BlackBerry::Platform::Graphics::lockAndBindBufferGLTexture(buffer, GL_TEXTURE_2D)) {
395        const GLES2Program& program = useProgram(LayerProgramRGBA);
396        glUniform1f(program.opacityLocation(), opacity);
397
398        glVertexAttribPointer(program.positionLocation(), 2, GL_FLOAT, GL_FALSE, 0, &vertices);
399        glVertexAttribPointer(program.texCoordLocation(), 2, GL_FLOAT, GL_FALSE, 0, texcoords);
400
401        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
402        BlackBerry::Platform::Graphics::releaseBufferGLTexture(buffer);
403    }
404}
405
406void LayerRenderer::drawColor(const TransformationMatrix& transform, const FloatRect& contents, const Color& color)
407{
408    FloatQuad vertices(transform.mapPoint(contents.minXMinYCorner()),
409        transform.mapPoint(contents.minXMaxYCorner()),
410        transform.mapPoint(contents.maxXMaxYCorner()),
411        transform.mapPoint(contents.maxXMinYCorner()));
412
413    if (!vertices.boundingBox().intersects(m_clipRect))
414        return;
415
416    const GLES2Program& program = useProgram(ColorProgram);
417
418    if (color.alpha() < 255) {
419        glEnable(GL_BLEND);
420        glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
421    } else
422        glDisable(GL_BLEND);
423
424    glUniform4f(m_colorColorLocation, color.red() / 255.0, color.green() / 255.0, color.blue() / 255.0, color.alpha() / 255.0);
425    glVertexAttribPointer(program.positionLocation(), 2, GL_FLOAT, GL_FALSE, 0, &vertices);
426
427    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
428}
429
430bool LayerRenderer::useSurface(LayerRendererSurface* surface)
431{
432    if (m_currentLayerRendererSurface == surface)
433        return true;
434
435    m_currentLayerRendererSurface = surface;
436    if (!surface) {
437        glBindFramebuffer(GL_FRAMEBUFFER, 0);
438        glViewport(m_viewport.x(), m_viewport.y(), m_viewport.width(), m_viewport.height());
439        return true;
440    }
441
442    surface->ensureTexture();
443
444    GLuint texid = surface->texture()->platformTexture();
445
446    if (!m_fbo)
447        glGenFramebuffers(1, &m_fbo);
448    glBindTexture(GL_TEXTURE_2D, 0);
449    glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
450    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texid, 0);
451
452#ifndef NDEBUG
453    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
454    if (status != GL_FRAMEBUFFER_COMPLETE) {
455        fprintf(stderr, "glCheckFramebufferStatus error %x\n", status);
456        return false;
457    }
458#endif
459
460    glViewport(0, 0, surface->size().width(), surface->size().height());
461    return true;
462}
463
464void LayerRenderer::drawLayersOnSurfaces(const Vector<RefPtr<LayerCompositingThread> >& surfaceLayers)
465{
466    // Normally, an upside-down transform is used, as is the GL custom. However, when drawing
467    // layers to surfaces, a right-side-up transform is used, so we need to switch the winding order
468    // for culling.
469    glFrontFace(GL_CCW);
470
471    for (int i = surfaceLayers.size() - 1; i >= 0; i--) {
472        LayerCompositingThread* layer = surfaceLayers[i].get();
473        LayerRendererSurface* surface = layer->layerRendererSurface();
474        if (!surface || !useSurface(surface))
475            continue;
476
477        glDisable(GL_SCISSOR_TEST);
478        glClearColor(0, 0, 0, 0);
479        glClear(GL_COLOR_BUFFER_BIT);
480
481        int currentStencilValue = 0;
482        FloatRect clipRect(-1, -1, 2, 2);
483        compositeLayersRecursive(surfaceLayers[i].get(), currentStencilValue, clipRect);
484
485#if ENABLE(CSS_FILTERS)
486        if (!m_filterRenderer)
487            m_filterRenderer = LayerFilterRenderer::create(GLES2Program::PositionAttributeIndex, GLES2Program::TexCoordAttributeIndex);
488        if (layer->filterOperationsChanged()) {
489            layer->setFilterOperationsChanged(false);
490            layer->setFilterActions(m_filterRenderer->actionsForOperations(surface, layer->filters().operations()));
491        }
492        m_filterRenderer->applyActions(m_fbo, layer, layer->filterActions());
493        glClearColor(0, 0, 0, 0);
494#endif
495    }
496
497    glFrontFace(GL_CW);
498
499    // If there are layers drawn on surfaces, we need to switch to default framebuffer.
500    // Otherwise, we just need to set viewport.
501    useSurface(0);
502    glEnable(GL_SCISSOR_TEST);
503    glScissor(m_scissorRect.x(), m_scissorRect.y(), m_scissorRect.width(), m_scissorRect.height());
504}
505
506void LayerRenderer::addLayer(LayerCompositingThread* layer)
507{
508    m_layers.add(layer);
509}
510
511bool LayerRenderer::removeLayer(LayerCompositingThread* layer)
512{
513    LayerSet::iterator iter = m_layers.find(layer);
514    if (iter == m_layers.end())
515        return false;
516    m_layers.remove(layer);
517    return true;
518}
519
520void LayerRenderer::addLayerToReleaseTextureResourcesList(LayerCompositingThread* layer)
521{
522    m_layersLockingTextureResources.add(layer);
523}
524
525static int glRound(float f)
526{
527    return floorf(f + 0.5f);
528}
529
530// Transform normalized device coordinates to window coordinates
531// as specified in the OpenGL ES 2.0 spec section 2.12.1.
532IntRect LayerRenderer::toOpenGLWindowCoordinates(const FloatRect& r) const
533{
534    float vw2 = m_viewport.width() / 2.0;
535    float vh2 = m_viewport.height() / 2.0;
536    float ox = m_viewport.x() + vw2;
537    float oy = m_viewport.y() + vh2;
538    return IntRect(glRound(r.x() * vw2 + ox), glRound(r.y() * vh2 + oy), glRound(r.width() * vw2), glRound(r.height() * vh2));
539}
540
541static FloatRect toPixelCoordinates(const FloatRect& rect, const IntRect& viewport, int surfaceHeight)
542{
543    float vw2 = viewport.width() / 2.0;
544    float vh2 = viewport.height() / 2.0;
545    float ox = viewport.x() + vw2;
546    float oy = surfaceHeight - (viewport.y() + vh2);
547    return FloatRect(rect.x() * vw2 + ox, -(rect.y() + rect.height()) * vh2 + oy, rect.width() * vw2, rect.height() * vh2);
548}
549
550// Transform normalized device coordinates to window coordinates as WebKit understands them.
551//
552// The OpenGL surface may be larger than the WebKit window, and OpenGL window coordinates
553// have origin in bottom left while WebKit window coordinates origin is in top left.
554// The viewport is setup to cover the upper portion of the larger OpenGL surface.
555IntRect LayerRenderer::toWindowCoordinates(const FloatRect& rect) const
556{
557    return enclosingIntRect(toPixelCoordinates(rect, m_viewport, m_client->context()->surfaceSize().height()));
558}
559
560IntRect LayerRenderer::toPixelViewportCoordinates(const FloatRect& rect) const
561{
562    // The clip rect defines the web page's pixel viewport (to use ViewportAccessor terminology),
563    // not to be confused with the GL viewport. So translate from window coordinates to pixel
564    // viewport coordinates.
565    int surfaceHeight = m_client->context()->surfaceSize().height();
566    FloatRect pixelViewport = toPixelCoordinates(m_clipRect, m_viewport, surfaceHeight);
567    FloatRect result = toPixelCoordinates(rect, m_viewport, surfaceHeight);
568    result.move(-pixelViewport.x(), -pixelViewport.y());
569    return enclosingIntRect(result);
570}
571
572IntRect LayerRenderer::toDocumentViewportCoordinates(const FloatRect& rect) const
573{
574    // Similar to toPixelViewportCoordinates except that this also takes any zoom into account.
575    FloatRect result = toPixelViewportCoordinates(rect);
576    result.scale(1 / m_scale);
577    return enclosingIntRect(result);
578}
579
580void LayerRenderer::drawDebugBorder(const Vector<FloatPoint>& transformedBounds, const Color& borderColor, float borderWidth)
581{
582    if (borderColor.alpha() < 255) {
583        glEnable(GL_BLEND);
584        glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
585    } else
586        glDisable(GL_BLEND);
587
588    const GLES2Program& program = useProgram(ColorProgram);
589    glVertexAttribPointer(program.positionLocation(), 2, GL_FLOAT, GL_FALSE, 0, transformedBounds.data());
590    glUniform4f(m_colorColorLocation, borderColor.red() / 255.0, borderColor.green() / 255.0, borderColor.blue() / 255.0, borderColor.alpha() / 255.0);
591
592    glLineWidth(borderWidth);
593    glDrawArrays(GL_LINE_LOOP, 0, transformedBounds.size());
594}
595
596// Draws a debug border around the layer's bounds.
597void LayerRenderer::drawDebugBorder(LayerCompositingThread* layer)
598{
599    Color borderColor = layer->borderColor();
600
601#if DEBUG_LAYER_ANIMATIONS
602    if (layer->hasRunningAnimations())
603        borderColor =  Color(0x00, 0xFF, 0x00, 0xFF);
604#endif
605
606    if (!borderColor.alpha())
607        return;
608
609    // If we're rendering to a surface, don't include debug border inside the surface.
610    if (m_currentLayerRendererSurface)
611        return;
612
613    Vector<FloatPoint> transformedBounds;
614    if (layerAlreadyOnSurface(layer))
615        transformedBounds = layer->layerRendererSurface()->transformedBounds();
616    else
617        transformedBounds = layer->transformedBounds();
618
619    drawDebugBorder(transformedBounds, borderColor, std::max(1.0f, layer->borderWidth()));
620}
621
622// Clears a rectangle inside the layer's bounds.
623void LayerRenderer::drawHolePunchRect(LayerCompositingThread* layer)
624{
625    const GLES2Program& program = useProgram(ColorProgram);
626    glUniform4f(m_colorColorLocation, 0, 0, 0, 0);
627
628    glEnable(GL_BLEND);
629    glBlendFunc(GL_ONE, GL_ZERO);
630    FloatQuad hole = layer->transformedHolePunchRect();
631    glVertexAttribPointer(program.positionLocation(), 2, GL_FLOAT, GL_FALSE, 0, &hole);
632    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
633    checkGLError();
634}
635
636void LayerRenderer::prepareFrameRecursive(LayerCompositingThread* layer, double animationTime, bool isContextCurrent)
637{
638    // This might cause the layer to recompute some attributes.
639    m_lastRenderingResults.needsAnimationFrame |= layer->updateAnimations(animationTime);
640
641    if (isContextCurrent) {
642        // Even non-visible layers need to perform their texture jobs, or they will
643        // pile up and waste memory.
644        if (layer->needsTexture())
645            layer->updateTextureContentsIfNeeded();
646        if (layer->maskLayer() && layer->maskLayer()->needsTexture())
647            layer->maskLayer()->updateTextureContentsIfNeeded();
648        if (layer->replicaLayer()) {
649            LayerCompositingThread* replica = layer->replicaLayer();
650            if (replica->needsTexture())
651                replica->updateTextureContentsIfNeeded();
652            if (replica->maskLayer() && replica->maskLayer()->needsTexture())
653                replica->maskLayer()->updateTextureContentsIfNeeded();
654        }
655    }
656
657    const Vector<RefPtr<LayerCompositingThread> >& sublayers = layer->sublayers();
658    for (size_t i = 0; i < sublayers.size(); i++)
659        prepareFrameRecursive(sublayers[i].get(), animationTime, isContextCurrent);
660}
661
662void LayerRenderer::updateLayersRecursive(LayerCompositingThread* layer, const TransformationMatrix& matrix, const TransformationMatrix& projectionMatrix, Vector<RefPtr<LayerCompositingThread> >& surfaceLayers, float opacity, FloatRect clipRect)
663{
664    // The contract for LayerCompositingThread::setLayerRenderer is it must be set if the layer has been rendered.
665    // So do it now, before we render it in compositeLayersRecursive.
666    layer->setLayerRenderer(this);
667    if (layer->maskLayer())
668        layer->maskLayer()->setLayerRenderer(this);
669    if (layer->replicaLayer()) {
670        LayerCompositingThread* replica = layer->replicaLayer();
671        replica->setLayerRenderer(this);
672        if (replica->maskLayer())
673            replica->maskLayer()->setLayerRenderer(this);
674    }
675
676    // Compute the new matrix transformation that will be applied to this layer and
677    // all its sublayers. It's important to remember that the layer's position
678    // is the position of the layer's anchor point. Also, the coordinate system used
679    // assumes that the origin is at the lower left even though the coordinates the browser
680    // gives us for the layers are for the upper left corner. The Y flip happens via
681    // the orthographic projection applied at render time.
682    // The transformation chain for the layer is (using the Matrix x Vector order):
683    // M = M[p] * Tr[l] * M[l] * Tr[c]
684    // Where M[p] is the parent matrix passed down to the function
685    //       Tr[l] is the translation matrix locating the layer's anchor point
686    //       Tr[c] is the translation offset between the anchor point and the center of the layer
687    //       M[l] is the layer's matrix (applied at the anchor point)
688    // This transform creates a coordinate system whose origin is the center of the layer.
689    // Note that the final matrix used by the shader for the layer is P * M * S . This final product
690    // is computed in drawTexturedQuad().
691    // Where: P is the projection matrix
692    //        M is the layer's matrix computed above
693    //        S is the scale adjustment (to scale up to the layer size)
694    FloatSize bounds = layer->bounds();
695    if (layer->sizeIsScaleInvariant())
696        bounds.scale(1.0 / m_scale);
697    FloatPoint anchorPoint = layer->anchorPoint();
698    FloatPoint position = layer->position();
699
700    // Layer whose hasFixedContainer is true will get scrolled relative to
701    // the fixed positioned parent.
702    if (!layer->hasFixedContainer() && (layer->isFixedPosition() || layer->hasFixedAncestorInDOMTree())) {
703        FloatRect layoutRect = m_layoutRect;
704        FloatSize contentsSize = m_contentsSize;
705        FloatRect visibleRect = m_visibleRect;
706        for (LayerCompositingThread* curr = layer->superlayer(); curr; curr = curr->superlayer()) {
707
708            if (curr->isContainerForFixedPositionLayers()) {
709                layoutRect = curr->frameVisibleRect();
710                contentsSize = curr->frameContentsSize();
711
712                // If we reach a container for fixed position layers, and it has its override's position set, it means it is a scrollable iframe
713                // currently being scrolled. Otherwise, use the WebKit-thread scroll position stored in frameVisibleRect().
714                if (curr->override()->isPositionSet()) {
715                    // Inverted logic of
716                    // FloatPoint layerPosition(-scrollPosition.x() + anchor.x() * bounds.width(),
717                    //                          -scrollPosition.y() + anchor.y() * bounds.height());
718                    FloatPoint scrollPosition(
719                        -(curr->override()->position().x() - (curr->anchorPoint().x() * curr->bounds().width())),
720                        -(curr->override()->position().y() - (curr->anchorPoint().y() * curr->bounds().height())));
721                    visibleRect = FloatRect(scrollPosition, layoutRect.size());
722                } else
723                    visibleRect = layoutRect;
724
725                break;
726            }
727        }
728
729        FloatPoint maximumScrollPosition = FloatPoint(0, 0) + (contentsSize - visibleRect.size());
730        FloatPoint maximumLayoutScrollPosition = FloatPoint(0, 0) + (contentsSize - layoutRect.size());
731
732        // The basic idea here is to set visible x/y to the value we want, and
733        // layout x/y to the value WebCore layouted the fixed element to.
734        float visibleY;
735        float layoutY;
736        if (layer->isFixedToTop()) {
737            visibleY = max(0.0f, min(maximumScrollPosition.y(), visibleRect.y()));
738            layoutY = max(0.0f, min(maximumLayoutScrollPosition.y(), layoutRect.y()));
739        } else {
740            visibleY = min(contentsSize.height(), visibleRect.y() + visibleRect.height());
741            layoutY = min(contentsSize.height(), max(0.0f, layoutRect.y()) + layoutRect.height());
742        }
743        position.setY(position.y() + (visibleY - layoutY));
744
745        float visibleX;
746        float layoutX;
747        if (layer->isFixedToLeft()) {
748            visibleX = max(0.0f, min(maximumScrollPosition.x(), visibleRect.x()));
749            layoutX = max(0.0f, min(maximumLayoutScrollPosition.x(), layoutRect.x()));
750        } else {
751            visibleX = min(contentsSize.width(), visibleRect.x() + visibleRect.width());
752            layoutX = min(contentsSize.width(), max(0.0f, layoutRect.x()) + layoutRect.width());
753        }
754        position.setX(position.x() + (visibleX - layoutX));
755    }
756
757    // Offset between anchor point and the center of the quad.
758    float centerOffsetX = (0.5 - anchorPoint.x()) * bounds.width();
759    float centerOffsetY = (0.5 - anchorPoint.y()) * bounds.height();
760
761    // M = M[p]
762    TransformationMatrix localMatrix = matrix;
763    // M = M[p] * Tr[l]
764    localMatrix.translate3d(position.x(), position.y(), layer->anchorPointZ());
765    // M = M[p] * Tr[l] * M[l]
766    localMatrix.multiply(layer->transform());
767    // M = M[p] * Tr[l] * M[l] * Tr[c]
768    localMatrix.translate3d(centerOffsetX, centerOffsetY, -layer->anchorPointZ());
769
770    // Calculate the layer's opacity.
771    opacity *= layer->opacity();
772
773    TransformationMatrix localProjectionMatrix = projectionMatrix;
774#if ENABLE(CSS_FILTERS)
775    bool useLayerRendererSurface = layer->maskLayer() || layer->replicaLayer() || layer->filters().size();
776#else
777    bool useLayerRendererSurface = layer->maskLayer() || layer->replicaLayer();
778#endif
779    if (!useLayerRendererSurface) {
780        layer->setDrawOpacity(opacity);
781        layer->clearLayerRendererSurface();
782    } else {
783        if (!layer->layerRendererSurface())
784            layer->createLayerRendererSurface();
785
786        LayerRendererSurface* surface = layer->layerRendererSurface();
787
788        layer->setDrawOpacity(1.0);
789        surface->setDrawOpacity(opacity);
790
791        surface->setDrawTransform(localMatrix, projectionMatrix);
792        if (layer->replicaLayer()) {
793            TransformationMatrix replicaMatrix = localMatrix;
794            replicaMatrix.translate3d(-0.5 * bounds.width(), -0.5 * bounds.height(), 0);
795            replicaMatrix.translate3d(layer->replicaLayer()->position().x(), layer->replicaLayer()->position().y(), 0);
796            replicaMatrix.multiply(layer->replicaLayer()->transform());
797            replicaMatrix.translate3d(centerOffsetX, centerOffsetY, 0);
798            surface->setReplicaDrawTransform(replicaMatrix, projectionMatrix);
799        }
800
801        IntRect contentRect = enclosingIntRect(FloatRect(FloatPoint::zero(), bounds));
802        surface->setContentRect(contentRect);
803
804        localProjectionMatrix = orthoMatrix(contentRect.x(), contentRect.maxX(), contentRect.y(), contentRect.maxY(), -1000, 1000);
805        // The origin of the new surface is the upper left corner of the layer.
806        TransformationMatrix drawTransform;
807        drawTransform.translate3d(0.5 * bounds.width(), 0.5 * bounds.height(), 0);
808        // This layer will start using new transformation.
809        localMatrix = drawTransform;
810
811        surfaceLayers.append(layer);
812    }
813
814    layer->setDrawTransform(m_scale, localMatrix, localProjectionMatrix);
815
816#if ENABLE(VIDEO)
817    bool layerVisible = clipRect.intersects(layer->boundingBox()) || layer->mediaPlayer();
818#else
819    bool layerVisible = clipRect.intersects(layer->boundingBox());
820#endif
821
822    if (layer->needsTexture() && layerVisible) {
823        IntRect dirtyRect = toWindowCoordinates(intersection(layer->boundingBox(), clipRect));
824        m_lastRenderingResults.addDirtyRect(dirtyRect);
825    }
826
827    if (layer->masksToBounds())
828        clipRect.intersect(layer->boundingBox());
829
830    // Flatten to 2D if the layer doesn't preserve 3D.
831    if (!layer->preserves3D()) {
832        localMatrix.setM13(0);
833        localMatrix.setM23(0);
834        localMatrix.setM31(0);
835        localMatrix.setM32(0);
836        localMatrix.setM33(1);
837        localMatrix.setM34(0);
838        localMatrix.setM43(0);
839    }
840
841    // Apply the sublayer transform.
842    localMatrix.multiply(layer->sublayerTransform());
843
844    // The origin of the sublayers is actually the bottom left corner of the layer
845    // (or top left when looking it it from the browser's pespective) instead of the center.
846    // The matrix passed down to the sublayers is therefore:
847    // M[s] = M * Tr[-center]
848    localMatrix.translate3d(-bounds.width() * 0.5, -bounds.height() * 0.5, 0);
849
850    const Vector<RefPtr<LayerCompositingThread> >& sublayers = layer->sublayers();
851    for (size_t i = 0; i < sublayers.size(); i++)
852        updateLayersRecursive(sublayers[i].get(), localMatrix, localProjectionMatrix, surfaceLayers, opacity, clipRect);
853}
854
855static bool hasRotationalComponent(const TransformationMatrix& m)
856{
857    return m.m12() || m.m13() || m.m23() || m.m21() || m.m31() || m.m32();
858}
859
860bool LayerRenderer::layerAlreadyOnSurface(LayerCompositingThread* layer) const
861{
862    return layer->layerRendererSurface() && layer->layerRendererSurface() != m_currentLayerRendererSurface;
863}
864
865static void collect3DPreservingLayers(Vector<LayerCompositingThread*>& layers)
866{
867    for (size_t i = 0; i < layers.size(); ++i) {
868        LayerCompositingThread* layer = layers[i];
869        if (!layer->preserves3D() || !layer->sublayers().size())
870            continue;
871
872        Vector<LayerCompositingThread*> sublayers = rawPtrVectorFromRefPtrVector(layer->sublayers());
873        collect3DPreservingLayers(sublayers);
874        layers.insert(i+1, sublayers);
875        i += sublayers.size();
876    }
877}
878
879void LayerRenderer::compositeLayersRecursive(LayerCompositingThread* layer, int stencilValue, FloatRect clipRect)
880{
881    FloatRect rect;
882    if (layerAlreadyOnSurface(layer))
883        rect = layer->layerRendererSurface()->boundingBox();
884    else
885        rect = layer->boundingBox();
886
887#if ENABLE(VIDEO)
888    bool layerVisible = clipRect.intersects(rect) || layer->mediaPlayer();
889#else
890    bool layerVisible = clipRect.intersects(rect);
891#endif
892
893    layer->setVisible(layerVisible);
894
895    // Note that there are two types of layers:
896    // 1. Layers that have their own GraphicsContext and can draw their contents on demand (layer->drawsContent() == true).
897    // 2. Layers that are just containers of images/video/etc that don't own a GraphicsContext (layer->contents() == true).
898
899    if ((layer->needsTexture() || layer->layerRendererSurface()) && layerVisible) {
900        updateScissorIfNeeded(clipRect);
901
902        if (stencilValue) {
903            glStencilFunc(GL_EQUAL, stencilValue, 0xff);
904            glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
905        }
906
907        if (layer->doubleSided())
908            glDisable(GL_CULL_FACE);
909        else
910            glEnable(GL_CULL_FACE);
911
912        if (layer->hasVisibleHolePunchRect())
913            drawHolePunchRect(layer);
914
915        // Draw the surface onto another surface or screen.
916        bool drawSurface = layerAlreadyOnSurface(layer);
917        // The texture format for the surface is RGBA.
918        LayerData::LayerProgram layerProgram = drawSurface ? LayerData::LayerProgramRGBA : layer->layerProgram();
919
920        if (!drawSurface) {
921            const GLES2Program& program = useLayerProgram(layerProgram);
922            layer->drawTextures(program, m_scale, m_visibleRect, clipRect);
923        } else {
924            // Draw the reflection if it exists.
925            if (layer->replicaLayer()) {
926                // If this layer and its reflection both have mask, we need another temporary surface.
927                // Since this use case should be rare, currently it's not handled and the mask for
928                // the reflection is applied only when this layer has no mask.
929                LayerCompositingThread* mask = layer->maskLayer();
930                if (!mask && layer->replicaLayer())
931                    mask = layer->replicaLayer()->maskLayer();
932
933                const GLES2Program& program = useLayerProgram(layerProgram, mask);
934                layer->drawSurface(program, layer->layerRendererSurface()->replicaDrawTransform(), mask);
935            }
936
937            const GLES2Program& program = useLayerProgram(layerProgram, layer->maskLayer());
938            layer->drawSurface(program, layer->layerRendererSurface()->drawTransform(), layer->maskLayer());
939        }
940    }
941
942    // Draw the debug border if there is one.
943    drawDebugBorder(layer);
944
945    // The texture for the LayerRendererSurface can be released after the surface was drawn on another surface.
946    if (layerAlreadyOnSurface(layer)) {
947        layer->layerRendererSurface()->releaseTexture();
948        return;
949    }
950
951    // If we need to mask to bounds but the transformation has a rotational component
952    // to it, scissoring is not enough and we need to use the stencil buffer for clipping.
953    bool stencilClip = layer->masksToBounds() && hasRotationalComponent(layer->drawTransform());
954
955    if (stencilClip) {
956        if (!m_stencilCleared) {
957            glStencilMask(0xffffffff);
958            glClearStencil(0);
959            glClear(GL_STENCIL_BUFFER_BIT);
960            m_stencilCleared = true;
961        }
962
963        glEnable(GL_STENCIL_TEST);
964        glStencilFunc(GL_EQUAL, stencilValue, 0xff);
965        glStencilOp(GL_KEEP, GL_INCR, GL_INCR);
966
967        updateScissorIfNeeded(clipRect);
968        const GLES2Program& program = useProgram(ColorProgram);
969        glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
970        glVertexAttribPointer(program.positionLocation(), 2, GL_FLOAT, GL_FALSE, 0, layer->transformedBounds().data());
971        glDrawArrays(GL_TRIANGLE_FAN, 0, layer->transformedBounds().size());
972        glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
973    }
974
975    if (layer->masksToBounds())
976        clipRect.intersect(layer->boundingBox());
977
978    // Here, we need to sort the whole subtree of layers with preserve-3d. It
979    // affects all children, and the children of any children with preserve-3d,
980    // and so on.
981    Vector<LayerCompositingThread*> sublayers = rawPtrVectorFromRefPtrVector(layer->sublayers());
982
983    bool preserves3D = layer->preserves3D();
984    bool superlayerPreserves3D = layer->superlayer() && layer->superlayer()->preserves3D();
985
986    // Collect and render all sublayers with preserves-3D.
987    // If the superlayer preserves 3D, we've already collected and rendered its
988    // children, so bail.
989    if (preserves3D && !superlayerPreserves3D) {
990        collect3DPreservingLayers(sublayers);
991        std::stable_sort(sublayers.begin(), sublayers.end(), compareLayerW);
992    }
993
994    int newStencilValue = stencilClip ? stencilValue+1 : stencilValue;
995    for (size_t i = 0; i < sublayers.size(); i++) {
996        LayerCompositingThread* sublayer = sublayers[i];
997        // The root of the 3d-preserving subtree has collected all
998        // 3d-preserving layers and their children and will render them all in
999        // the right order.
1000        if (preserves3D && superlayerPreserves3D)
1001            continue;
1002
1003        compositeLayersRecursive(sublayer, newStencilValue, clipRect);
1004    }
1005
1006    if (stencilClip) {
1007        glStencilFunc(GL_LEQUAL, stencilValue, 0xff);
1008        glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
1009
1010        updateScissorIfNeeded(clipRect);
1011        const GLES2Program& program = useProgram(ColorProgram);
1012        glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
1013        glVertexAttribPointer(program.positionLocation(), 2, GL_FLOAT, GL_FALSE, 0, layer->transformedBounds().data());
1014        glDrawArrays(GL_TRIANGLE_FAN, 0, layer->transformedBounds().size());
1015        glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1016
1017        if (!stencilValue)
1018            glDisable(GL_STENCIL_TEST);
1019    }
1020}
1021
1022void LayerRenderer::updateScissorIfNeeded(const FloatRect& clipRect)
1023{
1024#if DEBUG_CLIPPING
1025    printf("LayerRenderer::updateScissorIfNeeded(): clipRect=(%.2f,%.2f %.2fx%.2f)\n", clipRect.x(), clipRect.y(), clipRect.width(), clipRect.height());
1026    fflush(stdout);
1027#endif
1028    IntRect clipRectWC = toOpenGLWindowCoordinates(clipRect);
1029    if (m_scissorRect == clipRectWC)
1030        return;
1031
1032    m_scissorRect = clipRectWC;
1033#if DEBUG_CLIPPING
1034    printf("LayerRenderer::updateScissorIfNeeded(): clipping to (%d,%d %dx%d)\n", m_scissorRect.x(), m_scissorRect.y(), m_scissorRect.width(), m_scissorRect.height());
1035    fflush(stdout);
1036#endif
1037    glScissor(m_scissorRect.x(), m_scissorRect.y(), m_scissorRect.width(), m_scissorRect.height());
1038}
1039
1040bool LayerRenderer::makeContextCurrent()
1041{
1042    bool ret = m_client->context()->makeCurrent();
1043    if (ret && m_isRobustnessSupported) {
1044        if (m_glGetGraphicsResetStatusEXT() != GL_NO_ERROR) {
1045            BlackBerry::Platform::logAlways(BlackBerry::Platform::LogLevelCritical, "Robust OpenGL context has been reset. Aborting.");
1046            CRASH();
1047        }
1048    }
1049    return ret;
1050}
1051
1052bool LayerRenderer::createProgram(ProgramIndex program)
1053{
1054    // Shaders for drawing the layer contents.
1055    const char* vertexShaderString =
1056        "attribute vec4 a_position;   \n"
1057        "attribute vec2 a_texCoord;   \n"
1058        "varying vec2 v_texCoord;     \n"
1059        "void main()                  \n"
1060        "{                            \n"
1061        "  gl_Position = a_position;  \n"
1062        "  v_texCoord = a_texCoord;   \n"
1063        "}                            \n";
1064
1065    const char* fragmentShaderStringRGBA =
1066        "varying mediump vec2 v_texCoord;                           \n"
1067        "uniform lowp sampler2D s_texture;                          \n"
1068        "uniform lowp float alpha;                                  \n"
1069        "void main()                                                \n"
1070        "{                                                          \n"
1071        "  gl_FragColor = texture2D(s_texture, v_texCoord) * alpha; \n"
1072        "}                                                          \n";
1073
1074    const char* fragmentShaderStringBGRA =
1075        "varying mediump vec2 v_texCoord;                                \n"
1076        "uniform lowp sampler2D s_texture;                               \n"
1077        "uniform lowp float alpha;                                       \n"
1078        "void main()                                                     \n"
1079        "{                                                               \n"
1080        "  gl_FragColor = texture2D(s_texture, v_texCoord).bgra * alpha; \n"
1081        "}                                                               \n";
1082
1083    const char* fragmentShaderStringMaskRGBA =
1084        "varying mediump vec2 v_texCoord;                           \n"
1085        "uniform lowp sampler2D s_texture;                          \n"
1086        "uniform lowp sampler2D s_mask;                             \n"
1087        "uniform lowp float alpha;                                  \n"
1088        "void main()                                                \n"
1089        "{                                                          \n"
1090        "  lowp vec4 texColor = texture2D(s_texture, v_texCoord);   \n"
1091        "  lowp vec4 maskColor = texture2D(s_mask, v_texCoord);     \n"
1092        "  gl_FragColor = vec4(texColor.x, texColor.y, texColor.z, texColor.w) * alpha * maskColor.w;           \n"
1093        "}                                                          \n";
1094
1095    const char* fragmentShaderStringMaskBGRA =
1096        "varying mediump vec2 v_texCoord;                                \n"
1097        "uniform lowp sampler2D s_texture;                               \n"
1098        "uniform lowp sampler2D s_mask;                                  \n"
1099        "uniform lowp float alpha;                                       \n"
1100        "void main()                                                     \n"
1101        "{                                                               \n"
1102        "  lowp vec4 texColor = texture2D(s_texture, v_texCoord).bgra;             \n"
1103        "  lowp vec4 maskColor = texture2D(s_mask, v_texCoord).bgra;          \n"
1104        "  gl_FragColor = vec4(texColor.x, texColor.y, texColor.z, texColor.w) * alpha * maskColor.w;         \n"
1105        "}                                                               \n";
1106
1107    // Shaders for drawing the debug borders around the layers.
1108    const char* colorVertexShaderString =
1109        "attribute vec4 a_position;   \n"
1110        "void main()                  \n"
1111        "{                            \n"
1112        "   gl_Position = a_position; \n"
1113        "}                            \n";
1114
1115    const char* colorFragmentShaderString =
1116        "uniform lowp vec4 color;     \n"
1117        "void main()                  \n"
1118        "{                            \n"
1119        "  gl_FragColor = color;      \n"
1120        "}                            \n";
1121
1122    const char* vertexShader = 0;
1123    const char* fragmentShader = 0;
1124
1125    switch (program) {
1126    case LayerProgramRGBA:
1127    case LayerProgramBGRA:
1128    case LayerMaskProgramRGBA:
1129    case LayerMaskProgramBGRA:
1130        vertexShader = vertexShaderString;
1131        break;
1132    case ColorProgram:
1133        vertexShader = colorVertexShaderString;
1134        break;
1135    case NumberOfPrograms:
1136        return false;
1137    }
1138
1139    switch (program) {
1140    case LayerProgramRGBA:
1141        fragmentShader = fragmentShaderStringRGBA;
1142        break;
1143    case LayerProgramBGRA:
1144        fragmentShader = fragmentShaderStringBGRA;
1145        break;
1146    case LayerMaskProgramRGBA:
1147        fragmentShader = fragmentShaderStringMaskRGBA;
1148        break;
1149    case LayerMaskProgramBGRA:
1150        fragmentShader = fragmentShaderStringMaskBGRA;
1151        break;
1152    case ColorProgram:
1153        fragmentShader = colorFragmentShaderString;
1154        break;
1155    case NumberOfPrograms:
1156        return false;
1157    }
1158
1159    if (!vertexShader || !fragmentShader)
1160        return false;
1161
1162    GLuint programObject = loadShaderProgram(vertexShader, fragmentShader);
1163    if (!programObject) {
1164        LOG_ERROR("Failed to create program %u", program);
1165        return false;
1166    }
1167
1168    m_programs[program].m_program = programObject;
1169
1170    // Binds the given attribute name to a common location across all programs
1171    // used by the compositor. This allows the code to bind the attributes only once
1172    // even when switching between programs.
1173    glBindAttribLocation(programObject, GLES2Program::PositionAttributeIndex, "a_position");
1174    glBindAttribLocation(programObject, GLES2Program::TexCoordAttributeIndex, "a_texCoord");
1175
1176    checkGLError();
1177
1178    // Re-link the shader to get the new attrib location to take effect.
1179    glLinkProgram(programObject);
1180
1181    checkGLError();
1182
1183    // Get locations of uniforms for the layer content shader program.
1184    m_programs[program].m_locations[GLES2Program::OpacityUniform] = glGetUniformLocation(programObject, "alpha");
1185    switch (program) {
1186    case LayerProgramRGBA:
1187    case LayerProgramBGRA: {
1188        GLint samplerLocation = glGetUniformLocation(programObject, "s_texture");
1189        glUseProgram(programObject);
1190        glUniform1i(samplerLocation, 0);
1191        break;
1192    }
1193    case LayerMaskProgramRGBA:
1194    case LayerMaskProgramBGRA: {
1195        GLint maskSamplerLocation = glGetUniformLocation(programObject, "s_texture");
1196        GLint maskSamplerLocationMask = glGetUniformLocation(programObject, "s_mask");
1197        glUseProgram(programObject);
1198        glUniform1i(maskSamplerLocation, 0);
1199        glUniform1i(maskSamplerLocationMask, 1);
1200        break;
1201    }
1202    case ColorProgram:
1203        // Get locations of uniforms for the debug border shader program.
1204        m_colorColorLocation = glGetUniformLocation(programObject, "color");
1205        break;
1206    case NumberOfPrograms:
1207        return false;
1208    }
1209
1210    return true;
1211}
1212
1213const GLES2Program& LayerRenderer::useProgram(ProgramIndex index)
1214{
1215    ASSERT(index < NumberOfPrograms);
1216    const GLES2Program& program = m_programs[index];
1217    if (!program.isValid() && !createProgram(index))
1218        return program;
1219
1220    glUseProgram(program.m_program);
1221
1222    glEnableVertexAttribArray(program.positionLocation());
1223    if (index != ColorProgram)
1224        glEnableVertexAttribArray(program.texCoordLocation());
1225
1226    return program;
1227}
1228
1229const GLES2Program& LayerRenderer::useLayerProgram(LayerData::LayerProgram layerProgram, bool isMask /* = false */)
1230{
1231    int program = layerProgram;
1232    if (isMask)
1233        program += MaskPrograms;
1234    return useProgram(static_cast<ProgramIndex>(program));
1235}
1236
1237void LayerRenderingResults::addDirtyRect(const IntRect& rect)
1238{
1239    IntRect dirtyUnion[NumberOfDirtyRects];
1240    int smallestIncrease = INT_MAX;
1241    int modifiedRect = 0;
1242    for (int i = 0; i < NumberOfDirtyRects; ++i) {
1243        dirtyUnion[i] = m_dirtyRects[i];
1244        dirtyUnion[i].unite(rect);
1245        int increase = dirtyUnion[i].width()*dirtyUnion[i].height() - m_dirtyRects[i].width()*m_dirtyRects[i].height();
1246        if (increase < smallestIncrease) {
1247            smallestIncrease = increase;
1248            modifiedRect = i;
1249        }
1250    }
1251
1252    m_dirtyRects[modifiedRect] = dirtyUnion[modifiedRect];
1253}
1254
1255bool LayerRenderingResults::isEmpty() const
1256{
1257    for (int i = 0; i < NumberOfDirtyRects; ++i) {
1258        if (!m_dirtyRects[i].isEmpty())
1259            return false;
1260    }
1261    return true;
1262}
1263
1264} // namespace WebCore
1265
1266#endif // USE(ACCELERATED_COMPOSITING)
1267