blob: c2adf0790da12cf471125fc99f45a3ae66a793e2 [file] [log] [blame]
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001/*
2 * Copyright (C) 2007 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 "SurfaceFlinger"
18
19#include <stdlib.h>
20#include <stdio.h>
21#include <stdint.h>
22#include <unistd.h>
23#include <fcntl.h>
24#include <errno.h>
25#include <math.h>
Jean-Baptiste Queru20763732009-01-26 11:51:12 -080026#include <limits.h>
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070027#include <sys/types.h>
28#include <sys/stat.h>
29#include <sys/ioctl.h>
30
31#include <cutils/log.h>
32#include <cutils/properties.h>
33
34#include <utils/IPCThreadState.h>
35#include <utils/IServiceManager.h>
36#include <utils/MemoryDealer.h>
37#include <utils/MemoryBase.h>
38#include <utils/String8.h>
39#include <utils/String16.h>
40#include <utils/StopWatch.h>
41
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070042#include <ui/PixelFormat.h>
43#include <ui/DisplayInfo.h>
44#include <ui/EGLDisplaySurface.h>
45
46#include <pixelflinger/pixelflinger.h>
47#include <GLES/gl.h>
48
49#include "clz.h"
50#include "CPUGauge.h"
51#include "Layer.h"
52#include "LayerBlur.h"
53#include "LayerBuffer.h"
54#include "LayerDim.h"
55#include "LayerBitmap.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056#include "LayerOrientationAnim.h"
57#include "OrientationAnimation.h"
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070058#include "SurfaceFlinger.h"
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070059#include "VRamHeap.h"
60
61#include "DisplayHardware/DisplayHardware.h"
62#include "GPUHardware/GPUHardware.h"
63
64
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070065#define DISPLAY_COUNT 1
66
67namespace android {
68
69// ---------------------------------------------------------------------------
70
71void SurfaceFlinger::instantiate() {
72 defaultServiceManager()->addService(
73 String16("SurfaceFlinger"), new SurfaceFlinger());
74}
75
76void SurfaceFlinger::shutdown() {
77 // we should unregister here, but not really because
78 // when (if) the service manager goes away, all the services
79 // it has a reference to will leave too.
80}
81
82// ---------------------------------------------------------------------------
83
84SurfaceFlinger::LayerVector::LayerVector(const SurfaceFlinger::LayerVector& rhs)
85 : lookup(rhs.lookup), layers(rhs.layers)
86{
87}
88
89ssize_t SurfaceFlinger::LayerVector::indexOf(
90 LayerBase* key, size_t guess) const
91{
92 if (guess<size() && lookup.keyAt(guess) == key)
93 return guess;
94 const ssize_t i = lookup.indexOfKey(key);
95 if (i>=0) {
96 const size_t idx = lookup.valueAt(i);
97 LOG_ASSERT(layers[idx]==key,
98 "LayerVector[%p]: layers[%d]=%p, key=%p",
99 this, int(idx), layers[idx], key);
100 return idx;
101 }
102 return i;
103}
104
105ssize_t SurfaceFlinger::LayerVector::add(
106 LayerBase* layer,
107 Vector<LayerBase*>::compar_t cmp)
108{
109 size_t count = layers.size();
110 ssize_t l = 0;
111 ssize_t h = count-1;
112 ssize_t mid;
113 LayerBase* const* a = layers.array();
114 while (l <= h) {
115 mid = l + (h - l)/2;
116 const int c = cmp(a+mid, &layer);
117 if (c == 0) { l = mid; break; }
118 else if (c<0) { l = mid+1; }
119 else { h = mid-1; }
120 }
121 size_t order = l;
122 while (order<count && !cmp(&layer, a+order)) {
123 order++;
124 }
125 count = lookup.size();
126 for (size_t i=0 ; i<count ; i++) {
127 if (lookup.valueAt(i) >= order) {
128 lookup.editValueAt(i)++;
129 }
130 }
131 layers.insertAt(layer, order);
132 lookup.add(layer, order);
133 return order;
134}
135
136ssize_t SurfaceFlinger::LayerVector::remove(LayerBase* layer)
137{
138 const ssize_t keyIndex = lookup.indexOfKey(layer);
139 if (keyIndex >= 0) {
140 const size_t index = lookup.valueAt(keyIndex);
141 LOG_ASSERT(layers[index]==layer,
142 "LayerVector[%p]: layers[%u]=%p, layer=%p",
143 this, int(index), layers[index], layer);
144 layers.removeItemsAt(index);
145 lookup.removeItemsAt(keyIndex);
146 const size_t count = lookup.size();
147 for (size_t i=0 ; i<count ; i++) {
148 if (lookup.valueAt(i) >= size_t(index)) {
149 lookup.editValueAt(i)--;
150 }
151 }
152 return index;
153 }
154 return NAME_NOT_FOUND;
155}
156
157ssize_t SurfaceFlinger::LayerVector::reorder(
158 LayerBase* layer,
159 Vector<LayerBase*>::compar_t cmp)
160{
161 // XXX: it's a little lame. but oh well...
162 ssize_t err = remove(layer);
163 if (err >=0)
164 err = add(layer, cmp);
165 return err;
166}
167
168// ---------------------------------------------------------------------------
169#if 0
170#pragma mark -
171#endif
172
173SurfaceFlinger::SurfaceFlinger()
174 : BnSurfaceComposer(), Thread(false),
175 mTransactionFlags(0),
176 mTransactionCount(0),
177 mBootTime(systemTime()),
178 mLastScheduledBroadcast(NULL),
179 mVisibleRegionsDirty(false),
180 mDeferReleaseConsole(false),
181 mFreezeDisplay(false),
182 mFreezeCount(0),
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700183 mFreezeDisplayTime(0),
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700184 mDebugRegion(0),
185 mDebugCpu(0),
186 mDebugFps(0),
187 mDebugBackground(0),
188 mDebugNoBootAnimation(0),
189 mSyncObject(),
190 mDeplayedTransactionPending(0),
191 mConsoleSignals(0),
192 mSecureFrameBuffer(0)
193{
194 init();
195}
196
197void SurfaceFlinger::init()
198{
199 LOGI("SurfaceFlinger is starting");
200
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700201 // debugging stuff...
202 char value[PROPERTY_VALUE_MAX];
203 property_get("debug.sf.showupdates", value, "0");
204 mDebugRegion = atoi(value);
205 property_get("debug.sf.showcpu", value, "0");
206 mDebugCpu = atoi(value);
207 property_get("debug.sf.showbackground", value, "0");
208 mDebugBackground = atoi(value);
209 property_get("debug.sf.showfps", value, "0");
210 mDebugFps = atoi(value);
211 property_get("debug.sf.nobootanimation", value, "0");
212 mDebugNoBootAnimation = atoi(value);
213
214 LOGI_IF(mDebugRegion, "showupdates enabled");
215 LOGI_IF(mDebugCpu, "showcpu enabled");
216 LOGI_IF(mDebugBackground, "showbackground enabled");
217 LOGI_IF(mDebugFps, "showfps enabled");
218 LOGI_IF(mDebugNoBootAnimation, "boot animation disabled");
219}
220
221SurfaceFlinger::~SurfaceFlinger()
222{
223 glDeleteTextures(1, &mWormholeTexName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800224 delete mOrientationAnimation;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700225}
226
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800227copybit_device_t* SurfaceFlinger::getBlitEngine() const
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700228{
229 return graphicPlane(0).displayHardware().getBlitEngine();
230}
231
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800232overlay_control_device_t* SurfaceFlinger::getOverlayEngine() const
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800233{
234 return graphicPlane(0).displayHardware().getOverlayEngine();
235}
236
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700237sp<IMemory> SurfaceFlinger::getCblk() const
238{
239 return mServerCblkMemory;
240}
241
242status_t SurfaceFlinger::requestGPU(const sp<IGPUCallback>& callback,
243 gpu_info_t* gpu)
244{
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800245 IPCThreadState* ipc = IPCThreadState::self();
246 const int pid = ipc->getCallingPid();
247 status_t err = mGPU->request(pid, callback, gpu);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700248 return err;
249}
250
251status_t SurfaceFlinger::revokeGPU()
252{
253 return mGPU->friendlyRevoke();
254}
255
256sp<ISurfaceFlingerClient> SurfaceFlinger::createConnection()
257{
258 Mutex::Autolock _l(mStateLock);
259 uint32_t token = mTokens.acquire();
260
261 Client* client = new Client(token, this);
262 if ((client == 0) || (client->ctrlblk == 0)) {
263 mTokens.release(token);
264 return 0;
265 }
266 status_t err = mClientsMap.add(token, client);
267 if (err < 0) {
268 delete client;
269 mTokens.release(token);
270 return 0;
271 }
272 sp<BClient> bclient =
273 new BClient(this, token, client->controlBlockMemory());
274 return bclient;
275}
276
277void SurfaceFlinger::destroyConnection(ClientID cid)
278{
279 Mutex::Autolock _l(mStateLock);
280 Client* const client = mClientsMap.valueFor(cid);
281 if (client) {
282 // free all the layers this client owns
283 const Vector<LayerBaseClient*>& layers = client->getLayers();
284 const size_t count = layers.size();
285 for (size_t i=0 ; i<count ; i++) {
286 LayerBaseClient* const layer = layers[i];
287 removeLayer_l(layer);
288 }
289
290 // the resources associated with this client will be freed
291 // during the next transaction, after these surfaces have been
292 // properly removed from the screen
293
294 // remove this client from our ClientID->Client mapping.
295 mClientsMap.removeItem(cid);
296
297 // and add it to the list of disconnected clients
298 mDisconnectedClients.add(client);
299
300 // request a transaction
301 setTransactionFlags(eTransactionNeeded);
302 }
303}
304
305const GraphicPlane& SurfaceFlinger::graphicPlane(int dpy) const
306{
307 LOGE_IF(uint32_t(dpy) >= DISPLAY_COUNT, "Invalid DisplayID %d", dpy);
308 const GraphicPlane& plane(mGraphicPlanes[dpy]);
309 return plane;
310}
311
312GraphicPlane& SurfaceFlinger::graphicPlane(int dpy)
313{
314 return const_cast<GraphicPlane&>(
315 const_cast<SurfaceFlinger const *>(this)->graphicPlane(dpy));
316}
317
318void SurfaceFlinger::bootFinished()
319{
320 const nsecs_t now = systemTime();
321 const nsecs_t duration = now - mBootTime;
322 LOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
323 if (mBootAnimation != 0) {
324 mBootAnimation->requestExit();
325 mBootAnimation.clear();
326 }
327}
328
329void SurfaceFlinger::onFirstRef()
330{
331 run("SurfaceFlinger", PRIORITY_URGENT_DISPLAY);
332
333 // Wait for the main thread to be done with its initialization
334 mReadyToRunBarrier.wait();
335}
336
337
338static inline uint16_t pack565(int r, int g, int b) {
339 return (r<<11)|(g<<5)|b;
340}
341
342// this is defined in libGLES_CM.so
343extern ISurfaceComposer* GLES_localSurfaceManager;
344
345status_t SurfaceFlinger::readyToRun()
346{
347 LOGI( "SurfaceFlinger's main thread ready to run. "
348 "Initializing graphics H/W...");
349
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800350 // create the shared control-block
351 mServerHeap = new MemoryDealer(4096, MemoryDealer::READ_ONLY);
352 LOGE_IF(mServerHeap==0, "can't create shared memory dealer");
353
354 mServerCblkMemory = mServerHeap->allocate(4096);
355 LOGE_IF(mServerCblkMemory==0, "can't create shared control block");
356
357 mServerCblk = static_cast<surface_flinger_cblk_t *>(mServerCblkMemory->pointer());
358 LOGE_IF(mServerCblk==0, "can't get to shared control block's address");
359 new(mServerCblk) surface_flinger_cblk_t;
360
361 // get a reference to the GPU if we have one
362 mGPU = GPUFactory::getGPU();
363
364 // create the surface Heap manager, which manages the heaps
365 // (be it in RAM or VRAM) where surfaces are allocated
366 // We give 8 MB per client.
367 mSurfaceHeapManager = new SurfaceHeapManager(this, 8 << 20);
368
369
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700370 GLES_localSurfaceManager = static_cast<ISurfaceComposer*>(this);
371
372 // we only support one display currently
373 int dpy = 0;
374
375 {
376 // initialize the main display
377 GraphicPlane& plane(graphicPlane(dpy));
378 DisplayHardware* const hw = new DisplayHardware(this, dpy);
379 plane.setDisplayHardware(hw);
380 }
381
382 // initialize primary screen
383 // (other display should be initialized in the same manner, but
384 // asynchronously, as they could come and go. None of this is supported
385 // yet).
386 const GraphicPlane& plane(graphicPlane(dpy));
387 const DisplayHardware& hw = plane.displayHardware();
388 const uint32_t w = hw.getWidth();
389 const uint32_t h = hw.getHeight();
390 const uint32_t f = hw.getFormat();
391 hw.makeCurrent();
392
393 // initialize the shared control block
394 mServerCblk->connected |= 1<<dpy;
395 display_cblk_t* dcblk = mServerCblk->displays + dpy;
396 memset(dcblk, 0, sizeof(display_cblk_t));
397 dcblk->w = w;
398 dcblk->h = h;
399 dcblk->format = f;
400 dcblk->orientation = ISurfaceComposer::eOrientationDefault;
401 dcblk->xdpi = hw.getDpiX();
402 dcblk->ydpi = hw.getDpiY();
403 dcblk->fps = hw.getRefreshRate();
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800404 dcblk->density = hw.getDensity();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700405 asm volatile ("":::"memory");
406
407 // Initialize OpenGL|ES
408 glActiveTexture(GL_TEXTURE0);
409 glBindTexture(GL_TEXTURE_2D, 0);
410 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
411 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
412 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
413 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
414 glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
415 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800416 glPixelStorei(GL_PACK_ALIGNMENT, 4);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700417 glEnableClientState(GL_VERTEX_ARRAY);
418 glEnable(GL_SCISSOR_TEST);
419 glShadeModel(GL_FLAT);
420 glDisable(GL_DITHER);
421 glDisable(GL_CULL_FACE);
422
423 const uint16_t g0 = pack565(0x0F,0x1F,0x0F);
424 const uint16_t g1 = pack565(0x17,0x2f,0x17);
425 const uint16_t textureData[4] = { g0, g1, g1, g0 };
426 glGenTextures(1, &mWormholeTexName);
427 glBindTexture(GL_TEXTURE_2D, mWormholeTexName);
428 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
429 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
430 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
431 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
432 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0,
433 GL_RGB, GL_UNSIGNED_SHORT_5_6_5, textureData);
434
435 glViewport(0, 0, w, h);
436 glMatrixMode(GL_PROJECTION);
437 glLoadIdentity();
438 glOrthof(0, w, h, 0, 0, 1);
439
440 LayerDim::initDimmer(this, w, h);
441
442 mReadyToRunBarrier.open();
443
444 /*
445 * We're now ready to accept clients...
446 */
447
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800448 mOrientationAnimation = new OrientationAnimation(this);
449
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700450 // start CPU gauge display
451 if (mDebugCpu)
452 mCpuGauge = new CPUGauge(this, ms2ns(500));
453
454 // the boot animation!
455 if (mDebugNoBootAnimation == false)
456 mBootAnimation = new BootAnimation(this);
457
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700458 return NO_ERROR;
459}
460
461// ----------------------------------------------------------------------------
462#if 0
463#pragma mark -
464#pragma mark Events Handler
465#endif
466
467void SurfaceFlinger::waitForEvent()
468{
469 // wait for something to do
470 if (UNLIKELY(isFrozen())) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800471 // wait 5 seconds
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700472 const nsecs_t freezeDisplayTimeout = ms2ns(5000);
473 const nsecs_t now = systemTime();
474 if (mFreezeDisplayTime == 0) {
475 mFreezeDisplayTime = now;
476 }
477 nsecs_t waitTime = freezeDisplayTimeout - (now - mFreezeDisplayTime);
478 int err = (waitTime > 0) ? mSyncObject.wait(waitTime) : TIMED_OUT;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700479 if (err != NO_ERROR) {
480 if (isFrozen()) {
481 // we timed out and are still frozen
482 LOGW("timeout expired mFreezeDisplay=%d, mFreezeCount=%d",
483 mFreezeDisplay, mFreezeCount);
484 mFreezeCount = 0;
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700485 mFreezeDisplay = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700486 }
487 }
488 } else {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700489 mFreezeDisplayTime = 0;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700490 mSyncObject.wait();
491 }
492}
493
494void SurfaceFlinger::signalEvent() {
495 mSyncObject.open();
496}
497
498void SurfaceFlinger::signal() const {
499 mSyncObject.open();
500}
501
502void SurfaceFlinger::signalDelayedEvent(nsecs_t delay)
503{
504 if (android_atomic_or(1, &mDeplayedTransactionPending) == 0) {
505 sp<DelayedTransaction> delayedEvent(new DelayedTransaction(this, delay));
506 delayedEvent->run("DelayedeEvent", PRIORITY_URGENT_DISPLAY);
507 }
508}
509
510// ----------------------------------------------------------------------------
511#if 0
512#pragma mark -
513#pragma mark Main loop
514#endif
515
516bool SurfaceFlinger::threadLoop()
517{
518 waitForEvent();
519
520 // check for transactions
521 if (UNLIKELY(mConsoleSignals)) {
522 handleConsoleEvents();
523 }
524
525 if (LIKELY(mTransactionCount == 0)) {
526 // if we're in a global transaction, don't do anything.
527 const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
528 uint32_t transactionFlags = getTransactionFlags(mask);
529 if (LIKELY(transactionFlags)) {
530 handleTransaction(transactionFlags);
531 }
532 }
533
534 // post surfaces (if needed)
535 handlePageFlip();
536
537 const DisplayHardware& hw(graphicPlane(0).displayHardware());
538 if (LIKELY(hw.canDraw())) {
539 // repaint the framebuffer (if needed)
540 handleRepaint();
541
542 // release the clients before we flip ('cause flip might block)
543 unlockClients();
544 executeScheduledBroadcasts();
545
546 // sample the cpu gauge
547 if (UNLIKELY(mDebugCpu)) {
548 handleDebugCpu();
549 }
550
551 postFramebuffer();
552 } else {
553 // pretend we did the post
554 unlockClients();
555 executeScheduledBroadcasts();
556 usleep(16667); // 60 fps period
557 }
558 return true;
559}
560
561void SurfaceFlinger::postFramebuffer()
562{
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800563 const bool skip = mOrientationAnimation->run();
564 if (UNLIKELY(skip)) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700565 return;
566 }
567
568 if (!mInvalidRegion.isEmpty()) {
569 const DisplayHardware& hw(graphicPlane(0).displayHardware());
570
571 if (UNLIKELY(mDebugFps)) {
572 debugShowFPS();
573 }
574
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700575 hw.flip(mInvalidRegion);
576
577 mInvalidRegion.clear();
578
579 if (Layer::deletedTextures.size()) {
580 glDeleteTextures(
581 Layer::deletedTextures.size(),
582 Layer::deletedTextures.array());
583 Layer::deletedTextures.clear();
584 }
585 }
586}
587
588void SurfaceFlinger::handleConsoleEvents()
589{
590 // something to do with the console
591 const DisplayHardware& hw = graphicPlane(0).displayHardware();
592
593 int what = android_atomic_and(0, &mConsoleSignals);
594 if (what & eConsoleAcquired) {
595 hw.acquireScreen();
596 }
597
598 if (mDeferReleaseConsole && hw.canDraw()) {
599 // We got the release signal before the aquire signal
600 mDeferReleaseConsole = false;
601 revokeGPU();
602 hw.releaseScreen();
603 }
604
605 if (what & eConsoleReleased) {
606 if (hw.canDraw()) {
607 revokeGPU();
608 hw.releaseScreen();
609 } else {
610 mDeferReleaseConsole = true;
611 }
612 }
613
614 mDirtyRegion.set(hw.bounds());
615}
616
617void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
618{
619 Mutex::Autolock _l(mStateLock);
620
621 const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
622 const size_t count = currentLayers.size();
623
624 /*
625 * Traversal of the children
626 * (perform the transaction for each of them if needed)
627 */
628
629 const bool layersNeedTransaction = transactionFlags & eTraversalNeeded;
630 if (layersNeedTransaction) {
631 for (size_t i=0 ; i<count ; i++) {
632 LayerBase* const layer = currentLayers[i];
633 uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
634 if (!trFlags) continue;
635
636 const uint32_t flags = layer->doTransaction(0);
637 if (flags & Layer::eVisibleRegion)
638 mVisibleRegionsDirty = true;
639
640 if (flags & Layer::eRestartTransaction) {
641 // restart the transaction, but back-off a little
642 layer->setTransactionFlags(eTransactionNeeded);
643 setTransactionFlags(eTraversalNeeded, ms2ns(8));
644 }
645 }
646 }
647
648 /*
649 * Perform our own transaction if needed
650 */
651
652 if (transactionFlags & eTransactionNeeded) {
653 if (mCurrentState.orientation != mDrawingState.orientation) {
654 // the orientation has changed, recompute all visible regions
655 // and invalidate everything.
656
657 const int dpy = 0;
658 const int orientation = mCurrentState.orientation;
Mathias Agopianc75c43642009-03-25 23:18:56 -0700659 const uint32_t type = mCurrentState.orientationType;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700660 GraphicPlane& plane(graphicPlane(dpy));
661 plane.setOrientation(orientation);
662
663 // update the shared control block
664 const DisplayHardware& hw(plane.displayHardware());
665 volatile display_cblk_t* dcblk = mServerCblk->displays + dpy;
666 dcblk->orientation = orientation;
667 if (orientation & eOrientationSwapMask) {
668 // 90 or 270 degrees orientation
669 dcblk->w = hw.getHeight();
670 dcblk->h = hw.getWidth();
671 } else {
672 dcblk->w = hw.getWidth();
673 dcblk->h = hw.getHeight();
674 }
675
676 mVisibleRegionsDirty = true;
677 mDirtyRegion.set(hw.bounds());
Mathias Agopianc75c43642009-03-25 23:18:56 -0700678 mFreezeDisplayTime = 0;
679 mOrientationAnimation->onOrientationChanged(type);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700680 }
681
682 if (mCurrentState.freezeDisplay != mDrawingState.freezeDisplay) {
683 // freezing or unfreezing the display -> trigger animation if needed
684 mFreezeDisplay = mCurrentState.freezeDisplay;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700685 }
686
687 // some layers might have been removed, so
688 // we need to update the regions they're exposing.
689 size_t c = mRemovedLayers.size();
690 if (c) {
691 mVisibleRegionsDirty = true;
692 }
693
694 const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
695 if (currentLayers.size() > mDrawingState.layersSortedByZ.size()) {
696 // layers have been added
697 mVisibleRegionsDirty = true;
698 }
699
700 // get rid of all resources we don't need anymore
701 // (layers and clients)
702 free_resources_l();
703 }
704
705 commitTransaction();
706}
707
708sp<FreezeLock> SurfaceFlinger::getFreezeLock() const
709{
710 return new FreezeLock(const_cast<SurfaceFlinger *>(this));
711}
712
713void SurfaceFlinger::computeVisibleRegions(
714 LayerVector& currentLayers, Region& dirtyRegion, Region& opaqueRegion)
715{
716 const GraphicPlane& plane(graphicPlane(0));
717 const Transform& planeTransform(plane.transform());
718
719 Region aboveOpaqueLayers;
720 Region aboveCoveredLayers;
721 Region dirty;
722
723 bool secureFrameBuffer = false;
724
725 size_t i = currentLayers.size();
726 while (i--) {
727 LayerBase* const layer = currentLayers[i];
728 layer->validateVisibility(planeTransform);
729
730 // start with the whole surface at its current location
731 const Layer::State& s = layer->drawingState();
732 const Rect bounds(layer->visibleBounds());
733
734 // handle hidden surfaces by setting the visible region to empty
735 Region opaqueRegion;
736 Region visibleRegion;
737 Region coveredRegion;
738 if (UNLIKELY((s.flags & ISurfaceComposer::eLayerHidden) || !s.alpha)) {
739 visibleRegion.clear();
740 } else {
741 const bool translucent = layer->needsBlending();
742 visibleRegion.set(bounds);
743 coveredRegion = visibleRegion;
744
745 // Remove the transparent area from the visible region
746 if (translucent) {
747 visibleRegion.subtractSelf(layer->transparentRegionScreen);
748 }
749
750 // compute the opaque region
751 if (s.alpha==255 && !translucent && layer->getOrientation()>=0) {
752 // the opaque region is the visible region
753 opaqueRegion = visibleRegion;
754 }
755 }
756
757 // subtract the opaque region covered by the layers above us
758 visibleRegion.subtractSelf(aboveOpaqueLayers);
759 coveredRegion.andSelf(aboveCoveredLayers);
760
761 // compute this layer's dirty region
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800762 if (layer->contentDirty) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700763 // we need to invalidate the whole region
764 dirty = visibleRegion;
765 // as well, as the old visible region
766 dirty.orSelf(layer->visibleRegionScreen);
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800767 layer->contentDirty = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700768 } else {
769 // compute the exposed region
770 // dirty = what's visible now - what's wasn't covered before
771 // = what's visible now & what's was covered before
772 dirty = visibleRegion.intersect(layer->coveredRegionScreen);
773 }
774 dirty.subtractSelf(aboveOpaqueLayers);
775
776 // accumulate to the screen dirty region
777 dirtyRegion.orSelf(dirty);
778
779 // updade aboveOpaqueLayers/aboveCoveredLayers for next (lower) layer
780 aboveOpaqueLayers.orSelf(opaqueRegion);
781 aboveCoveredLayers.orSelf(bounds);
782
783 // Store the visible region is screen space
784 layer->setVisibleRegion(visibleRegion);
785 layer->setCoveredRegion(coveredRegion);
786
787 // If a secure layer is partially visible, lockdown the screen!
788 if (layer->isSecure() && !visibleRegion.isEmpty()) {
789 secureFrameBuffer = true;
790 }
791 }
792
793 mSecureFrameBuffer = secureFrameBuffer;
794 opaqueRegion = aboveOpaqueLayers;
795}
796
797
798void SurfaceFlinger::commitTransaction()
799{
800 mDrawingState = mCurrentState;
801 mTransactionCV.signal();
802}
803
804void SurfaceFlinger::handlePageFlip()
805{
806 bool visibleRegions = mVisibleRegionsDirty;
807 LayerVector& currentLayers = const_cast<LayerVector&>(mDrawingState.layersSortedByZ);
808 visibleRegions |= lockPageFlip(currentLayers);
809
810 const DisplayHardware& hw = graphicPlane(0).displayHardware();
811 const Region screenRegion(hw.bounds());
812 if (visibleRegions) {
813 Region opaqueRegion;
814 computeVisibleRegions(currentLayers, mDirtyRegion, opaqueRegion);
815 mWormholeRegion = screenRegion.subtract(opaqueRegion);
816 mVisibleRegionsDirty = false;
817 }
818
819 unlockPageFlip(currentLayers);
820 mDirtyRegion.andSelf(screenRegion);
821}
822
823bool SurfaceFlinger::lockPageFlip(const LayerVector& currentLayers)
824{
825 bool recomputeVisibleRegions = false;
826 size_t count = currentLayers.size();
827 LayerBase* const* layers = currentLayers.array();
828 for (size_t i=0 ; i<count ; i++) {
829 LayerBase* const layer = layers[i];
830 layer->lockPageFlip(recomputeVisibleRegions);
831 }
832 return recomputeVisibleRegions;
833}
834
835void SurfaceFlinger::unlockPageFlip(const LayerVector& currentLayers)
836{
837 const GraphicPlane& plane(graphicPlane(0));
838 const Transform& planeTransform(plane.transform());
839 size_t count = currentLayers.size();
840 LayerBase* const* layers = currentLayers.array();
841 for (size_t i=0 ; i<count ; i++) {
842 LayerBase* const layer = layers[i];
843 layer->unlockPageFlip(planeTransform, mDirtyRegion);
844 }
845}
846
847void SurfaceFlinger::handleRepaint()
848{
849 // set the frame buffer
850 const DisplayHardware& hw(graphicPlane(0).displayHardware());
851 glMatrixMode(GL_MODELVIEW);
852 glLoadIdentity();
853
854 if (UNLIKELY(mDebugRegion)) {
855 debugFlashRegions();
856 }
857
858 // compute the invalid region
859 mInvalidRegion.orSelf(mDirtyRegion);
860
861 uint32_t flags = hw.getFlags();
862 if (flags & DisplayHardware::BUFFER_PRESERVED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800863 // here we assume DisplayHardware::flip()'s implementation
864 // performs the copy-back optimization.
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700865 } else {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700866 if (flags & DisplayHardware::UPDATE_ON_DEMAND) {
867 // we need to fully redraw the part that will be updated
868 mDirtyRegion.set(mInvalidRegion.bounds());
869 } else {
870 // we need to redraw everything
871 mDirtyRegion.set(hw.bounds());
872 mInvalidRegion = mDirtyRegion;
873 }
874 }
875
876 // compose all surfaces
877 composeSurfaces(mDirtyRegion);
878
879 // clear the dirty regions
880 mDirtyRegion.clear();
881}
882
883void SurfaceFlinger::composeSurfaces(const Region& dirty)
884{
885 if (UNLIKELY(!mWormholeRegion.isEmpty())) {
886 // should never happen unless the window manager has a bug
887 // draw something...
888 drawWormhole();
889 }
890 const SurfaceFlinger& flinger(*this);
891 const LayerVector& drawingLayers(mDrawingState.layersSortedByZ);
892 const size_t count = drawingLayers.size();
893 LayerBase const* const* const layers = drawingLayers.array();
894 for (size_t i=0 ; i<count ; ++i) {
895 LayerBase const * const layer = layers[i];
896 const Region& visibleRegion(layer->visibleRegionScreen);
897 if (!visibleRegion.isEmpty()) {
898 const Region clip(dirty.intersect(visibleRegion));
899 if (!clip.isEmpty()) {
900 layer->draw(clip);
901 }
902 }
903 }
904}
905
906void SurfaceFlinger::unlockClients()
907{
908 const LayerVector& drawingLayers(mDrawingState.layersSortedByZ);
909 const size_t count = drawingLayers.size();
910 LayerBase* const* const layers = drawingLayers.array();
911 for (size_t i=0 ; i<count ; ++i) {
912 LayerBase* const layer = layers[i];
913 layer->finishPageFlip();
914 }
915}
916
917void SurfaceFlinger::scheduleBroadcast(Client* client)
918{
919 if (mLastScheduledBroadcast != client) {
920 mLastScheduledBroadcast = client;
921 mScheduledBroadcasts.add(client);
922 }
923}
924
925void SurfaceFlinger::executeScheduledBroadcasts()
926{
927 SortedVector<Client*>& list = mScheduledBroadcasts;
928 size_t count = list.size();
929 while (count--) {
930 per_client_cblk_t* const cblk = list[count]->ctrlblk;
931 if (cblk->lock.tryLock() == NO_ERROR) {
932 cblk->cv.broadcast();
933 list.removeAt(count);
934 cblk->lock.unlock();
935 } else {
936 // schedule another round
937 LOGW("executeScheduledBroadcasts() skipped, "
938 "contention on the client. We'll try again later...");
939 signalDelayedEvent(ms2ns(4));
940 }
941 }
942 mLastScheduledBroadcast = 0;
943}
944
945void SurfaceFlinger::handleDebugCpu()
946{
947 Mutex::Autolock _l(mDebugLock);
948 if (mCpuGauge != 0)
949 mCpuGauge->sample();
950}
951
952void SurfaceFlinger::debugFlashRegions()
953{
954 if (UNLIKELY(!mDirtyRegion.isRect())) {
955 // TODO: do this only if we don't have preserving
956 // swapBuffer. If we don't have update-on-demand,
957 // redraw everything.
958 composeSurfaces(Region(mDirtyRegion.bounds()));
959 }
960
961 glDisable(GL_TEXTURE_2D);
962 glDisable(GL_BLEND);
963 glDisable(GL_DITHER);
964 glDisable(GL_SCISSOR_TEST);
965
966 glColor4x(0x10000, 0, 0x10000, 0x10000);
967
968 Rect r;
969 Region::iterator iterator(mDirtyRegion);
970 while (iterator.iterate(&r)) {
971 GLfloat vertices[][2] = {
972 { r.left, r.top },
973 { r.left, r.bottom },
974 { r.right, r.bottom },
975 { r.right, r.top }
976 };
977 glVertexPointer(2, GL_FLOAT, 0, vertices);
978 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
979 }
980
981 const DisplayHardware& hw(graphicPlane(0).displayHardware());
982 hw.flip(mDirtyRegion.merge(mInvalidRegion));
983 mInvalidRegion.clear();
984
985 if (mDebugRegion > 1)
986 usleep(mDebugRegion * 1000);
987
988 glEnable(GL_SCISSOR_TEST);
989 //mDirtyRegion.dump("mDirtyRegion");
990}
991
992void SurfaceFlinger::drawWormhole() const
993{
994 const Region region(mWormholeRegion.intersect(mDirtyRegion));
995 if (region.isEmpty())
996 return;
997
998 const DisplayHardware& hw(graphicPlane(0).displayHardware());
999 const int32_t width = hw.getWidth();
1000 const int32_t height = hw.getHeight();
1001
1002 glDisable(GL_BLEND);
1003 glDisable(GL_DITHER);
1004
1005 if (LIKELY(!mDebugBackground)) {
1006 glClearColorx(0,0,0,0);
1007 Rect r;
1008 Region::iterator iterator(region);
1009 while (iterator.iterate(&r)) {
1010 const GLint sy = height - (r.top + r.height());
1011 glScissor(r.left, sy, r.width(), r.height());
1012 glClear(GL_COLOR_BUFFER_BIT);
1013 }
1014 } else {
1015 const GLshort vertices[][2] = { { 0, 0 }, { width, 0 },
1016 { width, height }, { 0, height } };
1017 const GLshort tcoords[][2] = { { 0, 0 }, { 1, 0 }, { 1, 1 }, { 0, 1 } };
1018 glVertexPointer(2, GL_SHORT, 0, vertices);
1019 glTexCoordPointer(2, GL_SHORT, 0, tcoords);
1020 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1021 glEnable(GL_TEXTURE_2D);
1022 glBindTexture(GL_TEXTURE_2D, mWormholeTexName);
1023 glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1024 glMatrixMode(GL_TEXTURE);
1025 glLoadIdentity();
1026 glScalef(width*(1.0f/32.0f), height*(1.0f/32.0f), 1);
1027 Rect r;
1028 Region::iterator iterator(region);
1029 while (iterator.iterate(&r)) {
1030 const GLint sy = height - (r.top + r.height());
1031 glScissor(r.left, sy, r.width(), r.height());
1032 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1033 }
1034 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1035 }
1036}
1037
1038void SurfaceFlinger::debugShowFPS() const
1039{
1040 static int mFrameCount;
1041 static int mLastFrameCount = 0;
1042 static nsecs_t mLastFpsTime = 0;
1043 static float mFps = 0;
1044 mFrameCount++;
1045 nsecs_t now = systemTime();
1046 nsecs_t diff = now - mLastFpsTime;
1047 if (diff > ms2ns(250)) {
1048 mFps = ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff;
1049 mLastFpsTime = now;
1050 mLastFrameCount = mFrameCount;
1051 }
1052 // XXX: mFPS has the value we want
1053 }
1054
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001055status_t SurfaceFlinger::addLayer(LayerBase* layer)
1056{
1057 Mutex::Autolock _l(mStateLock);
1058 addLayer_l(layer);
1059 setTransactionFlags(eTransactionNeeded|eTraversalNeeded);
1060 return NO_ERROR;
1061}
1062
1063status_t SurfaceFlinger::removeLayer(LayerBase* layer)
1064{
1065 Mutex::Autolock _l(mStateLock);
1066 removeLayer_l(layer);
1067 setTransactionFlags(eTransactionNeeded);
1068 return NO_ERROR;
1069}
1070
1071status_t SurfaceFlinger::invalidateLayerVisibility(LayerBase* layer)
1072{
1073 layer->forceVisibilityTransaction();
1074 setTransactionFlags(eTraversalNeeded);
1075 return NO_ERROR;
1076}
1077
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001078status_t SurfaceFlinger::addLayer_l(LayerBase* layer)
1079{
1080 ssize_t i = mCurrentState.layersSortedByZ.add(
1081 layer, &LayerBase::compareCurrentStateZ);
1082 LayerBaseClient* lbc = LayerBase::dynamicCast<LayerBaseClient*>(layer);
1083 if (lbc) {
1084 mLayerMap.add(lbc->serverIndex(), lbc);
1085 }
1086 mRemovedLayers.remove(layer);
1087 return NO_ERROR;
1088}
1089
1090status_t SurfaceFlinger::removeLayer_l(LayerBase* layerBase)
1091{
1092 ssize_t index = mCurrentState.layersSortedByZ.remove(layerBase);
1093 if (index >= 0) {
1094 mRemovedLayers.add(layerBase);
1095 LayerBaseClient* layer = LayerBase::dynamicCast<LayerBaseClient*>(layerBase);
1096 if (layer) {
1097 mLayerMap.removeItem(layer->serverIndex());
1098 }
1099 return NO_ERROR;
1100 }
1101 // it's possible that we don't find a layer, because it might
1102 // have been destroyed already -- this is not technically an error
1103 // from the user because there is a race between destroySurface,
1104 // destroyclient and destroySurface-from-a-transaction.
1105 return (index == NAME_NOT_FOUND) ? status_t(NO_ERROR) : index;
1106}
1107
1108void SurfaceFlinger::free_resources_l()
1109{
1110 // Destroy layers that were removed
1111 destroy_all_removed_layers_l();
1112
1113 // free resources associated with disconnected clients
1114 SortedVector<Client*>& scheduledBroadcasts(mScheduledBroadcasts);
1115 Vector<Client*>& disconnectedClients(mDisconnectedClients);
1116 const size_t count = disconnectedClients.size();
1117 for (size_t i=0 ; i<count ; i++) {
1118 Client* client = disconnectedClients[i];
1119 // if this client is the scheduled broadcast list,
1120 // remove it from there (and we don't need to signal it
1121 // since it is dead).
1122 int32_t index = scheduledBroadcasts.indexOf(client);
1123 if (index >= 0) {
1124 scheduledBroadcasts.removeItemsAt(index);
1125 }
1126 mTokens.release(client->cid);
1127 delete client;
1128 }
1129 disconnectedClients.clear();
1130}
1131
1132void SurfaceFlinger::destroy_all_removed_layers_l()
1133{
1134 size_t c = mRemovedLayers.size();
1135 while (c--) {
1136 LayerBase* const removed_layer = mRemovedLayers[c];
1137
1138 LOGE_IF(mCurrentState.layersSortedByZ.indexOf(removed_layer) >= 0,
1139 "layer %p removed but still in the current state list",
1140 removed_layer);
1141
1142 delete removed_layer;
1143 }
1144 mRemovedLayers.clear();
1145}
1146
1147
1148uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags)
1149{
1150 return android_atomic_and(~flags, &mTransactionFlags) & flags;
1151}
1152
1153uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags, nsecs_t delay)
1154{
1155 uint32_t old = android_atomic_or(flags, &mTransactionFlags);
1156 if ((old & flags)==0) { // wake the server up
1157 if (delay > 0) {
1158 signalDelayedEvent(delay);
1159 } else {
1160 signalEvent();
1161 }
1162 }
1163 return old;
1164}
1165
1166void SurfaceFlinger::openGlobalTransaction()
1167{
1168 android_atomic_inc(&mTransactionCount);
1169}
1170
1171void SurfaceFlinger::closeGlobalTransaction()
1172{
1173 if (android_atomic_dec(&mTransactionCount) == 1) {
1174 signalEvent();
1175 }
1176}
1177
1178status_t SurfaceFlinger::freezeDisplay(DisplayID dpy, uint32_t flags)
1179{
1180 if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
1181 return BAD_VALUE;
1182
1183 Mutex::Autolock _l(mStateLock);
1184 mCurrentState.freezeDisplay = 1;
1185 setTransactionFlags(eTransactionNeeded);
1186
1187 // flags is intended to communicate some sort of animation behavior
1188 // (for instance fadding)
1189 return NO_ERROR;
1190}
1191
1192status_t SurfaceFlinger::unfreezeDisplay(DisplayID dpy, uint32_t flags)
1193{
1194 if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
1195 return BAD_VALUE;
1196
1197 Mutex::Autolock _l(mStateLock);
1198 mCurrentState.freezeDisplay = 0;
1199 setTransactionFlags(eTransactionNeeded);
1200
1201 // flags is intended to communicate some sort of animation behavior
1202 // (for instance fadding)
1203 return NO_ERROR;
1204}
1205
Mathias Agopianc75c43642009-03-25 23:18:56 -07001206int SurfaceFlinger::setOrientation(DisplayID dpy,
1207 int orientation, uint32_t flags)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001208{
1209 if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
1210 return BAD_VALUE;
1211
1212 Mutex::Autolock _l(mStateLock);
1213 if (mCurrentState.orientation != orientation) {
1214 if (uint32_t(orientation)<=eOrientation270 || orientation==42) {
Mathias Agopianc75c43642009-03-25 23:18:56 -07001215 mCurrentState.orientationType = flags;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001216 mCurrentState.orientation = orientation;
1217 setTransactionFlags(eTransactionNeeded);
1218 mTransactionCV.wait(mStateLock);
1219 } else {
1220 orientation = BAD_VALUE;
1221 }
1222 }
1223 return orientation;
1224}
1225
1226sp<ISurface> SurfaceFlinger::createSurface(ClientID clientId, int pid,
1227 ISurfaceFlingerClient::surface_data_t* params,
1228 DisplayID d, uint32_t w, uint32_t h, PixelFormat format,
1229 uint32_t flags)
1230{
1231 LayerBaseClient* layer = 0;
1232 sp<LayerBaseClient::Surface> surfaceHandle;
1233 Mutex::Autolock _l(mStateLock);
1234 Client* const c = mClientsMap.valueFor(clientId);
1235 if (UNLIKELY(!c)) {
1236 LOGE("createSurface() failed, client not found (id=%d)", clientId);
1237 return surfaceHandle;
1238 }
1239
1240 //LOGD("createSurface for pid %d (%d x %d)", pid, w, h);
1241 int32_t id = c->generateId(pid);
1242 if (uint32_t(id) >= NUM_LAYERS_MAX) {
1243 LOGE("createSurface() failed, generateId = %d", id);
1244 return surfaceHandle;
1245 }
1246
1247 switch (flags & eFXSurfaceMask) {
1248 case eFXSurfaceNormal:
1249 if (UNLIKELY(flags & ePushBuffers)) {
1250 layer = createPushBuffersSurfaceLocked(c, d, id, w, h, flags);
1251 } else {
1252 layer = createNormalSurfaceLocked(c, d, id, w, h, format, flags);
1253 }
1254 break;
1255 case eFXSurfaceBlur:
1256 layer = createBlurSurfaceLocked(c, d, id, w, h, flags);
1257 break;
1258 case eFXSurfaceDim:
1259 layer = createDimSurfaceLocked(c, d, id, w, h, flags);
1260 break;
1261 }
1262
1263 if (layer) {
1264 setTransactionFlags(eTransactionNeeded);
1265 surfaceHandle = layer->getSurface();
1266 if (surfaceHandle != 0)
1267 surfaceHandle->getSurfaceData(params);
1268 }
1269
1270 return surfaceHandle;
1271}
1272
1273LayerBaseClient* SurfaceFlinger::createNormalSurfaceLocked(
1274 Client* client, DisplayID display,
1275 int32_t id, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags)
1276{
1277 // initialize the surfaces
1278 switch (format) { // TODO: take h/w into account
1279 case PIXEL_FORMAT_TRANSPARENT:
1280 case PIXEL_FORMAT_TRANSLUCENT:
1281 format = PIXEL_FORMAT_RGBA_8888;
1282 break;
1283 case PIXEL_FORMAT_OPAQUE:
1284 format = PIXEL_FORMAT_RGB_565;
1285 break;
1286 }
1287
1288 Layer* layer = new Layer(this, display, client, id);
1289 status_t err = layer->setBuffers(client, w, h, format, flags);
1290 if (LIKELY(err == NO_ERROR)) {
1291 layer->initStates(w, h, flags);
1292 addLayer_l(layer);
1293 } else {
1294 LOGE("createNormalSurfaceLocked() failed (%s)", strerror(-err));
1295 delete layer;
1296 return 0;
1297 }
1298 return layer;
1299}
1300
1301LayerBaseClient* SurfaceFlinger::createBlurSurfaceLocked(
1302 Client* client, DisplayID display,
1303 int32_t id, uint32_t w, uint32_t h, uint32_t flags)
1304{
1305 LayerBlur* layer = new LayerBlur(this, display, client, id);
1306 layer->initStates(w, h, flags);
1307 addLayer_l(layer);
1308 return layer;
1309}
1310
1311LayerBaseClient* SurfaceFlinger::createDimSurfaceLocked(
1312 Client* client, DisplayID display,
1313 int32_t id, uint32_t w, uint32_t h, uint32_t flags)
1314{
1315 LayerDim* layer = new LayerDim(this, display, client, id);
1316 layer->initStates(w, h, flags);
1317 addLayer_l(layer);
1318 return layer;
1319}
1320
1321LayerBaseClient* SurfaceFlinger::createPushBuffersSurfaceLocked(
1322 Client* client, DisplayID display,
1323 int32_t id, uint32_t w, uint32_t h, uint32_t flags)
1324{
1325 LayerBuffer* layer = new LayerBuffer(this, display, client, id);
1326 layer->initStates(w, h, flags);
1327 addLayer_l(layer);
1328 return layer;
1329}
1330
1331status_t SurfaceFlinger::destroySurface(SurfaceID index)
1332{
1333 Mutex::Autolock _l(mStateLock);
1334 LayerBaseClient* const layer = getLayerUser_l(index);
1335 status_t err = removeLayer_l(layer);
1336 if (err < 0)
1337 return err;
1338 setTransactionFlags(eTransactionNeeded);
1339 return NO_ERROR;
1340}
1341
1342status_t SurfaceFlinger::setClientState(
1343 ClientID cid,
1344 int32_t count,
1345 const layer_state_t* states)
1346{
1347 Mutex::Autolock _l(mStateLock);
1348 uint32_t flags = 0;
1349 cid <<= 16;
1350 for (int i=0 ; i<count ; i++) {
1351 const layer_state_t& s = states[i];
1352 LayerBaseClient* layer = getLayerUser_l(s.surface | cid);
1353 if (layer) {
1354 const uint32_t what = s.what;
1355 // check if it has been destroyed first
1356 if (what & eDestroyed) {
1357 if (removeLayer_l(layer) == NO_ERROR) {
1358 flags |= eTransactionNeeded;
1359 // we skip everything else... well, no, not really
1360 // we skip ONLY that transaction.
1361 continue;
1362 }
1363 }
1364 if (what & ePositionChanged) {
1365 if (layer->setPosition(s.x, s.y))
1366 flags |= eTraversalNeeded;
1367 }
1368 if (what & eLayerChanged) {
1369 if (layer->setLayer(s.z)) {
1370 mCurrentState.layersSortedByZ.reorder(
1371 layer, &Layer::compareCurrentStateZ);
1372 // we need traversal (state changed)
1373 // AND transaction (list changed)
1374 flags |= eTransactionNeeded|eTraversalNeeded;
1375 }
1376 }
1377 if (what & eSizeChanged) {
1378 if (layer->setSize(s.w, s.h))
1379 flags |= eTraversalNeeded;
1380 }
1381 if (what & eAlphaChanged) {
1382 if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f)))
1383 flags |= eTraversalNeeded;
1384 }
1385 if (what & eMatrixChanged) {
1386 if (layer->setMatrix(s.matrix))
1387 flags |= eTraversalNeeded;
1388 }
1389 if (what & eTransparentRegionChanged) {
1390 if (layer->setTransparentRegionHint(s.transparentRegion))
1391 flags |= eTraversalNeeded;
1392 }
1393 if (what & eVisibilityChanged) {
1394 if (layer->setFlags(s.flags, s.mask))
1395 flags |= eTraversalNeeded;
1396 }
1397 }
1398 }
1399 if (flags) {
1400 setTransactionFlags(flags);
1401 }
1402 return NO_ERROR;
1403}
1404
1405LayerBaseClient* SurfaceFlinger::getLayerUser_l(SurfaceID s) const
1406{
1407 return mLayerMap.valueFor(s);
1408}
1409
1410void SurfaceFlinger::screenReleased(int dpy)
1411{
1412 // this may be called by a signal handler, we can't do too much in here
1413 android_atomic_or(eConsoleReleased, &mConsoleSignals);
1414 signalEvent();
1415}
1416
1417void SurfaceFlinger::screenAcquired(int dpy)
1418{
1419 // this may be called by a signal handler, we can't do too much in here
1420 android_atomic_or(eConsoleAcquired, &mConsoleSignals);
1421 signalEvent();
1422}
1423
1424status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
1425{
1426 const size_t SIZE = 1024;
1427 char buffer[SIZE];
1428 String8 result;
1429 if (checkCallingPermission(
1430 String16("android.permission.DUMP")) == false)
1431 { // not allowed
1432 snprintf(buffer, SIZE, "Permission Denial: "
1433 "can't dump SurfaceFlinger from pid=%d, uid=%d\n",
1434 IPCThreadState::self()->getCallingPid(),
1435 IPCThreadState::self()->getCallingUid());
1436 result.append(buffer);
1437 } else {
1438 Mutex::Autolock _l(mStateLock);
1439 size_t s = mClientsMap.size();
1440 char name[64];
1441 for (size_t i=0 ; i<s ; i++) {
1442 Client* client = mClientsMap.valueAt(i);
1443 sprintf(name, " Client (id=0x%08x)", client->cid);
1444 client->dump(name);
1445 }
1446 const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
1447 const size_t count = currentLayers.size();
1448 for (size_t i=0 ; i<count ; i++) {
1449 /*** LayerBase ***/
1450 LayerBase const * const layer = currentLayers[i];
1451 const Layer::State& s = layer->drawingState();
1452 snprintf(buffer, SIZE,
1453 "+ %s %p\n"
1454 " "
1455 "z=%9d, pos=(%4d,%4d), size=(%4d,%4d), "
1456 "needsBlending=%1d, invalidate=%1d, "
1457 "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n",
1458 layer->getTypeID(), layer,
1459 s.z, layer->tx(), layer->ty(), s.w, s.h,
The Android Open Source Projectb7986892009-01-09 17:51:23 -08001460 layer->needsBlending(), layer->contentDirty,
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001461 s.alpha, s.flags,
1462 s.transform[0], s.transform[1],
1463 s.transform[2], s.transform[3]);
1464 result.append(buffer);
1465 buffer[0] = 0;
1466 /*** LayerBaseClient ***/
1467 LayerBaseClient* const lbc =
1468 LayerBase::dynamicCast<LayerBaseClient*>((LayerBase*)layer);
1469 if (lbc) {
1470 snprintf(buffer, SIZE,
1471 " "
1472 "id=0x%08x, client=0x%08x, identity=%u\n",
1473 lbc->clientIndex(), lbc->client ? lbc->client->cid : 0,
1474 lbc->getIdentity());
1475 }
1476 result.append(buffer);
1477 buffer[0] = 0;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001478 /*** Layer ***/
1479 Layer* const l = LayerBase::dynamicCast<Layer*>((LayerBase*)layer);
1480 if (l) {
1481 const LayerBitmap& buf0(l->getBuffer(0));
1482 const LayerBitmap& buf1(l->getBuffer(1));
1483 snprintf(buffer, SIZE,
1484 " "
1485 "format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u], mTextureName=%d,"
1486 " freezeLock=%p, swapState=0x%08x\n",
1487 l->pixelFormat(),
1488 buf0.width(), buf0.height(), buf0.stride(),
1489 buf1.width(), buf1.height(), buf1.stride(),
1490 l->getTextureName(), l->getFreezeLock().get(),
1491 l->lcblk->swapState);
1492 }
1493 result.append(buffer);
1494 buffer[0] = 0;
1495 s.transparentRegion.dump(result, "transparentRegion");
1496 layer->transparentRegionScreen.dump(result, "transparentRegionScreen");
1497 layer->visibleRegionScreen.dump(result, "visibleRegionScreen");
1498 }
1499 mWormholeRegion.dump(result, "WormholeRegion");
1500 const DisplayHardware& hw(graphicPlane(0).displayHardware());
1501 snprintf(buffer, SIZE,
1502 " display frozen: %s, freezeCount=%d, orientation=%d, canDraw=%d\n",
1503 mFreezeDisplay?"yes":"no", mFreezeCount,
1504 mCurrentState.orientation, hw.canDraw());
1505 result.append(buffer);
1506
1507 sp<AllocatorInterface> allocator;
1508 if (mGPU != 0) {
1509 snprintf(buffer, SIZE, " GPU owner: %d\n", mGPU->getOwner());
1510 result.append(buffer);
1511 allocator = mGPU->getAllocator();
1512 if (allocator != 0) {
1513 allocator->dump(result, "GPU Allocator");
1514 }
1515 }
1516 allocator = mSurfaceHeapManager->getAllocator(NATIVE_MEMORY_TYPE_PMEM);
1517 if (allocator != 0) {
1518 allocator->dump(result, "PMEM Allocator");
1519 }
1520 }
1521 write(fd, result.string(), result.size());
1522 return NO_ERROR;
1523}
1524
1525status_t SurfaceFlinger::onTransact(
1526 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
1527{
1528 switch (code) {
1529 case CREATE_CONNECTION:
1530 case OPEN_GLOBAL_TRANSACTION:
1531 case CLOSE_GLOBAL_TRANSACTION:
1532 case SET_ORIENTATION:
1533 case FREEZE_DISPLAY:
1534 case UNFREEZE_DISPLAY:
1535 case BOOT_FINISHED:
1536 case REVOKE_GPU:
1537 {
1538 // codes that require permission check
1539 IPCThreadState* ipc = IPCThreadState::self();
1540 const int pid = ipc->getCallingPid();
1541 const int self_pid = getpid();
1542 if (UNLIKELY(pid != self_pid)) {
1543 // we're called from a different process, do the real check
1544 if (!checkCallingPermission(
1545 String16("android.permission.ACCESS_SURFACE_FLINGER")))
1546 {
1547 const int uid = ipc->getCallingUid();
1548 LOGE("Permission Denial: "
1549 "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
1550 return PERMISSION_DENIED;
1551 }
1552 }
1553 }
1554 }
1555
1556 status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags);
1557 if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001558 // HARDWARE_TEST stuff...
1559 if (UNLIKELY(checkCallingPermission(
1560 String16("android.permission.HARDWARE_TEST")) == false))
1561 { // not allowed
1562 LOGE("Permission Denial: pid=%d, uid=%d\n",
1563 IPCThreadState::self()->getCallingPid(),
1564 IPCThreadState::self()->getCallingUid());
1565 return PERMISSION_DENIED;
1566 }
1567 int n;
1568 switch (code) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001569 case 1000: // SHOW_CPU
1570 n = data.readInt32();
1571 mDebugCpu = n ? 1 : 0;
1572 if (mDebugCpu) {
1573 if (mCpuGauge == 0) {
1574 mCpuGauge = new CPUGauge(this, ms2ns(500));
1575 }
1576 } else {
1577 if (mCpuGauge != 0) {
1578 mCpuGauge->requestExitAndWait();
1579 Mutex::Autolock _l(mDebugLock);
1580 mCpuGauge.clear();
1581 }
1582 }
1583 return NO_ERROR;
1584 case 1001: // SHOW_FPS
1585 n = data.readInt32();
1586 mDebugFps = n ? 1 : 0;
1587 return NO_ERROR;
1588 case 1002: // SHOW_UPDATES
1589 n = data.readInt32();
1590 mDebugRegion = n ? n : (mDebugRegion ? 0 : 1);
1591 return NO_ERROR;
1592 case 1003: // SHOW_BACKGROUND
1593 n = data.readInt32();
1594 mDebugBackground = n ? 1 : 0;
1595 return NO_ERROR;
1596 case 1004:{ // repaint everything
1597 Mutex::Autolock _l(mStateLock);
1598 const DisplayHardware& hw(graphicPlane(0).displayHardware());
1599 mDirtyRegion.set(hw.bounds()); // careful that's not thread-safe
1600 signalEvent();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001601 }
1602 return NO_ERROR;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001603 case 1005: // ask GPU revoke
1604 mGPU->friendlyRevoke();
1605 return NO_ERROR;
1606 case 1006: // revoke GPU
1607 mGPU->unconditionalRevoke();
1608 return NO_ERROR;
1609 case 1007: // set mFreezeCount
1610 mFreezeCount = data.readInt32();
1611 return NO_ERROR;
1612 case 1010: // interrogate.
1613 reply->writeInt32(mDebugCpu);
1614 reply->writeInt32(0);
1615 reply->writeInt32(mDebugRegion);
1616 reply->writeInt32(mDebugBackground);
1617 return NO_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001618 case 1013: {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001619 Mutex::Autolock _l(mStateLock);
1620 const DisplayHardware& hw(graphicPlane(0).displayHardware());
1621 reply->writeInt32(hw.getPageFlipCount());
1622 }
1623 return NO_ERROR;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001624 }
1625 }
1626 return err;
1627}
1628
1629// ---------------------------------------------------------------------------
1630#if 0
1631#pragma mark -
1632#endif
1633
1634Client::Client(ClientID clientID, const sp<SurfaceFlinger>& flinger)
1635 : ctrlblk(0), cid(clientID), mPid(0), mBitmap(0), mFlinger(flinger)
1636{
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -08001637 mSharedHeapAllocator = getSurfaceHeapManager()->createHeap();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001638 const int pgsize = getpagesize();
1639 const int cblksize=((sizeof(per_client_cblk_t)+(pgsize-1))&~(pgsize-1));
1640 mCblkHeap = new MemoryDealer(cblksize);
1641 mCblkMemory = mCblkHeap->allocate(cblksize);
1642 if (mCblkMemory != 0) {
1643 ctrlblk = static_cast<per_client_cblk_t *>(mCblkMemory->pointer());
1644 if (ctrlblk) { // construct the shared structure in-place.
1645 new(ctrlblk) per_client_cblk_t;
1646 }
1647 }
1648}
1649
1650Client::~Client() {
1651 if (ctrlblk) {
1652 const int pgsize = getpagesize();
1653 ctrlblk->~per_client_cblk_t(); // destroy our shared-structure.
1654 }
1655}
1656
1657const sp<SurfaceHeapManager>& Client::getSurfaceHeapManager() const {
1658 return mFlinger->getSurfaceHeapManager();
1659}
1660
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001661int32_t Client::generateId(int pid)
1662{
1663 const uint32_t i = clz( ~mBitmap );
1664 if (i >= NUM_LAYERS_MAX) {
1665 return NO_MEMORY;
1666 }
1667 mPid = pid;
1668 mInUse.add(uint8_t(i));
1669 mBitmap |= 1<<(31-i);
1670 return i;
1671}
1672status_t Client::bindLayer(LayerBaseClient* layer, int32_t id)
1673{
1674 ssize_t idx = mInUse.indexOf(id);
1675 if (idx < 0)
1676 return NAME_NOT_FOUND;
1677 return mLayers.insertAt(layer, idx);
1678}
1679void Client::free(int32_t id)
1680{
1681 ssize_t idx = mInUse.remove(uint8_t(id));
1682 if (idx >= 0) {
1683 mBitmap &= ~(1<<(31-id));
1684 mLayers.removeItemsAt(idx);
1685 }
1686}
1687
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -08001688sp<MemoryDealer> Client::createAllocator(uint32_t flags)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001689{
1690 sp<MemoryDealer> allocator;
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -08001691 allocator = getSurfaceHeapManager()->createHeap(
1692 flags, getClientPid(), mSharedHeapAllocator);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001693 return allocator;
1694}
1695
1696bool Client::isValid(int32_t i) const {
1697 return (uint32_t(i)<NUM_LAYERS_MAX) && (mBitmap & (1<<(31-i)));
1698}
1699const uint8_t* Client::inUseArray() const {
1700 return mInUse.array();
1701}
1702size_t Client::numActiveLayers() const {
1703 return mInUse.size();
1704}
1705LayerBaseClient* Client::getLayerUser(int32_t i) const {
1706 ssize_t idx = mInUse.indexOf(uint8_t(i));
1707 if (idx<0) return 0;
1708 return mLayers[idx];
1709}
1710
1711void Client::dump(const char* what)
1712{
1713}
1714
1715// ---------------------------------------------------------------------------
1716#if 0
1717#pragma mark -
1718#endif
1719
1720BClient::BClient(SurfaceFlinger *flinger, ClientID cid, const sp<IMemory>& cblk)
1721 : mId(cid), mFlinger(flinger), mCblk(cblk)
1722{
1723}
1724
1725BClient::~BClient() {
1726 // destroy all resources attached to this client
1727 mFlinger->destroyConnection(mId);
1728}
1729
1730void BClient::getControlBlocks(sp<IMemory>* ctrl) const {
1731 *ctrl = mCblk;
1732}
1733
1734sp<ISurface> BClient::createSurface(
1735 ISurfaceFlingerClient::surface_data_t* params, int pid,
1736 DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
1737 uint32_t flags)
1738{
1739 return mFlinger->createSurface(mId, pid, params, display, w, h, format, flags);
1740}
1741
1742status_t BClient::destroySurface(SurfaceID sid)
1743{
1744 sid |= (mId << 16); // add the client-part to id
1745 return mFlinger->destroySurface(sid);
1746}
1747
1748status_t BClient::setState(int32_t count, const layer_state_t* states)
1749{
1750 return mFlinger->setClientState(mId, count, states);
1751}
1752
1753// ---------------------------------------------------------------------------
1754
1755GraphicPlane::GraphicPlane()
1756 : mHw(0)
1757{
1758}
1759
1760GraphicPlane::~GraphicPlane() {
1761 delete mHw;
1762}
1763
1764bool GraphicPlane::initialized() const {
1765 return mHw ? true : false;
1766}
1767
1768void GraphicPlane::setDisplayHardware(DisplayHardware *hw) {
1769 mHw = hw;
1770}
1771
1772void GraphicPlane::setTransform(const Transform& tr) {
1773 mTransform = tr;
1774 mGlobalTransform = mOrientationTransform * mTransform;
1775}
1776
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001777status_t GraphicPlane::orientationToTransfrom(
1778 int orientation, int w, int h, Transform* tr)
1779{
1780 float a, b, c, d, x, y;
1781 switch (orientation) {
1782 case ISurfaceComposer::eOrientationDefault:
1783 a=1; b=0; c=0; d=1; x=0; y=0;
1784 break;
1785 case ISurfaceComposer::eOrientation90:
1786 a=0; b=-1; c=1; d=0; x=w; y=0;
1787 break;
1788 case ISurfaceComposer::eOrientation180:
1789 a=-1; b=0; c=0; d=-1; x=w; y=h;
1790 break;
1791 case ISurfaceComposer::eOrientation270:
1792 a=0; b=1; c=-1; d=0; x=0; y=h;
1793 break;
1794 default:
1795 return BAD_VALUE;
1796 }
1797 tr->set(a, b, c, d);
1798 tr->set(x, y);
1799 return NO_ERROR;
1800}
1801
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001802status_t GraphicPlane::setOrientation(int orientation)
1803{
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001804 const DisplayHardware& hw(displayHardware());
1805 const float w = hw.getWidth();
1806 const float h = hw.getHeight();
1807
1808 if (orientation == ISurfaceComposer::eOrientationDefault) {
1809 // make sure the default orientation is optimal
1810 mOrientationTransform.reset();
Mathias Agopiand2f34e52009-03-25 21:42:35 -07001811 mOrientation = orientation;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001812 mGlobalTransform = mTransform;
1813 return NO_ERROR;
1814 }
1815
1816 // If the rotation can be handled in hardware, this is where
1817 // the magic should happen.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001818 if (UNLIKELY(orientation == 42)) {
1819 float a, b, c, d, x, y;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001820 const float r = (3.14159265f / 180.0f) * 42.0f;
1821 const float si = sinf(r);
1822 const float co = cosf(r);
1823 a=co; b=-si; c=si; d=co;
1824 x = si*(h*0.5f) + (1-co)*(w*0.5f);
1825 y =-si*(w*0.5f) + (1-co)*(h*0.5f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001826 mOrientationTransform.set(a, b, c, d);
1827 mOrientationTransform.set(x, y);
1828 } else {
1829 GraphicPlane::orientationToTransfrom(orientation, w, h,
1830 &mOrientationTransform);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001831 }
Mathias Agopiand2f34e52009-03-25 21:42:35 -07001832 mOrientation = orientation;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001833 mGlobalTransform = mOrientationTransform * mTransform;
1834 return NO_ERROR;
1835}
1836
1837const DisplayHardware& GraphicPlane::displayHardware() const {
1838 return *mHw;
1839}
1840
1841const Transform& GraphicPlane::transform() const {
1842 return mGlobalTransform;
1843}
1844
1845// ---------------------------------------------------------------------------
1846
1847}; // namespace android