blob: dc1951beec7283a56e547f4cbba5c7889bececd1 [file] [log] [blame]
John Reck23b797a2014-01-03 18:08:34 -08001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "CanvasContext"
18
19#include "CanvasContext.h"
20
21#include <cutils/properties.h>
John Reck4f02bf42014-01-03 18:09:17 -080022#include <private/hwui/DrawGlInfo.h>
John Reck23b797a2014-01-03 18:08:34 -080023#include <strings.h>
24
John Reck4f02bf42014-01-03 18:09:17 -080025#include "RenderThread.h"
John Reck23b797a2014-01-03 18:08:34 -080026#include "../Caches.h"
John Reck19b6bcf2014-02-14 20:03:38 -080027#include "../DeferredLayerUpdater.h"
28#include "../LayerRenderer.h"
John Reck4f02bf42014-01-03 18:09:17 -080029#include "../OpenGLRenderer.h"
John Reck23b797a2014-01-03 18:08:34 -080030#include "../Stencil.h"
31
32#define PROPERTY_RENDER_DIRTY_REGIONS "debug.hwui.render_dirty_regions"
33#define GLES_VERSION 2
34
John Reck4f02bf42014-01-03 18:09:17 -080035// Android-specific addition that is used to show when frames began in systrace
36EGLAPI void EGLAPIENTRY eglBeginFrame(EGLDisplay dpy, EGLSurface surface);
John Reck4f02bf42014-01-03 18:09:17 -080037
John Reck23b797a2014-01-03 18:08:34 -080038namespace android {
39namespace uirenderer {
40namespace renderthread {
41
42#define ERROR_CASE(x) case x: return #x;
43static const char* egl_error_str(EGLint error) {
44 switch (error) {
45 ERROR_CASE(EGL_SUCCESS)
46 ERROR_CASE(EGL_NOT_INITIALIZED)
47 ERROR_CASE(EGL_BAD_ACCESS)
48 ERROR_CASE(EGL_BAD_ALLOC)
49 ERROR_CASE(EGL_BAD_ATTRIBUTE)
50 ERROR_CASE(EGL_BAD_CONFIG)
51 ERROR_CASE(EGL_BAD_CONTEXT)
52 ERROR_CASE(EGL_BAD_CURRENT_SURFACE)
53 ERROR_CASE(EGL_BAD_DISPLAY)
54 ERROR_CASE(EGL_BAD_MATCH)
55 ERROR_CASE(EGL_BAD_NATIVE_PIXMAP)
56 ERROR_CASE(EGL_BAD_NATIVE_WINDOW)
57 ERROR_CASE(EGL_BAD_PARAMETER)
58 ERROR_CASE(EGL_BAD_SURFACE)
59 ERROR_CASE(EGL_CONTEXT_LOST)
60 default:
61 return "Unknown error";
62 }
63}
64static const char* egl_error_str() {
65 return egl_error_str(eglGetError());
66}
67
68static bool load_dirty_regions_property() {
69 char buf[PROPERTY_VALUE_MAX];
70 int len = property_get(PROPERTY_RENDER_DIRTY_REGIONS, buf, "true");
71 return !strncasecmp("true", buf, len);
72}
73
74// This class contains the shared global EGL objects, such as EGLDisplay
75// and EGLConfig, which are re-used by CanvasContext
76class GlobalContext {
77public:
78 static GlobalContext* get();
79
John Reck4f02bf42014-01-03 18:09:17 -080080 // Returns true on success, false on failure
81 void initialize();
John Reck23b797a2014-01-03 18:08:34 -080082
John Reck0d1f6342014-03-28 20:30:27 -070083 bool hasContext();
84
John Reck4f02bf42014-01-03 18:09:17 -080085 void usePBufferSurface();
John Reck23b797a2014-01-03 18:08:34 -080086 EGLSurface createSurface(EGLNativeWindowType window);
87 void destroySurface(EGLSurface surface);
88
89 void destroy();
90
91 bool isCurrent(EGLSurface surface) { return mCurrentSurface == surface; }
John Reckdbc9a862014-04-17 20:25:13 -070092 // Returns true if the current surface changed, false if it was already current
93 bool makeCurrent(EGLSurface surface);
John Reck4f02bf42014-01-03 18:09:17 -080094 void beginFrame(EGLSurface surface, EGLint* width, EGLint* height);
95 void swapBuffers(EGLSurface surface);
John Reck23b797a2014-01-03 18:08:34 -080096
97 bool enableDirtyRegions(EGLSurface surface);
98
John Reck66f0be62014-05-13 13:39:31 -070099 void setTextureAtlas(const sp<GraphicBuffer>& buffer, int64_t* map, size_t mapSize);
100
John Reck23b797a2014-01-03 18:08:34 -0800101private:
102 GlobalContext();
103 // GlobalContext is never destroyed, method is purposely not implemented
104 ~GlobalContext();
105
John Reck4f02bf42014-01-03 18:09:17 -0800106 void loadConfig();
107 void createContext();
108 void initAtlas();
John Reck23b797a2014-01-03 18:08:34 -0800109
110 static GlobalContext* sContext;
111
112 EGLDisplay mEglDisplay;
113 EGLConfig mEglConfig;
114 EGLContext mEglContext;
115 EGLSurface mPBufferSurface;
116
117 const bool mRequestDirtyRegions;
118 bool mCanSetDirtyRegions;
119
120 EGLSurface mCurrentSurface;
John Reck66f0be62014-05-13 13:39:31 -0700121
122 sp<GraphicBuffer> mAtlasBuffer;
123 int64_t* mAtlasMap;
124 size_t mAtlasMapSize;
John Reck23b797a2014-01-03 18:08:34 -0800125};
126
127GlobalContext* GlobalContext::sContext = 0;
128
129GlobalContext* GlobalContext::get() {
130 if (!sContext) {
131 sContext = new GlobalContext();
132 }
133 return sContext;
134}
135
136GlobalContext::GlobalContext()
137 : mEglDisplay(EGL_NO_DISPLAY)
138 , mEglConfig(0)
139 , mEglContext(EGL_NO_CONTEXT)
140 , mPBufferSurface(EGL_NO_SURFACE)
141 , mRequestDirtyRegions(load_dirty_regions_property())
John Reck66f0be62014-05-13 13:39:31 -0700142 , mCurrentSurface(EGL_NO_SURFACE)
143 , mAtlasMap(NULL)
144 , mAtlasMapSize(0) {
John Reck23b797a2014-01-03 18:08:34 -0800145 mCanSetDirtyRegions = mRequestDirtyRegions;
146 ALOGD("Render dirty regions requested: %s", mRequestDirtyRegions ? "true" : "false");
147}
148
John Reck4f02bf42014-01-03 18:09:17 -0800149void GlobalContext::initialize() {
John Reck0d1f6342014-03-28 20:30:27 -0700150 if (hasContext()) return;
John Reck23b797a2014-01-03 18:08:34 -0800151
152 mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
John Reck4f02bf42014-01-03 18:09:17 -0800153 LOG_ALWAYS_FATAL_IF(mEglDisplay == EGL_NO_DISPLAY,
154 "Failed to get EGL_DEFAULT_DISPLAY! err=%s", egl_error_str());
John Reck23b797a2014-01-03 18:08:34 -0800155
156 EGLint major, minor;
John Reck4f02bf42014-01-03 18:09:17 -0800157 LOG_ALWAYS_FATAL_IF(eglInitialize(mEglDisplay, &major, &minor) == EGL_FALSE,
158 "Failed to initialize display %p! err=%s", mEglDisplay, egl_error_str());
159
John Reck23b797a2014-01-03 18:08:34 -0800160 ALOGI("Initialized EGL, version %d.%d", (int)major, (int)minor);
161
John Reck4f02bf42014-01-03 18:09:17 -0800162 loadConfig();
163 createContext();
164 usePBufferSurface();
165 Caches::getInstance().init();
166 initAtlas();
John Reck23b797a2014-01-03 18:08:34 -0800167}
168
John Reck0d1f6342014-03-28 20:30:27 -0700169bool GlobalContext::hasContext() {
170 return mEglDisplay != EGL_NO_DISPLAY;
171}
172
John Reck4f02bf42014-01-03 18:09:17 -0800173void GlobalContext::loadConfig() {
John Reck23b797a2014-01-03 18:08:34 -0800174 EGLint swapBehavior = mCanSetDirtyRegions ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
175 EGLint attribs[] = {
176 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
177 EGL_RED_SIZE, 8,
178 EGL_GREEN_SIZE, 8,
179 EGL_BLUE_SIZE, 8,
180 EGL_ALPHA_SIZE, 8,
181 EGL_DEPTH_SIZE, 0,
182 EGL_CONFIG_CAVEAT, EGL_NONE,
183 EGL_STENCIL_SIZE, Stencil::getStencilSize(),
184 EGL_SURFACE_TYPE, EGL_WINDOW_BIT | swapBehavior,
185 EGL_NONE
186 };
187
188 EGLint num_configs = 1;
189 if (!eglChooseConfig(mEglDisplay, attribs, &mEglConfig, num_configs, &num_configs)
190 || num_configs != 1) {
191 // Failed to get a valid config
192 if (mCanSetDirtyRegions) {
193 ALOGW("Failed to choose config with EGL_SWAP_BEHAVIOR_PRESERVED, retrying without...");
194 // Try again without dirty regions enabled
195 mCanSetDirtyRegions = false;
196 loadConfig();
197 } else {
John Reck4f02bf42014-01-03 18:09:17 -0800198 LOG_ALWAYS_FATAL("Failed to choose config, error = %s", egl_error_str());
John Reck23b797a2014-01-03 18:08:34 -0800199 }
200 }
John Reck23b797a2014-01-03 18:08:34 -0800201}
202
John Reck4f02bf42014-01-03 18:09:17 -0800203void GlobalContext::createContext() {
John Reck23b797a2014-01-03 18:08:34 -0800204 EGLint attribs[] = { EGL_CONTEXT_CLIENT_VERSION, GLES_VERSION, EGL_NONE };
205 mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT, attribs);
John Reck4f02bf42014-01-03 18:09:17 -0800206 LOG_ALWAYS_FATAL_IF(mEglContext == EGL_NO_CONTEXT,
207 "Failed to create context, error = %s", egl_error_str());
John Reck23b797a2014-01-03 18:08:34 -0800208}
209
John Reck66f0be62014-05-13 13:39:31 -0700210void GlobalContext::setTextureAtlas(const sp<GraphicBuffer>& buffer,
211 int64_t* map, size_t mapSize) {
212
213 // Already initialized
214 if (mAtlasBuffer.get()) {
215 ALOGW("Multiple calls to setTextureAtlas!");
216 delete map;
217 return;
218 }
219
220 mAtlasBuffer = buffer;
221 mAtlasMap = map;
222 mAtlasMapSize = mapSize;
223
224 if (hasContext()) {
225 usePBufferSurface();
226 initAtlas();
227 }
228}
229
John Reck4f02bf42014-01-03 18:09:17 -0800230void GlobalContext::initAtlas() {
John Reckc8affe02014-05-29 14:50:37 -0700231 if (mAtlasBuffer.get()) {
John Reckcdfeef62014-05-14 16:35:46 -0700232 Caches::getInstance().assetAtlas.init(mAtlasBuffer, mAtlasMap, mAtlasMapSize);
233 }
John Reck4f02bf42014-01-03 18:09:17 -0800234}
235
236void GlobalContext::usePBufferSurface() {
237 LOG_ALWAYS_FATAL_IF(mEglDisplay == EGL_NO_DISPLAY,
238 "usePBufferSurface() called on uninitialized GlobalContext!");
John Reck23b797a2014-01-03 18:08:34 -0800239
240 if (mPBufferSurface == EGL_NO_SURFACE) {
241 EGLint attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
242 mPBufferSurface = eglCreatePbufferSurface(mEglDisplay, mEglConfig, attribs);
243 }
John Reck4f02bf42014-01-03 18:09:17 -0800244 makeCurrent(mPBufferSurface);
John Reck23b797a2014-01-03 18:08:34 -0800245}
246
247EGLSurface GlobalContext::createSurface(EGLNativeWindowType window) {
248 initialize();
249 return eglCreateWindowSurface(mEglDisplay, mEglConfig, window, NULL);
250}
251
252void GlobalContext::destroySurface(EGLSurface surface) {
253 if (isCurrent(surface)) {
254 makeCurrent(EGL_NO_SURFACE);
255 }
256 if (!eglDestroySurface(mEglDisplay, surface)) {
257 ALOGW("Failed to destroy surface %p, error=%s", (void*)surface, egl_error_str());
258 }
259}
260
261void GlobalContext::destroy() {
262 if (mEglDisplay == EGL_NO_DISPLAY) return;
263
264 usePBufferSurface();
265 if (Caches::hasInstance()) {
266 Caches::getInstance().terminate();
267 }
268
269 eglDestroyContext(mEglDisplay, mEglContext);
270 eglDestroySurface(mEglDisplay, mPBufferSurface);
271 eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
272 eglTerminate(mEglDisplay);
273 eglReleaseThread();
274
275 mEglDisplay = EGL_NO_DISPLAY;
276 mEglContext = EGL_NO_CONTEXT;
277 mPBufferSurface = EGL_NO_SURFACE;
278 mCurrentSurface = EGL_NO_SURFACE;
279}
280
John Reckdbc9a862014-04-17 20:25:13 -0700281bool GlobalContext::makeCurrent(EGLSurface surface) {
282 if (isCurrent(surface)) return false;
John Reck23b797a2014-01-03 18:08:34 -0800283
284 if (surface == EGL_NO_SURFACE) {
285 // If we are setting EGL_NO_SURFACE we don't care about any of the potential
286 // return errors, which would only happen if mEglDisplay had already been
287 // destroyed in which case the current context is already NO_CONTEXT
288 eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
289 } else if (!eglMakeCurrent(mEglDisplay, surface, surface, mEglContext)) {
John Reck4f02bf42014-01-03 18:09:17 -0800290 LOG_ALWAYS_FATAL("Failed to make current on surface %p, error=%s",
291 (void*)surface, egl_error_str());
John Reck23b797a2014-01-03 18:08:34 -0800292 }
293 mCurrentSurface = surface;
John Reckdbc9a862014-04-17 20:25:13 -0700294 return true;
John Reck23b797a2014-01-03 18:08:34 -0800295}
296
John Reck4f02bf42014-01-03 18:09:17 -0800297void GlobalContext::beginFrame(EGLSurface surface, EGLint* width, EGLint* height) {
298 LOG_ALWAYS_FATAL_IF(surface == EGL_NO_SURFACE,
299 "Tried to beginFrame on EGL_NO_SURFACE!");
300 makeCurrent(surface);
301 if (width) {
302 eglQuerySurface(mEglDisplay, surface, EGL_WIDTH, width);
John Reck23b797a2014-01-03 18:08:34 -0800303 }
John Reck4f02bf42014-01-03 18:09:17 -0800304 if (height) {
305 eglQuerySurface(mEglDisplay, surface, EGL_HEIGHT, height);
306 }
307 eglBeginFrame(mEglDisplay, surface);
308}
309
310void GlobalContext::swapBuffers(EGLSurface surface) {
311 eglSwapBuffers(mEglDisplay, surface);
312 EGLint err = eglGetError();
John Reck4f02bf42014-01-03 18:09:17 -0800313 LOG_ALWAYS_FATAL_IF(err != EGL_SUCCESS,
314 "Encountered EGL error %d %s during rendering", err, egl_error_str(err));
John Reck23b797a2014-01-03 18:08:34 -0800315}
316
317bool GlobalContext::enableDirtyRegions(EGLSurface surface) {
318 if (!mRequestDirtyRegions) return false;
319
320 if (mCanSetDirtyRegions) {
321 if (!eglSurfaceAttrib(mEglDisplay, surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED)) {
322 ALOGW("Failed to set EGL_SWAP_BEHAVIOR on surface %p, error=%s",
323 (void*) surface, egl_error_str());
324 return false;
325 }
326 return true;
327 }
328 // Perhaps it is already enabled?
329 EGLint value;
330 if (!eglQuerySurface(mEglDisplay, surface, EGL_SWAP_BEHAVIOR, &value)) {
331 ALOGW("Failed to query EGL_SWAP_BEHAVIOR on surface %p, error=%p",
332 (void*) surface, egl_error_str());
333 return false;
334 }
335 return value == EGL_BUFFER_PRESERVED;
336}
337
John Recke45b1fd2014-04-15 09:50:16 -0700338CanvasContext::CanvasContext(bool translucent, RenderNode* rootRenderNode)
John Reck4f02bf42014-01-03 18:09:17 -0800339 : mRenderThread(RenderThread::getInstance())
340 , mEglSurface(EGL_NO_SURFACE)
341 , mDirtyRegionsEnabled(false)
342 , mOpaque(!translucent)
343 , mCanvas(0)
John Recke45b1fd2014-04-15 09:50:16 -0700344 , mHaveNewSurface(false)
345 , mRootRenderNode(rootRenderNode) {
John Reck23b797a2014-01-03 18:08:34 -0800346 mGlobalContext = GlobalContext::get();
347}
348
349CanvasContext::~CanvasContext() {
John Reckfae904d2014-04-14 11:01:57 -0700350 destroyCanvasAndSurface();
John Recke45b1fd2014-04-15 09:50:16 -0700351 mRenderThread.removeFrameCallback(this);
John Reck4f02bf42014-01-03 18:09:17 -0800352}
353
John Reckfae904d2014-04-14 11:01:57 -0700354void CanvasContext::destroyCanvasAndSurface() {
John Reck4f02bf42014-01-03 18:09:17 -0800355 if (mCanvas) {
356 delete mCanvas;
357 mCanvas = 0;
358 }
John Reck23b797a2014-01-03 18:08:34 -0800359 setSurface(NULL);
360}
361
John Recka5dda642014-05-22 15:43:54 -0700362void CanvasContext::setSurface(ANativeWindow* window) {
363 mNativeWindow = window;
364
John Reck23b797a2014-01-03 18:08:34 -0800365 if (mEglSurface != EGL_NO_SURFACE) {
366 mGlobalContext->destroySurface(mEglSurface);
367 mEglSurface = EGL_NO_SURFACE;
368 }
369
370 if (window) {
371 mEglSurface = mGlobalContext->createSurface(window);
John Reck4f02bf42014-01-03 18:09:17 -0800372 LOG_ALWAYS_FATAL_IF(mEglSurface == EGL_NO_SURFACE,
373 "Failed to create EGLSurface for window %p, eglErr = %s",
374 (void*) window, egl_error_str());
John Reck23b797a2014-01-03 18:08:34 -0800375 }
376
377 if (mEglSurface != EGL_NO_SURFACE) {
378 mDirtyRegionsEnabled = mGlobalContext->enableDirtyRegions(mEglSurface);
John Reck4f02bf42014-01-03 18:09:17 -0800379 mHaveNewSurface = true;
John Reckdbc9a862014-04-17 20:25:13 -0700380 makeCurrent();
John Reck368cdd82014-05-07 13:11:00 -0700381 } else {
382 mRenderThread.removeFrameCallback(this);
John Reck23b797a2014-01-03 18:08:34 -0800383 }
John Reck23b797a2014-01-03 18:08:34 -0800384}
385
John Reck4f02bf42014-01-03 18:09:17 -0800386void CanvasContext::swapBuffers() {
387 mGlobalContext->swapBuffers(mEglSurface);
388 mHaveNewSurface = false;
John Reck23b797a2014-01-03 18:08:34 -0800389}
390
John Reckf7d9c1d2014-04-09 10:01:03 -0700391void CanvasContext::requireSurface() {
392 LOG_ALWAYS_FATAL_IF(mEglSurface == EGL_NO_SURFACE,
393 "requireSurface() called but no surface set!");
John Reckdbc9a862014-04-17 20:25:13 -0700394 makeCurrent();
John Reck23b797a2014-01-03 18:08:34 -0800395}
396
John Recka5dda642014-05-22 15:43:54 -0700397bool CanvasContext::initialize(ANativeWindow* window) {
John Reck4f02bf42014-01-03 18:09:17 -0800398 if (mCanvas) return false;
399 setSurface(window);
John Reck4f02bf42014-01-03 18:09:17 -0800400 mCanvas = new OpenGLRenderer();
401 mCanvas->initProperties();
402 return true;
403}
404
John Recka5dda642014-05-22 15:43:54 -0700405void CanvasContext::updateSurface(ANativeWindow* window) {
John Reck4f02bf42014-01-03 18:09:17 -0800406 setSurface(window);
John Reckf7d9c1d2014-04-09 10:01:03 -0700407}
408
John Recka5dda642014-05-22 15:43:54 -0700409void CanvasContext::pauseSurface(ANativeWindow* window) {
John Reckf7d9c1d2014-04-09 10:01:03 -0700410 // TODO: For now we just need a fence, in the future suspend any animations
411 // and such to prevent from trying to render into this surface
John Reck4f02bf42014-01-03 18:09:17 -0800412}
413
Chris Craik797b95b2014-05-20 18:10:25 -0700414void CanvasContext::setup(int width, int height, const Vector3& lightCenter, float lightRadius) {
John Reck4f02bf42014-01-03 18:09:17 -0800415 if (!mCanvas) return;
416 mCanvas->setViewport(width, height);
Chris Craik797b95b2014-05-20 18:10:25 -0700417 mCanvas->initializeLight(lightCenter, lightRadius);
John Reck4f02bf42014-01-03 18:09:17 -0800418}
419
John Reck63a06672014-05-07 13:45:54 -0700420void CanvasContext::setOpaque(bool opaque) {
421 mOpaque = opaque;
422}
423
John Reck860d1552014-04-11 19:15:05 -0700424void CanvasContext::makeCurrent() {
John Reckdbc9a862014-04-17 20:25:13 -0700425 // TODO: Figure out why this workaround is needed, see b/13913604
426 // In the meantime this matches the behavior of GLRenderer, so it is not a regression
427 mHaveNewSurface |= mGlobalContext->makeCurrent(mEglSurface);
John Reck860d1552014-04-11 19:15:05 -0700428}
429
John Reckd72e0a32014-05-29 18:56:11 -0700430void CanvasContext::processLayerUpdate(DeferredLayerUpdater* layerUpdater, TreeInfo& info) {
431 bool success = layerUpdater->apply(info);
432 LOG_ALWAYS_FATAL_IF(!success, "Failed to update layer!");
433 if (layerUpdater->backingLayer()->deferredUpdateScheduled) {
434 mCanvas->pushLayerUpdate(layerUpdater->backingLayer());
John Reck19b6bcf2014-02-14 20:03:38 -0800435 }
436}
437
John Recke45b1fd2014-04-15 09:50:16 -0700438void CanvasContext::prepareTree(TreeInfo& info) {
John Reckf9be7792014-05-02 18:21:16 -0700439 mRenderThread.removeFrameCallback(this);
John Reck18f16e62014-05-02 16:46:41 -0700440
John Reckf9be7792014-05-02 18:21:16 -0700441 info.frameTimeMs = mRenderThread.timeLord().frameTimeMs();
John Recke4267ea2014-06-03 15:53:15 -0700442 info.damageAccumulator = &mDamageAccumulator;
John Reck25fbb3f2014-06-12 13:46:45 -0700443 info.renderer = mCanvas;
John Recke45b1fd2014-04-15 09:50:16 -0700444 mRootRenderNode->prepareTree(info);
445
John Recka5dda642014-05-22 15:43:54 -0700446 int runningBehind = 0;
447 // TODO: This query is moderately expensive, investigate adding some sort
448 // of fast-path based off when we last called eglSwapBuffers() as well as
449 // last vsync time. Or something.
450 mNativeWindow->query(mNativeWindow.get(),
451 NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &runningBehind);
452 info.out.canDrawThisFrame = !runningBehind;
453
454 if (info.out.hasAnimations || !info.out.canDrawThisFrame) {
John Reckf9be7792014-05-02 18:21:16 -0700455 if (info.out.hasFunctors) {
456 info.out.requiresUiRedraw = true;
457 } else if (!info.out.requiresUiRedraw) {
458 // If animationsNeedsRedraw is set don't bother posting for an RT anim
459 // as we will just end up fighting the UI thread.
460 mRenderThread.postFrameCallback(this);
461 }
John Recke45b1fd2014-04-15 09:50:16 -0700462 }
463}
464
John Recka5dda642014-05-22 15:43:54 -0700465void CanvasContext::notifyFramePending() {
466 ATRACE_CALL();
467 mRenderThread.pushBackFrameCallback(this);
468}
469
John Recke4267ea2014-06-03 15:53:15 -0700470void CanvasContext::draw() {
John Reck4f02bf42014-01-03 18:09:17 -0800471 LOG_ALWAYS_FATAL_IF(!mCanvas || mEglSurface == EGL_NO_SURFACE,
472 "drawDisplayList called on a context with no canvas or surface!");
473
John Reckfe5e7b72014-05-23 17:42:28 -0700474 profiler().markPlaybackStart();
475
John Recke4267ea2014-06-03 15:53:15 -0700476 SkRect dirty;
477 mDamageAccumulator.finish(&dirty);
478
John Reck4f02bf42014-01-03 18:09:17 -0800479 EGLint width, height;
480 mGlobalContext->beginFrame(mEglSurface, &width, &height);
481 if (width != mCanvas->getViewportWidth() || height != mCanvas->getViewportHeight()) {
482 mCanvas->setViewport(width, height);
John Recke4267ea2014-06-03 15:53:15 -0700483 dirty.setEmpty();
John Reck4f02bf42014-01-03 18:09:17 -0800484 } else if (!mDirtyRegionsEnabled || mHaveNewSurface) {
John Recke4267ea2014-06-03 15:53:15 -0700485 dirty.setEmpty();
John Reckfe5e7b72014-05-23 17:42:28 -0700486 } else {
John Recke4267ea2014-06-03 15:53:15 -0700487 profiler().unionDirty(&dirty);
John Reck4f02bf42014-01-03 18:09:17 -0800488 }
489
490 status_t status;
John Recke4267ea2014-06-03 15:53:15 -0700491 if (!dirty.isEmpty()) {
492 status = mCanvas->prepareDirty(dirty.fLeft, dirty.fTop,
493 dirty.fRight, dirty.fBottom, mOpaque);
John Reck4f02bf42014-01-03 18:09:17 -0800494 } else {
495 status = mCanvas->prepare(mOpaque);
496 }
497
498 Rect outBounds;
John Recke45b1fd2014-04-15 09:50:16 -0700499 status |= mCanvas->drawDisplayList(mRootRenderNode.get(), outBounds);
John Reck4f02bf42014-01-03 18:09:17 -0800500
John Reckfe5e7b72014-05-23 17:42:28 -0700501 profiler().draw(mCanvas);
John Reck4f02bf42014-01-03 18:09:17 -0800502
503 mCanvas->finish();
504
John Reckfe5e7b72014-05-23 17:42:28 -0700505 profiler().markPlaybackEnd();
506
John Reck4f02bf42014-01-03 18:09:17 -0800507 if (status & DrawGlInfo::kStatusDrew) {
508 swapBuffers();
509 }
John Reckfe5e7b72014-05-23 17:42:28 -0700510
511 profiler().finishFrame();
John Reck4f02bf42014-01-03 18:09:17 -0800512}
513
John Recke45b1fd2014-04-15 09:50:16 -0700514// Called by choreographer to do an RT-driven animation
John Reck18f16e62014-05-02 16:46:41 -0700515void CanvasContext::doFrame() {
John Reck368cdd82014-05-07 13:11:00 -0700516 if (CC_UNLIKELY(!mCanvas || mEglSurface == EGL_NO_SURFACE)) {
517 return;
518 }
519
John Recke45b1fd2014-04-15 09:50:16 -0700520 ATRACE_CALL();
521
John Reckfe5e7b72014-05-23 17:42:28 -0700522 profiler().startFrame();
523
John Recke4267ea2014-06-03 15:53:15 -0700524 TreeInfo info(TreeInfo::MODE_RT_ONLY);
John Recke45b1fd2014-04-15 09:50:16 -0700525 info.prepareTextures = false;
526
527 prepareTree(info);
John Recka5dda642014-05-22 15:43:54 -0700528 if (info.out.canDrawThisFrame) {
John Recke4267ea2014-06-03 15:53:15 -0700529 draw();
John Recka5dda642014-05-22 15:43:54 -0700530 }
John Recke45b1fd2014-04-15 09:50:16 -0700531}
532
John Reck0d1f6342014-03-28 20:30:27 -0700533void CanvasContext::invokeFunctor(Functor* functor) {
John Reckd3d8daf2014-04-10 15:00:13 -0700534 ATRACE_CALL();
John Reck0d1f6342014-03-28 20:30:27 -0700535 DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext;
536 if (mGlobalContext->hasContext()) {
537 requireGlContext();
538 mode = DrawGlInfo::kModeProcess;
539 }
John Reck6f07a0d2014-04-16 21:31:25 -0700540
541 if (mCanvas) {
Chris Craik734df4b2014-06-16 12:05:54 -0700542 mCanvas->interrupt();
543 }
544 (*functor)(mode, NULL);
545 if (mCanvas) {
John Reck6f07a0d2014-04-16 21:31:25 -0700546 mCanvas->resume();
547 }
John Reck23b797a2014-01-03 18:08:34 -0800548}
549
John Reck19b6bcf2014-02-14 20:03:38 -0800550bool CanvasContext::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
551 requireGlContext();
John Recke4267ea2014-06-03 15:53:15 -0700552 TreeInfo info(TreeInfo::MODE_FULL);
John Reck860d1552014-04-11 19:15:05 -0700553 layer->apply(info);
John Reck19b6bcf2014-02-14 20:03:38 -0800554 return LayerRenderer::copyLayer(layer->backingLayer(), bitmap);
555}
556
John Recke1628b72014-05-23 15:11:19 -0700557void CanvasContext::flushCaches(Caches::FlushMode flushMode) {
558 if (mGlobalContext->hasContext()) {
559 requireGlContext();
560 Caches::getInstance().flush(flushMode);
561 }
562}
563
John Reckfc53ef272014-02-11 10:40:25 -0800564void CanvasContext::runWithGlContext(RenderTask* task) {
John Reck19b6bcf2014-02-14 20:03:38 -0800565 requireGlContext();
566 task->run();
567}
568
John Reck1949e792014-04-08 15:18:56 -0700569Layer* CanvasContext::createRenderLayer(int width, int height) {
John Reckf7d9c1d2014-04-09 10:01:03 -0700570 requireSurface();
John Reck1949e792014-04-08 15:18:56 -0700571 return LayerRenderer::createRenderLayer(width, height);
572}
573
574Layer* CanvasContext::createTextureLayer() {
John Reckf7d9c1d2014-04-09 10:01:03 -0700575 requireSurface();
John Reck1949e792014-04-08 15:18:56 -0700576 return LayerRenderer::createTextureLayer();
577}
578
John Reck19b6bcf2014-02-14 20:03:38 -0800579void CanvasContext::requireGlContext() {
John Reckfc53ef272014-02-11 10:40:25 -0800580 if (mEglSurface != EGL_NO_SURFACE) {
John Reckdbc9a862014-04-17 20:25:13 -0700581 makeCurrent();
John Reckfc53ef272014-02-11 10:40:25 -0800582 } else {
583 mGlobalContext->usePBufferSurface();
584 }
John Reckfc53ef272014-02-11 10:40:25 -0800585}
586
John Reck66f0be62014-05-13 13:39:31 -0700587void CanvasContext::setTextureAtlas(const sp<GraphicBuffer>& buffer,
588 int64_t* map, size_t mapSize) {
589 GlobalContext::get()->setTextureAtlas(buffer, map, mapSize);
590}
591
John Reck23b797a2014-01-03 18:08:34 -0800592} /* namespace renderthread */
593} /* namespace uirenderer */
594} /* namespace android */