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