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, double currentTime)
117 if (!m_glWebViewState)
120 bool goingDown = m_previousVisible.fTop - viewport.fTop <= 0;
121 bool goingLeft = m_previousVisible.fLeft - viewport.fLeft >= 0;
123 m_glWebViewState->setViewport(viewport, scale);
125 const SkIRect& viewportTileBounds = m_glWebViewState->viewportTileBounds();
126 XLOG("drawBasePicture, TX: %d, TY: %d scale %.2f", viewportTileBounds.fLeft,
127 viewportTileBounds.fTop, scale);
129 if (scale == m_glWebViewState->currentScale()
130 || m_glWebViewState->preZoomBounds().isEmpty())
131 m_glWebViewState->setPreZoomBounds(viewportTileBounds);
133 bool prepareNextTiledPage = false;
134 // If we have a different scale than the current one, we have to
135 // decide what to do. The current behaviour is to delay an update,
136 // so that we do not slow down zooming unnecessarily.
137 if ((m_glWebViewState->currentScale() != scale && (m_glWebViewState->scaleRequestState() == GLWebViewState::kNoScaleRequest || m_glWebViewState->futureScale() != scale))
138 || m_glWebViewState->scaleRequestState() == GLWebViewState::kWillScheduleRequest) {
140 // schedule the new request
141 m_glWebViewState->scheduleUpdate(currentTime, viewportTileBounds, scale);
143 // If it's a new request, we will have to prepare the page.
144 if (m_glWebViewState->scaleRequestState() == GLWebViewState::kRequestNewScale)
145 prepareNextTiledPage = true;
148 // If the viewport has changed since we scheduled the request, we also need to prepare.
149 if ((m_glWebViewState->scaleRequestState() == GLWebViewState::kRequestNewScale || m_glWebViewState->scaleRequestState() == GLWebViewState::kReceivedNewScale)
150 && m_glWebViewState->futureViewport() != viewportTileBounds)
151 prepareNextTiledPage = true;
153 bool zooming = false;
154 if (m_glWebViewState->scaleRequestState() != GLWebViewState::kNoScaleRequest) {
155 prepareNextTiledPage = true;
159 // Display the current page
160 TiledPage* tiledPage = m_glWebViewState->frontPage();
161 tiledPage->setScale(m_glWebViewState->currentScale());
163 // Let's prepare the page if needed
164 if (prepareNextTiledPage) {
165 TiledPage* nextTiledPage = m_glWebViewState->backPage();
166 nextTiledPage->setScale(scale);
167 m_glWebViewState->setFutureViewport(viewportTileBounds);
168 m_glWebViewState->lockBaseLayerUpdate();
169 nextTiledPage->prepare(goingDown, goingLeft, viewportTileBounds);
170 // Cancel pending paints for the foreground page
171 TilesManager::instance()->removePaintOperationsForPage(tiledPage, false);
174 float transparency = 1;
177 // If we fired a request, let's check if it's ready to use
178 if (m_glWebViewState->scaleRequestState() == GLWebViewState::kRequestNewScale) {
179 TiledPage* nextTiledPage = m_glWebViewState->backPage();
180 if (nextTiledPage->ready(viewportTileBounds, m_glWebViewState->futureScale()))
181 m_glWebViewState->setScaleRequestState(GLWebViewState::kReceivedNewScale);
184 // If the page is ready, display it. We do a short transition between
185 // the two pages (current one and future one with the new scale factor)
186 if (m_glWebViewState->scaleRequestState() == GLWebViewState::kReceivedNewScale) {
187 TiledPage* nextTiledPage = m_glWebViewState->backPage();
188 double transitionTime = (scale < m_glWebViewState->currentScale()) ?
189 m_glWebViewState->zoomOutTransitionTime(currentTime) :
190 m_glWebViewState->zoomInTransitionTime(currentTime);
192 float newTilesTransparency = 1;
193 if (scale < m_glWebViewState->currentScale())
194 newTilesTransparency = 1 - m_glWebViewState->zoomOutTransparency(currentTime);
196 transparency = m_glWebViewState->zoomInTransparency(currentTime);
198 nextTiledPage->draw(newTilesTransparency, viewportTileBounds);
200 // The transition between the two pages is finished, swap them
201 if (currentTime > transitionTime) {
202 m_glWebViewState->resetTransitionTime();
207 const SkIRect& preZoomBounds = m_glWebViewState->preZoomBounds();
209 TiledPage* nextTiledPage = m_glWebViewState->backPage();
210 bool needsRedraw = false;
212 // We are now using an hybrid model -- during scrolling,
213 // we will display the current tiledPage even if some tiles are
214 // out of date. When standing still on the other hand, we wait until
215 // the back page is ready before swapping the pages, ensuring that the
216 // displayed content is in sync.
217 if (!doSwap && !zooming && !m_glWebViewState->moving()) {
218 if (!tiledPage->ready(preZoomBounds, m_glWebViewState->currentScale())) {
219 m_glWebViewState->lockBaseLayerUpdate();
220 nextTiledPage->setScale(m_glWebViewState->currentScale());
221 nextTiledPage->prepare(goingDown, goingLeft, preZoomBounds);
223 if (nextTiledPage->ready(preZoomBounds, m_glWebViewState->currentScale())) {
224 nextTiledPage->draw(transparency, preZoomBounds);
225 m_glWebViewState->resetFrameworkInval();
226 m_glWebViewState->unlockBaseLayerUpdate();
229 tiledPage->draw(transparency, preZoomBounds);
232 if (tiledPage->ready(preZoomBounds, m_glWebViewState->currentScale()))
233 m_glWebViewState->resetFrameworkInval();
235 // Ask for the tiles and draw -- tiles may be out of date.
237 m_glWebViewState->unlockBaseLayerUpdate();
239 if (!prepareNextTiledPage)
240 tiledPage->prepare(goingDown, goingLeft, preZoomBounds);
241 tiledPage->draw(transparency, preZoomBounds);
244 if (m_glWebViewState->scaleRequestState() != GLWebViewState::kNoScaleRequest
245 || !tiledPage->ready(preZoomBounds, m_glWebViewState->currentScale()))
249 m_glWebViewState->setCurrentScale(scale);
250 m_glWebViewState->swapPages();
251 m_glWebViewState->unlockBaseLayerUpdate();
254 m_glWebViewState->paintExtras();
257 #endif // USE(ACCELERATED_COMPOSITING)
259 bool BaseLayerAndroid::drawGL(LayerAndroid* compositedRoot,
260 IntRect& viewRect, SkRect& visibleRect,
261 IntRect& webViewRect, int titleBarHeight,
262 IntRect& screenClip, float scale, SkColor color)
264 bool needsRedraw = false;
265 #if USE(ACCELERATED_COMPOSITING)
266 int left = viewRect.x();
267 int top = viewRect.y();
268 int width = viewRect.width();
269 int height = viewRect.height();
270 XLOG("drawBasePicture drawGL() viewRect: %d, %d, %d, %d - %.2f",
271 left, top, width, height, scale);
273 m_glWebViewState->setBackgroundColor(color);
274 glClearColor((float)m_color.red() / 255.0,
275 (float)m_color.green() / 255.0,
276 (float)m_color.blue() / 255.0, 1);
277 glClear(GL_COLOR_BUFFER_BIT);
279 glViewport(left, top, width, height);
280 ShaderProgram* shader = TilesManager::instance()->shader();
281 if (shader->program() == -1) {
282 XLOG("Reinit shader");
285 glUseProgram(shader->program());
286 glUniform1i(shader->textureSampler(), 0);
287 shader->setViewRect(viewRect);
288 shader->setViewport(visibleRect);
289 shader->setWebViewRect(webViewRect);
290 shader->setTitleBarHeight(titleBarHeight);
291 shader->setScreenClip(screenClip);
292 shader->resetBlending();
294 double currentTime = WTF::currentTime();
295 needsRedraw = drawBasePictureInGL(visibleRect, scale, currentTime);
296 bool goingDown = m_previousVisible.fTop - visibleRect.fTop <= 0;
297 bool goingLeft = m_previousVisible.fLeft - visibleRect.fLeft >= 0;
298 m_glWebViewState->setDirection(goingDown, goingLeft);
300 m_glWebViewState->resetFrameworkInval();
302 if (compositedRoot) {
303 TransformationMatrix ident;
305 bool animsRunning = compositedRoot->evaluateAnimations();
309 compositedRoot->updateFixedLayersPositions(visibleRect);
310 FloatRect clip(0, 0, viewRect.width(), viewRect.height());
311 compositedRoot->updateGLPositions(ident, clip, 1);
313 matrix.setTranslate(left, top);
315 // Get the current scale; if we are zooming, we don't change the scale
316 // factor immediately (see BaseLayerAndroid::drawBasePictureInGL()), but
317 // we change the scaleRequestState. When the state is kReceivedNewScale
318 // we can use the future scale instead of the current scale to request
319 // new textures. After a transition time, the scaleRequestState will be
320 // reset and the current scale will be set to the future scale.
321 float scale = m_glWebViewState->currentScale();
322 if (m_glWebViewState->scaleRequestState() == GLWebViewState::kReceivedNewScale) {
323 scale = m_glWebViewState->futureScale();
325 compositedRoot->setScale(scale);
328 int size = compositedRoot->countTextureSize();
329 int nbLayers = compositedRoot->nbLayers();
330 XLOG("We are using %d Mb for %d layers", size / 1024 / 1024, nbLayers);
331 compositedRoot->showLayers();
333 // Clean up GL textures for video layer.
334 TilesManager::instance()->videoLayerManager()->deleteUnusedTextures();
336 if (compositedRoot->drawGL(m_glWebViewState, matrix))
338 else if (!animsRunning)
339 m_glWebViewState->resetLayersDirtyArea();
343 glBindBuffer(GL_ARRAY_BUFFER, 0);
344 m_previousVisible = visibleRect;
346 #endif // USE(ACCELERATED_COMPOSITING)
348 ClassTracker::instance()->show();
353 } // namespace WebCore