2 * Copyright 2010, The Android Open Source Project
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "BaseLayerAndroid.h"
29 #if USE(ACCELERATED_COMPOSITING)
30 #include "ClassTracker.h"
32 #include "ShaderProgram.h"
34 #include "TilesManager.h"
35 #include <GLES2/gl2.h>
36 #include <wtf/CurrentTime.h>
37 #endif // USE(ACCELERATED_COMPOSITING)
41 #include <cutils/log.h>
42 #include <wtf/text/CString.h>
45 #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "BaseLayerAndroid", __VA_ARGS__)
56 using namespace android;
58 BaseLayerAndroid::BaseLayerAndroid()
59 #if USE(ACCELERATED_COMPOSITING)
60 : m_glWebViewState(0),
65 ClassTracker::instance()->increment("BaseLayerAndroid");
69 BaseLayerAndroid::~BaseLayerAndroid()
71 #if USE(ACCELERATED_COMPOSITING)
72 if (TilesManager::hardwareAccelerationEnabled())
73 TilesManager::instance()->removeOperationsForBaseLayer(this);
77 ClassTracker::instance()->decrement("BaseLayerAndroid");
81 void BaseLayerAndroid::setContent(const PictureSet& src)
83 #if USE(ACCELERATED_COMPOSITING)
84 // FIXME: We lock here because we do not want
85 // to paint and change the m_content concurrently.
86 // We should instead refactor PictureSet to use
87 // an atomic refcounting scheme and use atomic operations
88 // to swap PictureSets.
89 android::Mutex::Autolock lock(m_drawLock);
92 // FIXME: We cannot set the size of the base layer because it will screw up
93 // the matrix used. We need to fix matrix computation for the base layer
94 // and then we can set the size.
95 // setSize(src.width(), src.height());
98 void BaseLayerAndroid::setExtra(SkPicture& src)
100 #if USE(ACCELERATED_COMPOSITING)
101 android::Mutex::Autolock lock(m_drawLock);
106 void BaseLayerAndroid::drawCanvas(SkCanvas* canvas)
108 #if USE(ACCELERATED_COMPOSITING)
109 android::Mutex::Autolock lock(m_drawLock);
111 if (!m_content.isEmpty())
112 m_content.draw(canvas);
113 // TODO : replace with !m_extra.isEmpty() once such a call exists
114 if (m_extra.width() > 0)
115 m_extra.draw(canvas);
118 #if USE(ACCELERATED_COMPOSITING)
119 bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale, double currentTime)
121 if (!m_glWebViewState)
124 bool goingDown = m_previousVisible.fTop - viewport.fTop <= 0;
125 bool goingLeft = m_previousVisible.fLeft - viewport.fLeft >= 0;
127 m_glWebViewState->setViewport(viewport, scale);
129 const SkIRect& viewportTileBounds = m_glWebViewState->viewportTileBounds();
130 XLOG("drawBasePicture, TX: %d, TY: %d scale %.2f", viewportTileBounds.fLeft,
131 viewportTileBounds.fTop, scale);
133 if (scale == m_glWebViewState->currentScale()
134 || m_glWebViewState->preZoomBounds().isEmpty())
135 m_glWebViewState->setPreZoomBounds(viewportTileBounds);
137 bool prepareNextTiledPage = false;
138 // If we have a different scale than the current one, we have to
139 // decide what to do. The current behaviour is to delay an update,
140 // so that we do not slow down zooming unnecessarily.
141 if ((m_glWebViewState->currentScale() != scale && (m_glWebViewState->scaleRequestState() == GLWebViewState::kNoScaleRequest || m_glWebViewState->futureScale() != scale))
142 || m_glWebViewState->scaleRequestState() == GLWebViewState::kWillScheduleRequest) {
144 // schedule the new request
145 m_glWebViewState->scheduleUpdate(currentTime, viewportTileBounds, scale);
147 // If it's a new request, we will have to prepare the page.
148 if (m_glWebViewState->scaleRequestState() == GLWebViewState::kRequestNewScale)
149 prepareNextTiledPage = true;
152 // If the viewport has changed since we scheduled the request, we also need to prepare.
153 if ((m_glWebViewState->scaleRequestState() == GLWebViewState::kRequestNewScale || m_glWebViewState->scaleRequestState() == GLWebViewState::kReceivedNewScale)
154 && m_glWebViewState->futureViewport() != viewportTileBounds)
155 prepareNextTiledPage = true;
157 bool zooming = false;
158 if (m_glWebViewState->scaleRequestState() != GLWebViewState::kNoScaleRequest) {
159 prepareNextTiledPage = true;
163 // Display the current page
164 TiledPage* tiledPage = m_glWebViewState->frontPage();
165 tiledPage->setScale(m_glWebViewState->currentScale());
167 // Let's prepare the page if needed
168 if (prepareNextTiledPage) {
169 TiledPage* nextTiledPage = m_glWebViewState->backPage();
170 nextTiledPage->setScale(scale);
171 m_glWebViewState->setFutureViewport(viewportTileBounds);
172 m_glWebViewState->lockBaseLayerUpdate();
173 nextTiledPage->prepare(goingDown, goingLeft, viewportTileBounds);
174 // Cancel pending paints for the foreground page
175 TilesManager::instance()->removePaintOperationsForPage(tiledPage, false);
178 float transparency = 1;
181 // If we fired a request, let's check if it's ready to use
182 if (m_glWebViewState->scaleRequestState() == GLWebViewState::kRequestNewScale) {
183 TiledPage* nextTiledPage = m_glWebViewState->backPage();
184 if (nextTiledPage->ready(viewportTileBounds, m_glWebViewState->futureScale()))
185 m_glWebViewState->setScaleRequestState(GLWebViewState::kReceivedNewScale);
188 // If the page is ready, display it. We do a short transition between
189 // the two pages (current one and future one with the new scale factor)
190 if (m_glWebViewState->scaleRequestState() == GLWebViewState::kReceivedNewScale) {
191 TiledPage* nextTiledPage = m_glWebViewState->backPage();
192 double transitionTime = (scale < m_glWebViewState->currentScale()) ?
193 m_glWebViewState->zoomOutTransitionTime(currentTime) :
194 m_glWebViewState->zoomInTransitionTime(currentTime);
196 float newTilesTransparency = 1;
197 if (scale < m_glWebViewState->currentScale())
198 newTilesTransparency = 1 - m_glWebViewState->zoomOutTransparency(currentTime);
200 transparency = m_glWebViewState->zoomInTransparency(currentTime);
202 nextTiledPage->draw(newTilesTransparency, viewportTileBounds);
204 // The transition between the two pages is finished, swap them
205 if (currentTime > transitionTime) {
206 m_glWebViewState->resetTransitionTime();
211 const SkIRect& preZoomBounds = m_glWebViewState->preZoomBounds();
213 TiledPage* nextTiledPage = m_glWebViewState->backPage();
214 bool needsRedraw = false;
216 // We are now using an hybrid model -- during scrolling,
217 // we will display the current tiledPage even if some tiles are
218 // out of date. When standing still on the other hand, we wait until
219 // the back page is ready before swapping the pages, ensuring that the
220 // displayed content is in sync.
221 if (!doSwap && !zooming && !m_glWebViewState->moving()) {
222 if (!tiledPage->ready(preZoomBounds, m_glWebViewState->currentScale())) {
223 m_glWebViewState->lockBaseLayerUpdate();
224 nextTiledPage->setScale(m_glWebViewState->currentScale());
225 nextTiledPage->prepare(goingDown, goingLeft, preZoomBounds);
227 if (nextTiledPage->ready(preZoomBounds, m_glWebViewState->currentScale())) {
228 nextTiledPage->draw(transparency, preZoomBounds);
229 m_glWebViewState->resetFrameworkInval();
230 m_glWebViewState->unlockBaseLayerUpdate();
233 tiledPage->draw(transparency, preZoomBounds);
236 if (tiledPage->ready(preZoomBounds, m_glWebViewState->currentScale()))
237 m_glWebViewState->resetFrameworkInval();
239 // Ask for the tiles and draw -- tiles may be out of date.
241 m_glWebViewState->unlockBaseLayerUpdate();
243 if (!prepareNextTiledPage)
244 tiledPage->prepare(goingDown, goingLeft, preZoomBounds);
245 tiledPage->draw(transparency, preZoomBounds);
248 if (m_glWebViewState->scaleRequestState() != GLWebViewState::kNoScaleRequest
249 || !tiledPage->ready(preZoomBounds, m_glWebViewState->currentScale()))
253 m_glWebViewState->setCurrentScale(scale);
254 m_glWebViewState->swapPages();
255 m_glWebViewState->unlockBaseLayerUpdate();
258 m_glWebViewState->paintExtras();
261 #endif // USE(ACCELERATED_COMPOSITING)
263 bool BaseLayerAndroid::drawGL(LayerAndroid* compositedRoot,
264 IntRect& viewRect, SkRect& visibleRect,
265 IntRect& webViewRect, int titleBarHeight,
266 IntRect& screenClip, float scale, SkColor color)
268 bool needsRedraw = false;
269 #if USE(ACCELERATED_COMPOSITING)
270 int left = viewRect.x();
271 int top = viewRect.y();
272 int width = viewRect.width();
273 int height = viewRect.height();
274 XLOG("drawBasePicture drawGL() viewRect: %d, %d, %d, %d - %.2f",
275 left, top, width, height, scale);
277 m_glWebViewState->setBackgroundColor(color);
278 glClearColor((float)m_color.red() / 255.0,
279 (float)m_color.green() / 255.0,
280 (float)m_color.blue() / 255.0, 1);
281 glClear(GL_COLOR_BUFFER_BIT);
283 glViewport(left, top, width, height);
284 ShaderProgram* shader = TilesManager::instance()->shader();
285 if (shader->program() == -1) {
286 XLOG("Reinit shader");
289 glUseProgram(shader->program());
290 glUniform1i(shader->textureSampler(), 0);
291 shader->setViewRect(viewRect);
292 shader->setViewport(visibleRect);
293 shader->setWebViewRect(webViewRect);
294 shader->setTitleBarHeight(titleBarHeight);
295 shader->setScreenClip(screenClip);
296 shader->resetBlending();
298 double currentTime = WTF::currentTime();
299 needsRedraw = drawBasePictureInGL(visibleRect, scale, currentTime);
301 m_glWebViewState->resetFrameworkInval();
303 if (compositedRoot) {
304 TransformationMatrix ident;
306 bool animsRunning = compositedRoot->evaluateAnimations();
310 compositedRoot->updateFixedLayersPositions(visibleRect);
311 FloatRect clip(0, 0, viewRect.width(), viewRect.height());
312 compositedRoot->updateGLPositions(ident, clip, 1);
314 matrix.setTranslate(left, top);
316 // At this point, the previous LayerAndroid* root has been destroyed,
317 // which will have removed the layers as owners of the textures.
318 // Let's now do a pass to reserve the textures for the current tree;
319 // it will only reserve existing textures, not create them on demand.
321 TilesManager::instance()->printLayersTextures("reserve");
323 // Get the current scale; if we are zooming, we don't change the scale
324 // factor immediately (see BaseLayerAndroid::drawBasePictureInGL()), but
325 // we change the scaleRequestState. When the state is kReceivedNewScale
326 // we can use the future scale instead of the current scale to request
327 // new textures. After a transition time, the scaleRequestState will be
328 // reset and the current scale will be set to the future scale.
329 float scale = m_glWebViewState->currentScale();
330 if (m_glWebViewState->scaleRequestState() == GLWebViewState::kReceivedNewScale) {
331 scale = m_glWebViewState->futureScale();
333 bool fullSetup = true;
334 if ((m_glWebViewState->previouslyUsedRoot() == compositedRoot) &&
335 (compositedRoot->getScale() == scale) &&
336 (!m_glWebViewState->moving()))
339 compositedRoot->setScale(scale);
342 compositedRoot->computeTextureSize(currentTime);
343 compositedRoot->reserveGLTextures();
346 int size = compositedRoot->countTextureSize();
347 int nbLayers = compositedRoot->nbLayers();
348 XLOG("We are using %d Mb for %d layers", size / 1024 / 1024, nbLayers);
349 compositedRoot->showLayers();
351 // Now that we marked the textures being used, we delete
352 // the unnecessary ones to make space...
353 TilesManager::instance()->cleanupLayersTextures(compositedRoot);
355 // Clean up GL textures for video layer.
356 TilesManager::instance()->videoLayerManager()->deleteUnusedTextures();
358 // Finally do another pass to create new textures and schedule
359 // repaints if needed
360 compositedRoot->createGLTextures();
362 if (compositedRoot->drawGL(m_glWebViewState, matrix))
364 else if (!animsRunning)
365 m_glWebViewState->resetLayersDirtyArea();
368 TilesManager::instance()->cleanupLayersTextures(0);
371 glBindBuffer(GL_ARRAY_BUFFER, 0);
372 m_previousVisible = visibleRect;
374 #endif // USE(ACCELERATED_COMPOSITING)
376 ClassTracker::instance()->show();
381 } // namespace WebCore