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