Home | History | Annotate | Download | only in layers
      1 /*
      2  * Copyright 2012, 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 "CanvasTexture"
     27 #define LOG_NDEBUG 1
     28 
     29 #include "config.h"
     30 #include "CanvasTexture.h"
     31 
     32 #if USE(ACCELERATED_COMPOSITING)
     33 
     34 #include "AndroidLog.h"
     35 #include "GLUtils.h"
     36 #include "Image.h"
     37 #include "ImageBuffer.h"
     38 #include "SkBitmap.h"
     39 #include "SkBitmapRef.h"
     40 #include "SkDevice.h"
     41 #include "SkPixelRef.h"
     42 
     43 #include <android/native_window.h>
     44 #include <gui/GLConsumer.h>
     45 #include <gui/Surface.h>
     46 
     47 namespace WebCore {
     48 
     49 static int s_maxTextureSize = 0;
     50 static HashMap<int, CanvasTexture*> s_textures;
     51 static android::Mutex s_texturesLock;
     52 
     53 /********************************************
     54  * Called by both threads
     55  ********************************************/
     56 
     57 PassRefPtr<CanvasTexture> CanvasTexture::getCanvasTexture(CanvasLayer* layer)
     58 {
     59     android::Mutex::Autolock lock(s_texturesLock);
     60     RefPtr<CanvasTexture> texture = s_textures.get(layer->uniqueId());
     61     if (texture.get())
     62         return texture.release();
     63     return adoptRef(new CanvasTexture(layer->uniqueId()));
     64 }
     65 
     66 bool CanvasTexture::setHwAccelerated(bool hwAccelerated)
     67 {
     68     android::Mutex::Autolock lock(m_surfaceLock);
     69     if (m_useHwAcceleration == hwAccelerated)
     70         return false;
     71     m_useHwAcceleration = hwAccelerated;
     72     if (!m_ANW.get())
     73         return false;
     74     destroySurfaceTextureLocked();
     75     return true;
     76 }
     77 
     78 /********************************************
     79  * Called by WebKit thread
     80  ********************************************/
     81 
     82 void CanvasTexture::setSize(const IntSize& size)
     83 {
     84     android::Mutex::Autolock lock(m_surfaceLock);
     85     if (m_size == size)
     86         return;
     87     m_size = size;
     88     if (m_ANW.get()) {
     89         if (useSurfaceTexture()) {
     90             int result = native_window_set_buffers_dimensions(m_ANW.get(),
     91                     m_size.width(), m_size.height());
     92             GLUtils::checkSurfaceTextureError("native_window_set_buffers_dimensions", result);
     93             if (result != NO_ERROR)
     94                 m_useHwAcceleration = false; // On error, drop out of HWA
     95         }
     96         if (!useSurfaceTexture())
     97             destroySurfaceTextureLocked();
     98     }
     99 }
    100 
    101 android::Surface* CanvasTexture::nativeWindow()
    102 {
    103     android::Mutex::Autolock lock(m_surfaceLock);
    104     if (m_ANW.get())
    105         return m_ANW.get();
    106     if (!m_texture)
    107         return 0;
    108     if (!useSurfaceTexture())
    109         return 0;
    110     m_surfaceTexture = new android::GLConsumer(m_texture, false);
    111     m_ANW = new android::Surface(m_surfaceTexture->getBufferQueue());
    112     int result = native_window_set_buffers_format(m_ANW.get(), HAL_PIXEL_FORMAT_RGBA_8888);
    113     GLUtils::checkSurfaceTextureError("native_window_set_buffers_format", result);
    114     if (result == NO_ERROR) {
    115         result = native_window_set_buffers_dimensions(m_ANW.get(),
    116                 m_size.width(), m_size.height());
    117         GLUtils::checkSurfaceTextureError("native_window_set_buffers_dimensions", result);
    118     }
    119     if (result != NO_ERROR) {
    120         m_useHwAcceleration = false;
    121         destroySurfaceTextureLocked();
    122         return 0;
    123     }
    124     return m_ANW.get();
    125 }
    126 
    127 bool CanvasTexture::uploadImageBuffer(ImageBuffer* imageBuffer)
    128 {
    129     m_hasValidTexture = false;
    130     android::Surface* anw = nativeWindow();
    131     if (!anw)
    132         return false;
    133     // Size mismatch, early abort (will fall back to software)
    134     if (imageBuffer->size() != m_size)
    135         return false;
    136     SkCanvas* canvas = imageBufferCanvas(imageBuffer);
    137     if (!canvas)
    138         return false;
    139     const SkBitmap& bitmap = canvas->getDevice()->accessBitmap(false);
    140     if (!GLUtils::updateSharedSurfaceTextureWithBitmap(anw, bitmap))
    141         return false;
    142     m_hasValidTexture = true;
    143     return true;
    144 }
    145 
    146 /********************************************
    147  * Called by UI thread WITH GL context
    148  ********************************************/
    149 
    150 CanvasTexture::~CanvasTexture()
    151 {
    152     if (m_layerId) {
    153         s_texturesLock.lock();
    154         s_textures.remove(m_layerId);
    155         s_texturesLock.unlock();
    156     }
    157     if (m_texture)
    158         GLUtils::deleteTexture(&m_texture);
    159 }
    160 
    161 void CanvasTexture::requireTexture()
    162 {
    163     android::Mutex::Autolock lock(m_surfaceLock);
    164     if (!m_texture)
    165         glGenTextures(1, &m_texture);
    166     if (!s_maxTextureSize)
    167         glGetIntegerv(GL_MAX_TEXTURE_SIZE, &s_maxTextureSize);
    168 }
    169 
    170 bool CanvasTexture::updateTexImage()
    171 {
    172     android::Mutex::Autolock lock(m_surfaceLock);
    173     if (!m_surfaceTexture.get())
    174         return false;
    175     status_t result = m_surfaceTexture->updateTexImage();
    176     if (result != OK) {
    177         ALOGE("unexpected error: updateTexImage return %d", result);
    178         return false;
    179     }
    180     return true;
    181 }
    182 
    183 /********************************************
    184  * Called by both threads
    185  ********************************************/
    186 
    187 void CanvasTexture::destroySurfaceTextureLocked()
    188 {
    189     if (m_ANW.get()) {
    190         m_ANW.clear();
    191         m_surfaceTexture->abandon();
    192         m_surfaceTexture.clear();
    193     }
    194 }
    195 
    196 /********************************************
    197  * Called by WebKit thread
    198  ********************************************/
    199 
    200 CanvasTexture::CanvasTexture(int layerId)
    201     : m_size()
    202     , m_layerId(layerId)
    203     , m_texture(0)
    204     , m_surfaceTexture(0)
    205     , m_ANW(0)
    206     , m_hasValidTexture(false)
    207     , m_useHwAcceleration(true)
    208 {
    209     s_textures.add(m_layerId, this);
    210 }
    211 
    212 // TODO: Have a global limit as well as a way to react to low memory situations
    213 bool CanvasTexture::useSurfaceTexture()
    214 {
    215     if (!m_useHwAcceleration)
    216         return false;
    217     if (m_size.isEmpty())
    218         return false;
    219     return (m_size.width() < s_maxTextureSize) && (m_size.height() < s_maxTextureSize);
    220 }
    221 
    222 } // namespace WebCore
    223 
    224 #endif // USE(ACCELERATED_COMPOSITING)
    225