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