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()
73 ClassTracker::instance()->decrement("BaseLayerAndroid");
77 void BaseLayerAndroid::setContent(const PictureSet& src)
79 #if USE(ACCELERATED_COMPOSITING)
80 // FIXME: We lock here because we do not want
81 // to paint and change the m_content concurrently.
82 // We should instead refactor PictureSet to use
83 // an atomic refcounting scheme and use atomic operations
84 // to swap PictureSets.
85 android::Mutex::Autolock lock(m_drawLock);
88 // FIXME: We cannot set the size of the base layer because it will screw up
89 // the matrix used. We need to fix matrix computation for the base layer
90 // and then we can set the size.
91 // setSize(src.width(), src.height());
94 void BaseLayerAndroid::setExtra(SkPicture& src)
96 #if USE(ACCELERATED_COMPOSITING)
97 android::Mutex::Autolock lock(m_drawLock);
102 void BaseLayerAndroid::drawCanvas(SkCanvas* canvas)
104 #if USE(ACCELERATED_COMPOSITING)
105 android::Mutex::Autolock lock(m_drawLock);
107 if (!m_content.isEmpty())
108 m_content.draw(canvas);
109 // TODO : replace with !m_extra.isEmpty() once such a call exists
110 if (m_extra.width() > 0)
111 m_extra.draw(canvas);
114 #if USE(ACCELERATED_COMPOSITING)
115 bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale,
116 double currentTime, bool* pagesSwapped)
118 if (!m_glWebViewState)
121 bool goingDown = m_previousVisible.fTop - viewport.fTop <= 0;
122 bool goingLeft = m_previousVisible.fLeft - viewport.fLeft >= 0;
124 m_glWebViewState->setViewport(viewport, scale);
126 const SkIRect& viewportTileBounds = m_glWebViewState->viewportTileBounds();
127 XLOG("drawBasePicture, TX: %d, TY: %d scale %.2f", viewportTileBounds.fLeft,
128 viewportTileBounds.fTop, scale);
130 if (scale == m_glWebViewState->currentScale()
131 || m_glWebViewState->preZoomBounds().isEmpty())
132 m_glWebViewState->setPreZoomBounds(viewportTileBounds);
134 bool prepareNextTiledPage = false;
135 // If we have a different scale than the current one, we have to
136 // decide what to do. The current behaviour is to delay an update,
137 // so that we do not slow down zooming unnecessarily.
138 if ((m_glWebViewState->currentScale() != scale && (m_glWebViewState->scaleRequestState() == GLWebViewState::kNoScaleRequest || m_glWebViewState->futureScale() != scale))
139 || m_glWebViewState->scaleRequestState() == GLWebViewState::kWillScheduleRequest) {
141 // schedule the new request
142 m_glWebViewState->scheduleUpdate(currentTime, viewportTileBounds, scale);
144 // If it's a new request, we will have to prepare the page.
145 if (m_glWebViewState->scaleRequestState() == GLWebViewState::kRequestNewScale)
146 prepareNextTiledPage = true;
149 // If the viewport has changed since we scheduled the request, we also need to prepare.
150 if ((m_glWebViewState->scaleRequestState() == GLWebViewState::kRequestNewScale || m_glWebViewState->scaleRequestState() == GLWebViewState::kReceivedNewScale)
151 && m_glWebViewState->futureViewport() != viewportTileBounds)
152 prepareNextTiledPage = true;
154 bool zooming = false;
155 if (m_glWebViewState->scaleRequestState() != GLWebViewState::kNoScaleRequest) {
156 prepareNextTiledPage = true;
160 // Display the current page
161 TiledPage* tiledPage = m_glWebViewState->frontPage();
162 tiledPage->setScale(m_glWebViewState->currentScale());
164 // Let's prepare the page if needed
165 if (prepareNextTiledPage) {
166 TiledPage* nextTiledPage = m_glWebViewState->backPage();
167 nextTiledPage->setScale(scale);
168 m_glWebViewState->setFutureViewport(viewportTileBounds);
169 m_glWebViewState->lockBaseLayerUpdate();
170 nextTiledPage->prepare(goingDown, goingLeft, viewportTileBounds);
171 // Cancel pending paints for the foreground page
172 TilesManager::instance()->removePaintOperationsForPage(tiledPage, false);
175 float transparency = 1;
178 // If we fired a request, let's check if it's ready to use
179 if (m_glWebViewState->scaleRequestState() == GLWebViewState::kRequestNewScale) {
180 TiledPage* nextTiledPage = m_glWebViewState->backPage();
181 if (nextTiledPage->ready(viewportTileBounds, m_glWebViewState->futureScale()))
182 m_glWebViewState->setScaleRequestState(GLWebViewState::kReceivedNewScale);
185 // If the page is ready, display it. We do a short transition between
186 // the two pages (current one and future one with the new scale factor)
187 if (m_glWebViewState->scaleRequestState() == GLWebViewState::kReceivedNewScale) {
188 TiledPage* nextTiledPage = m_glWebViewState->backPage();
189 double transitionTime = (scale < m_glWebViewState->currentScale()) ?
190 m_glWebViewState->zoomOutTransitionTime(currentTime) :
191 m_glWebViewState->zoomInTransitionTime(currentTime);
193 float newTilesTransparency = 1;
194 if (scale < m_glWebViewState->currentScale())
195 newTilesTransparency = 1 - m_glWebViewState->zoomOutTransparency(currentTime);
197 transparency = m_glWebViewState->zoomInTransparency(currentTime);
199 nextTiledPage->draw(newTilesTransparency, viewportTileBounds);
201 // The transition between the two pages is finished, swap them
202 if (currentTime > transitionTime) {
203 m_glWebViewState->resetTransitionTime();
208 const SkIRect& preZoomBounds = m_glWebViewState->preZoomBounds();
210 TiledPage* nextTiledPage = m_glWebViewState->backPage();
211 bool needsRedraw = false;
213 // We are now using an hybrid model -- during scrolling,
214 // we will display the current tiledPage even if some tiles are
215 // out of date. When standing still on the other hand, we wait until
216 // the back page is ready before swapping the pages, ensuring that the
217 // displayed content is in sync.
218 if (!doSwap && !zooming && !m_glWebViewState->moving()) {
219 if (!tiledPage->ready(preZoomBounds, m_glWebViewState->currentScale())) {
220 m_glWebViewState->lockBaseLayerUpdate();
221 nextTiledPage->setScale(m_glWebViewState->currentScale());
222 nextTiledPage->prepare(goingDown, goingLeft, preZoomBounds);
224 if (nextTiledPage->ready(preZoomBounds, m_glWebViewState->currentScale())) {
225 nextTiledPage->draw(transparency, preZoomBounds);
226 m_glWebViewState->resetFrameworkInval();
227 m_glWebViewState->unlockBaseLayerUpdate();
230 tiledPage->draw(transparency, preZoomBounds);
233 if (tiledPage->ready(preZoomBounds, m_glWebViewState->currentScale()))
234 m_glWebViewState->resetFrameworkInval();
236 // Ask for the tiles and draw -- tiles may be out of date.
238 m_glWebViewState->unlockBaseLayerUpdate();
240 if (!prepareNextTiledPage)
241 tiledPage->prepare(goingDown, goingLeft, preZoomBounds);
242 tiledPage->draw(transparency, preZoomBounds);
245 if (m_glWebViewState->scaleRequestState() != GLWebViewState::kNoScaleRequest
246 || !tiledPage->ready(preZoomBounds, m_glWebViewState->currentScale()))
250 m_glWebViewState->setCurrentScale(scale);
251 m_glWebViewState->swapPages();
252 m_glWebViewState->unlockBaseLayerUpdate();
254 *pagesSwapped = true;
257 m_glWebViewState->paintExtras();
260 #endif // USE(ACCELERATED_COMPOSITING)
262 bool BaseLayerAndroid::drawGL(LayerAndroid* compositedRoot,
263 IntRect& viewRect, SkRect& visibleRect,
264 IntRect& webViewRect, int titleBarHeight,
265 IntRect& screenClip, float scale,
266 bool* pagesSwapped, 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 if (TilesManager::instance()->invertedScreen()) {
279 float color = 1.0 - ((((float) m_color.red() / 255.0) +
280 ((float) m_color.green() / 255.0) +
281 ((float) m_color.blue() / 255.0)) / 3.0);
282 glClearColor(color, color, color, 1);
284 glClearColor((float)m_color.red() / 255.0,
285 (float)m_color.green() / 255.0,
286 (float)m_color.blue() / 255.0, 1);
288 glClear(GL_COLOR_BUFFER_BIT);
290 glViewport(left, top, width, height);
291 ShaderProgram* shader = TilesManager::instance()->shader();
292 if (shader->program() == -1) {
293 XLOG("Reinit shader");
296 glUseProgram(shader->program());
297 glUniform1i(shader->textureSampler(), 0);
298 shader->setViewRect(viewRect);
299 shader->setViewport(visibleRect);
300 shader->setWebViewRect(webViewRect);
301 shader->setTitleBarHeight(titleBarHeight);
302 shader->setScreenClip(screenClip);
303 shader->resetBlending();
305 double currentTime = WTF::currentTime();
306 needsRedraw = drawBasePictureInGL(visibleRect, scale, currentTime,
308 bool goingDown = m_previousVisible.fTop - visibleRect.fTop <= 0;
309 bool goingLeft = m_previousVisible.fLeft - visibleRect.fLeft >= 0;
310 m_glWebViewState->setDirection(goingDown, goingLeft);
312 m_glWebViewState->resetFrameworkInval();
314 if (compositedRoot) {
315 TransformationMatrix ident;
317 bool animsRunning = compositedRoot->evaluateAnimations();
321 compositedRoot->updateFixedLayersPositions(visibleRect);
322 FloatRect clip(0, 0, viewRect.width(), viewRect.height());
323 compositedRoot->updateGLPositions(ident, clip, 1);
325 matrix.setTranslate(left, top);
327 // Get the current scale; if we are zooming, we don't change the scale
328 // factor immediately (see BaseLayerAndroid::drawBasePictureInGL()), but
329 // we change the scaleRequestState. When the state is kReceivedNewScale
330 // we can use the future scale instead of the current scale to request
331 // new textures. After a transition time, the scaleRequestState will be
332 // reset and the current scale will be set to the future scale.
333 float scale = m_glWebViewState->currentScale();
334 if (m_glWebViewState->scaleRequestState() == GLWebViewState::kReceivedNewScale) {
335 scale = m_glWebViewState->futureScale();
337 compositedRoot->setScale(scale);
340 compositedRoot->showLayer(0);
341 XLOG("We have %d layers, %d textured",
342 compositedRoot->nbLayers(),
343 compositedRoot->nbTexturedLayers());
346 // Clean up GL textures for video layer.
347 TilesManager::instance()->videoLayerManager()->deleteUnusedTextures();
349 if (compositedRoot->drawGL(m_glWebViewState, matrix))
351 else if (!animsRunning)
352 m_glWebViewState->resetLayersDirtyArea();
356 glBindBuffer(GL_ARRAY_BUFFER, 0);
357 m_previousVisible = visibleRect;
359 #endif // USE(ACCELERATED_COMPOSITING)
361 ClassTracker::instance()->show();
366 } // namespace WebCore