1/*
2 * Copyright 2010, The Android Open Source Project
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *  * Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 *  * Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#define LOG_TAG "GLUtils"
27#define LOG_NDEBUG 1
28
29#include "config.h"
30#include "GLUtils.h"
31
32#if USE(ACCELERATED_COMPOSITING)
33
34#include "AndroidLog.h"
35#include "BaseRenderer.h"
36#include "TextureInfo.h"
37#include "Tile.h"
38#include "TilesManager.h"
39#include "TransferQueue.h"
40
41#include <android/native_window.h>
42#include <gui/SurfaceTexture.h>
43#include <wtf/CurrentTime.h>
44
45// We will limit GL error logging for LOG_VOLUME_PER_CYCLE times every
46// LOG_VOLUME_PER_CYCLE seconds.
47#define LOG_CYCLE 30.0
48#define LOG_VOLUME_PER_CYCLE 20
49
50struct ANativeWindowBuffer;
51
52namespace WebCore {
53
54using namespace android;
55
56/////////////////////////////////////////////////////////////////////////////////////////
57// Matrix utilities
58/////////////////////////////////////////////////////////////////////////////////////////
59
60void GLUtils::toGLMatrix(GLfloat* flattened, const TransformationMatrix& m)
61{
62    flattened[0] = m.m11(); // scaleX
63    flattened[1] = m.m12(); // skewY
64    flattened[2] = m.m13();
65    flattened[3] = m.m14(); // persp0
66    flattened[4] = m.m21(); // skewX
67    flattened[5] = m.m22(); // scaleY
68    flattened[6] = m.m23();
69    flattened[7] = m.m24(); // persp1
70    flattened[8] = m.m31();
71    flattened[9] = m.m32();
72    flattened[10] = m.m33();
73    flattened[11] = m.m34();
74    flattened[12] = m.m41(); // transX
75    flattened[13] = m.m42(); // transY
76    flattened[14] = m.m43();
77    flattened[15] = m.m44(); // persp2
78}
79
80void GLUtils::toSkMatrix(SkMatrix& matrix, const TransformationMatrix& m)
81{
82    matrix[0] = m.m11(); // scaleX
83    matrix[1] = m.m21(); // skewX
84    matrix[2] = m.m41(); // transX
85    matrix[3] = m.m12(); // skewY
86    matrix[4] = m.m22(); // scaleY
87    matrix[5] = m.m42(); // transY
88    matrix[6] = m.m14(); // persp0
89    matrix[7] = m.m24(); // persp1
90    matrix[8] = m.m44(); // persp2
91}
92
93void GLUtils::setOrthographicMatrix(TransformationMatrix& ortho, float left, float top,
94                                    float right, float bottom, float nearZ, float farZ)
95{
96    float deltaX = right - left;
97    float deltaY = top - bottom;
98    float deltaZ = farZ - nearZ;
99    if (!deltaX || !deltaY || !deltaZ)
100        return;
101
102    ortho.setM11(2.0f / deltaX);
103    ortho.setM41(-(right + left) / deltaX);
104    ortho.setM22(2.0f / deltaY);
105    ortho.setM42(-(top + bottom) / deltaY);
106    ortho.setM33(-2.0f / deltaZ);
107    ortho.setM43(-(nearZ + farZ) / deltaZ);
108}
109
110bool GLUtils::has3dTransform(const TransformationMatrix& matrix)
111{
112    return matrix.m13() != 0 || matrix.m23() != 0
113        || matrix.m31() != 0 || matrix.m32() != 0
114        || matrix.m33() != 1 || matrix.m34() != 0
115        || matrix.m43() != 0;
116}
117
118/////////////////////////////////////////////////////////////////////////////////////////
119// GL & EGL error checks
120/////////////////////////////////////////////////////////////////////////////////////////
121
122double GLUtils::m_previousLogTime = 0;
123int GLUtils::m_currentLogCounter = 0;
124
125bool GLUtils::allowGLLog()
126{
127    if (m_currentLogCounter < LOG_VOLUME_PER_CYCLE) {
128        m_currentLogCounter++;
129        return true;
130    }
131
132    // when we are in Log cycle and over the log limit, just return false
133    double currentTime = WTF::currentTime();
134    double delta = currentTime - m_previousLogTime;
135    bool inLogCycle = (delta <= LOG_CYCLE) && (delta > 0);
136    if (inLogCycle)
137        return false;
138
139    // When we are out of Log Cycle and over the log limit, we need to reset
140    // the counter and timer.
141    m_previousLogTime = currentTime;
142    m_currentLogCounter = 0;
143    return false;
144}
145
146static void crashIfOOM(GLint errorCode)
147{
148    const GLint OOM_ERROR_CODE = 0x505;
149    if (errorCode == OOM_ERROR_CODE) {
150        ALOGE("ERROR: Fatal OOM detected.");
151        CRASH();
152    }
153}
154
155void GLUtils::checkEglError(const char* op, EGLBoolean returnVal)
156{
157    if (returnVal != EGL_TRUE) {
158#ifndef DEBUG
159        if (allowGLLog())
160#endif
161        ALOGE("EGL ERROR - %s() returned %d\n", op, returnVal);
162    }
163
164    for (EGLint error = eglGetError(); error != EGL_SUCCESS; error = eglGetError()) {
165#ifndef DEBUG
166        if (allowGLLog())
167#endif
168        ALOGE("after %s() eglError (0x%x)\n", op, error);
169        crashIfOOM(error);
170    }
171}
172
173bool GLUtils::checkGlError(const char* op)
174{
175    bool ret = false;
176    for (GLint error = glGetError(); error; error = glGetError()) {
177#ifndef DEBUG
178        if (allowGLLog())
179#endif
180        ALOGE("GL ERROR - after %s() glError (0x%x)\n", op, error);
181        crashIfOOM(error);
182        ret = true;
183    }
184    return ret;
185}
186
187bool GLUtils::checkGlErrorOn(void* p, const char* op)
188{
189    bool ret = false;
190    for (GLint error = glGetError(); error; error = glGetError()) {
191#ifndef DEBUG
192        if (allowGLLog())
193#endif
194        ALOGE("GL ERROR on %x - after %s() glError (0x%x)\n", p, op, error);
195        crashIfOOM(error);
196        ret = true;
197    }
198    return ret;
199}
200
201void GLUtils::checkSurfaceTextureError(const char* functionName, int status)
202{
203    if (status !=  NO_ERROR) {
204#ifndef DEBUG
205        if (allowGLLog())
206#endif
207        ALOGE("ERROR at calling %s status is (%d)", functionName, status);
208    }
209}
210/////////////////////////////////////////////////////////////////////////////////////////
211// GL & EGL extension checks
212/////////////////////////////////////////////////////////////////////////////////////////
213
214bool GLUtils::isEGLImageSupported()
215{
216    const char* eglExtensions = eglQueryString(eglGetCurrentDisplay(), EGL_EXTENSIONS);
217    const char* glExtensions = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
218
219    return eglExtensions && glExtensions
220        && strstr(eglExtensions, "EGL_KHR_image_base")
221        && strstr(eglExtensions, "EGL_KHR_gl_texture_2D_image")
222        && strstr(glExtensions, "GL_OES_EGL_image");
223}
224
225bool GLUtils::isEGLFenceSyncSupported()
226{
227    const char* eglExtensions = eglQueryString(eglGetCurrentDisplay(), EGL_EXTENSIONS);
228    return eglExtensions && strstr(eglExtensions, "EGL_KHR_fence_sync");
229}
230
231/////////////////////////////////////////////////////////////////////////////////////////
232// Textures utilities
233/////////////////////////////////////////////////////////////////////////////////////////
234
235static GLenum getInternalFormat(SkBitmap::Config config)
236{
237    switch (config) {
238    case SkBitmap::kA8_Config:
239        return GL_ALPHA;
240    case SkBitmap::kARGB_4444_Config:
241        return GL_RGBA;
242    case SkBitmap::kARGB_8888_Config:
243        return GL_RGBA;
244    case SkBitmap::kRGB_565_Config:
245        return GL_RGB;
246    default:
247        return -1;
248    }
249}
250
251static GLenum getType(SkBitmap::Config config)
252{
253    switch (config) {
254    case SkBitmap::kA8_Config:
255        return GL_UNSIGNED_BYTE;
256    case SkBitmap::kARGB_4444_Config:
257        return GL_UNSIGNED_SHORT_4_4_4_4;
258    case SkBitmap::kARGB_8888_Config:
259        return GL_UNSIGNED_BYTE;
260    case SkBitmap::kIndex8_Config:
261        return -1; // No type for compressed data.
262    case SkBitmap::kRGB_565_Config:
263        return GL_UNSIGNED_SHORT_5_6_5;
264    default:
265        return -1;
266    }
267}
268
269static EGLConfig defaultPbufferConfig(EGLDisplay display)
270{
271    EGLConfig config;
272    EGLint numConfigs;
273
274    static const EGLint configAttribs[] = {
275        EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
276        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
277        EGL_NONE
278    };
279
280    eglChooseConfig(display, configAttribs, &config, 1, &numConfigs);
281    GLUtils::checkEglError("eglPbufferConfig");
282    if (numConfigs != 1)
283        ALOGI("eglPbufferConfig failed (%d)\n", numConfigs);
284
285    return config;
286}
287
288static EGLSurface createPbufferSurface(EGLDisplay display, const EGLConfig& config,
289                                       EGLint* errorCode)
290{
291    const EGLint attribList[] = {
292        EGL_WIDTH, 1,
293        EGL_HEIGHT, 1,
294        EGL_NONE
295    };
296    EGLSurface surface = eglCreatePbufferSurface(display, config, attribList);
297
298    if (errorCode)
299        *errorCode = eglGetError();
300    else
301        GLUtils::checkEglError("eglCreatePbufferSurface");
302
303    if (surface == EGL_NO_SURFACE)
304        return EGL_NO_SURFACE;
305
306    return surface;
307}
308
309void GLUtils::deleteTexture(GLuint* texture)
310{
311    glDeleteTextures(1, texture);
312    GLUtils::checkGlError("glDeleteTexture");
313    *texture = 0;
314}
315
316GLuint GLUtils::createSampleColorTexture(int r, int g, int b)
317{
318    GLuint texture;
319    glGenTextures(1, &texture);
320    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
321    GLubyte pixels[4 *3] = {
322        r, g, b,
323        r, g, b,
324        r, g, b,
325        r, g, b
326    };
327    glBindTexture(GL_TEXTURE_2D, texture);
328    GLUtils::checkGlError("glBindTexture");
329    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
330    GLUtils::checkGlError("glTexImage2D");
331    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
332    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
333    return texture;
334}
335
336GLuint GLUtils::createSampleTexture()
337{
338    GLuint texture;
339    glGenTextures(1, &texture);
340    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
341    GLubyte pixels[4 *3] = {
342        255, 0, 0,
343        0, 255, 0,
344        0, 0, 255,
345        255, 255, 0
346    };
347    glBindTexture(GL_TEXTURE_2D, texture);
348    GLUtils::checkGlError("glBindTexture");
349    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
350    GLUtils::checkGlError("glTexImage2D");
351    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
352    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
353    return texture;
354}
355
356GLuint GLUtils::createTileGLTexture(int width, int height)
357{
358    GLuint texture;
359    glGenTextures(1, &texture);
360    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
361    GLubyte* pixels = 0;
362#ifdef DEBUG
363    int length = width * height * 4;
364    pixels = new GLubyte[length];
365    for (int i = 0; i < length; i++)
366        pixels[i] = i % 256;
367#endif
368    glBindTexture(GL_TEXTURE_2D, texture);
369    GLUtils::checkGlError("glBindTexture");
370    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
371    GLUtils::checkGlError("glTexImage2D");
372    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
373    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
374    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
375    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
376#ifdef DEBUG
377    delete pixels;
378#endif
379    return texture;
380}
381
382bool GLUtils::isPureColorBitmap(const SkBitmap& bitmap, Color& pureColor)
383{
384    // If the bitmap is the pure color, skip the transfer step, and update the Tile Info.
385    // This check is taking < 1ms if we do full bitmap check per tile.
386    // TODO: use the SkPicture to determine whether or not a tile is single color.
387    TRACE_METHOD();
388    pureColor = Color(Color::transparent);
389    bitmap.lockPixels();
390    bool sameColor = true;
391    int bitmapWidth = bitmap.width();
392
393    // Create a row of pure color using the first pixel.
394    // TODO: improve the perf here, by either picking a random pixel, or
395    // creating an array of rows with pre-defined commonly used color, add
396    // smart LUT to speed things up if possible.
397    int* firstPixelPtr = static_cast<int*> (bitmap.getPixels());
398    int* pixelsRow = new int[bitmapWidth];
399    for (int i = 0; i < bitmapWidth; i++)
400        pixelsRow[i] = (*firstPixelPtr);
401
402    // Then compare the pure color row with each row of the bitmap.
403    for (int j = 0; j < bitmap.height(); j++) {
404        if (memcmp(pixelsRow, &firstPixelPtr[bitmapWidth * j], 4 * bitmapWidth)) {
405            sameColor = false;
406            break;
407        }
408    }
409    delete pixelsRow;
410    pixelsRow = 0;
411
412    if (sameColor) {
413        unsigned char* rgbaPtr = static_cast<unsigned char*>(bitmap.getPixels());
414        pureColor = Color(rgbaPtr[0], rgbaPtr[1], rgbaPtr[2], rgbaPtr[3]);
415        ALOGV("sameColor tile found , %x at (%d, %d, %d, %d)",
416              *firstPixelPtr, rgbaPtr[0], rgbaPtr[1], rgbaPtr[2], rgbaPtr[3]);
417    }
418    bitmap.unlockPixels();
419
420    return sameColor;
421}
422
423// Return true when the tile is pure color.
424bool GLUtils::skipTransferForPureColor(const TileRenderInfo* renderInfo,
425                                       const SkBitmap& bitmap)
426{
427    bool skipTransfer = false;
428    Tile* tilePtr = renderInfo->baseTile;
429
430    if (tilePtr) {
431        TileTexture* tileTexture = tilePtr->backTexture();
432        // Check the bitmap, and make everything ready here.
433        if (tileTexture && renderInfo->isPureColor) {
434            // update basetile's info
435            // Note that we are skipping the whole TransferQueue.
436            renderInfo->textureInfo->m_width = bitmap.width();
437            renderInfo->textureInfo->m_height = bitmap.height();
438            renderInfo->textureInfo->m_internalFormat = GL_RGBA;
439
440            TilesManager::instance()->transferQueue()->addItemInPureColorQueue(renderInfo);
441
442            skipTransfer = true;
443        }
444    }
445    return skipTransfer;
446}
447
448void GLUtils::paintTextureWithBitmap(const TileRenderInfo* renderInfo,
449                                     SkBitmap& bitmap)
450{
451    if (!renderInfo)
452        return;
453    const SkSize& requiredSize = renderInfo->tileSize;
454    TextureInfo* textureInfo = renderInfo->textureInfo;
455
456    if (skipTransferForPureColor(renderInfo, bitmap))
457        return;
458
459    if (requiredSize.equals(textureInfo->m_width, textureInfo->m_height))
460        GLUtils::updateQueueWithBitmap(renderInfo, bitmap);
461    else {
462        if (!requiredSize.equals(bitmap.width(), bitmap.height())) {
463            ALOGV("The bitmap size (%d,%d) does not equal the texture size (%d,%d)",
464                  bitmap.width(), bitmap.height(),
465                  requiredSize.width(), requiredSize.height());
466        }
467        GLUtils::updateQueueWithBitmap(renderInfo, bitmap);
468
469        textureInfo->m_width = bitmap.width();
470        textureInfo->m_height = bitmap.height();
471        textureInfo->m_internalFormat = GL_RGBA;
472    }
473}
474
475void GLUtils::updateQueueWithBitmap(const TileRenderInfo* renderInfo, SkBitmap& bitmap)
476{
477    if (!renderInfo
478        || !renderInfo->textureInfo
479        || !renderInfo->baseTile)
480        return;
481
482    TilesManager::instance()->transferQueue()->updateQueueWithBitmap(renderInfo, bitmap);
483}
484
485bool GLUtils::updateSharedSurfaceTextureWithBitmap(ANativeWindow* anw, const SkBitmap& bitmap)
486{
487    TRACE_METHOD();
488    SkAutoLockPixels alp(bitmap);
489    if (!bitmap.getPixels())
490        return false;
491    ANativeWindow_Buffer buffer;
492    if (ANativeWindow_lock(anw, &buffer, 0))
493        return false;
494    if (buffer.width < bitmap.width() || buffer.height < bitmap.height()) {
495        ALOGW("bitmap (%dx%d) too large for buffer (%dx%d)!",
496                bitmap.width(), bitmap.height(),
497                buffer.width, buffer.height);
498        ANativeWindow_unlockAndPost(anw);
499        return false;
500    }
501    uint8_t* img = (uint8_t*)buffer.bits;
502    int row;
503    int bpp = 4; // Now we only deal with RGBA8888 format.
504    bitmap.lockPixels();
505    uint8_t* bitmapOrigin = static_cast<uint8_t*>(bitmap.getPixels());
506
507    if (buffer.stride != bitmap.width())
508        // Copied line by line since we need to handle the offsets and stride.
509        for (row = 0 ; row < bitmap.height(); row ++) {
510            uint8_t* dst = &(img[buffer.stride * row * bpp]);
511            uint8_t* src = &(bitmapOrigin[bitmap.width() * row * bpp]);
512            memcpy(dst, src, bpp * bitmap.width());
513        }
514    else
515        memcpy(img, bitmapOrigin, bpp * bitmap.width() * bitmap.height());
516
517    bitmap.unlockPixels();
518    ANativeWindow_unlockAndPost(anw);
519    return true;
520}
521
522void GLUtils::createTextureWithBitmap(GLuint texture, const SkBitmap& bitmap, GLint filter)
523{
524    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
525    glBindTexture(GL_TEXTURE_2D, texture);
526    GLUtils::checkGlError("glBindTexture");
527    SkBitmap::Config config = bitmap.getConfig();
528    int internalformat = getInternalFormat(config);
529    int type = getType(config);
530    bitmap.lockPixels();
531    glTexImage2D(GL_TEXTURE_2D, 0, internalformat, bitmap.width(), bitmap.height(),
532                 0, internalformat, type, bitmap.getPixels());
533    bitmap.unlockPixels();
534    if (GLUtils::checkGlError("glTexImage2D")) {
535#ifndef DEBUG
536        if (allowGLLog())
537#endif
538        ALOGE("GL ERROR: glTexImage2D parameters are : textureId %d,"
539              " bitmap.width() %d, bitmap.height() %d,"
540              " internalformat 0x%x, type 0x%x, bitmap.getPixels() %p",
541              texture, bitmap.width(), bitmap.height(), internalformat, type,
542              bitmap.getPixels());
543    }
544    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
545    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
546}
547
548void GLUtils::updateTextureWithBitmap(GLuint texture, const SkBitmap& bitmap,
549                                      const IntRect& inval, GLint filter)
550{
551    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
552    glBindTexture(GL_TEXTURE_2D, texture);
553    GLUtils::checkGlError("glBindTexture");
554    SkBitmap::Config config = bitmap.getConfig();
555    int internalformat = getInternalFormat(config);
556    int type = getType(config);
557    bitmap.lockPixels();
558    if (inval.isEmpty()) {
559        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(),
560                        internalformat, type, bitmap.getPixels());
561    } else {
562        glTexSubImage2D(GL_TEXTURE_2D, 0, inval.x(), inval.y(), inval.width(), inval.height(),
563                        internalformat, type, bitmap.getPixels());
564    }
565    bitmap.unlockPixels();
566    if (GLUtils::checkGlError("glTexSubImage2D")) {
567#ifndef DEBUG
568        if (allowGLLog())
569#endif
570        ALOGE("GL ERROR: glTexSubImage2D parameters are : textureId %d,"
571              " bitmap.width() %d, bitmap.height() %d,"
572              " internalformat 0x%x, type 0x%x, bitmap.getPixels() %p",
573              texture, bitmap.width(), bitmap.height(), internalformat, type,
574              bitmap.getPixels());
575    }
576    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
577    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
578}
579
580void GLUtils::createEGLImageFromTexture(GLuint texture, EGLImageKHR* image)
581{
582    EGLClientBuffer buffer = reinterpret_cast<EGLClientBuffer>(texture);
583    static const EGLint attr[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE };
584    *image = eglCreateImageKHR(eglGetCurrentDisplay(), eglGetCurrentContext(),
585                               EGL_GL_TEXTURE_2D_KHR, buffer, attr);
586    GLUtils::checkEglError("eglCreateImage", (*image != EGL_NO_IMAGE_KHR));
587}
588
589void GLUtils::createTextureFromEGLImage(GLuint texture, EGLImageKHR image, GLint filter)
590{
591    glBindTexture(GL_TEXTURE_2D, texture);
592    GLUtils::checkGlError("glBindTexture");
593    glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image);
594    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
595    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
596}
597
598void GLUtils::convertToTransformationMatrix(const float* matrix, TransformationMatrix& transformMatrix)
599{
600    transformMatrix.setMatrix(
601        matrix[0], matrix[1], matrix[2], matrix[3],
602        matrix[4], matrix[5], matrix[6], matrix[7],
603        matrix[8], matrix[9], matrix[10], matrix[11],
604        matrix[12], matrix[13], matrix[14], matrix[15]);
605}
606
607void GLUtils::clearBackgroundIfOpaque(const Color* backgroundColor)
608{
609    if (!backgroundColor->hasAlpha()) {
610        if (TilesManager::instance()->invertedScreen()) {
611            float color = 1.0 - ((((float) backgroundColor->red() / 255.0) +
612                          ((float) backgroundColor->green() / 255.0) +
613                          ((float) backgroundColor->blue() / 255.0)) / 3.0);
614            glClearColor(color, color, color, 1);
615        } else {
616            glClearColor((float)backgroundColor->red() / 255.0,
617                         (float)backgroundColor->green() / 255.0,
618                         (float)backgroundColor->blue() / 255.0, 1);
619        }
620        glClear(GL_COLOR_BUFFER_BIT);
621    }
622}
623
624bool GLUtils::deepCopyBitmapSubset(const SkBitmap& sourceBitmap,
625                                   SkBitmap& subset, int leftOffset, int topOffset)
626{
627    sourceBitmap.lockPixels();
628    subset.lockPixels();
629    char* srcPixels = (char*) sourceBitmap.getPixels();
630    char* dstPixels = (char*) subset.getPixels();
631    if (!dstPixels || !srcPixels || !subset.lockPixelsAreWritable()) {
632        ALOGD("no pixels :( %p, %p (writable=%d)", srcPixels, dstPixels,
633              subset.lockPixelsAreWritable());
634        subset.unlockPixels();
635        sourceBitmap.unlockPixels();
636        return false;
637    }
638    int srcRowSize = sourceBitmap.rowBytes();
639    int destRowSize = subset.rowBytes();
640    for (int i = 0; i < subset.height(); i++) {
641        int srcOffset = (i + topOffset) * srcRowSize;
642        srcOffset += (leftOffset * sourceBitmap.bytesPerPixel());
643        int dstOffset = i * destRowSize;
644        memcpy(dstPixels + dstOffset, srcPixels + srcOffset, destRowSize);
645    }
646    subset.unlockPixels();
647    sourceBitmap.unlockPixels();
648    return true;
649}
650
651} // namespace WebCore
652
653#endif // USE(ACCELERATED_COMPOSITING)
654