blob: 9ebee1d7fbd450038011394c5e8014c48767f2d0 [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 Recke45b1fd2014-04-15 09:50:16 -0700442 mRootRenderNode->prepareTree(info);
443
John Recka5dda642014-05-22 15:43:54 -0700444 int runningBehind = 0;
445 // TODO: This query is moderately expensive, investigate adding some sort
446 // of fast-path based off when we last called eglSwapBuffers() as well as
447 // last vsync time. Or something.
448 mNativeWindow->query(mNativeWindow.get(),
449 NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &runningBehind);
450 info.out.canDrawThisFrame = !runningBehind;
451
452 if (info.out.hasAnimations || !info.out.canDrawThisFrame) {
John Reckf9be7792014-05-02 18:21:16 -0700453 if (info.out.hasFunctors) {
454 info.out.requiresUiRedraw = true;
455 } else if (!info.out.requiresUiRedraw) {
456 // If animationsNeedsRedraw is set don't bother posting for an RT anim
457 // as we will just end up fighting the UI thread.
458 mRenderThread.postFrameCallback(this);
459 }
John Recke45b1fd2014-04-15 09:50:16 -0700460 }
461}
462
John Recka5dda642014-05-22 15:43:54 -0700463void CanvasContext::notifyFramePending() {
464 ATRACE_CALL();
465 mRenderThread.pushBackFrameCallback(this);
466}
467
John Recke45b1fd2014-04-15 09:50:16 -0700468void CanvasContext::draw(Rect* dirty) {
John Reck4f02bf42014-01-03 18:09:17 -0800469 LOG_ALWAYS_FATAL_IF(!mCanvas || mEglSurface == EGL_NO_SURFACE,
470 "drawDisplayList called on a context with no canvas or surface!");
471
John Reckfe5e7b72014-05-23 17:42:28 -0700472 profiler().markPlaybackStart();
473
John Reck4f02bf42014-01-03 18:09:17 -0800474 EGLint width, height;
475 mGlobalContext->beginFrame(mEglSurface, &width, &height);
476 if (width != mCanvas->getViewportWidth() || height != mCanvas->getViewportHeight()) {
477 mCanvas->setViewport(width, height);
478 dirty = NULL;
479 } else if (!mDirtyRegionsEnabled || mHaveNewSurface) {
480 dirty = NULL;
John Reckfe5e7b72014-05-23 17:42:28 -0700481 } else {
482 profiler().unionDirty(dirty);
John Reck4f02bf42014-01-03 18:09:17 -0800483 }
484
485 status_t status;
John Recke45b1fd2014-04-15 09:50:16 -0700486 if (dirty && !dirty->isEmpty()) {
John Reck4f02bf42014-01-03 18:09:17 -0800487 status = mCanvas->prepareDirty(dirty->left, dirty->top,
488 dirty->right, dirty->bottom, mOpaque);
489 } else {
490 status = mCanvas->prepare(mOpaque);
491 }
492
493 Rect outBounds;
John Recke45b1fd2014-04-15 09:50:16 -0700494 status |= mCanvas->drawDisplayList(mRootRenderNode.get(), outBounds);
John Reck4f02bf42014-01-03 18:09:17 -0800495
John Reckfe5e7b72014-05-23 17:42:28 -0700496 profiler().draw(mCanvas);
John Reck4f02bf42014-01-03 18:09:17 -0800497
498 mCanvas->finish();
499
John Reckfe5e7b72014-05-23 17:42:28 -0700500 profiler().markPlaybackEnd();
501
John Reck4f02bf42014-01-03 18:09:17 -0800502 if (status & DrawGlInfo::kStatusDrew) {
503 swapBuffers();
504 }
John Reckfe5e7b72014-05-23 17:42:28 -0700505
506 profiler().finishFrame();
John Reck4f02bf42014-01-03 18:09:17 -0800507}
508
John Recke45b1fd2014-04-15 09:50:16 -0700509// Called by choreographer to do an RT-driven animation
John Reck18f16e62014-05-02 16:46:41 -0700510void CanvasContext::doFrame() {
John Reck368cdd82014-05-07 13:11:00 -0700511 if (CC_UNLIKELY(!mCanvas || mEglSurface == EGL_NO_SURFACE)) {
512 return;
513 }
514
John Recke45b1fd2014-04-15 09:50:16 -0700515 ATRACE_CALL();
516
John Reckfe5e7b72014-05-23 17:42:28 -0700517 profiler().startFrame();
518
John Recke45b1fd2014-04-15 09:50:16 -0700519 TreeInfo info;
520 info.evaluateAnimations = true;
John Recke45b1fd2014-04-15 09:50:16 -0700521 info.performStagingPush = false;
522 info.prepareTextures = false;
523
524 prepareTree(info);
John Recka5dda642014-05-22 15:43:54 -0700525 if (info.out.canDrawThisFrame) {
526 draw(NULL);
527 }
John Recke45b1fd2014-04-15 09:50:16 -0700528}
529
John Reck0d1f6342014-03-28 20:30:27 -0700530void CanvasContext::invokeFunctor(Functor* functor) {
John Reckd3d8daf2014-04-10 15:00:13 -0700531 ATRACE_CALL();
John Reck0d1f6342014-03-28 20:30:27 -0700532 DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext;
533 if (mGlobalContext->hasContext()) {
534 requireGlContext();
535 mode = DrawGlInfo::kModeProcess;
536 }
John Reck832b15142014-05-07 14:39:44 -0700537 (*functor)(mode, NULL);
John Reck6f07a0d2014-04-16 21:31:25 -0700538
539 if (mCanvas) {
540 mCanvas->resume();
541 }
John Reck23b797a2014-01-03 18:08:34 -0800542}
543
John Reck19b6bcf2014-02-14 20:03:38 -0800544bool CanvasContext::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
545 requireGlContext();
John Reck860d1552014-04-11 19:15:05 -0700546 TreeInfo info;
547 layer->apply(info);
John Reck19b6bcf2014-02-14 20:03:38 -0800548 return LayerRenderer::copyLayer(layer->backingLayer(), bitmap);
549}
550
John Recke1628b72014-05-23 15:11:19 -0700551void CanvasContext::flushCaches(Caches::FlushMode flushMode) {
552 if (mGlobalContext->hasContext()) {
553 requireGlContext();
554 Caches::getInstance().flush(flushMode);
555 }
556}
557
John Reckfc53ef272014-02-11 10:40:25 -0800558void CanvasContext::runWithGlContext(RenderTask* task) {
John Reck19b6bcf2014-02-14 20:03:38 -0800559 requireGlContext();
560 task->run();
561}
562
John Reck1949e792014-04-08 15:18:56 -0700563Layer* CanvasContext::createRenderLayer(int width, int height) {
John Reckf7d9c1d2014-04-09 10:01:03 -0700564 requireSurface();
John Reck1949e792014-04-08 15:18:56 -0700565 return LayerRenderer::createRenderLayer(width, height);
566}
567
568Layer* CanvasContext::createTextureLayer() {
John Reckf7d9c1d2014-04-09 10:01:03 -0700569 requireSurface();
John Reck1949e792014-04-08 15:18:56 -0700570 return LayerRenderer::createTextureLayer();
571}
572
John Reck19b6bcf2014-02-14 20:03:38 -0800573void CanvasContext::requireGlContext() {
John Reckfc53ef272014-02-11 10:40:25 -0800574 if (mEglSurface != EGL_NO_SURFACE) {
John Reckdbc9a862014-04-17 20:25:13 -0700575 makeCurrent();
John Reckfc53ef272014-02-11 10:40:25 -0800576 } else {
577 mGlobalContext->usePBufferSurface();
578 }
John Reckfc53ef272014-02-11 10:40:25 -0800579}
580
John Reck66f0be62014-05-13 13:39:31 -0700581void CanvasContext::setTextureAtlas(const sp<GraphicBuffer>& buffer,
582 int64_t* map, size_t mapSize) {
583 GlobalContext::get()->setTextureAtlas(buffer, map, mapSize);
584}
585
John Reck23b797a2014-01-03 18:08:34 -0800586} /* namespace renderthread */
587} /* namespace uirenderer */
588} /* namespace android */