blob: 5754536b06a6cf9170936015d1cc0d394995e53f [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#ifdef USE_OPENGL_RENDERER
36// Android-specific addition that is used to show when frames began in systrace
37EGLAPI void EGLAPIENTRY eglBeginFrame(EGLDisplay dpy, EGLSurface surface);
38#endif
39
John Reck23b797a2014-01-03 18:08:34 -080040namespace android {
41namespace uirenderer {
42namespace renderthread {
43
44#define ERROR_CASE(x) case x: return #x;
45static const char* egl_error_str(EGLint error) {
46 switch (error) {
47 ERROR_CASE(EGL_SUCCESS)
48 ERROR_CASE(EGL_NOT_INITIALIZED)
49 ERROR_CASE(EGL_BAD_ACCESS)
50 ERROR_CASE(EGL_BAD_ALLOC)
51 ERROR_CASE(EGL_BAD_ATTRIBUTE)
52 ERROR_CASE(EGL_BAD_CONFIG)
53 ERROR_CASE(EGL_BAD_CONTEXT)
54 ERROR_CASE(EGL_BAD_CURRENT_SURFACE)
55 ERROR_CASE(EGL_BAD_DISPLAY)
56 ERROR_CASE(EGL_BAD_MATCH)
57 ERROR_CASE(EGL_BAD_NATIVE_PIXMAP)
58 ERROR_CASE(EGL_BAD_NATIVE_WINDOW)
59 ERROR_CASE(EGL_BAD_PARAMETER)
60 ERROR_CASE(EGL_BAD_SURFACE)
61 ERROR_CASE(EGL_CONTEXT_LOST)
62 default:
63 return "Unknown error";
64 }
65}
66static const char* egl_error_str() {
67 return egl_error_str(eglGetError());
68}
69
70static bool load_dirty_regions_property() {
71 char buf[PROPERTY_VALUE_MAX];
72 int len = property_get(PROPERTY_RENDER_DIRTY_REGIONS, buf, "true");
73 return !strncasecmp("true", buf, len);
74}
75
76// This class contains the shared global EGL objects, such as EGLDisplay
77// and EGLConfig, which are re-used by CanvasContext
78class GlobalContext {
79public:
80 static GlobalContext* get();
81
John Reck4f02bf42014-01-03 18:09:17 -080082 // Returns true on success, false on failure
83 void initialize();
John Reck23b797a2014-01-03 18:08:34 -080084
John Reck0d1f6342014-03-28 20:30:27 -070085 bool hasContext();
86
John Reck4f02bf42014-01-03 18:09:17 -080087 void usePBufferSurface();
John Reck23b797a2014-01-03 18:08:34 -080088 EGLSurface createSurface(EGLNativeWindowType window);
89 void destroySurface(EGLSurface surface);
90
91 void destroy();
92
93 bool isCurrent(EGLSurface surface) { return mCurrentSurface == surface; }
John Reckdbc9a862014-04-17 20:25:13 -070094 // Returns true if the current surface changed, false if it was already current
95 bool makeCurrent(EGLSurface surface);
John Reck4f02bf42014-01-03 18:09:17 -080096 void beginFrame(EGLSurface surface, EGLint* width, EGLint* height);
97 void swapBuffers(EGLSurface surface);
John Reck23b797a2014-01-03 18:08:34 -080098
99 bool enableDirtyRegions(EGLSurface surface);
100
John Reck66f0be62014-05-13 13:39:31 -0700101 void setTextureAtlas(const sp<GraphicBuffer>& buffer, int64_t* map, size_t mapSize);
102
John Reck23b797a2014-01-03 18:08:34 -0800103private:
104 GlobalContext();
105 // GlobalContext is never destroyed, method is purposely not implemented
106 ~GlobalContext();
107
John Reck4f02bf42014-01-03 18:09:17 -0800108 void loadConfig();
109 void createContext();
110 void initAtlas();
John Reck23b797a2014-01-03 18:08:34 -0800111
112 static GlobalContext* sContext;
113
114 EGLDisplay mEglDisplay;
115 EGLConfig mEglConfig;
116 EGLContext mEglContext;
117 EGLSurface mPBufferSurface;
118
119 const bool mRequestDirtyRegions;
120 bool mCanSetDirtyRegions;
121
122 EGLSurface mCurrentSurface;
John Reck66f0be62014-05-13 13:39:31 -0700123
124 sp<GraphicBuffer> mAtlasBuffer;
125 int64_t* mAtlasMap;
126 size_t mAtlasMapSize;
John Reck23b797a2014-01-03 18:08:34 -0800127};
128
129GlobalContext* GlobalContext::sContext = 0;
130
131GlobalContext* GlobalContext::get() {
132 if (!sContext) {
133 sContext = new GlobalContext();
134 }
135 return sContext;
136}
137
138GlobalContext::GlobalContext()
139 : mEglDisplay(EGL_NO_DISPLAY)
140 , mEglConfig(0)
141 , mEglContext(EGL_NO_CONTEXT)
142 , mPBufferSurface(EGL_NO_SURFACE)
143 , mRequestDirtyRegions(load_dirty_regions_property())
John Reck66f0be62014-05-13 13:39:31 -0700144 , mCurrentSurface(EGL_NO_SURFACE)
145 , mAtlasMap(NULL)
146 , mAtlasMapSize(0) {
John Reck23b797a2014-01-03 18:08:34 -0800147 mCanSetDirtyRegions = mRequestDirtyRegions;
148 ALOGD("Render dirty regions requested: %s", mRequestDirtyRegions ? "true" : "false");
149}
150
John Reck4f02bf42014-01-03 18:09:17 -0800151void GlobalContext::initialize() {
John Reck0d1f6342014-03-28 20:30:27 -0700152 if (hasContext()) return;
John Reck23b797a2014-01-03 18:08:34 -0800153
154 mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
John Reck4f02bf42014-01-03 18:09:17 -0800155 LOG_ALWAYS_FATAL_IF(mEglDisplay == EGL_NO_DISPLAY,
156 "Failed to get EGL_DEFAULT_DISPLAY! err=%s", egl_error_str());
John Reck23b797a2014-01-03 18:08:34 -0800157
158 EGLint major, minor;
John Reck4f02bf42014-01-03 18:09:17 -0800159 LOG_ALWAYS_FATAL_IF(eglInitialize(mEglDisplay, &major, &minor) == EGL_FALSE,
160 "Failed to initialize display %p! err=%s", mEglDisplay, egl_error_str());
161
John Reck23b797a2014-01-03 18:08:34 -0800162 ALOGI("Initialized EGL, version %d.%d", (int)major, (int)minor);
163
John Reck4f02bf42014-01-03 18:09:17 -0800164 loadConfig();
165 createContext();
166 usePBufferSurface();
167 Caches::getInstance().init();
168 initAtlas();
John Reck23b797a2014-01-03 18:08:34 -0800169}
170
John Reck0d1f6342014-03-28 20:30:27 -0700171bool GlobalContext::hasContext() {
172 return mEglDisplay != EGL_NO_DISPLAY;
173}
174
John Reck4f02bf42014-01-03 18:09:17 -0800175void GlobalContext::loadConfig() {
John Reck23b797a2014-01-03 18:08:34 -0800176 EGLint swapBehavior = mCanSetDirtyRegions ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
177 EGLint attribs[] = {
178 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
179 EGL_RED_SIZE, 8,
180 EGL_GREEN_SIZE, 8,
181 EGL_BLUE_SIZE, 8,
182 EGL_ALPHA_SIZE, 8,
183 EGL_DEPTH_SIZE, 0,
184 EGL_CONFIG_CAVEAT, EGL_NONE,
185 EGL_STENCIL_SIZE, Stencil::getStencilSize(),
186 EGL_SURFACE_TYPE, EGL_WINDOW_BIT | swapBehavior,
187 EGL_NONE
188 };
189
190 EGLint num_configs = 1;
191 if (!eglChooseConfig(mEglDisplay, attribs, &mEglConfig, num_configs, &num_configs)
192 || num_configs != 1) {
193 // Failed to get a valid config
194 if (mCanSetDirtyRegions) {
195 ALOGW("Failed to choose config with EGL_SWAP_BEHAVIOR_PRESERVED, retrying without...");
196 // Try again without dirty regions enabled
197 mCanSetDirtyRegions = false;
198 loadConfig();
199 } else {
John Reck4f02bf42014-01-03 18:09:17 -0800200 LOG_ALWAYS_FATAL("Failed to choose config, error = %s", egl_error_str());
John Reck23b797a2014-01-03 18:08:34 -0800201 }
202 }
John Reck23b797a2014-01-03 18:08:34 -0800203}
204
John Reck4f02bf42014-01-03 18:09:17 -0800205void GlobalContext::createContext() {
John Reck23b797a2014-01-03 18:08:34 -0800206 EGLint attribs[] = { EGL_CONTEXT_CLIENT_VERSION, GLES_VERSION, EGL_NONE };
207 mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT, attribs);
John Reck4f02bf42014-01-03 18:09:17 -0800208 LOG_ALWAYS_FATAL_IF(mEglContext == EGL_NO_CONTEXT,
209 "Failed to create context, error = %s", egl_error_str());
John Reck23b797a2014-01-03 18:08:34 -0800210}
211
John Reck66f0be62014-05-13 13:39:31 -0700212void GlobalContext::setTextureAtlas(const sp<GraphicBuffer>& buffer,
213 int64_t* map, size_t mapSize) {
214
215 // Already initialized
216 if (mAtlasBuffer.get()) {
217 ALOGW("Multiple calls to setTextureAtlas!");
218 delete map;
219 return;
220 }
221
222 mAtlasBuffer = buffer;
223 mAtlasMap = map;
224 mAtlasMapSize = mapSize;
225
226 if (hasContext()) {
227 usePBufferSurface();
228 initAtlas();
229 }
230}
231
John Reck4f02bf42014-01-03 18:09:17 -0800232void GlobalContext::initAtlas() {
John Reck66f0be62014-05-13 13:39:31 -0700233 Caches::getInstance().assetAtlas.init(mAtlasBuffer, mAtlasMap, mAtlasMapSize);
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 Reck4f02bf42014-01-03 18:09:17 -0800362void CanvasContext::setSurface(EGLNativeWindowType window) {
John Reck23b797a2014-01-03 18:08:34 -0800363 if (mEglSurface != EGL_NO_SURFACE) {
364 mGlobalContext->destroySurface(mEglSurface);
365 mEglSurface = EGL_NO_SURFACE;
366 }
367
368 if (window) {
369 mEglSurface = mGlobalContext->createSurface(window);
John Reck4f02bf42014-01-03 18:09:17 -0800370 LOG_ALWAYS_FATAL_IF(mEglSurface == EGL_NO_SURFACE,
371 "Failed to create EGLSurface for window %p, eglErr = %s",
372 (void*) window, egl_error_str());
John Reck23b797a2014-01-03 18:08:34 -0800373 }
374
375 if (mEglSurface != EGL_NO_SURFACE) {
376 mDirtyRegionsEnabled = mGlobalContext->enableDirtyRegions(mEglSurface);
John Reck4f02bf42014-01-03 18:09:17 -0800377 mHaveNewSurface = true;
John Reckdbc9a862014-04-17 20:25:13 -0700378 makeCurrent();
John Reck368cdd82014-05-07 13:11:00 -0700379 } else {
380 mRenderThread.removeFrameCallback(this);
John Reck23b797a2014-01-03 18:08:34 -0800381 }
John Reck23b797a2014-01-03 18:08:34 -0800382}
383
John Reck4f02bf42014-01-03 18:09:17 -0800384void CanvasContext::swapBuffers() {
385 mGlobalContext->swapBuffers(mEglSurface);
386 mHaveNewSurface = false;
John Reck23b797a2014-01-03 18:08:34 -0800387}
388
John Reckf7d9c1d2014-04-09 10:01:03 -0700389void CanvasContext::requireSurface() {
390 LOG_ALWAYS_FATAL_IF(mEglSurface == EGL_NO_SURFACE,
391 "requireSurface() called but no surface set!");
John Reckdbc9a862014-04-17 20:25:13 -0700392 makeCurrent();
John Reck23b797a2014-01-03 18:08:34 -0800393}
394
John Reck4f02bf42014-01-03 18:09:17 -0800395bool CanvasContext::initialize(EGLNativeWindowType window) {
396 if (mCanvas) return false;
397 setSurface(window);
John Reck4f02bf42014-01-03 18:09:17 -0800398 mCanvas = new OpenGLRenderer();
399 mCanvas->initProperties();
400 return true;
401}
402
403void CanvasContext::updateSurface(EGLNativeWindowType window) {
404 setSurface(window);
John Reckf7d9c1d2014-04-09 10:01:03 -0700405}
406
407void CanvasContext::pauseSurface(EGLNativeWindowType window) {
408 // TODO: For now we just need a fence, in the future suspend any animations
409 // and such to prevent from trying to render into this surface
John Reck4f02bf42014-01-03 18:09:17 -0800410}
411
412void CanvasContext::setup(int width, int height) {
413 if (!mCanvas) return;
414 mCanvas->setViewport(width, height);
415}
416
John Reck63a06672014-05-07 13:45:54 -0700417void CanvasContext::setOpaque(bool opaque) {
418 mOpaque = opaque;
419}
420
John Reck860d1552014-04-11 19:15:05 -0700421void CanvasContext::makeCurrent() {
John Reckdbc9a862014-04-17 20:25:13 -0700422 // TODO: Figure out why this workaround is needed, see b/13913604
423 // In the meantime this matches the behavior of GLRenderer, so it is not a regression
424 mHaveNewSurface |= mGlobalContext->makeCurrent(mEglSurface);
John Reck860d1552014-04-11 19:15:05 -0700425}
426
John Reckf9be7792014-05-02 18:21:16 -0700427void CanvasContext::prepareDraw(const Vector<DeferredLayerUpdater*>* layerUpdaters,
428 TreeInfo& info) {
429 LOG_ALWAYS_FATAL_IF(!mCanvas, "Cannot prepareDraw without a canvas!");
430 makeCurrent();
431
432 processLayerUpdates(layerUpdaters, info);
433 if (info.out.hasAnimations) {
434 // TODO: Uh... crap?
435 }
436 prepareTree(info);
437}
438
John Reck860d1552014-04-11 19:15:05 -0700439void CanvasContext::processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters,
440 TreeInfo& info) {
John Reck19b6bcf2014-02-14 20:03:38 -0800441 for (size_t i = 0; i < layerUpdaters->size(); i++) {
442 DeferredLayerUpdater* update = layerUpdaters->itemAt(i);
John Reck860d1552014-04-11 19:15:05 -0700443 bool success = update->apply(info);
444 LOG_ALWAYS_FATAL_IF(!success, "Failed to update layer!");
John Reck19b6bcf2014-02-14 20:03:38 -0800445 if (update->backingLayer()->deferredUpdateScheduled) {
446 mCanvas->pushLayerUpdate(update->backingLayer());
447 }
448 }
449}
450
John Recke45b1fd2014-04-15 09:50:16 -0700451void CanvasContext::prepareTree(TreeInfo& info) {
John Reckf9be7792014-05-02 18:21:16 -0700452 mRenderThread.removeFrameCallback(this);
John Reck18f16e62014-05-02 16:46:41 -0700453
John Reckf9be7792014-05-02 18:21:16 -0700454 info.frameTimeMs = mRenderThread.timeLord().frameTimeMs();
John Recke45b1fd2014-04-15 09:50:16 -0700455 mRootRenderNode->prepareTree(info);
456
John Reckf9be7792014-05-02 18:21:16 -0700457 if (info.out.hasAnimations) {
458 if (info.out.hasFunctors) {
459 info.out.requiresUiRedraw = true;
460 } else if (!info.out.requiresUiRedraw) {
461 // If animationsNeedsRedraw is set don't bother posting for an RT anim
462 // as we will just end up fighting the UI thread.
463 mRenderThread.postFrameCallback(this);
464 }
John Recke45b1fd2014-04-15 09:50:16 -0700465 }
466}
467
468void 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
472 EGLint width, height;
473 mGlobalContext->beginFrame(mEglSurface, &width, &height);
474 if (width != mCanvas->getViewportWidth() || height != mCanvas->getViewportHeight()) {
475 mCanvas->setViewport(width, height);
476 dirty = NULL;
477 } else if (!mDirtyRegionsEnabled || mHaveNewSurface) {
478 dirty = NULL;
479 }
480
481 status_t status;
John Recke45b1fd2014-04-15 09:50:16 -0700482 if (dirty && !dirty->isEmpty()) {
John Reck4f02bf42014-01-03 18:09:17 -0800483 status = mCanvas->prepareDirty(dirty->left, dirty->top,
484 dirty->right, dirty->bottom, mOpaque);
485 } else {
486 status = mCanvas->prepare(mOpaque);
487 }
488
489 Rect outBounds;
John Recke45b1fd2014-04-15 09:50:16 -0700490 status |= mCanvas->drawDisplayList(mRootRenderNode.get(), outBounds);
John Reck4f02bf42014-01-03 18:09:17 -0800491
492 // TODO: Draw debug info
493 // TODO: Performance tracking
494
495 mCanvas->finish();
496
497 if (status & DrawGlInfo::kStatusDrew) {
498 swapBuffers();
499 }
500}
501
John Recke45b1fd2014-04-15 09:50:16 -0700502// Called by choreographer to do an RT-driven animation
John Reck18f16e62014-05-02 16:46:41 -0700503void CanvasContext::doFrame() {
John Reck368cdd82014-05-07 13:11:00 -0700504 if (CC_UNLIKELY(!mCanvas || mEglSurface == EGL_NO_SURFACE)) {
505 return;
506 }
507
John Recke45b1fd2014-04-15 09:50:16 -0700508 ATRACE_CALL();
509
510 TreeInfo info;
511 info.evaluateAnimations = true;
John Recke45b1fd2014-04-15 09:50:16 -0700512 info.performStagingPush = false;
513 info.prepareTextures = false;
514
515 prepareTree(info);
516 draw(NULL);
517}
518
John Reck0d1f6342014-03-28 20:30:27 -0700519void CanvasContext::invokeFunctor(Functor* functor) {
John Reckd3d8daf2014-04-10 15:00:13 -0700520 ATRACE_CALL();
John Reck0d1f6342014-03-28 20:30:27 -0700521 DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext;
522 if (mGlobalContext->hasContext()) {
523 requireGlContext();
524 mode = DrawGlInfo::kModeProcess;
525 }
John Reck832b15142014-05-07 14:39:44 -0700526 (*functor)(mode, NULL);
John Reck6f07a0d2014-04-16 21:31:25 -0700527
528 if (mCanvas) {
529 mCanvas->resume();
530 }
John Reck23b797a2014-01-03 18:08:34 -0800531}
532
John Reck19b6bcf2014-02-14 20:03:38 -0800533bool CanvasContext::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
534 requireGlContext();
John Reck860d1552014-04-11 19:15:05 -0700535 TreeInfo info;
536 layer->apply(info);
John Reck19b6bcf2014-02-14 20:03:38 -0800537 return LayerRenderer::copyLayer(layer->backingLayer(), bitmap);
538}
539
John Reckfc53ef272014-02-11 10:40:25 -0800540void CanvasContext::runWithGlContext(RenderTask* task) {
John Reck19b6bcf2014-02-14 20:03:38 -0800541 requireGlContext();
542 task->run();
543}
544
John Reck1949e792014-04-08 15:18:56 -0700545Layer* CanvasContext::createRenderLayer(int width, int height) {
John Reckf7d9c1d2014-04-09 10:01:03 -0700546 requireSurface();
John Reck1949e792014-04-08 15:18:56 -0700547 return LayerRenderer::createRenderLayer(width, height);
548}
549
550Layer* CanvasContext::createTextureLayer() {
John Reckf7d9c1d2014-04-09 10:01:03 -0700551 requireSurface();
John Reck1949e792014-04-08 15:18:56 -0700552 return LayerRenderer::createTextureLayer();
553}
554
John Reck19b6bcf2014-02-14 20:03:38 -0800555void CanvasContext::requireGlContext() {
John Reckfc53ef272014-02-11 10:40:25 -0800556 if (mEglSurface != EGL_NO_SURFACE) {
John Reckdbc9a862014-04-17 20:25:13 -0700557 makeCurrent();
John Reckfc53ef272014-02-11 10:40:25 -0800558 } else {
559 mGlobalContext->usePBufferSurface();
560 }
John Reckfc53ef272014-02-11 10:40:25 -0800561}
562
John Reck66f0be62014-05-13 13:39:31 -0700563void CanvasContext::setTextureAtlas(const sp<GraphicBuffer>& buffer,
564 int64_t* map, size_t mapSize) {
565 GlobalContext::get()->setTextureAtlas(buffer, map, mapSize);
566}
567
John Reck23b797a2014-01-03 18:08:34 -0800568} /* namespace renderthread */
569} /* namespace uirenderer */
570} /* namespace android */