2009-03-04 03:31:44 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2007 The Android Open Source Project
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <math.h>
|
2009-01-26 19:51:12 +00:00
|
|
|
#include <limits.h>
|
2009-03-04 03:31:44 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
|
|
|
|
#include <cutils/log.h>
|
|
|
|
#include <cutils/properties.h>
|
|
|
|
|
2009-05-20 02:08:10 +00:00
|
|
|
#include <binder/IPCThreadState.h>
|
|
|
|
#include <binder/IServiceManager.h>
|
2009-07-03 01:11:53 +00:00
|
|
|
#include <binder/MemoryHeapBase.h>
|
|
|
|
|
2009-03-04 03:31:44 +00:00
|
|
|
#include <utils/String8.h>
|
|
|
|
#include <utils/String16.h>
|
|
|
|
#include <utils/StopWatch.h>
|
|
|
|
|
2009-10-06 00:07:12 +00:00
|
|
|
#include <ui/GraphicBufferAllocator.h>
|
2010-09-14 05:57:58 +00:00
|
|
|
#include <ui/GraphicLog.h>
|
2009-03-04 03:31:44 +00:00
|
|
|
#include <ui/PixelFormat.h>
|
|
|
|
|
|
|
|
#include <pixelflinger/pixelflinger.h>
|
|
|
|
#include <GLES/gl.h>
|
|
|
|
|
|
|
|
#include "clz.h"
|
2010-06-26 01:02:21 +00:00
|
|
|
#include "GLExtensions.h"
|
2009-03-04 03:31:44 +00:00
|
|
|
#include "Layer.h"
|
|
|
|
#include "LayerDim.h"
|
|
|
|
#include "SurfaceFlinger.h"
|
|
|
|
|
|
|
|
#include "DisplayHardware/DisplayHardware.h"
|
2010-08-11 00:14:02 +00:00
|
|
|
#include "DisplayHardware/HWComposer.h"
|
2009-03-04 03:31:44 +00:00
|
|
|
|
2009-05-22 02:21:59 +00:00
|
|
|
/* ideally AID_GRAPHICS would be in a semi-public header
|
|
|
|
* or there would be a way to map a user/group name to its id
|
|
|
|
*/
|
|
|
|
#ifndef AID_GRAPHICS
|
|
|
|
#define AID_GRAPHICS 1003
|
|
|
|
#endif
|
|
|
|
|
2009-03-04 03:31:44 +00:00
|
|
|
#define DISPLAY_COUNT 1
|
|
|
|
|
|
|
|
namespace android {
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
SurfaceFlinger::SurfaceFlinger()
|
|
|
|
: BnSurfaceComposer(), Thread(false),
|
|
|
|
mTransactionFlags(0),
|
|
|
|
mTransactionCount(0),
|
fix [2068105] implement queueBuffer/lockBuffer/dequeueBuffer properly
Rewrote SurfaceFlinger's buffer management from the ground-up.
The design now support an arbitrary number of buffers per surface, however the current implementation is limited to four. Currently only 2 buffers are used in practice.
The main new feature is to be able to dequeue all buffers at once (very important when there are only two).
A client can dequeue all buffers until there are none available, it can lock all buffers except the last one that is used for composition. The client will block then, until a new buffer is enqueued.
The current implementation requires that buffers are locked in the same order they are dequeued and enqueued in the same order they are locked. Only one buffer can be locked at a time.
eg. Allowed sequence: DQ, DQ, LOCK, Q, LOCK, Q
eg. Forbidden sequence: DQ, DQ, LOCK, LOCK, Q, Q
2009-09-07 23:32:45 +00:00
|
|
|
mResizeTransationPending(false),
|
2009-04-10 21:24:30 +00:00
|
|
|
mLayersRemoved(false),
|
2009-03-04 03:31:44 +00:00
|
|
|
mBootTime(systemTime()),
|
2009-06-16 01:24:59 +00:00
|
|
|
mHardwareTest("android.permission.HARDWARE_TEST"),
|
|
|
|
mAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"),
|
2010-09-24 18:26:58 +00:00
|
|
|
mReadFramebuffer("android.permission.READ_FRAME_BUFFER"),
|
2009-06-16 01:24:59 +00:00
|
|
|
mDump("android.permission.DUMP"),
|
2009-03-04 03:31:44 +00:00
|
|
|
mVisibleRegionsDirty(false),
|
2010-08-11 00:14:02 +00:00
|
|
|
mHwWorkListDirty(false),
|
2009-03-04 03:31:44 +00:00
|
|
|
mDeferReleaseConsole(false),
|
|
|
|
mFreezeDisplay(false),
|
2010-10-14 21:54:06 +00:00
|
|
|
mElectronBeamAnimationMode(0),
|
2009-03-04 03:31:44 +00:00
|
|
|
mFreezeCount(0),
|
2009-03-11 19:11:56 +00:00
|
|
|
mFreezeDisplayTime(0),
|
2009-03-04 03:31:44 +00:00
|
|
|
mDebugRegion(0),
|
|
|
|
mDebugBackground(0),
|
2010-09-23 01:58:01 +00:00
|
|
|
mDebugDisableHWC(0),
|
2009-08-26 23:36:26 +00:00
|
|
|
mDebugInSwapBuffers(0),
|
|
|
|
mLastSwapBufferTime(0),
|
|
|
|
mDebugInTransaction(0),
|
|
|
|
mLastTransactionTime(0),
|
2009-10-06 00:07:12 +00:00
|
|
|
mBootFinished(false),
|
2009-03-04 03:31:44 +00:00
|
|
|
mConsoleSignals(0),
|
|
|
|
mSecureFrameBuffer(0)
|
|
|
|
{
|
|
|
|
init();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SurfaceFlinger::init()
|
|
|
|
{
|
|
|
|
LOGI("SurfaceFlinger is starting");
|
|
|
|
|
|
|
|
// debugging stuff...
|
|
|
|
char value[PROPERTY_VALUE_MAX];
|
|
|
|
property_get("debug.sf.showupdates", value, "0");
|
|
|
|
mDebugRegion = atoi(value);
|
|
|
|
property_get("debug.sf.showbackground", value, "0");
|
|
|
|
mDebugBackground = atoi(value);
|
|
|
|
|
2010-04-20 21:51:04 +00:00
|
|
|
LOGI_IF(mDebugRegion, "showupdates enabled");
|
|
|
|
LOGI_IF(mDebugBackground, "showbackground enabled");
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SurfaceFlinger::~SurfaceFlinger()
|
|
|
|
{
|
|
|
|
glDeleteTextures(1, &mWormholeTexName);
|
|
|
|
}
|
|
|
|
|
2009-07-03 01:11:53 +00:00
|
|
|
sp<IMemoryHeap> SurfaceFlinger::getCblk() const
|
2009-03-04 03:31:44 +00:00
|
|
|
{
|
2009-07-03 01:11:53 +00:00
|
|
|
return mServerHeap;
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
2010-05-28 21:22:23 +00:00
|
|
|
sp<ISurfaceComposerClient> SurfaceFlinger::createConnection()
|
2009-03-04 03:31:44 +00:00
|
|
|
{
|
2010-06-03 06:28:45 +00:00
|
|
|
sp<ISurfaceComposerClient> bclient;
|
|
|
|
sp<Client> client(new Client(this));
|
|
|
|
status_t err = client->initCheck();
|
|
|
|
if (err == NO_ERROR) {
|
|
|
|
bclient = client;
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
return bclient;
|
|
|
|
}
|
|
|
|
|
2010-06-01 22:12:58 +00:00
|
|
|
sp<ISurfaceComposerClient> SurfaceFlinger::createClientConnection()
|
|
|
|
{
|
|
|
|
sp<ISurfaceComposerClient> bclient;
|
|
|
|
sp<UserClient> client(new UserClient(this));
|
|
|
|
status_t err = client->initCheck();
|
|
|
|
if (err == NO_ERROR) {
|
|
|
|
bclient = client;
|
|
|
|
}
|
|
|
|
return bclient;
|
|
|
|
}
|
|
|
|
|
2011-01-13 02:30:40 +00:00
|
|
|
sp<IGraphicBufferAlloc> SurfaceFlinger::createGraphicBufferAlloc()
|
|
|
|
{
|
|
|
|
sp<GraphicBufferAlloc> gba(new GraphicBufferAlloc());
|
|
|
|
return gba;
|
|
|
|
}
|
2010-06-01 22:12:58 +00:00
|
|
|
|
2009-03-04 03:31:44 +00:00
|
|
|
const GraphicPlane& SurfaceFlinger::graphicPlane(int dpy) const
|
|
|
|
{
|
|
|
|
LOGE_IF(uint32_t(dpy) >= DISPLAY_COUNT, "Invalid DisplayID %d", dpy);
|
|
|
|
const GraphicPlane& plane(mGraphicPlanes[dpy]);
|
|
|
|
return plane;
|
|
|
|
}
|
|
|
|
|
|
|
|
GraphicPlane& SurfaceFlinger::graphicPlane(int dpy)
|
|
|
|
{
|
|
|
|
return const_cast<GraphicPlane&>(
|
|
|
|
const_cast<SurfaceFlinger const *>(this)->graphicPlane(dpy));
|
|
|
|
}
|
|
|
|
|
|
|
|
void SurfaceFlinger::bootFinished()
|
|
|
|
{
|
|
|
|
const nsecs_t now = systemTime();
|
|
|
|
const nsecs_t duration = now - mBootTime;
|
2010-08-16 15:49:37 +00:00
|
|
|
LOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
|
2009-10-06 00:07:12 +00:00
|
|
|
mBootFinished = true;
|
2009-05-22 02:21:59 +00:00
|
|
|
property_set("ctl.stop", "bootanim");
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SurfaceFlinger::onFirstRef()
|
|
|
|
{
|
|
|
|
run("SurfaceFlinger", PRIORITY_URGENT_DISPLAY);
|
|
|
|
|
|
|
|
// Wait for the main thread to be done with its initialization
|
|
|
|
mReadyToRunBarrier.wait();
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline uint16_t pack565(int r, int g, int b) {
|
|
|
|
return (r<<11)|(g<<5)|b;
|
|
|
|
}
|
|
|
|
|
|
|
|
status_t SurfaceFlinger::readyToRun()
|
|
|
|
{
|
|
|
|
LOGI( "SurfaceFlinger's main thread ready to run. "
|
|
|
|
"Initializing graphics H/W...");
|
|
|
|
|
|
|
|
// we only support one display currently
|
|
|
|
int dpy = 0;
|
|
|
|
|
|
|
|
{
|
|
|
|
// initialize the main display
|
|
|
|
GraphicPlane& plane(graphicPlane(dpy));
|
|
|
|
DisplayHardware* const hw = new DisplayHardware(this, dpy);
|
|
|
|
plane.setDisplayHardware(hw);
|
|
|
|
}
|
|
|
|
|
2009-07-03 01:11:53 +00:00
|
|
|
// create the shared control-block
|
|
|
|
mServerHeap = new MemoryHeapBase(4096,
|
|
|
|
MemoryHeapBase::READ_ONLY, "SurfaceFlinger read-only heap");
|
|
|
|
LOGE_IF(mServerHeap==0, "can't create shared memory dealer");
|
2010-08-16 15:49:37 +00:00
|
|
|
|
2009-07-03 01:11:53 +00:00
|
|
|
mServerCblk = static_cast<surface_flinger_cblk_t*>(mServerHeap->getBase());
|
|
|
|
LOGE_IF(mServerCblk==0, "can't get to shared control block's address");
|
2010-08-16 15:49:37 +00:00
|
|
|
|
2009-07-03 01:11:53 +00:00
|
|
|
new(mServerCblk) surface_flinger_cblk_t;
|
|
|
|
|
2009-03-04 03:31:44 +00:00
|
|
|
// initialize primary screen
|
|
|
|
// (other display should be initialized in the same manner, but
|
|
|
|
// asynchronously, as they could come and go. None of this is supported
|
|
|
|
// yet).
|
|
|
|
const GraphicPlane& plane(graphicPlane(dpy));
|
|
|
|
const DisplayHardware& hw = plane.displayHardware();
|
|
|
|
const uint32_t w = hw.getWidth();
|
|
|
|
const uint32_t h = hw.getHeight();
|
|
|
|
const uint32_t f = hw.getFormat();
|
|
|
|
hw.makeCurrent();
|
|
|
|
|
|
|
|
// initialize the shared control block
|
|
|
|
mServerCblk->connected |= 1<<dpy;
|
|
|
|
display_cblk_t* dcblk = mServerCblk->displays + dpy;
|
|
|
|
memset(dcblk, 0, sizeof(display_cblk_t));
|
2010-02-08 23:49:35 +00:00
|
|
|
dcblk->w = plane.getWidth();
|
|
|
|
dcblk->h = plane.getHeight();
|
2009-03-04 03:31:44 +00:00
|
|
|
dcblk->format = f;
|
|
|
|
dcblk->orientation = ISurfaceComposer::eOrientationDefault;
|
|
|
|
dcblk->xdpi = hw.getDpiX();
|
|
|
|
dcblk->ydpi = hw.getDpiY();
|
|
|
|
dcblk->fps = hw.getRefreshRate();
|
|
|
|
dcblk->density = hw.getDensity();
|
|
|
|
|
|
|
|
// Initialize OpenGL|ES
|
|
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
2010-08-16 15:49:37 +00:00
|
|
|
glPixelStorei(GL_PACK_ALIGNMENT, 4);
|
2009-03-04 03:31:44 +00:00
|
|
|
glEnableClientState(GL_VERTEX_ARRAY);
|
|
|
|
glEnable(GL_SCISSOR_TEST);
|
|
|
|
glShadeModel(GL_FLAT);
|
|
|
|
glDisable(GL_DITHER);
|
|
|
|
glDisable(GL_CULL_FACE);
|
|
|
|
|
|
|
|
const uint16_t g0 = pack565(0x0F,0x1F,0x0F);
|
|
|
|
const uint16_t g1 = pack565(0x17,0x2f,0x17);
|
|
|
|
const uint16_t textureData[4] = { g0, g1, g1, g0 };
|
|
|
|
glGenTextures(1, &mWormholeTexName);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, mWormholeTexName);
|
|
|
|
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
|
|
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
|
|
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
|
|
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0,
|
|
|
|
GL_RGB, GL_UNSIGNED_SHORT_5_6_5, textureData);
|
|
|
|
|
|
|
|
glViewport(0, 0, w, h);
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glLoadIdentity();
|
|
|
|
glOrthof(0, w, h, 0, 0, 1);
|
|
|
|
|
|
|
|
mReadyToRunBarrier.open();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We're now ready to accept clients...
|
|
|
|
*/
|
|
|
|
|
2009-05-22 02:21:59 +00:00
|
|
|
// start boot animation
|
|
|
|
property_set("ctl.start", "bootanim");
|
2010-08-16 15:49:37 +00:00
|
|
|
|
2009-03-04 03:31:44 +00:00
|
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
#if 0
|
|
|
|
#pragma mark -
|
|
|
|
#pragma mark Events Handler
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void SurfaceFlinger::waitForEvent()
|
|
|
|
{
|
2009-04-21 02:39:12 +00:00
|
|
|
while (true) {
|
|
|
|
nsecs_t timeout = -1;
|
2009-12-02 01:23:28 +00:00
|
|
|
const nsecs_t freezeDisplayTimeout = ms2ns(5000);
|
2009-04-21 02:39:12 +00:00
|
|
|
if (UNLIKELY(isFrozen())) {
|
|
|
|
// wait 5 seconds
|
|
|
|
const nsecs_t now = systemTime();
|
|
|
|
if (mFreezeDisplayTime == 0) {
|
|
|
|
mFreezeDisplayTime = now;
|
|
|
|
}
|
|
|
|
nsecs_t waitTime = freezeDisplayTimeout - (now - mFreezeDisplayTime);
|
|
|
|
timeout = waitTime>0 ? waitTime : 0;
|
2009-03-11 19:11:56 +00:00
|
|
|
}
|
2009-04-21 02:39:12 +00:00
|
|
|
|
2010-05-19 00:06:55 +00:00
|
|
|
sp<MessageBase> msg = mEventQueue.waitMessage(timeout);
|
2009-12-02 01:23:28 +00:00
|
|
|
|
|
|
|
// see if we timed out
|
|
|
|
if (isFrozen()) {
|
|
|
|
const nsecs_t now = systemTime();
|
|
|
|
nsecs_t frozenTime = (now - mFreezeDisplayTime);
|
|
|
|
if (frozenTime >= freezeDisplayTimeout) {
|
2009-03-04 03:31:44 +00:00
|
|
|
// we timed out and are still frozen
|
|
|
|
LOGW("timeout expired mFreezeDisplay=%d, mFreezeCount=%d",
|
|
|
|
mFreezeDisplay, mFreezeCount);
|
2009-12-02 01:23:28 +00:00
|
|
|
mFreezeDisplayTime = 0;
|
2009-03-04 03:31:44 +00:00
|
|
|
mFreezeCount = 0;
|
2009-03-11 19:11:56 +00:00
|
|
|
mFreezeDisplay = false;
|
2009-12-02 01:23:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (msg != 0) {
|
|
|
|
switch (msg->what) {
|
|
|
|
case MessageQueue::INVALIDATE:
|
|
|
|
// invalidate message, just return to the main loop
|
|
|
|
return;
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SurfaceFlinger::signalEvent() {
|
2009-04-21 02:39:12 +00:00
|
|
|
mEventQueue.invalidate();
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SurfaceFlinger::signal() const {
|
2009-04-21 02:39:12 +00:00
|
|
|
// this is the IPC call
|
|
|
|
const_cast<SurfaceFlinger*>(this)->signalEvent();
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
2011-03-08 20:18:54 +00:00
|
|
|
bool SurfaceFlinger::authenticateSurface(const sp<ISurface>& surface) const {
|
|
|
|
Mutex::Autolock _l(mStateLock);
|
|
|
|
sp<IBinder> surfBinder(surface->asBinder());
|
|
|
|
|
|
|
|
// Check the visible layer list for the ISurface
|
|
|
|
const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
|
|
|
|
size_t count = currentLayers.size();
|
|
|
|
for (size_t i=0 ; i<count ; i++) {
|
|
|
|
const sp<LayerBase>& layer(currentLayers[i]);
|
|
|
|
sp<LayerBaseClient> lbc(layer->getLayerBaseClient());
|
|
|
|
if (lbc != NULL && lbc->getSurfaceBinder() == surfBinder) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check the layers in the purgatory. This check is here so that if a
|
|
|
|
// Surface gets destroyed before all the clients are done using it, the
|
|
|
|
// error will not be reported as "surface XYZ is not authenticated", but
|
|
|
|
// will instead fail later on when the client tries to use the surface,
|
|
|
|
// which should be reported as "surface XYZ returned an -ENODEV". The
|
|
|
|
// purgatorized layers are no less authentic than the visible ones, so this
|
|
|
|
// should not cause any harm.
|
|
|
|
size_t purgatorySize = mLayerPurgatory.size();
|
|
|
|
for (size_t i=0 ; i<purgatorySize ; i++) {
|
|
|
|
const sp<LayerBase>& layer(mLayerPurgatory.itemAt(i));
|
|
|
|
sp<LayerBaseClient> lbc(layer->getLayerBaseClient());
|
|
|
|
if (lbc != NULL && lbc->getSurfaceBinder() == surfBinder) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-05-19 00:06:55 +00:00
|
|
|
status_t SurfaceFlinger::postMessageAsync(const sp<MessageBase>& msg,
|
|
|
|
nsecs_t reltime, uint32_t flags)
|
2009-03-04 03:31:44 +00:00
|
|
|
{
|
2010-05-19 00:06:55 +00:00
|
|
|
return mEventQueue.postMessage(msg, reltime, flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
status_t SurfaceFlinger::postMessageSync(const sp<MessageBase>& msg,
|
|
|
|
nsecs_t reltime, uint32_t flags)
|
|
|
|
{
|
|
|
|
status_t res = mEventQueue.postMessage(msg, reltime, flags);
|
|
|
|
if (res == NO_ERROR) {
|
|
|
|
msg->wait();
|
|
|
|
}
|
|
|
|
return res;
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
#if 0
|
|
|
|
#pragma mark -
|
|
|
|
#pragma mark Main loop
|
|
|
|
#endif
|
|
|
|
|
|
|
|
bool SurfaceFlinger::threadLoop()
|
|
|
|
{
|
|
|
|
waitForEvent();
|
|
|
|
|
|
|
|
// check for transactions
|
|
|
|
if (UNLIKELY(mConsoleSignals)) {
|
|
|
|
handleConsoleEvents();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (LIKELY(mTransactionCount == 0)) {
|
|
|
|
// if we're in a global transaction, don't do anything.
|
|
|
|
const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
|
2011-06-17 00:15:51 +00:00
|
|
|
uint32_t transactionFlags = getTransactionFlags(mask);
|
2009-03-04 03:31:44 +00:00
|
|
|
if (LIKELY(transactionFlags)) {
|
|
|
|
handleTransaction(transactionFlags);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// post surfaces (if needed)
|
|
|
|
handlePageFlip();
|
|
|
|
|
2010-08-11 00:14:02 +00:00
|
|
|
if (UNLIKELY(mHwWorkListDirty)) {
|
|
|
|
// build the h/w work list
|
|
|
|
handleWorkList();
|
|
|
|
}
|
|
|
|
|
2009-03-04 03:31:44 +00:00
|
|
|
const DisplayHardware& hw(graphicPlane(0).displayHardware());
|
2009-09-28 05:47:27 +00:00
|
|
|
if (LIKELY(hw.canDraw() && !isFrozen())) {
|
2009-03-04 03:31:44 +00:00
|
|
|
// repaint the framebuffer (if needed)
|
2010-09-14 05:57:58 +00:00
|
|
|
|
|
|
|
const int index = hw.getCurrentBufferIndex();
|
|
|
|
GraphicLog& logger(GraphicLog::getInstance());
|
|
|
|
|
|
|
|
logger.log(GraphicLog::SF_REPAINT, index);
|
2009-03-04 03:31:44 +00:00
|
|
|
handleRepaint();
|
|
|
|
|
2009-09-17 23:18:16 +00:00
|
|
|
// inform the h/w that we're done compositing
|
2010-09-14 05:57:58 +00:00
|
|
|
logger.log(GraphicLog::SF_COMPOSITION_COMPLETE, index);
|
2009-09-17 23:18:16 +00:00
|
|
|
hw.compositionComplete();
|
|
|
|
|
2010-09-14 05:57:58 +00:00
|
|
|
logger.log(GraphicLog::SF_SWAP_BUFFERS, index);
|
2010-09-08 13:37:14 +00:00
|
|
|
postFramebuffer();
|
|
|
|
|
2010-09-14 05:57:58 +00:00
|
|
|
logger.log(GraphicLog::SF_REPAINT_DONE, index);
|
2009-03-04 03:31:44 +00:00
|
|
|
} else {
|
|
|
|
// pretend we did the post
|
2010-12-15 22:41:59 +00:00
|
|
|
hw.compositionComplete();
|
2009-03-04 03:31:44 +00:00
|
|
|
usleep(16667); // 60 fps period
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SurfaceFlinger::postFramebuffer()
|
|
|
|
{
|
|
|
|
if (!mInvalidRegion.isEmpty()) {
|
|
|
|
const DisplayHardware& hw(graphicPlane(0).displayHardware());
|
2009-08-26 23:36:26 +00:00
|
|
|
const nsecs_t now = systemTime();
|
|
|
|
mDebugInSwapBuffers = now;
|
2009-03-04 03:31:44 +00:00
|
|
|
hw.flip(mInvalidRegion);
|
2009-08-26 23:36:26 +00:00
|
|
|
mLastSwapBufferTime = systemTime() - now;
|
|
|
|
mDebugInSwapBuffers = 0;
|
2009-03-04 03:31:44 +00:00
|
|
|
mInvalidRegion.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SurfaceFlinger::handleConsoleEvents()
|
|
|
|
{
|
|
|
|
// something to do with the console
|
|
|
|
const DisplayHardware& hw = graphicPlane(0).displayHardware();
|
|
|
|
|
|
|
|
int what = android_atomic_and(0, &mConsoleSignals);
|
|
|
|
if (what & eConsoleAcquired) {
|
|
|
|
hw.acquireScreen();
|
2010-10-12 23:05:48 +00:00
|
|
|
// this is a temporary work-around, eventually this should be called
|
|
|
|
// by the power-manager
|
2010-10-14 21:54:06 +00:00
|
|
|
SurfaceFlinger::turnElectronBeamOn(mElectronBeamAnimationMode);
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
2010-10-11 19:37:43 +00:00
|
|
|
if (mDeferReleaseConsole && hw.isScreenAcquired()) {
|
2009-04-15 06:02:51 +00:00
|
|
|
// We got the release signal before the acquire signal
|
2009-03-04 03:31:44 +00:00
|
|
|
mDeferReleaseConsole = false;
|
|
|
|
hw.releaseScreen();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (what & eConsoleReleased) {
|
2010-10-11 19:37:43 +00:00
|
|
|
if (hw.isScreenAcquired()) {
|
2009-03-04 03:31:44 +00:00
|
|
|
hw.releaseScreen();
|
|
|
|
} else {
|
|
|
|
mDeferReleaseConsole = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mDirtyRegion.set(hw.bounds());
|
|
|
|
}
|
|
|
|
|
|
|
|
void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
|
|
|
|
{
|
2011-06-17 00:15:51 +00:00
|
|
|
Vector< sp<LayerBase> > ditchedLayers;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Perform and commit the transaction
|
|
|
|
*/
|
2010-08-11 00:19:56 +00:00
|
|
|
|
2011-06-17 00:15:51 +00:00
|
|
|
{ // scope for the lock
|
|
|
|
Mutex::Autolock _l(mStateLock);
|
|
|
|
const nsecs_t now = systemTime();
|
|
|
|
mDebugInTransaction = now;
|
|
|
|
handleTransactionLocked(transactionFlags, ditchedLayers);
|
|
|
|
mLastTransactionTime = systemTime() - now;
|
|
|
|
mDebugInTransaction = 0;
|
|
|
|
invalidateHwcGeometry();
|
|
|
|
// here the transaction has been committed
|
|
|
|
}
|
2009-06-05 01:46:21 +00:00
|
|
|
|
2011-06-17 00:15:51 +00:00
|
|
|
/*
|
|
|
|
* Clean-up all layers that went away
|
|
|
|
* (do this without the lock held)
|
|
|
|
*/
|
2010-08-11 00:14:02 +00:00
|
|
|
|
2011-06-17 00:15:51 +00:00
|
|
|
const size_t count = ditchedLayers.size();
|
|
|
|
for (size_t i=0 ; i<count ; i++) {
|
|
|
|
if (ditchedLayers[i] != 0) {
|
|
|
|
//LOGD("ditching layer %p", ditchedLayers[i].get());
|
|
|
|
ditchedLayers[i]->ditch();
|
|
|
|
}
|
|
|
|
}
|
2009-06-05 01:46:21 +00:00
|
|
|
}
|
2009-03-04 03:31:44 +00:00
|
|
|
|
2011-06-17 00:15:51 +00:00
|
|
|
void SurfaceFlinger::handleTransactionLocked(
|
|
|
|
uint32_t transactionFlags, Vector< sp<LayerBase> >& ditchedLayers)
|
2009-06-05 01:46:21 +00:00
|
|
|
{
|
|
|
|
const LayerVector& currentLayers(mCurrentState.layersSortedByZ);
|
2009-03-04 03:31:44 +00:00
|
|
|
const size_t count = currentLayers.size();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Traversal of the children
|
|
|
|
* (perform the transaction for each of them if needed)
|
|
|
|
*/
|
|
|
|
|
|
|
|
const bool layersNeedTransaction = transactionFlags & eTraversalNeeded;
|
|
|
|
if (layersNeedTransaction) {
|
|
|
|
for (size_t i=0 ; i<count ; i++) {
|
2009-04-10 21:24:30 +00:00
|
|
|
const sp<LayerBase>& layer = currentLayers[i];
|
2009-03-04 03:31:44 +00:00
|
|
|
uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
|
|
|
|
if (!trFlags) continue;
|
|
|
|
|
|
|
|
const uint32_t flags = layer->doTransaction(0);
|
|
|
|
if (flags & Layer::eVisibleRegion)
|
|
|
|
mVisibleRegionsDirty = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Perform our own transaction if needed
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (transactionFlags & eTransactionNeeded) {
|
|
|
|
if (mCurrentState.orientation != mDrawingState.orientation) {
|
|
|
|
// the orientation has changed, recompute all visible regions
|
|
|
|
// and invalidate everything.
|
|
|
|
|
|
|
|
const int dpy = 0;
|
|
|
|
const int orientation = mCurrentState.orientation;
|
2009-03-28 01:11:38 +00:00
|
|
|
const uint32_t type = mCurrentState.orientationType;
|
2009-03-04 03:31:44 +00:00
|
|
|
GraphicPlane& plane(graphicPlane(dpy));
|
|
|
|
plane.setOrientation(orientation);
|
|
|
|
|
|
|
|
// update the shared control block
|
|
|
|
const DisplayHardware& hw(plane.displayHardware());
|
|
|
|
volatile display_cblk_t* dcblk = mServerCblk->displays + dpy;
|
|
|
|
dcblk->orientation = orientation;
|
2010-02-08 23:49:35 +00:00
|
|
|
dcblk->w = plane.getWidth();
|
|
|
|
dcblk->h = plane.getHeight();
|
2009-03-04 03:31:44 +00:00
|
|
|
|
|
|
|
mVisibleRegionsDirty = true;
|
|
|
|
mDirtyRegion.set(hw.bounds());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mCurrentState.freezeDisplay != mDrawingState.freezeDisplay) {
|
|
|
|
// freezing or unfreezing the display -> trigger animation if needed
|
|
|
|
mFreezeDisplay = mCurrentState.freezeDisplay;
|
2010-03-02 01:51:17 +00:00
|
|
|
if (mFreezeDisplay)
|
|
|
|
mFreezeDisplayTime = 0;
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
2009-04-22 22:23:34 +00:00
|
|
|
if (currentLayers.size() > mDrawingState.layersSortedByZ.size()) {
|
|
|
|
// layers have been added
|
2009-03-04 03:31:44 +00:00
|
|
|
mVisibleRegionsDirty = true;
|
|
|
|
}
|
|
|
|
|
2009-04-22 22:23:34 +00:00
|
|
|
// some layers might have been removed, so
|
|
|
|
// we need to update the regions they're exposing.
|
|
|
|
if (mLayersRemoved) {
|
2009-09-11 02:41:18 +00:00
|
|
|
mLayersRemoved = false;
|
2009-03-04 03:31:44 +00:00
|
|
|
mVisibleRegionsDirty = true;
|
2009-04-22 22:23:34 +00:00
|
|
|
const LayerVector& previousLayers(mDrawingState.layersSortedByZ);
|
2009-06-05 01:46:21 +00:00
|
|
|
const size_t count = previousLayers.size();
|
|
|
|
for (size_t i=0 ; i<count ; i++) {
|
2009-04-22 22:23:34 +00:00
|
|
|
const sp<LayerBase>& layer(previousLayers[i]);
|
|
|
|
if (currentLayers.indexOf( layer ) < 0) {
|
|
|
|
// this layer is not visible anymore
|
2011-06-17 00:15:51 +00:00
|
|
|
ditchedLayers.add(layer);
|
2009-07-28 21:20:21 +00:00
|
|
|
mDirtyRegionRemovedLayer.orSelf(layer->visibleRegionScreen);
|
2009-04-22 22:23:34 +00:00
|
|
|
}
|
|
|
|
}
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
commitTransaction();
|
|
|
|
}
|
|
|
|
|
|
|
|
sp<FreezeLock> SurfaceFlinger::getFreezeLock() const
|
|
|
|
{
|
|
|
|
return new FreezeLock(const_cast<SurfaceFlinger *>(this));
|
|
|
|
}
|
|
|
|
|
|
|
|
void SurfaceFlinger::computeVisibleRegions(
|
|
|
|
LayerVector& currentLayers, Region& dirtyRegion, Region& opaqueRegion)
|
|
|
|
{
|
|
|
|
const GraphicPlane& plane(graphicPlane(0));
|
|
|
|
const Transform& planeTransform(plane.transform());
|
2010-03-16 23:41:46 +00:00
|
|
|
const DisplayHardware& hw(plane.displayHardware());
|
|
|
|
const Region screenRegion(hw.bounds());
|
2009-03-04 03:31:44 +00:00
|
|
|
|
|
|
|
Region aboveOpaqueLayers;
|
|
|
|
Region aboveCoveredLayers;
|
|
|
|
Region dirty;
|
|
|
|
|
|
|
|
bool secureFrameBuffer = false;
|
|
|
|
|
|
|
|
size_t i = currentLayers.size();
|
|
|
|
while (i--) {
|
2009-04-10 21:24:30 +00:00
|
|
|
const sp<LayerBase>& layer = currentLayers[i];
|
2009-03-04 03:31:44 +00:00
|
|
|
layer->validateVisibility(planeTransform);
|
|
|
|
|
|
|
|
// start with the whole surface at its current location
|
2009-07-28 17:57:27 +00:00
|
|
|
const Layer::State& s(layer->drawingState());
|
2009-03-04 03:31:44 +00:00
|
|
|
|
2010-03-16 23:41:46 +00:00
|
|
|
/*
|
|
|
|
* opaqueRegion: area of a surface that is fully opaque.
|
|
|
|
*/
|
2009-03-04 03:31:44 +00:00
|
|
|
Region opaqueRegion;
|
2010-03-16 23:41:46 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* visibleRegion: area of a surface that is visible on screen
|
|
|
|
* and not fully transparent. This is essentially the layer's
|
|
|
|
* footprint minus the opaque regions above it.
|
|
|
|
* Areas covered by a translucent surface are considered visible.
|
|
|
|
*/
|
2009-03-04 03:31:44 +00:00
|
|
|
Region visibleRegion;
|
2010-03-16 23:41:46 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* coveredRegion: area of a surface that is covered by all
|
|
|
|
* visible regions above it (which includes the translucent areas).
|
|
|
|
*/
|
2009-03-04 03:31:44 +00:00
|
|
|
Region coveredRegion;
|
2010-03-16 23:41:46 +00:00
|
|
|
|
|
|
|
|
|
|
|
// handle hidden surfaces by setting the visible region to empty
|
2009-07-28 17:57:27 +00:00
|
|
|
if (LIKELY(!(s.flags & ISurfaceComposer::eLayerHidden) && s.alpha)) {
|
2009-03-04 03:31:44 +00:00
|
|
|
const bool translucent = layer->needsBlending();
|
2009-07-28 17:57:27 +00:00
|
|
|
const Rect bounds(layer->visibleBounds());
|
2009-03-04 03:31:44 +00:00
|
|
|
visibleRegion.set(bounds);
|
2010-03-16 23:41:46 +00:00
|
|
|
visibleRegion.andSelf(screenRegion);
|
|
|
|
if (!visibleRegion.isEmpty()) {
|
|
|
|
// Remove the transparent area from the visible region
|
|
|
|
if (translucent) {
|
|
|
|
visibleRegion.subtractSelf(layer->transparentRegionScreen);
|
|
|
|
}
|
2009-03-04 03:31:44 +00:00
|
|
|
|
2010-03-16 23:41:46 +00:00
|
|
|
// compute the opaque region
|
|
|
|
const int32_t layerOrientation = layer->getOrientation();
|
|
|
|
if (s.alpha==255 && !translucent &&
|
|
|
|
((layerOrientation & Transform::ROT_INVALID) == false)) {
|
|
|
|
// the opaque region is the layer's footprint
|
|
|
|
opaqueRegion = visibleRegion;
|
|
|
|
}
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-16 23:41:46 +00:00
|
|
|
// Clip the covered region to the visible region
|
|
|
|
coveredRegion = aboveCoveredLayers.intersect(visibleRegion);
|
|
|
|
|
|
|
|
// Update aboveCoveredLayers for next (lower) layer
|
|
|
|
aboveCoveredLayers.orSelf(visibleRegion);
|
|
|
|
|
2009-03-04 03:31:44 +00:00
|
|
|
// subtract the opaque region covered by the layers above us
|
|
|
|
visibleRegion.subtractSelf(aboveOpaqueLayers);
|
|
|
|
|
|
|
|
// compute this layer's dirty region
|
|
|
|
if (layer->contentDirty) {
|
|
|
|
// we need to invalidate the whole region
|
|
|
|
dirty = visibleRegion;
|
|
|
|
// as well, as the old visible region
|
|
|
|
dirty.orSelf(layer->visibleRegionScreen);
|
|
|
|
layer->contentDirty = false;
|
|
|
|
} else {
|
2009-06-28 09:54:16 +00:00
|
|
|
/* compute the exposed region:
|
2010-03-16 23:41:46 +00:00
|
|
|
* the exposed region consists of two components:
|
|
|
|
* 1) what's VISIBLE now and was COVERED before
|
|
|
|
* 2) what's EXPOSED now less what was EXPOSED before
|
|
|
|
*
|
|
|
|
* note that (1) is conservative, we start with the whole
|
|
|
|
* visible region but only keep what used to be covered by
|
|
|
|
* something -- which mean it may have been exposed.
|
|
|
|
*
|
|
|
|
* (2) handles areas that were not covered by anything but got
|
|
|
|
* exposed because of a resize.
|
2009-06-28 09:54:16 +00:00
|
|
|
*/
|
2010-03-16 23:41:46 +00:00
|
|
|
const Region newExposed = visibleRegion - coveredRegion;
|
|
|
|
const Region oldVisibleRegion = layer->visibleRegionScreen;
|
|
|
|
const Region oldCoveredRegion = layer->coveredRegionScreen;
|
|
|
|
const Region oldExposed = oldVisibleRegion - oldCoveredRegion;
|
|
|
|
dirty = (visibleRegion&oldCoveredRegion) | (newExposed-oldExposed);
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
dirty.subtractSelf(aboveOpaqueLayers);
|
|
|
|
|
|
|
|
// accumulate to the screen dirty region
|
|
|
|
dirtyRegion.orSelf(dirty);
|
|
|
|
|
2010-03-16 23:41:46 +00:00
|
|
|
// Update aboveOpaqueLayers for next (lower) layer
|
2009-03-04 03:31:44 +00:00
|
|
|
aboveOpaqueLayers.orSelf(opaqueRegion);
|
2010-08-16 15:49:37 +00:00
|
|
|
|
2009-03-04 03:31:44 +00:00
|
|
|
// Store the visible region is screen space
|
|
|
|
layer->setVisibleRegion(visibleRegion);
|
|
|
|
layer->setCoveredRegion(coveredRegion);
|
|
|
|
|
2009-07-28 17:57:27 +00:00
|
|
|
// If a secure layer is partially visible, lock-down the screen!
|
2009-03-04 03:31:44 +00:00
|
|
|
if (layer->isSecure() && !visibleRegion.isEmpty()) {
|
|
|
|
secureFrameBuffer = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-28 17:57:27 +00:00
|
|
|
// invalidate the areas where a layer was removed
|
|
|
|
dirtyRegion.orSelf(mDirtyRegionRemovedLayer);
|
|
|
|
mDirtyRegionRemovedLayer.clear();
|
|
|
|
|
2009-03-04 03:31:44 +00:00
|
|
|
mSecureFrameBuffer = secureFrameBuffer;
|
|
|
|
opaqueRegion = aboveOpaqueLayers;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SurfaceFlinger::commitTransaction()
|
|
|
|
{
|
|
|
|
mDrawingState = mCurrentState;
|
fix [2068105] implement queueBuffer/lockBuffer/dequeueBuffer properly
Rewrote SurfaceFlinger's buffer management from the ground-up.
The design now support an arbitrary number of buffers per surface, however the current implementation is limited to four. Currently only 2 buffers are used in practice.
The main new feature is to be able to dequeue all buffers at once (very important when there are only two).
A client can dequeue all buffers until there are none available, it can lock all buffers except the last one that is used for composition. The client will block then, until a new buffer is enqueued.
The current implementation requires that buffers are locked in the same order they are dequeued and enqueued in the same order they are locked. Only one buffer can be locked at a time.
eg. Allowed sequence: DQ, DQ, LOCK, Q, LOCK, Q
eg. Forbidden sequence: DQ, DQ, LOCK, LOCK, Q, Q
2009-09-07 23:32:45 +00:00
|
|
|
mResizeTransationPending = false;
|
|
|
|
mTransactionCV.broadcast();
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SurfaceFlinger::handlePageFlip()
|
|
|
|
{
|
|
|
|
bool visibleRegions = mVisibleRegionsDirty;
|
2010-08-11 00:14:02 +00:00
|
|
|
LayerVector& currentLayers(
|
|
|
|
const_cast<LayerVector&>(mDrawingState.layersSortedByZ));
|
2009-03-04 03:31:44 +00:00
|
|
|
visibleRegions |= lockPageFlip(currentLayers);
|
|
|
|
|
|
|
|
const DisplayHardware& hw = graphicPlane(0).displayHardware();
|
|
|
|
const Region screenRegion(hw.bounds());
|
|
|
|
if (visibleRegions) {
|
|
|
|
Region opaqueRegion;
|
|
|
|
computeVisibleRegions(currentLayers, mDirtyRegion, opaqueRegion);
|
2010-08-11 00:19:56 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* rebuild the visible layer list
|
|
|
|
*/
|
|
|
|
mVisibleLayersSortedByZ.clear();
|
|
|
|
const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
|
|
|
|
size_t count = currentLayers.size();
|
|
|
|
mVisibleLayersSortedByZ.setCapacity(count);
|
|
|
|
for (size_t i=0 ; i<count ; i++) {
|
|
|
|
if (!currentLayers[i]->visibleRegionScreen.isEmpty())
|
|
|
|
mVisibleLayersSortedByZ.add(currentLayers[i]);
|
|
|
|
}
|
|
|
|
|
2009-03-04 03:31:44 +00:00
|
|
|
mWormholeRegion = screenRegion.subtract(opaqueRegion);
|
|
|
|
mVisibleRegionsDirty = false;
|
2011-01-14 01:53:01 +00:00
|
|
|
invalidateHwcGeometry();
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
unlockPageFlip(currentLayers);
|
|
|
|
mDirtyRegion.andSelf(screenRegion);
|
|
|
|
}
|
|
|
|
|
2011-01-14 01:53:01 +00:00
|
|
|
void SurfaceFlinger::invalidateHwcGeometry()
|
|
|
|
{
|
|
|
|
mHwWorkListDirty = true;
|
|
|
|
}
|
|
|
|
|
2009-03-04 03:31:44 +00:00
|
|
|
bool SurfaceFlinger::lockPageFlip(const LayerVector& currentLayers)
|
|
|
|
{
|
|
|
|
bool recomputeVisibleRegions = false;
|
|
|
|
size_t count = currentLayers.size();
|
2009-04-10 21:24:30 +00:00
|
|
|
sp<LayerBase> const* layers = currentLayers.array();
|
2009-03-04 03:31:44 +00:00
|
|
|
for (size_t i=0 ; i<count ; i++) {
|
2010-06-01 22:12:58 +00:00
|
|
|
const sp<LayerBase>& layer(layers[i]);
|
2009-03-04 03:31:44 +00:00
|
|
|
layer->lockPageFlip(recomputeVisibleRegions);
|
|
|
|
}
|
|
|
|
return recomputeVisibleRegions;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SurfaceFlinger::unlockPageFlip(const LayerVector& currentLayers)
|
|
|
|
{
|
|
|
|
const GraphicPlane& plane(graphicPlane(0));
|
|
|
|
const Transform& planeTransform(plane.transform());
|
|
|
|
size_t count = currentLayers.size();
|
2009-04-10 21:24:30 +00:00
|
|
|
sp<LayerBase> const* layers = currentLayers.array();
|
2009-03-04 03:31:44 +00:00
|
|
|
for (size_t i=0 ; i<count ; i++) {
|
2010-06-01 22:12:58 +00:00
|
|
|
const sp<LayerBase>& layer(layers[i]);
|
2009-03-04 03:31:44 +00:00
|
|
|
layer->unlockPageFlip(planeTransform, mDirtyRegion);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-11 00:14:02 +00:00
|
|
|
void SurfaceFlinger::handleWorkList()
|
|
|
|
{
|
|
|
|
mHwWorkListDirty = false;
|
|
|
|
HWComposer& hwc(graphicPlane(0).displayHardware().getHwComposer());
|
|
|
|
if (hwc.initCheck() == NO_ERROR) {
|
|
|
|
const Vector< sp<LayerBase> >& currentLayers(mVisibleLayersSortedByZ);
|
|
|
|
const size_t count = currentLayers.size();
|
|
|
|
hwc.createWorkList(count);
|
2010-08-12 22:03:26 +00:00
|
|
|
hwc_layer_t* const cur(hwc.getLayers());
|
|
|
|
for (size_t i=0 ; cur && i<count ; i++) {
|
|
|
|
currentLayers[i]->setGeometry(&cur[i]);
|
2010-09-23 01:58:01 +00:00
|
|
|
if (mDebugDisableHWC) {
|
|
|
|
cur[i].compositionType = HWC_FRAMEBUFFER;
|
|
|
|
cur[i].flags |= HWC_SKIP_LAYER;
|
|
|
|
}
|
2010-08-11 00:14:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-06-27 02:06:36 +00:00
|
|
|
|
2009-03-04 03:31:44 +00:00
|
|
|
void SurfaceFlinger::handleRepaint()
|
|
|
|
{
|
2009-06-27 02:06:36 +00:00
|
|
|
// compute the invalid region
|
|
|
|
mInvalidRegion.orSelf(mDirtyRegion);
|
2009-03-04 03:31:44 +00:00
|
|
|
|
|
|
|
if (UNLIKELY(mDebugRegion)) {
|
|
|
|
debugFlashRegions();
|
|
|
|
}
|
|
|
|
|
2009-06-27 02:06:36 +00:00
|
|
|
// set the frame buffer
|
|
|
|
const DisplayHardware& hw(graphicPlane(0).displayHardware());
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
2009-03-04 03:31:44 +00:00
|
|
|
|
|
|
|
uint32_t flags = hw.getFlags();
|
2010-08-16 15:49:37 +00:00
|
|
|
if ((flags & DisplayHardware::SWAP_RECTANGLE) ||
|
|
|
|
(flags & DisplayHardware::BUFFER_PRESERVED))
|
2009-05-05 02:29:25 +00:00
|
|
|
{
|
2009-06-30 01:49:56 +00:00
|
|
|
// we can redraw only what's dirty, but since SWAP_RECTANGLE only
|
|
|
|
// takes a rectangle, we must make sure to update that whole
|
|
|
|
// rectangle in that case
|
|
|
|
if (flags & DisplayHardware::SWAP_RECTANGLE) {
|
2010-06-01 22:12:58 +00:00
|
|
|
// TODO: we really should be able to pass a region to
|
2009-06-30 01:49:56 +00:00
|
|
|
// SWAP_RECTANGLE so that we don't have to redraw all this.
|
|
|
|
mDirtyRegion.set(mInvalidRegion.bounds());
|
|
|
|
} else {
|
|
|
|
// in the BUFFER_PRESERVED case, obviously, we can update only
|
|
|
|
// what's needed and nothing more.
|
|
|
|
// NOTE: this is NOT a common case, as preserving the backbuffer
|
|
|
|
// is costly and usually involves copying the whole update back.
|
|
|
|
}
|
2009-03-04 03:31:44 +00:00
|
|
|
} else {
|
2009-09-24 21:57:26 +00:00
|
|
|
if (flags & DisplayHardware::PARTIAL_UPDATES) {
|
2009-06-30 01:49:56 +00:00
|
|
|
// We need to redraw the rectangle that will be updated
|
2009-05-05 02:29:25 +00:00
|
|
|
// (pushed to the framebuffer).
|
2009-09-24 21:57:26 +00:00
|
|
|
// This is needed because PARTIAL_UPDATES only takes one
|
2009-06-30 01:49:56 +00:00
|
|
|
// rectangle instead of a region (see DisplayHardware::flip())
|
2009-03-04 03:31:44 +00:00
|
|
|
mDirtyRegion.set(mInvalidRegion.bounds());
|
|
|
|
} else {
|
2009-06-30 01:49:56 +00:00
|
|
|
// we need to redraw everything (the whole screen)
|
2009-03-04 03:31:44 +00:00
|
|
|
mDirtyRegion.set(hw.bounds());
|
|
|
|
mInvalidRegion = mDirtyRegion;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// compose all surfaces
|
|
|
|
composeSurfaces(mDirtyRegion);
|
|
|
|
|
|
|
|
// clear the dirty regions
|
|
|
|
mDirtyRegion.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SurfaceFlinger::composeSurfaces(const Region& dirty)
|
|
|
|
{
|
|
|
|
if (UNLIKELY(!mWormholeRegion.isEmpty())) {
|
|
|
|
// should never happen unless the window manager has a bug
|
|
|
|
// draw something...
|
|
|
|
drawWormhole();
|
|
|
|
}
|
2010-08-11 00:14:02 +00:00
|
|
|
|
|
|
|
status_t err = NO_ERROR;
|
2010-08-11 00:19:56 +00:00
|
|
|
const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
|
2010-08-12 22:03:26 +00:00
|
|
|
size_t count = layers.size();
|
2010-08-11 00:14:02 +00:00
|
|
|
|
|
|
|
const DisplayHardware& hw(graphicPlane(0).displayHardware());
|
|
|
|
HWComposer& hwc(hw.getHwComposer());
|
2010-08-12 22:03:26 +00:00
|
|
|
hwc_layer_t* const cur(hwc.getLayers());
|
2010-08-11 00:14:02 +00:00
|
|
|
|
2010-08-12 22:03:26 +00:00
|
|
|
LOGE_IF(cur && hwc.getNumLayers() != count,
|
|
|
|
"HAL number of layers (%d) doesn't match surfaceflinger (%d)",
|
|
|
|
hwc.getNumLayers(), count);
|
2010-08-11 00:14:02 +00:00
|
|
|
|
2010-08-12 22:03:26 +00:00
|
|
|
// just to be extra-safe, use the smallest count
|
2010-08-13 06:21:40 +00:00
|
|
|
if (hwc.initCheck() == NO_ERROR) {
|
|
|
|
count = count < hwc.getNumLayers() ? count : hwc.getNumLayers();
|
|
|
|
}
|
2010-08-11 00:14:02 +00:00
|
|
|
|
2010-08-12 22:03:26 +00:00
|
|
|
/*
|
|
|
|
* update the per-frame h/w composer data for each layer
|
|
|
|
* and build the transparent region of the FB
|
|
|
|
*/
|
|
|
|
Region transparent;
|
|
|
|
if (cur) {
|
|
|
|
for (size_t i=0 ; i<count ; i++) {
|
|
|
|
const sp<LayerBase>& layer(layers[i]);
|
|
|
|
layer->setPerFrameData(&cur[i]);
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
2010-08-12 22:03:26 +00:00
|
|
|
err = hwc.prepare();
|
|
|
|
LOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
|
2010-08-11 00:14:02 +00:00
|
|
|
|
2011-01-19 23:24:23 +00:00
|
|
|
if (err == NO_ERROR) {
|
|
|
|
for (size_t i=0 ; i<count ; i++) {
|
|
|
|
if (cur[i].hints & HWC_HINT_CLEAR_FB) {
|
|
|
|
const sp<LayerBase>& layer(layers[i]);
|
|
|
|
if (!(layer->needsBlending())) {
|
|
|
|
transparent.orSelf(layer->visibleRegionScreen);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* clear the area of the FB that need to be transparent
|
|
|
|
*/
|
|
|
|
transparent.andSelf(dirty);
|
|
|
|
if (!transparent.isEmpty()) {
|
|
|
|
glClearColor(0,0,0,0);
|
|
|
|
Region::const_iterator it = transparent.begin();
|
|
|
|
Region::const_iterator const end = transparent.end();
|
|
|
|
const int32_t height = hw.getHeight();
|
|
|
|
while (it != end) {
|
|
|
|
const Rect& r(*it++);
|
|
|
|
const GLint sy = height - (r.top + r.height());
|
|
|
|
glScissor(r.left, sy, r.width(), r.height());
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
}
|
|
|
|
}
|
2010-08-11 00:14:02 +00:00
|
|
|
}
|
|
|
|
}
|
2010-08-12 22:03:26 +00:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* and then, render the layers targeted at the framebuffer
|
|
|
|
*/
|
|
|
|
for (size_t i=0 ; i<count ; i++) {
|
|
|
|
if (cur) {
|
2010-09-09 09:32:30 +00:00
|
|
|
if ((cur[i].compositionType != HWC_FRAMEBUFFER) &&
|
|
|
|
!(cur[i].flags & HWC_SKIP_LAYER)) {
|
2010-08-12 22:03:26 +00:00
|
|
|
// skip layers handled by the HAL
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2010-09-23 01:58:01 +00:00
|
|
|
|
2010-08-12 22:03:26 +00:00
|
|
|
const sp<LayerBase>& layer(layers[i]);
|
|
|
|
const Region clip(dirty.intersect(layer->visibleRegionScreen));
|
|
|
|
if (!clip.isEmpty()) {
|
|
|
|
layer->draw(clip);
|
|
|
|
}
|
|
|
|
}
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SurfaceFlinger::debugFlashRegions()
|
|
|
|
{
|
2010-06-15 04:20:00 +00:00
|
|
|
const DisplayHardware& hw(graphicPlane(0).displayHardware());
|
|
|
|
const uint32_t flags = hw.getFlags();
|
|
|
|
|
|
|
|
if (!((flags & DisplayHardware::SWAP_RECTANGLE) ||
|
|
|
|
(flags & DisplayHardware::BUFFER_PRESERVED))) {
|
|
|
|
const Region repaint((flags & DisplayHardware::PARTIAL_UPDATES) ?
|
|
|
|
mDirtyRegion.bounds() : hw.bounds());
|
|
|
|
composeSurfaces(repaint);
|
|
|
|
}
|
|
|
|
|
|
|
|
TextureManager::deactivateTextures();
|
2009-05-05 02:29:25 +00:00
|
|
|
|
2009-03-04 03:31:44 +00:00
|
|
|
glDisable(GL_BLEND);
|
|
|
|
glDisable(GL_DITHER);
|
|
|
|
glDisable(GL_SCISSOR_TEST);
|
|
|
|
|
2009-05-04 21:17:04 +00:00
|
|
|
static int toggle = 0;
|
|
|
|
toggle = 1 - toggle;
|
|
|
|
if (toggle) {
|
2010-06-15 04:20:00 +00:00
|
|
|
glColor4f(1, 0, 1, 1);
|
2009-05-04 21:17:04 +00:00
|
|
|
} else {
|
2010-06-15 04:20:00 +00:00
|
|
|
glColor4f(1, 1, 0, 1);
|
2009-05-04 21:17:04 +00:00
|
|
|
}
|
2009-03-04 03:31:44 +00:00
|
|
|
|
2009-05-11 07:03:41 +00:00
|
|
|
Region::const_iterator it = mDirtyRegion.begin();
|
|
|
|
Region::const_iterator const end = mDirtyRegion.end();
|
|
|
|
while (it != end) {
|
|
|
|
const Rect& r = *it++;
|
2009-03-04 03:31:44 +00:00
|
|
|
GLfloat vertices[][2] = {
|
|
|
|
{ r.left, r.top },
|
|
|
|
{ r.left, r.bottom },
|
|
|
|
{ r.right, r.bottom },
|
|
|
|
{ r.right, r.top }
|
|
|
|
};
|
|
|
|
glVertexPointer(2, GL_FLOAT, 0, vertices);
|
|
|
|
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
|
|
|
}
|
2010-06-15 04:20:00 +00:00
|
|
|
|
2009-06-27 02:06:36 +00:00
|
|
|
if (mInvalidRegion.isEmpty()) {
|
|
|
|
mDirtyRegion.dump("mDirtyRegion");
|
|
|
|
mInvalidRegion.dump("mInvalidRegion");
|
|
|
|
}
|
|
|
|
hw.flip(mInvalidRegion);
|
2009-03-04 03:31:44 +00:00
|
|
|
|
|
|
|
if (mDebugRegion > 1)
|
2010-06-15 04:20:00 +00:00
|
|
|
usleep(mDebugRegion * 1000);
|
2009-03-04 03:31:44 +00:00
|
|
|
|
|
|
|
glEnable(GL_SCISSOR_TEST);
|
|
|
|
//mDirtyRegion.dump("mDirtyRegion");
|
|
|
|
}
|
|
|
|
|
|
|
|
void SurfaceFlinger::drawWormhole() const
|
|
|
|
{
|
|
|
|
const Region region(mWormholeRegion.intersect(mDirtyRegion));
|
|
|
|
if (region.isEmpty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
const DisplayHardware& hw(graphicPlane(0).displayHardware());
|
|
|
|
const int32_t width = hw.getWidth();
|
|
|
|
const int32_t height = hw.getHeight();
|
|
|
|
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
glDisable(GL_DITHER);
|
|
|
|
|
|
|
|
if (LIKELY(!mDebugBackground)) {
|
2010-06-15 04:20:00 +00:00
|
|
|
glClearColor(0,0,0,0);
|
2009-05-11 07:03:41 +00:00
|
|
|
Region::const_iterator it = region.begin();
|
|
|
|
Region::const_iterator const end = region.end();
|
|
|
|
while (it != end) {
|
|
|
|
const Rect& r = *it++;
|
2009-03-04 03:31:44 +00:00
|
|
|
const GLint sy = height - (r.top + r.height());
|
|
|
|
glScissor(r.left, sy, r.width(), r.height());
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
const GLshort vertices[][2] = { { 0, 0 }, { width, 0 },
|
|
|
|
{ width, height }, { 0, height } };
|
|
|
|
const GLshort tcoords[][2] = { { 0, 0 }, { 1, 0 }, { 1, 1 }, { 0, 1 } };
|
|
|
|
glVertexPointer(2, GL_SHORT, 0, vertices);
|
|
|
|
glTexCoordPointer(2, GL_SHORT, 0, tcoords);
|
|
|
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
2010-09-15 22:46:24 +00:00
|
|
|
#if defined(GL_OES_EGL_image_external)
|
2010-06-26 01:02:21 +00:00
|
|
|
if (GLExtensions::getInstance().haveTextureExternal()) {
|
|
|
|
glDisable(GL_TEXTURE_EXTERNAL_OES);
|
|
|
|
}
|
2010-06-15 04:20:00 +00:00
|
|
|
#endif
|
2009-03-04 03:31:44 +00:00
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, mWormholeTexName);
|
|
|
|
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
|
|
glMatrixMode(GL_TEXTURE);
|
|
|
|
glLoadIdentity();
|
|
|
|
glScalef(width*(1.0f/32.0f), height*(1.0f/32.0f), 1);
|
2009-05-11 07:03:41 +00:00
|
|
|
Region::const_iterator it = region.begin();
|
|
|
|
Region::const_iterator const end = region.end();
|
|
|
|
while (it != end) {
|
|
|
|
const Rect& r = *it++;
|
2009-03-04 03:31:44 +00:00
|
|
|
const GLint sy = height - (r.top + r.height());
|
|
|
|
glScissor(r.left, sy, r.width(), r.height());
|
|
|
|
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
|
|
|
}
|
|
|
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
2010-12-15 02:38:36 +00:00
|
|
|
glLoadIdentity();
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SurfaceFlinger::debugShowFPS() const
|
|
|
|
{
|
|
|
|
static int mFrameCount;
|
|
|
|
static int mLastFrameCount = 0;
|
|
|
|
static nsecs_t mLastFpsTime = 0;
|
|
|
|
static float mFps = 0;
|
|
|
|
mFrameCount++;
|
|
|
|
nsecs_t now = systemTime();
|
|
|
|
nsecs_t diff = now - mLastFpsTime;
|
|
|
|
if (diff > ms2ns(250)) {
|
|
|
|
mFps = ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff;
|
|
|
|
mLastFpsTime = now;
|
|
|
|
mLastFrameCount = mFrameCount;
|
|
|
|
}
|
|
|
|
// XXX: mFPS has the value we want
|
|
|
|
}
|
|
|
|
|
2009-04-10 21:24:30 +00:00
|
|
|
status_t SurfaceFlinger::addLayer(const sp<LayerBase>& layer)
|
2009-03-04 03:31:44 +00:00
|
|
|
{
|
|
|
|
Mutex::Autolock _l(mStateLock);
|
|
|
|
addLayer_l(layer);
|
|
|
|
setTransactionFlags(eTransactionNeeded|eTraversalNeeded);
|
|
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
|
2009-04-10 21:24:30 +00:00
|
|
|
status_t SurfaceFlinger::addLayer_l(const sp<LayerBase>& layer)
|
2009-03-04 03:31:44 +00:00
|
|
|
{
|
2010-08-11 01:09:09 +00:00
|
|
|
ssize_t i = mCurrentState.layersSortedByZ.add(layer);
|
2010-04-21 00:55:49 +00:00
|
|
|
return (i < 0) ? status_t(i) : status_t(NO_ERROR);
|
|
|
|
}
|
|
|
|
|
2010-06-03 06:28:45 +00:00
|
|
|
ssize_t SurfaceFlinger::addClientLayer(const sp<Client>& client,
|
|
|
|
const sp<LayerBaseClient>& lbc)
|
2010-04-21 00:55:49 +00:00
|
|
|
{
|
2011-06-06 16:55:15 +00:00
|
|
|
Mutex::Autolock _l(mStateLock);
|
2010-06-03 06:28:45 +00:00
|
|
|
|
2011-06-17 00:15:51 +00:00
|
|
|
// attach this layer to the client
|
|
|
|
ssize_t name = client->attachLayer(lbc);
|
|
|
|
|
2010-06-03 06:28:45 +00:00
|
|
|
// add this layer to the current state list
|
|
|
|
addLayer_l(lbc);
|
|
|
|
|
2011-06-17 00:15:51 +00:00
|
|
|
return name;
|
2010-06-03 06:28:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
status_t SurfaceFlinger::removeLayer(const sp<LayerBase>& layer)
|
|
|
|
{
|
|
|
|
Mutex::Autolock _l(mStateLock);
|
|
|
|
status_t err = purgatorizeLayer_l(layer);
|
|
|
|
if (err == NO_ERROR)
|
|
|
|
setTransactionFlags(eTransactionNeeded);
|
|
|
|
return err;
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
2009-04-10 21:24:30 +00:00
|
|
|
status_t SurfaceFlinger::removeLayer_l(const sp<LayerBase>& layerBase)
|
2009-03-04 03:31:44 +00:00
|
|
|
{
|
2010-06-01 22:12:58 +00:00
|
|
|
sp<LayerBaseClient> lbc(layerBase->getLayerBaseClient());
|
|
|
|
if (lbc != 0) {
|
2011-01-26 04:17:45 +00:00
|
|
|
mLayerMap.removeItem( lbc->getSurfaceBinder() );
|
2010-06-01 22:12:58 +00:00
|
|
|
}
|
2009-03-04 03:31:44 +00:00
|
|
|
ssize_t index = mCurrentState.layersSortedByZ.remove(layerBase);
|
|
|
|
if (index >= 0) {
|
2009-04-10 21:24:30 +00:00
|
|
|
mLayersRemoved = true;
|
2009-03-04 03:31:44 +00:00
|
|
|
return NO_ERROR;
|
|
|
|
}
|
2009-06-05 01:46:21 +00:00
|
|
|
return status_t(index);
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
2009-04-18 02:36:26 +00:00
|
|
|
status_t SurfaceFlinger::purgatorizeLayer_l(const sp<LayerBase>& layerBase)
|
|
|
|
{
|
2011-01-15 01:37:42 +00:00
|
|
|
// First add the layer to the purgatory list, which makes sure it won't
|
|
|
|
// go away, then remove it from the main list (through a transaction).
|
2009-04-18 02:36:26 +00:00
|
|
|
ssize_t err = removeLayer_l(layerBase);
|
2011-01-15 01:37:42 +00:00
|
|
|
if (err >= 0) {
|
|
|
|
mLayerPurgatory.add(layerBase);
|
|
|
|
}
|
2009-09-23 23:44:00 +00:00
|
|
|
|
2009-10-03 01:12:30 +00:00
|
|
|
layerBase->onRemoved();
|
|
|
|
|
2009-06-05 01:46:21 +00:00
|
|
|
// it's possible that we don't find a layer, because it might
|
|
|
|
// have been destroyed already -- this is not technically an error
|
2010-06-03 06:28:45 +00:00
|
|
|
// from the user because there is a race between Client::destroySurface(),
|
|
|
|
// ~Client() and ~ISurface().
|
2009-04-18 02:36:26 +00:00
|
|
|
return (err == NAME_NOT_FOUND) ? status_t(NO_ERROR) : err;
|
|
|
|
}
|
|
|
|
|
2010-06-03 06:28:45 +00:00
|
|
|
status_t SurfaceFlinger::invalidateLayerVisibility(const sp<LayerBase>& layer)
|
2009-03-04 03:31:44 +00:00
|
|
|
{
|
2010-06-03 06:28:45 +00:00
|
|
|
layer->forceVisibilityTransaction();
|
|
|
|
setTransactionFlags(eTraversalNeeded);
|
|
|
|
return NO_ERROR;
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags)
|
|
|
|
{
|
|
|
|
return android_atomic_and(~flags, &mTransactionFlags) & flags;
|
|
|
|
}
|
|
|
|
|
2010-05-19 00:06:55 +00:00
|
|
|
uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags)
|
2009-03-04 03:31:44 +00:00
|
|
|
{
|
|
|
|
uint32_t old = android_atomic_or(flags, &mTransactionFlags);
|
|
|
|
if ((old & flags)==0) { // wake the server up
|
2010-05-19 00:06:55 +00:00
|
|
|
signalEvent();
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
return old;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SurfaceFlinger::openGlobalTransaction()
|
|
|
|
{
|
|
|
|
android_atomic_inc(&mTransactionCount);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SurfaceFlinger::closeGlobalTransaction()
|
|
|
|
{
|
|
|
|
if (android_atomic_dec(&mTransactionCount) == 1) {
|
|
|
|
signalEvent();
|
fix [2068105] implement queueBuffer/lockBuffer/dequeueBuffer properly
Rewrote SurfaceFlinger's buffer management from the ground-up.
The design now support an arbitrary number of buffers per surface, however the current implementation is limited to four. Currently only 2 buffers are used in practice.
The main new feature is to be able to dequeue all buffers at once (very important when there are only two).
A client can dequeue all buffers until there are none available, it can lock all buffers except the last one that is used for composition. The client will block then, until a new buffer is enqueued.
The current implementation requires that buffers are locked in the same order they are dequeued and enqueued in the same order they are locked. Only one buffer can be locked at a time.
eg. Allowed sequence: DQ, DQ, LOCK, Q, LOCK, Q
eg. Forbidden sequence: DQ, DQ, LOCK, LOCK, Q, Q
2009-09-07 23:32:45 +00:00
|
|
|
|
2010-08-16 15:49:37 +00:00
|
|
|
// if there is a transaction with a resize, wait for it to
|
fix [2068105] implement queueBuffer/lockBuffer/dequeueBuffer properly
Rewrote SurfaceFlinger's buffer management from the ground-up.
The design now support an arbitrary number of buffers per surface, however the current implementation is limited to four. Currently only 2 buffers are used in practice.
The main new feature is to be able to dequeue all buffers at once (very important when there are only two).
A client can dequeue all buffers until there are none available, it can lock all buffers except the last one that is used for composition. The client will block then, until a new buffer is enqueued.
The current implementation requires that buffers are locked in the same order they are dequeued and enqueued in the same order they are locked. Only one buffer can be locked at a time.
eg. Allowed sequence: DQ, DQ, LOCK, Q, LOCK, Q
eg. Forbidden sequence: DQ, DQ, LOCK, LOCK, Q, Q
2009-09-07 23:32:45 +00:00
|
|
|
// take effect before returning.
|
|
|
|
Mutex::Autolock _l(mStateLock);
|
|
|
|
while (mResizeTransationPending) {
|
2009-09-30 21:42:13 +00:00
|
|
|
status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
|
|
|
|
if (CC_UNLIKELY(err != NO_ERROR)) {
|
|
|
|
// just in case something goes wrong in SF, return to the
|
|
|
|
// called after a few seconds.
|
|
|
|
LOGW_IF(err == TIMED_OUT, "closeGlobalTransaction timed out!");
|
|
|
|
mResizeTransationPending = false;
|
|
|
|
break;
|
|
|
|
}
|
fix [2068105] implement queueBuffer/lockBuffer/dequeueBuffer properly
Rewrote SurfaceFlinger's buffer management from the ground-up.
The design now support an arbitrary number of buffers per surface, however the current implementation is limited to four. Currently only 2 buffers are used in practice.
The main new feature is to be able to dequeue all buffers at once (very important when there are only two).
A client can dequeue all buffers until there are none available, it can lock all buffers except the last one that is used for composition. The client will block then, until a new buffer is enqueued.
The current implementation requires that buffers are locked in the same order they are dequeued and enqueued in the same order they are locked. Only one buffer can be locked at a time.
eg. Allowed sequence: DQ, DQ, LOCK, Q, LOCK, Q
eg. Forbidden sequence: DQ, DQ, LOCK, LOCK, Q, Q
2009-09-07 23:32:45 +00:00
|
|
|
}
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
status_t SurfaceFlinger::freezeDisplay(DisplayID dpy, uint32_t flags)
|
|
|
|
{
|
|
|
|
if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
|
|
|
|
return BAD_VALUE;
|
|
|
|
|
|
|
|
Mutex::Autolock _l(mStateLock);
|
|
|
|
mCurrentState.freezeDisplay = 1;
|
|
|
|
setTransactionFlags(eTransactionNeeded);
|
|
|
|
|
|
|
|
// flags is intended to communicate some sort of animation behavior
|
2009-04-15 06:02:51 +00:00
|
|
|
// (for instance fading)
|
2009-03-04 03:31:44 +00:00
|
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
status_t SurfaceFlinger::unfreezeDisplay(DisplayID dpy, uint32_t flags)
|
|
|
|
{
|
|
|
|
if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
|
|
|
|
return BAD_VALUE;
|
|
|
|
|
|
|
|
Mutex::Autolock _l(mStateLock);
|
|
|
|
mCurrentState.freezeDisplay = 0;
|
|
|
|
setTransactionFlags(eTransactionNeeded);
|
|
|
|
|
|
|
|
// flags is intended to communicate some sort of animation behavior
|
2009-04-15 06:02:51 +00:00
|
|
|
// (for instance fading)
|
2009-03-04 03:31:44 +00:00
|
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
|
2010-08-16 15:49:37 +00:00
|
|
|
int SurfaceFlinger::setOrientation(DisplayID dpy,
|
2009-03-28 01:11:38 +00:00
|
|
|
int orientation, uint32_t flags)
|
2009-03-04 03:31:44 +00:00
|
|
|
{
|
|
|
|
if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
|
|
|
|
return BAD_VALUE;
|
|
|
|
|
|
|
|
Mutex::Autolock _l(mStateLock);
|
|
|
|
if (mCurrentState.orientation != orientation) {
|
|
|
|
if (uint32_t(orientation)<=eOrientation270 || orientation==42) {
|
2009-03-28 01:11:38 +00:00
|
|
|
mCurrentState.orientationType = flags;
|
2009-03-04 03:31:44 +00:00
|
|
|
mCurrentState.orientation = orientation;
|
|
|
|
setTransactionFlags(eTransactionNeeded);
|
|
|
|
mTransactionCV.wait(mStateLock);
|
|
|
|
} else {
|
|
|
|
orientation = BAD_VALUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return orientation;
|
|
|
|
}
|
|
|
|
|
2010-06-03 06:28:45 +00:00
|
|
|
sp<ISurface> SurfaceFlinger::createSurface(const sp<Client>& client, int pid,
|
2010-05-28 21:22:23 +00:00
|
|
|
const String8& name, ISurfaceComposerClient::surface_data_t* params,
|
2009-03-04 03:31:44 +00:00
|
|
|
DisplayID d, uint32_t w, uint32_t h, PixelFormat format,
|
|
|
|
uint32_t flags)
|
|
|
|
{
|
2009-04-10 21:24:30 +00:00
|
|
|
sp<LayerBaseClient> layer;
|
2009-03-04 03:31:44 +00:00
|
|
|
sp<LayerBaseClient::Surface> surfaceHandle;
|
2009-07-10 01:16:43 +00:00
|
|
|
|
|
|
|
if (int32_t(w|h) < 0) {
|
|
|
|
LOGE("createSurface() failed, w or h is negative (w=%d, h=%d)",
|
|
|
|
int(w), int(h));
|
|
|
|
return surfaceHandle;
|
|
|
|
}
|
2010-08-16 15:49:37 +00:00
|
|
|
|
2009-03-04 03:31:44 +00:00
|
|
|
//LOGD("createSurface for pid %d (%d x %d)", pid, w, h);
|
2010-06-01 22:12:58 +00:00
|
|
|
sp<Layer> normalLayer;
|
2009-03-04 03:31:44 +00:00
|
|
|
switch (flags & eFXSurfaceMask) {
|
|
|
|
case eFXSurfaceNormal:
|
2010-12-08 03:38:17 +00:00
|
|
|
normalLayer = createNormalSurface(client, d, w, h, flags, format);
|
|
|
|
layer = normalLayer;
|
2009-03-04 03:31:44 +00:00
|
|
|
break;
|
|
|
|
case eFXSurfaceBlur:
|
2010-12-09 01:13:19 +00:00
|
|
|
// for now we treat Blur as Dim, until we can implement it
|
|
|
|
// efficiently.
|
2009-03-04 03:31:44 +00:00
|
|
|
case eFXSurfaceDim:
|
2010-06-03 06:28:45 +00:00
|
|
|
layer = createDimSurface(client, d, w, h, flags);
|
2009-03-04 03:31:44 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-04-10 21:24:30 +00:00
|
|
|
if (layer != 0) {
|
2010-06-03 06:28:45 +00:00
|
|
|
layer->initStates(w, h, flags);
|
2010-03-02 00:09:43 +00:00
|
|
|
layer->setName(name);
|
2010-06-03 06:28:45 +00:00
|
|
|
ssize_t token = addClientLayer(client, layer);
|
2010-06-01 22:12:58 +00:00
|
|
|
|
2009-03-04 03:31:44 +00:00
|
|
|
surfaceHandle = layer->getSurface();
|
2010-08-16 15:49:37 +00:00
|
|
|
if (surfaceHandle != 0) {
|
2010-06-03 06:28:45 +00:00
|
|
|
params->token = token;
|
2009-08-20 00:46:26 +00:00
|
|
|
params->identity = surfaceHandle->getIdentity();
|
|
|
|
params->width = w;
|
|
|
|
params->height = h;
|
|
|
|
params->format = format;
|
2010-06-01 22:12:58 +00:00
|
|
|
if (normalLayer != 0) {
|
|
|
|
Mutex::Autolock _l(mStateLock);
|
|
|
|
mLayerMap.add(surfaceHandle->asBinder(), normalLayer);
|
|
|
|
}
|
2009-08-20 00:46:26 +00:00
|
|
|
}
|
2010-06-01 22:12:58 +00:00
|
|
|
|
2010-06-03 06:28:45 +00:00
|
|
|
setTransactionFlags(eTransactionNeeded);
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return surfaceHandle;
|
|
|
|
}
|
|
|
|
|
2010-06-01 22:12:58 +00:00
|
|
|
sp<Layer> SurfaceFlinger::createNormalSurface(
|
2009-06-20 00:00:27 +00:00
|
|
|
const sp<Client>& client, DisplayID display,
|
2010-06-03 06:28:45 +00:00
|
|
|
uint32_t w, uint32_t h, uint32_t flags,
|
2009-08-20 00:46:26 +00:00
|
|
|
PixelFormat& format)
|
2009-03-04 03:31:44 +00:00
|
|
|
{
|
|
|
|
// initialize the surfaces
|
|
|
|
switch (format) { // TODO: take h/w into account
|
|
|
|
case PIXEL_FORMAT_TRANSPARENT:
|
|
|
|
case PIXEL_FORMAT_TRANSLUCENT:
|
|
|
|
format = PIXEL_FORMAT_RGBA_8888;
|
|
|
|
break;
|
|
|
|
case PIXEL_FORMAT_OPAQUE:
|
2010-06-30 22:43:47 +00:00
|
|
|
#ifdef NO_RGBX_8888
|
|
|
|
format = PIXEL_FORMAT_RGB_565;
|
|
|
|
#else
|
2010-04-06 01:01:24 +00:00
|
|
|
format = PIXEL_FORMAT_RGBX_8888;
|
2010-06-30 22:43:47 +00:00
|
|
|
#endif
|
2009-03-04 03:31:44 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-06-30 22:43:47 +00:00
|
|
|
#ifdef NO_RGBX_8888
|
|
|
|
if (format == PIXEL_FORMAT_RGBX_8888)
|
|
|
|
format = PIXEL_FORMAT_RGBA_8888;
|
|
|
|
#endif
|
|
|
|
|
2010-06-03 06:28:45 +00:00
|
|
|
sp<Layer> layer = new Layer(this, display, client);
|
2009-06-20 00:00:27 +00:00
|
|
|
status_t err = layer->setBuffers(w, h, format, flags);
|
2010-06-03 06:28:45 +00:00
|
|
|
if (LIKELY(err != NO_ERROR)) {
|
2009-03-04 03:31:44 +00:00
|
|
|
LOGE("createNormalSurfaceLocked() failed (%s)", strerror(-err));
|
2009-04-10 21:24:30 +00:00
|
|
|
layer.clear();
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
return layer;
|
|
|
|
}
|
|
|
|
|
2010-06-01 22:12:58 +00:00
|
|
|
sp<LayerDim> SurfaceFlinger::createDimSurface(
|
2009-06-20 00:00:27 +00:00
|
|
|
const sp<Client>& client, DisplayID display,
|
2010-06-03 06:28:45 +00:00
|
|
|
uint32_t w, uint32_t h, uint32_t flags)
|
2009-03-04 03:31:44 +00:00
|
|
|
{
|
2010-06-03 06:28:45 +00:00
|
|
|
sp<LayerDim> layer = new LayerDim(this, display, client);
|
2009-03-04 03:31:44 +00:00
|
|
|
layer->initStates(w, h, flags);
|
|
|
|
return layer;
|
|
|
|
}
|
|
|
|
|
2010-06-03 06:28:45 +00:00
|
|
|
status_t SurfaceFlinger::removeSurface(const sp<Client>& client, SurfaceID sid)
|
2009-04-18 02:36:26 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* called by the window manager, when a surface should be marked for
|
|
|
|
* destruction.
|
2010-08-16 15:49:37 +00:00
|
|
|
*
|
2009-04-22 22:23:34 +00:00
|
|
|
* The surface is removed from the current and drawing lists, but placed
|
|
|
|
* in the purgatory queue, so it's not destroyed right-away (we need
|
|
|
|
* to wait for all client's references to go away first).
|
2009-04-18 02:36:26 +00:00
|
|
|
*/
|
|
|
|
|
2009-09-11 02:41:18 +00:00
|
|
|
status_t err = NAME_NOT_FOUND;
|
2009-04-22 22:23:34 +00:00
|
|
|
Mutex::Autolock _l(mStateLock);
|
2010-06-03 06:28:45 +00:00
|
|
|
sp<LayerBaseClient> layer = client->getLayerUser(sid);
|
2009-09-11 02:41:18 +00:00
|
|
|
if (layer != 0) {
|
|
|
|
err = purgatorizeLayer_l(layer);
|
|
|
|
if (err == NO_ERROR) {
|
|
|
|
setTransactionFlags(eTransactionNeeded);
|
|
|
|
}
|
2009-04-18 02:36:26 +00:00
|
|
|
}
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2011-06-17 00:15:51 +00:00
|
|
|
status_t SurfaceFlinger::destroySurface(const sp<LayerBaseClient>& layer)
|
2009-03-04 03:31:44 +00:00
|
|
|
{
|
2009-07-03 00:33:40 +00:00
|
|
|
// called by ~ISurface() when all references are gone
|
2011-06-17 00:15:51 +00:00
|
|
|
|
|
|
|
class MessageDestroySurface : public MessageBase {
|
|
|
|
SurfaceFlinger* flinger;
|
|
|
|
sp<LayerBaseClient> layer;
|
|
|
|
public:
|
|
|
|
MessageDestroySurface(
|
|
|
|
SurfaceFlinger* flinger, const sp<LayerBaseClient>& layer)
|
|
|
|
: flinger(flinger), layer(layer) { }
|
|
|
|
virtual bool handler() {
|
|
|
|
sp<LayerBaseClient> l(layer);
|
|
|
|
layer.clear(); // clear it outside of the lock;
|
|
|
|
Mutex::Autolock _l(flinger->mStateLock);
|
|
|
|
/*
|
|
|
|
* remove the layer from the current list -- chances are that it's
|
|
|
|
* not in the list anyway, because it should have been removed
|
|
|
|
* already upon request of the client (eg: window manager).
|
|
|
|
* However, a buggy client could have not done that.
|
|
|
|
* Since we know we don't have any more clients, we don't need
|
|
|
|
* to use the purgatory.
|
|
|
|
*/
|
|
|
|
status_t err = flinger->removeLayer_l(l);
|
|
|
|
if (err == NAME_NOT_FOUND) {
|
|
|
|
// The surface wasn't in the current list, which means it was
|
|
|
|
// removed already, which means it is in the purgatory,
|
|
|
|
// and need to be removed from there.
|
|
|
|
// This needs to happen from the main thread since its dtor
|
|
|
|
// must run from there (b/c of OpenGL ES). Additionally, we
|
|
|
|
// can't really acquire our internal lock from
|
|
|
|
// destroySurface() -- see postMessage() below.
|
|
|
|
ssize_t idx = flinger->mLayerPurgatory.remove(l);
|
|
|
|
LOGE_IF(idx < 0,
|
|
|
|
"layer=%p is not in the purgatory list", l.get());
|
|
|
|
}
|
|
|
|
|
|
|
|
LOGE_IF(err<0 && err != NAME_NOT_FOUND,
|
|
|
|
"error removing layer=%p (%s)", l.get(), strerror(-err));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
postMessageAsync( new MessageDestroySurface(this, layer) );
|
|
|
|
return NO_ERROR;
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
status_t SurfaceFlinger::setClientState(
|
2010-06-03 06:28:45 +00:00
|
|
|
const sp<Client>& client,
|
2009-03-04 03:31:44 +00:00
|
|
|
int32_t count,
|
|
|
|
const layer_state_t* states)
|
|
|
|
{
|
|
|
|
Mutex::Autolock _l(mStateLock);
|
|
|
|
uint32_t flags = 0;
|
|
|
|
for (int i=0 ; i<count ; i++) {
|
2010-06-03 06:28:45 +00:00
|
|
|
const layer_state_t& s(states[i]);
|
|
|
|
sp<LayerBaseClient> layer(client->getLayerUser(s.surface));
|
2009-04-10 21:24:30 +00:00
|
|
|
if (layer != 0) {
|
2009-03-04 03:31:44 +00:00
|
|
|
const uint32_t what = s.what;
|
|
|
|
if (what & ePositionChanged) {
|
|
|
|
if (layer->setPosition(s.x, s.y))
|
|
|
|
flags |= eTraversalNeeded;
|
|
|
|
}
|
|
|
|
if (what & eLayerChanged) {
|
2010-08-11 01:09:09 +00:00
|
|
|
ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
|
2009-03-04 03:31:44 +00:00
|
|
|
if (layer->setLayer(s.z)) {
|
2010-08-11 01:09:09 +00:00
|
|
|
mCurrentState.layersSortedByZ.removeAt(idx);
|
|
|
|
mCurrentState.layersSortedByZ.add(layer);
|
2009-03-04 03:31:44 +00:00
|
|
|
// we need traversal (state changed)
|
|
|
|
// AND transaction (list changed)
|
|
|
|
flags |= eTransactionNeeded|eTraversalNeeded;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (what & eSizeChanged) {
|
fix [2068105] implement queueBuffer/lockBuffer/dequeueBuffer properly
Rewrote SurfaceFlinger's buffer management from the ground-up.
The design now support an arbitrary number of buffers per surface, however the current implementation is limited to four. Currently only 2 buffers are used in practice.
The main new feature is to be able to dequeue all buffers at once (very important when there are only two).
A client can dequeue all buffers until there are none available, it can lock all buffers except the last one that is used for composition. The client will block then, until a new buffer is enqueued.
The current implementation requires that buffers are locked in the same order they are dequeued and enqueued in the same order they are locked. Only one buffer can be locked at a time.
eg. Allowed sequence: DQ, DQ, LOCK, Q, LOCK, Q
eg. Forbidden sequence: DQ, DQ, LOCK, LOCK, Q, Q
2009-09-07 23:32:45 +00:00
|
|
|
if (layer->setSize(s.w, s.h)) {
|
2009-03-04 03:31:44 +00:00
|
|
|
flags |= eTraversalNeeded;
|
fix [2068105] implement queueBuffer/lockBuffer/dequeueBuffer properly
Rewrote SurfaceFlinger's buffer management from the ground-up.
The design now support an arbitrary number of buffers per surface, however the current implementation is limited to four. Currently only 2 buffers are used in practice.
The main new feature is to be able to dequeue all buffers at once (very important when there are only two).
A client can dequeue all buffers until there are none available, it can lock all buffers except the last one that is used for composition. The client will block then, until a new buffer is enqueued.
The current implementation requires that buffers are locked in the same order they are dequeued and enqueued in the same order they are locked. Only one buffer can be locked at a time.
eg. Allowed sequence: DQ, DQ, LOCK, Q, LOCK, Q
eg. Forbidden sequence: DQ, DQ, LOCK, LOCK, Q, Q
2009-09-07 23:32:45 +00:00
|
|
|
mResizeTransationPending = true;
|
|
|
|
}
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
if (what & eAlphaChanged) {
|
|
|
|
if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f)))
|
|
|
|
flags |= eTraversalNeeded;
|
|
|
|
}
|
|
|
|
if (what & eMatrixChanged) {
|
|
|
|
if (layer->setMatrix(s.matrix))
|
|
|
|
flags |= eTraversalNeeded;
|
|
|
|
}
|
|
|
|
if (what & eTransparentRegionChanged) {
|
|
|
|
if (layer->setTransparentRegionHint(s.transparentRegion))
|
|
|
|
flags |= eTraversalNeeded;
|
|
|
|
}
|
|
|
|
if (what & eVisibilityChanged) {
|
|
|
|
if (layer->setFlags(s.flags, s.mask))
|
|
|
|
flags |= eTraversalNeeded;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (flags) {
|
|
|
|
setTransactionFlags(flags);
|
|
|
|
}
|
|
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SurfaceFlinger::screenReleased(int dpy)
|
|
|
|
{
|
|
|
|
// this may be called by a signal handler, we can't do too much in here
|
|
|
|
android_atomic_or(eConsoleReleased, &mConsoleSignals);
|
|
|
|
signalEvent();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SurfaceFlinger::screenAcquired(int dpy)
|
|
|
|
{
|
|
|
|
// this may be called by a signal handler, we can't do too much in here
|
|
|
|
android_atomic_or(eConsoleAcquired, &mConsoleSignals);
|
|
|
|
signalEvent();
|
|
|
|
}
|
|
|
|
|
|
|
|
status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
|
|
|
|
{
|
2010-12-02 00:38:01 +00:00
|
|
|
const size_t SIZE = 4096;
|
2009-03-04 03:31:44 +00:00
|
|
|
char buffer[SIZE];
|
|
|
|
String8 result;
|
2009-06-16 01:24:59 +00:00
|
|
|
if (!mDump.checkCalling()) {
|
2009-03-04 03:31:44 +00:00
|
|
|
snprintf(buffer, SIZE, "Permission Denial: "
|
|
|
|
"can't dump SurfaceFlinger from pid=%d, uid=%d\n",
|
|
|
|
IPCThreadState::self()->getCallingPid(),
|
|
|
|
IPCThreadState::self()->getCallingUid());
|
|
|
|
result.append(buffer);
|
|
|
|
} else {
|
2009-08-26 23:36:26 +00:00
|
|
|
|
|
|
|
// figure out if we're stuck somewhere
|
|
|
|
const nsecs_t now = systemTime();
|
|
|
|
const nsecs_t inSwapBuffers(mDebugInSwapBuffers);
|
|
|
|
const nsecs_t inTransaction(mDebugInTransaction);
|
|
|
|
nsecs_t inSwapBuffersDuration = (inSwapBuffers) ? now-inSwapBuffers : 0;
|
|
|
|
nsecs_t inTransactionDuration = (inTransaction) ? now-inTransaction : 0;
|
|
|
|
|
|
|
|
// Try to get the main lock, but don't insist if we can't
|
|
|
|
// (this would indicate SF is stuck, but we want to be able to
|
|
|
|
// print something in dumpsys).
|
|
|
|
int retry = 3;
|
|
|
|
while (mStateLock.tryLock()<0 && --retry>=0) {
|
|
|
|
usleep(1000000);
|
|
|
|
}
|
|
|
|
const bool locked(retry >= 0);
|
|
|
|
if (!locked) {
|
2010-08-16 15:49:37 +00:00
|
|
|
snprintf(buffer, SIZE,
|
2009-08-26 23:36:26 +00:00
|
|
|
"SurfaceFlinger appears to be unresponsive, "
|
|
|
|
"dumping anyways (no locks held)\n");
|
|
|
|
result.append(buffer);
|
|
|
|
}
|
|
|
|
|
2011-01-20 00:15:53 +00:00
|
|
|
/*
|
|
|
|
* Dump the visible layer list
|
|
|
|
*/
|
2009-03-04 03:31:44 +00:00
|
|
|
const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
|
|
|
|
const size_t count = currentLayers.size();
|
2011-01-20 00:15:53 +00:00
|
|
|
snprintf(buffer, SIZE, "Visible layers (count = %d)\n", count);
|
|
|
|
result.append(buffer);
|
2009-03-04 03:31:44 +00:00
|
|
|
for (size_t i=0 ; i<count ; i++) {
|
2010-04-21 00:55:49 +00:00
|
|
|
const sp<LayerBase>& layer(currentLayers[i]);
|
|
|
|
layer->dump(result, buffer, SIZE);
|
|
|
|
const Layer::State& s(layer->drawingState());
|
2009-03-04 03:31:44 +00:00
|
|
|
s.transparentRegion.dump(result, "transparentRegion");
|
|
|
|
layer->transparentRegionScreen.dump(result, "transparentRegionScreen");
|
|
|
|
layer->visibleRegionScreen.dump(result, "visibleRegionScreen");
|
|
|
|
}
|
2010-04-21 00:55:49 +00:00
|
|
|
|
2011-01-20 00:15:53 +00:00
|
|
|
/*
|
|
|
|
* Dump the layers in the purgatory
|
|
|
|
*/
|
|
|
|
|
|
|
|
const size_t purgatorySize = mLayerPurgatory.size();
|
|
|
|
snprintf(buffer, SIZE, "Purgatory state (%d entries)\n", purgatorySize);
|
|
|
|
result.append(buffer);
|
|
|
|
for (size_t i=0 ; i<purgatorySize ; i++) {
|
|
|
|
const sp<LayerBase>& layer(mLayerPurgatory.itemAt(i));
|
|
|
|
layer->shortDump(result, buffer, SIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Dump SurfaceFlinger global state
|
|
|
|
*/
|
|
|
|
|
|
|
|
snprintf(buffer, SIZE, "SurfaceFlinger global state\n");
|
|
|
|
result.append(buffer);
|
2009-03-04 03:31:44 +00:00
|
|
|
mWormholeRegion.dump(result, "WormholeRegion");
|
|
|
|
const DisplayHardware& hw(graphicPlane(0).displayHardware());
|
|
|
|
snprintf(buffer, SIZE,
|
|
|
|
" display frozen: %s, freezeCount=%d, orientation=%d, canDraw=%d\n",
|
|
|
|
mFreezeDisplay?"yes":"no", mFreezeCount,
|
|
|
|
mCurrentState.orientation, hw.canDraw());
|
|
|
|
result.append(buffer);
|
2009-08-26 23:36:26 +00:00
|
|
|
snprintf(buffer, SIZE,
|
|
|
|
" last eglSwapBuffers() time: %f us\n"
|
|
|
|
" last transaction time : %f us\n",
|
|
|
|
mLastSwapBufferTime/1000.0, mLastTransactionTime/1000.0);
|
|
|
|
result.append(buffer);
|
2010-04-21 00:55:49 +00:00
|
|
|
|
2009-08-26 23:36:26 +00:00
|
|
|
if (inSwapBuffersDuration || !locked) {
|
|
|
|
snprintf(buffer, SIZE, " eglSwapBuffers time: %f us\n",
|
|
|
|
inSwapBuffersDuration/1000.0);
|
|
|
|
result.append(buffer);
|
|
|
|
}
|
2010-04-21 00:55:49 +00:00
|
|
|
|
2009-08-26 23:36:26 +00:00
|
|
|
if (inTransactionDuration || !locked) {
|
|
|
|
snprintf(buffer, SIZE, " transaction time: %f us\n",
|
|
|
|
inTransactionDuration/1000.0);
|
|
|
|
result.append(buffer);
|
|
|
|
}
|
2010-04-21 00:55:49 +00:00
|
|
|
|
2011-01-20 00:15:53 +00:00
|
|
|
/*
|
|
|
|
* Dump HWComposer state
|
|
|
|
*/
|
2010-09-23 01:58:01 +00:00
|
|
|
HWComposer& hwc(hw.getHwComposer());
|
|
|
|
snprintf(buffer, SIZE, " h/w composer %s and %s\n",
|
|
|
|
hwc.initCheck()==NO_ERROR ? "present" : "not present",
|
|
|
|
mDebugDisableHWC ? "disabled" : "enabled");
|
|
|
|
result.append(buffer);
|
2010-09-24 01:13:21 +00:00
|
|
|
hwc.dump(result, buffer, SIZE);
|
2010-09-23 01:58:01 +00:00
|
|
|
|
2011-01-20 00:15:53 +00:00
|
|
|
/*
|
|
|
|
* Dump gralloc state
|
|
|
|
*/
|
2009-10-06 00:07:12 +00:00
|
|
|
const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
|
2009-04-10 21:24:30 +00:00
|
|
|
alloc.dump(result);
|
2010-12-02 00:38:01 +00:00
|
|
|
hw.dump(result);
|
2009-08-26 23:36:26 +00:00
|
|
|
|
|
|
|
if (locked) {
|
|
|
|
mStateLock.unlock();
|
|
|
|
}
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
write(fd, result.string(), result.size());
|
|
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
status_t SurfaceFlinger::onTransact(
|
|
|
|
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
|
|
|
|
{
|
|
|
|
switch (code) {
|
|
|
|
case CREATE_CONNECTION:
|
|
|
|
case OPEN_GLOBAL_TRANSACTION:
|
|
|
|
case CLOSE_GLOBAL_TRANSACTION:
|
|
|
|
case SET_ORIENTATION:
|
|
|
|
case FREEZE_DISPLAY:
|
|
|
|
case UNFREEZE_DISPLAY:
|
|
|
|
case BOOT_FINISHED:
|
2010-10-11 19:37:43 +00:00
|
|
|
case TURN_ELECTRON_BEAM_OFF:
|
2010-10-12 23:05:48 +00:00
|
|
|
case TURN_ELECTRON_BEAM_ON:
|
2009-03-04 03:31:44 +00:00
|
|
|
{
|
|
|
|
// codes that require permission check
|
|
|
|
IPCThreadState* ipc = IPCThreadState::self();
|
|
|
|
const int pid = ipc->getCallingPid();
|
2009-05-22 02:21:59 +00:00
|
|
|
const int uid = ipc->getCallingUid();
|
2009-06-16 01:24:59 +00:00
|
|
|
if ((uid != AID_GRAPHICS) && !mAccessSurfaceFlinger.check(pid, uid)) {
|
|
|
|
LOGE("Permission Denial: "
|
|
|
|
"can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
|
|
|
|
return PERMISSION_DENIED;
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
2010-09-24 18:26:58 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case CAPTURE_SCREEN:
|
|
|
|
{
|
|
|
|
// codes that require permission check
|
|
|
|
IPCThreadState* ipc = IPCThreadState::self();
|
|
|
|
const int pid = ipc->getCallingPid();
|
|
|
|
const int uid = ipc->getCallingUid();
|
|
|
|
if ((uid != AID_GRAPHICS) && !mReadFramebuffer.check(pid, uid)) {
|
|
|
|
LOGE("Permission Denial: "
|
|
|
|
"can't read framebuffer pid=%d, uid=%d", pid, uid);
|
|
|
|
return PERMISSION_DENIED;
|
|
|
|
}
|
|
|
|
break;
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
}
|
2010-09-24 18:26:58 +00:00
|
|
|
|
2009-03-04 03:31:44 +00:00
|
|
|
status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags);
|
|
|
|
if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) {
|
2009-06-27 02:06:36 +00:00
|
|
|
CHECK_INTERFACE(ISurfaceComposer, data, reply);
|
2009-06-16 01:24:59 +00:00
|
|
|
if (UNLIKELY(!mHardwareTest.checkCalling())) {
|
|
|
|
IPCThreadState* ipc = IPCThreadState::self();
|
|
|
|
const int pid = ipc->getCallingPid();
|
|
|
|
const int uid = ipc->getCallingUid();
|
|
|
|
LOGE("Permission Denial: "
|
|
|
|
"can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
|
2009-03-04 03:31:44 +00:00
|
|
|
return PERMISSION_DENIED;
|
|
|
|
}
|
|
|
|
int n;
|
|
|
|
switch (code) {
|
2009-04-17 03:04:08 +00:00
|
|
|
case 1000: // SHOW_CPU, NOT SUPPORTED ANYMORE
|
2010-09-14 05:57:58 +00:00
|
|
|
case 1001: // SHOW_FPS, NOT SUPPORTED ANYMORE
|
2009-03-04 03:31:44 +00:00
|
|
|
return NO_ERROR;
|
|
|
|
case 1002: // SHOW_UPDATES
|
|
|
|
n = data.readInt32();
|
|
|
|
mDebugRegion = n ? n : (mDebugRegion ? 0 : 1);
|
|
|
|
return NO_ERROR;
|
|
|
|
case 1003: // SHOW_BACKGROUND
|
|
|
|
n = data.readInt32();
|
|
|
|
mDebugBackground = n ? 1 : 0;
|
|
|
|
return NO_ERROR;
|
2010-09-23 01:58:01 +00:00
|
|
|
case 1008: // toggle use of hw composer
|
|
|
|
n = data.readInt32();
|
|
|
|
mDebugDisableHWC = n ? 1 : 0;
|
2011-01-14 01:53:01 +00:00
|
|
|
invalidateHwcGeometry();
|
2010-09-23 01:58:01 +00:00
|
|
|
// fall-through...
|
2009-03-04 03:31:44 +00:00
|
|
|
case 1004:{ // repaint everything
|
|
|
|
Mutex::Autolock _l(mStateLock);
|
|
|
|
const DisplayHardware& hw(graphicPlane(0).displayHardware());
|
|
|
|
mDirtyRegion.set(hw.bounds()); // careful that's not thread-safe
|
|
|
|
signalEvent();
|
fix [2068105] implement queueBuffer/lockBuffer/dequeueBuffer properly
Rewrote SurfaceFlinger's buffer management from the ground-up.
The design now support an arbitrary number of buffers per surface, however the current implementation is limited to four. Currently only 2 buffers are used in practice.
The main new feature is to be able to dequeue all buffers at once (very important when there are only two).
A client can dequeue all buffers until there are none available, it can lock all buffers except the last one that is used for composition. The client will block then, until a new buffer is enqueued.
The current implementation requires that buffers are locked in the same order they are dequeued and enqueued in the same order they are locked. Only one buffer can be locked at a time.
eg. Allowed sequence: DQ, DQ, LOCK, Q, LOCK, Q
eg. Forbidden sequence: DQ, DQ, LOCK, LOCK, Q, Q
2009-09-07 23:32:45 +00:00
|
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
case 1005:{ // force transaction
|
|
|
|
setTransactionFlags(eTransactionNeeded|eTraversalNeeded);
|
|
|
|
return NO_ERROR;
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
2010-09-14 05:57:58 +00:00
|
|
|
case 1006:{ // enable/disable GraphicLog
|
|
|
|
int enabled = data.readInt32();
|
|
|
|
GraphicLog::getInstance().setEnabled(enabled);
|
|
|
|
return NO_ERROR;
|
|
|
|
}
|
2009-03-04 03:31:44 +00:00
|
|
|
case 1007: // set mFreezeCount
|
|
|
|
mFreezeCount = data.readInt32();
|
2009-12-02 01:23:28 +00:00
|
|
|
mFreezeDisplayTime = 0;
|
2009-03-04 03:31:44 +00:00
|
|
|
return NO_ERROR;
|
|
|
|
case 1010: // interrogate.
|
2009-04-17 03:04:08 +00:00
|
|
|
reply->writeInt32(0);
|
2009-03-04 03:31:44 +00:00
|
|
|
reply->writeInt32(0);
|
|
|
|
reply->writeInt32(mDebugRegion);
|
|
|
|
reply->writeInt32(mDebugBackground);
|
|
|
|
return NO_ERROR;
|
|
|
|
case 1013: {
|
|
|
|
Mutex::Autolock _l(mStateLock);
|
|
|
|
const DisplayHardware& hw(graphicPlane(0).displayHardware());
|
|
|
|
reply->writeInt32(hw.getPageFlipCount());
|
|
|
|
}
|
|
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2010-10-11 19:37:43 +00:00
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
2010-10-12 23:05:48 +00:00
|
|
|
status_t SurfaceFlinger::renderScreenToTextureLocked(DisplayID dpy,
|
|
|
|
GLuint* textureName, GLfloat* uOut, GLfloat* vOut)
|
2010-10-11 19:37:43 +00:00
|
|
|
{
|
|
|
|
if (!GLExtensions::getInstance().haveFramebufferObject())
|
|
|
|
return INVALID_OPERATION;
|
|
|
|
|
|
|
|
// get screen geometry
|
|
|
|
const DisplayHardware& hw(graphicPlane(dpy).displayHardware());
|
|
|
|
const uint32_t hw_w = hw.getWidth();
|
|
|
|
const uint32_t hw_h = hw.getHeight();
|
|
|
|
GLfloat u = 1;
|
|
|
|
GLfloat v = 1;
|
|
|
|
|
|
|
|
// make sure to clear all GL error flags
|
|
|
|
while ( glGetError() != GL_NO_ERROR ) ;
|
|
|
|
|
|
|
|
// create a FBO
|
|
|
|
GLuint name, tname;
|
|
|
|
glGenTextures(1, &tname);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, tname);
|
2010-10-12 23:05:48 +00:00
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
|
|
|
|
hw_w, hw_h, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
|
2010-10-11 19:37:43 +00:00
|
|
|
if (glGetError() != GL_NO_ERROR) {
|
2010-10-14 19:19:37 +00:00
|
|
|
while ( glGetError() != GL_NO_ERROR ) ;
|
2010-10-11 19:37:43 +00:00
|
|
|
GLint tw = (2 << (31 - clz(hw_w)));
|
|
|
|
GLint th = (2 << (31 - clz(hw_h)));
|
2010-10-12 23:05:48 +00:00
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
|
|
|
|
tw, th, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
|
2010-10-11 19:37:43 +00:00
|
|
|
u = GLfloat(hw_w) / tw;
|
|
|
|
v = GLfloat(hw_h) / th;
|
|
|
|
}
|
|
|
|
glGenFramebuffersOES(1, &name);
|
|
|
|
glBindFramebufferOES(GL_FRAMEBUFFER_OES, name);
|
2010-10-12 23:05:48 +00:00
|
|
|
glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES,
|
|
|
|
GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, tname, 0);
|
2010-10-11 19:37:43 +00:00
|
|
|
|
2010-10-12 23:05:48 +00:00
|
|
|
// redraw the screen entirely...
|
|
|
|
glClearColor(0,0,0,1);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
|
|
|
|
const size_t count = layers.size();
|
|
|
|
for (size_t i=0 ; i<count ; ++i) {
|
|
|
|
const sp<LayerBase>& layer(layers[i]);
|
|
|
|
layer->drawForSreenShot();
|
|
|
|
}
|
2010-10-11 19:37:43 +00:00
|
|
|
|
2010-10-12 23:05:48 +00:00
|
|
|
// back to main framebuffer
|
|
|
|
glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
|
|
|
|
glDisable(GL_SCISSOR_TEST);
|
|
|
|
glDeleteFramebuffersOES(1, &name);
|
2010-10-11 19:37:43 +00:00
|
|
|
|
2010-10-12 23:05:48 +00:00
|
|
|
*textureName = tname;
|
|
|
|
*uOut = u;
|
|
|
|
*vOut = v;
|
|
|
|
return NO_ERROR;
|
|
|
|
}
|
2010-10-11 19:37:43 +00:00
|
|
|
|
2010-10-12 23:05:48 +00:00
|
|
|
// ---------------------------------------------------------------------------
|
2010-10-11 19:37:43 +00:00
|
|
|
|
2010-10-12 23:05:48 +00:00
|
|
|
status_t SurfaceFlinger::electronBeamOffAnimationImplLocked()
|
|
|
|
{
|
|
|
|
status_t result = PERMISSION_DENIED;
|
2010-10-11 19:37:43 +00:00
|
|
|
|
2010-10-12 23:05:48 +00:00
|
|
|
if (!GLExtensions::getInstance().haveFramebufferObject())
|
|
|
|
return INVALID_OPERATION;
|
2010-10-11 19:37:43 +00:00
|
|
|
|
2010-10-12 23:05:48 +00:00
|
|
|
// get screen geometry
|
|
|
|
const DisplayHardware& hw(graphicPlane(0).displayHardware());
|
|
|
|
const uint32_t hw_w = hw.getWidth();
|
|
|
|
const uint32_t hw_h = hw.getHeight();
|
|
|
|
const Region screenBounds(hw.bounds());
|
2010-10-11 19:37:43 +00:00
|
|
|
|
2010-10-12 23:05:48 +00:00
|
|
|
GLfloat u, v;
|
|
|
|
GLuint tname;
|
|
|
|
result = renderScreenToTextureLocked(0, &tname, &u, &v);
|
|
|
|
if (result != NO_ERROR) {
|
|
|
|
return result;
|
|
|
|
}
|
2010-10-11 19:37:43 +00:00
|
|
|
|
2010-10-12 23:05:48 +00:00
|
|
|
GLfloat vtx[8];
|
|
|
|
const GLfloat texCoords[4][2] = { {0,v}, {0,0}, {u,0}, {u,v} };
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, tname);
|
|
|
|
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
|
|
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
|
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
|
|
|
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
|
|
glVertexPointer(2, GL_FLOAT, 0, vtx);
|
|
|
|
|
|
|
|
class s_curve_interpolator {
|
|
|
|
const float nbFrames, s, v;
|
|
|
|
public:
|
|
|
|
s_curve_interpolator(int nbFrames, float s)
|
|
|
|
: nbFrames(1.0f / (nbFrames-1)), s(s),
|
|
|
|
v(1.0f + expf(-s + 0.5f*s)) {
|
|
|
|
}
|
|
|
|
float operator()(int f) {
|
|
|
|
const float x = f * nbFrames;
|
|
|
|
return ((1.0f/(1.0f + expf(-x*s + 0.5f*s))) - 0.5f) * v + 0.5f;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class v_stretch {
|
|
|
|
const GLfloat hw_w, hw_h;
|
|
|
|
public:
|
|
|
|
v_stretch(uint32_t hw_w, uint32_t hw_h)
|
|
|
|
: hw_w(hw_w), hw_h(hw_h) {
|
|
|
|
}
|
|
|
|
void operator()(GLfloat* vtx, float v) {
|
|
|
|
const GLfloat w = hw_w + (hw_w * v);
|
|
|
|
const GLfloat h = hw_h - (hw_h * v);
|
|
|
|
const GLfloat x = (hw_w - w) * 0.5f;
|
|
|
|
const GLfloat y = (hw_h - h) * 0.5f;
|
|
|
|
vtx[0] = x; vtx[1] = y;
|
|
|
|
vtx[2] = x; vtx[3] = y + h;
|
|
|
|
vtx[4] = x + w; vtx[5] = y + h;
|
|
|
|
vtx[6] = x + w; vtx[7] = y;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class h_stretch {
|
|
|
|
const GLfloat hw_w, hw_h;
|
|
|
|
public:
|
|
|
|
h_stretch(uint32_t hw_w, uint32_t hw_h)
|
|
|
|
: hw_w(hw_w), hw_h(hw_h) {
|
2010-10-11 19:37:43 +00:00
|
|
|
}
|
2010-10-12 23:05:48 +00:00
|
|
|
void operator()(GLfloat* vtx, float v) {
|
|
|
|
const GLfloat w = hw_w - (hw_w * v);
|
|
|
|
const GLfloat h = 1.0f;
|
|
|
|
const GLfloat x = (hw_w - w) * 0.5f;
|
|
|
|
const GLfloat y = (hw_h - h) * 0.5f;
|
|
|
|
vtx[0] = x; vtx[1] = y;
|
|
|
|
vtx[2] = x; vtx[3] = y + h;
|
|
|
|
vtx[4] = x + w; vtx[5] = y + h;
|
|
|
|
vtx[6] = x + w; vtx[7] = y;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// the full animation is 24 frames
|
|
|
|
const int nbFrames = 12;
|
|
|
|
s_curve_interpolator itr(nbFrames, 7.5f);
|
|
|
|
s_curve_interpolator itg(nbFrames, 8.0f);
|
|
|
|
s_curve_interpolator itb(nbFrames, 8.5f);
|
|
|
|
|
|
|
|
v_stretch vverts(hw_w, hw_h);
|
|
|
|
glEnable(GL_BLEND);
|
|
|
|
glBlendFunc(GL_ONE, GL_ONE);
|
|
|
|
for (int i=0 ; i<nbFrames ; i++) {
|
|
|
|
float x, y, w, h;
|
|
|
|
const float vr = itr(i);
|
|
|
|
const float vg = itg(i);
|
|
|
|
const float vb = itb(i);
|
|
|
|
|
|
|
|
// clear screen
|
|
|
|
glColorMask(1,1,1,1);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
2010-10-11 19:37:43 +00:00
|
|
|
|
2010-10-12 23:05:48 +00:00
|
|
|
// draw the red plane
|
|
|
|
vverts(vtx, vr);
|
|
|
|
glColorMask(1,0,0,1);
|
|
|
|
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
|
|
|
|
|
|
|
// draw the green plane
|
|
|
|
vverts(vtx, vg);
|
|
|
|
glColorMask(0,1,0,1);
|
|
|
|
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
|
|
|
|
|
|
|
// draw the blue plane
|
|
|
|
vverts(vtx, vb);
|
|
|
|
glColorMask(0,0,1,1);
|
|
|
|
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
|
|
|
|
|
|
|
// draw the white highlight (we use the last vertices)
|
2010-10-11 19:37:43 +00:00
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
|
|
glColorMask(1,1,1,1);
|
2010-10-12 23:05:48 +00:00
|
|
|
glColor4f(vg, vg, vg, 1);
|
|
|
|
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
|
|
|
hw.flip(screenBounds);
|
|
|
|
}
|
|
|
|
|
|
|
|
h_stretch hverts(hw_w, hw_h);
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
|
|
glColorMask(1,1,1,1);
|
|
|
|
for (int i=0 ; i<nbFrames ; i++) {
|
|
|
|
const float v = itg(i);
|
|
|
|
hverts(vtx, v);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
glColor4f(1-v, 1-v, 1-v, 1);
|
|
|
|
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
|
|
|
hw.flip(screenBounds);
|
|
|
|
}
|
|
|
|
|
|
|
|
glColorMask(1,1,1,1);
|
|
|
|
glEnable(GL_SCISSOR_TEST);
|
|
|
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
|
|
glDeleteTextures(1, &tname);
|
|
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
status_t SurfaceFlinger::electronBeamOnAnimationImplLocked()
|
|
|
|
{
|
|
|
|
status_t result = PERMISSION_DENIED;
|
|
|
|
|
|
|
|
if (!GLExtensions::getInstance().haveFramebufferObject())
|
|
|
|
return INVALID_OPERATION;
|
|
|
|
|
|
|
|
|
|
|
|
// get screen geometry
|
|
|
|
const DisplayHardware& hw(graphicPlane(0).displayHardware());
|
|
|
|
const uint32_t hw_w = hw.getWidth();
|
|
|
|
const uint32_t hw_h = hw.getHeight();
|
|
|
|
const Region screenBounds(hw.bounds());
|
|
|
|
|
|
|
|
GLfloat u, v;
|
|
|
|
GLuint tname;
|
|
|
|
result = renderScreenToTextureLocked(0, &tname, &u, &v);
|
|
|
|
if (result != NO_ERROR) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// back to main framebuffer
|
|
|
|
glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
|
|
|
|
glDisable(GL_SCISSOR_TEST);
|
|
|
|
|
|
|
|
GLfloat vtx[8];
|
|
|
|
const GLfloat texCoords[4][2] = { {0,v}, {0,0}, {u,0}, {u,v} };
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, tname);
|
|
|
|
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
|
|
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
|
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
|
|
|
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
|
|
glVertexPointer(2, GL_FLOAT, 0, vtx);
|
|
|
|
|
|
|
|
class s_curve_interpolator {
|
|
|
|
const float nbFrames, s, v;
|
|
|
|
public:
|
|
|
|
s_curve_interpolator(int nbFrames, float s)
|
|
|
|
: nbFrames(1.0f / (nbFrames-1)), s(s),
|
|
|
|
v(1.0f + expf(-s + 0.5f*s)) {
|
|
|
|
}
|
|
|
|
float operator()(int f) {
|
|
|
|
const float x = f * nbFrames;
|
|
|
|
return ((1.0f/(1.0f + expf(-x*s + 0.5f*s))) - 0.5f) * v + 0.5f;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class v_stretch {
|
|
|
|
const GLfloat hw_w, hw_h;
|
|
|
|
public:
|
|
|
|
v_stretch(uint32_t hw_w, uint32_t hw_h)
|
|
|
|
: hw_w(hw_w), hw_h(hw_h) {
|
2010-10-11 19:37:43 +00:00
|
|
|
}
|
2010-10-12 23:05:48 +00:00
|
|
|
void operator()(GLfloat* vtx, float v) {
|
|
|
|
const GLfloat w = hw_w + (hw_w * v);
|
|
|
|
const GLfloat h = hw_h - (hw_h * v);
|
|
|
|
const GLfloat x = (hw_w - w) * 0.5f;
|
|
|
|
const GLfloat y = (hw_h - h) * 0.5f;
|
|
|
|
vtx[0] = x; vtx[1] = y;
|
|
|
|
vtx[2] = x; vtx[3] = y + h;
|
|
|
|
vtx[4] = x + w; vtx[5] = y + h;
|
|
|
|
vtx[6] = x + w; vtx[7] = y;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class h_stretch {
|
|
|
|
const GLfloat hw_w, hw_h;
|
|
|
|
public:
|
|
|
|
h_stretch(uint32_t hw_w, uint32_t hw_h)
|
|
|
|
: hw_w(hw_w), hw_h(hw_h) {
|
|
|
|
}
|
|
|
|
void operator()(GLfloat* vtx, float v) {
|
|
|
|
const GLfloat w = hw_w - (hw_w * v);
|
|
|
|
const GLfloat h = 1.0f;
|
|
|
|
const GLfloat x = (hw_w - w) * 0.5f;
|
|
|
|
const GLfloat y = (hw_h - h) * 0.5f;
|
|
|
|
vtx[0] = x; vtx[1] = y;
|
|
|
|
vtx[2] = x; vtx[3] = y + h;
|
|
|
|
vtx[4] = x + w; vtx[5] = y + h;
|
|
|
|
vtx[6] = x + w; vtx[7] = y;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2010-10-14 19:33:07 +00:00
|
|
|
// the full animation is 12 frames
|
|
|
|
int nbFrames = 8;
|
2010-10-12 23:05:48 +00:00
|
|
|
s_curve_interpolator itr(nbFrames, 7.5f);
|
|
|
|
s_curve_interpolator itg(nbFrames, 8.0f);
|
|
|
|
s_curve_interpolator itb(nbFrames, 8.5f);
|
|
|
|
|
|
|
|
h_stretch hverts(hw_w, hw_h);
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
|
|
glColorMask(1,1,1,1);
|
|
|
|
for (int i=nbFrames-1 ; i>=0 ; i--) {
|
|
|
|
const float v = itg(i);
|
|
|
|
hverts(vtx, v);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
glColor4f(1-v, 1-v, 1-v, 1);
|
|
|
|
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
|
|
|
hw.flip(screenBounds);
|
|
|
|
}
|
|
|
|
|
2010-10-14 19:33:07 +00:00
|
|
|
nbFrames = 4;
|
2010-10-12 23:05:48 +00:00
|
|
|
v_stretch vverts(hw_w, hw_h);
|
|
|
|
glEnable(GL_BLEND);
|
|
|
|
glBlendFunc(GL_ONE, GL_ONE);
|
|
|
|
for (int i=nbFrames-1 ; i>=0 ; i--) {
|
|
|
|
float x, y, w, h;
|
|
|
|
const float vr = itr(i);
|
|
|
|
const float vg = itg(i);
|
|
|
|
const float vb = itb(i);
|
2010-10-11 19:37:43 +00:00
|
|
|
|
2010-10-12 23:05:48 +00:00
|
|
|
// clear screen
|
2010-10-11 19:37:43 +00:00
|
|
|
glColorMask(1,1,1,1);
|
2010-10-12 23:05:48 +00:00
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
|
|
|
|
// draw the red plane
|
|
|
|
vverts(vtx, vr);
|
|
|
|
glColorMask(1,0,0,1);
|
|
|
|
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
|
|
|
|
|
|
|
// draw the green plane
|
|
|
|
vverts(vtx, vg);
|
|
|
|
glColorMask(0,1,0,1);
|
|
|
|
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
|
|
|
|
|
|
|
// draw the blue plane
|
|
|
|
vverts(vtx, vb);
|
|
|
|
glColorMask(0,0,1,1);
|
|
|
|
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
|
|
|
|
|
|
|
hw.flip(screenBounds);
|
2010-10-11 19:37:43 +00:00
|
|
|
}
|
|
|
|
|
2010-10-12 23:05:48 +00:00
|
|
|
glColorMask(1,1,1,1);
|
|
|
|
glEnable(GL_SCISSOR_TEST);
|
|
|
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
2010-10-11 19:37:43 +00:00
|
|
|
glDeleteTextures(1, &tname);
|
|
|
|
|
2010-10-12 23:05:48 +00:00
|
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
2010-10-14 21:54:06 +00:00
|
|
|
status_t SurfaceFlinger::turnElectronBeamOffImplLocked(int32_t mode)
|
2010-10-12 23:05:48 +00:00
|
|
|
{
|
|
|
|
DisplayHardware& hw(graphicPlane(0).editDisplayHardware());
|
|
|
|
if (!hw.canDraw()) {
|
|
|
|
// we're already off
|
|
|
|
return NO_ERROR;
|
|
|
|
}
|
2010-10-14 21:54:06 +00:00
|
|
|
if (mode & ISurfaceComposer::eElectronBeamAnimationOff) {
|
|
|
|
electronBeamOffAnimationImplLocked();
|
|
|
|
}
|
|
|
|
|
|
|
|
// always clear the whole screen at the end of the animation
|
|
|
|
glClearColor(0,0,0,1);
|
|
|
|
glDisable(GL_SCISSOR_TEST);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
glEnable(GL_SCISSOR_TEST);
|
|
|
|
hw.flip( Region(hw.bounds()) );
|
|
|
|
|
2010-10-14 19:19:37 +00:00
|
|
|
hw.setCanDraw(false);
|
|
|
|
return NO_ERROR;
|
2010-10-11 19:37:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
status_t SurfaceFlinger::turnElectronBeamOff(int32_t mode)
|
|
|
|
{
|
|
|
|
class MessageTurnElectronBeamOff : public MessageBase {
|
|
|
|
SurfaceFlinger* flinger;
|
2010-10-14 21:54:06 +00:00
|
|
|
int32_t mode;
|
2010-10-11 19:37:43 +00:00
|
|
|
status_t result;
|
|
|
|
public:
|
2010-10-14 21:54:06 +00:00
|
|
|
MessageTurnElectronBeamOff(SurfaceFlinger* flinger, int32_t mode)
|
|
|
|
: flinger(flinger), mode(mode), result(PERMISSION_DENIED) {
|
2010-10-11 19:37:43 +00:00
|
|
|
}
|
|
|
|
status_t getResult() const {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
virtual bool handler() {
|
|
|
|
Mutex::Autolock _l(flinger->mStateLock);
|
2010-10-14 21:54:06 +00:00
|
|
|
result = flinger->turnElectronBeamOffImplLocked(mode);
|
2010-10-11 19:37:43 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2010-10-14 21:54:06 +00:00
|
|
|
sp<MessageBase> msg = new MessageTurnElectronBeamOff(this, mode);
|
2010-10-11 19:37:43 +00:00
|
|
|
status_t res = postMessageSync(msg);
|
|
|
|
if (res == NO_ERROR) {
|
|
|
|
res = static_cast<MessageTurnElectronBeamOff*>( msg.get() )->getResult();
|
2010-10-12 23:05:48 +00:00
|
|
|
|
|
|
|
// work-around: when the power-manager calls us we activate the
|
|
|
|
// animation. eventually, the "on" animation will be called
|
|
|
|
// by the power-manager itself
|
2010-10-14 21:54:06 +00:00
|
|
|
mElectronBeamAnimationMode = mode;
|
2010-10-11 19:37:43 +00:00
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2009-03-04 03:31:44 +00:00
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
2010-10-14 21:54:06 +00:00
|
|
|
status_t SurfaceFlinger::turnElectronBeamOnImplLocked(int32_t mode)
|
2010-10-12 23:05:48 +00:00
|
|
|
{
|
|
|
|
DisplayHardware& hw(graphicPlane(0).editDisplayHardware());
|
|
|
|
if (hw.canDraw()) {
|
|
|
|
// we're already on
|
|
|
|
return NO_ERROR;
|
|
|
|
}
|
2010-10-14 21:54:06 +00:00
|
|
|
if (mode & ISurfaceComposer::eElectronBeamAnimationOn) {
|
|
|
|
electronBeamOnAnimationImplLocked();
|
|
|
|
}
|
2010-10-14 19:19:37 +00:00
|
|
|
hw.setCanDraw(true);
|
2010-10-14 19:46:24 +00:00
|
|
|
|
|
|
|
// make sure to redraw the whole screen when the animation is done
|
|
|
|
mDirtyRegion.set(hw.bounds());
|
|
|
|
signalEvent();
|
|
|
|
|
2010-10-14 19:19:37 +00:00
|
|
|
return NO_ERROR;
|
2010-10-12 23:05:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
status_t SurfaceFlinger::turnElectronBeamOn(int32_t mode)
|
|
|
|
{
|
|
|
|
class MessageTurnElectronBeamOn : public MessageBase {
|
|
|
|
SurfaceFlinger* flinger;
|
2010-10-14 21:54:06 +00:00
|
|
|
int32_t mode;
|
2010-10-12 23:05:48 +00:00
|
|
|
status_t result;
|
|
|
|
public:
|
2010-10-14 21:54:06 +00:00
|
|
|
MessageTurnElectronBeamOn(SurfaceFlinger* flinger, int32_t mode)
|
|
|
|
: flinger(flinger), mode(mode), result(PERMISSION_DENIED) {
|
2010-10-12 23:05:48 +00:00
|
|
|
}
|
|
|
|
status_t getResult() const {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
virtual bool handler() {
|
|
|
|
Mutex::Autolock _l(flinger->mStateLock);
|
2010-10-14 21:54:06 +00:00
|
|
|
result = flinger->turnElectronBeamOnImplLocked(mode);
|
2010-10-12 23:05:48 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2010-10-14 21:54:06 +00:00
|
|
|
postMessageAsync( new MessageTurnElectronBeamOn(this, mode) );
|
2010-10-12 23:05:48 +00:00
|
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
2010-09-29 20:02:36 +00:00
|
|
|
status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy,
|
|
|
|
sp<IMemoryHeap>* heap,
|
|
|
|
uint32_t* w, uint32_t* h, PixelFormat* f,
|
2010-12-11 00:22:31 +00:00
|
|
|
uint32_t sw, uint32_t sh,
|
|
|
|
uint32_t minLayerZ, uint32_t maxLayerZ)
|
2010-09-29 20:02:36 +00:00
|
|
|
{
|
|
|
|
status_t result = PERMISSION_DENIED;
|
|
|
|
|
|
|
|
// only one display supported for now
|
|
|
|
if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
|
|
|
|
return BAD_VALUE;
|
|
|
|
|
2011-03-10 01:05:02 +00:00
|
|
|
// make sure none of the layers are protected
|
|
|
|
const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
|
|
|
|
const size_t count = layers.size();
|
|
|
|
for (size_t i=0 ; i<count ; ++i) {
|
|
|
|
const sp<LayerBase>& layer(layers[i]);
|
|
|
|
const uint32_t z = layer->drawingState().z;
|
|
|
|
if (z >= minLayerZ && z <= maxLayerZ) {
|
|
|
|
if (layer->isProtected()) {
|
|
|
|
return INVALID_OPERATION;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-29 20:02:36 +00:00
|
|
|
if (!GLExtensions::getInstance().haveFramebufferObject())
|
|
|
|
return INVALID_OPERATION;
|
|
|
|
|
|
|
|
// get screen geometry
|
|
|
|
const DisplayHardware& hw(graphicPlane(dpy).displayHardware());
|
|
|
|
const uint32_t hw_w = hw.getWidth();
|
|
|
|
const uint32_t hw_h = hw.getHeight();
|
|
|
|
|
|
|
|
if ((sw > hw_w) || (sh > hw_h))
|
|
|
|
return BAD_VALUE;
|
|
|
|
|
|
|
|
sw = (!sw) ? hw_w : sw;
|
|
|
|
sh = (!sh) ? hw_h : sh;
|
|
|
|
const size_t size = sw * sh * 4;
|
|
|
|
|
2011-03-03 02:45:50 +00:00
|
|
|
//LOGD("screenshot: sw=%d, sh=%d, minZ=%d, maxZ=%d",
|
|
|
|
// sw, sh, minLayerZ, maxLayerZ);
|
2011-01-16 22:05:02 +00:00
|
|
|
|
2010-09-29 20:02:36 +00:00
|
|
|
// make sure to clear all GL error flags
|
|
|
|
while ( glGetError() != GL_NO_ERROR ) ;
|
|
|
|
|
|
|
|
// create a FBO
|
|
|
|
GLuint name, tname;
|
|
|
|
glGenRenderbuffersOES(1, &tname);
|
|
|
|
glBindRenderbufferOES(GL_RENDERBUFFER_OES, tname);
|
|
|
|
glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_RGBA8_OES, sw, sh);
|
|
|
|
glGenFramebuffersOES(1, &name);
|
|
|
|
glBindFramebufferOES(GL_FRAMEBUFFER_OES, name);
|
|
|
|
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES,
|
|
|
|
GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, tname);
|
|
|
|
|
|
|
|
GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
|
2011-01-16 22:05:02 +00:00
|
|
|
|
2010-09-29 20:02:36 +00:00
|
|
|
if (status == GL_FRAMEBUFFER_COMPLETE_OES) {
|
|
|
|
|
|
|
|
// invert everything, b/c glReadPixel() below will invert the FB
|
|
|
|
glViewport(0, 0, sw, sh);
|
2010-12-17 02:46:17 +00:00
|
|
|
glScissor(0, 0, sw, sh);
|
2010-09-29 20:02:36 +00:00
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glPushMatrix();
|
|
|
|
glLoadIdentity();
|
|
|
|
glOrthof(0, hw_w, 0, hw_h, 0, 1);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
|
|
|
|
// redraw the screen entirely...
|
|
|
|
glClearColor(0,0,0,1);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
2010-12-17 02:46:17 +00:00
|
|
|
|
2010-09-29 20:02:36 +00:00
|
|
|
for (size_t i=0 ; i<count ; ++i) {
|
|
|
|
const sp<LayerBase>& layer(layers[i]);
|
2010-12-11 00:22:31 +00:00
|
|
|
const uint32_t z = layer->drawingState().z;
|
|
|
|
if (z >= minLayerZ && z <= maxLayerZ) {
|
|
|
|
layer->drawForSreenShot();
|
|
|
|
}
|
2010-09-29 20:02:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// XXX: this is needed on tegra
|
|
|
|
glScissor(0, 0, sw, sh);
|
|
|
|
|
|
|
|
// check for errors and return screen capture
|
|
|
|
if (glGetError() != GL_NO_ERROR) {
|
|
|
|
// error while rendering
|
|
|
|
result = INVALID_OPERATION;
|
|
|
|
} else {
|
|
|
|
// allocate shared memory large enough to hold the
|
|
|
|
// screen capture
|
|
|
|
sp<MemoryHeapBase> base(
|
|
|
|
new MemoryHeapBase(size, 0, "screen-capture") );
|
|
|
|
void* const ptr = base->getBase();
|
|
|
|
if (ptr) {
|
|
|
|
// capture the screen with glReadPixels()
|
|
|
|
glReadPixels(0, 0, sw, sh, GL_RGBA, GL_UNSIGNED_BYTE, ptr);
|
|
|
|
if (glGetError() == GL_NO_ERROR) {
|
|
|
|
*heap = base;
|
|
|
|
*w = sw;
|
|
|
|
*h = sh;
|
|
|
|
*f = PIXEL_FORMAT_RGBA_8888;
|
|
|
|
result = NO_ERROR;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
result = NO_MEMORY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
glEnable(GL_SCISSOR_TEST);
|
|
|
|
glViewport(0, 0, hw_w, hw_h);
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glPopMatrix();
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
} else {
|
|
|
|
result = BAD_VALUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// release FBO resources
|
|
|
|
glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
|
|
|
|
glDeleteRenderbuffersOES(1, &tname);
|
|
|
|
glDeleteFramebuffersOES(1, &name);
|
2010-12-15 22:41:59 +00:00
|
|
|
|
|
|
|
hw.compositionComplete();
|
|
|
|
|
2011-03-03 02:45:50 +00:00
|
|
|
// LOGD("screenshot: result = %s", result<0 ? strerror(result) : "OK");
|
2011-01-16 22:05:02 +00:00
|
|
|
|
2010-09-29 20:02:36 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-09-24 18:26:58 +00:00
|
|
|
status_t SurfaceFlinger::captureScreen(DisplayID dpy,
|
|
|
|
sp<IMemoryHeap>* heap,
|
2010-09-29 20:02:36 +00:00
|
|
|
uint32_t* width, uint32_t* height, PixelFormat* format,
|
2010-12-11 00:22:31 +00:00
|
|
|
uint32_t sw, uint32_t sh,
|
|
|
|
uint32_t minLayerZ, uint32_t maxLayerZ)
|
2010-09-24 18:26:58 +00:00
|
|
|
{
|
|
|
|
// only one display supported for now
|
|
|
|
if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
|
|
|
|
return BAD_VALUE;
|
|
|
|
|
|
|
|
if (!GLExtensions::getInstance().haveFramebufferObject())
|
|
|
|
return INVALID_OPERATION;
|
|
|
|
|
|
|
|
class MessageCaptureScreen : public MessageBase {
|
|
|
|
SurfaceFlinger* flinger;
|
|
|
|
DisplayID dpy;
|
|
|
|
sp<IMemoryHeap>* heap;
|
|
|
|
uint32_t* w;
|
|
|
|
uint32_t* h;
|
|
|
|
PixelFormat* f;
|
2010-09-29 20:02:36 +00:00
|
|
|
uint32_t sw;
|
|
|
|
uint32_t sh;
|
2010-12-11 00:22:31 +00:00
|
|
|
uint32_t minLayerZ;
|
|
|
|
uint32_t maxLayerZ;
|
2010-09-24 18:26:58 +00:00
|
|
|
status_t result;
|
|
|
|
public:
|
|
|
|
MessageCaptureScreen(SurfaceFlinger* flinger, DisplayID dpy,
|
2010-09-29 20:02:36 +00:00
|
|
|
sp<IMemoryHeap>* heap, uint32_t* w, uint32_t* h, PixelFormat* f,
|
2010-12-11 00:22:31 +00:00
|
|
|
uint32_t sw, uint32_t sh,
|
|
|
|
uint32_t minLayerZ, uint32_t maxLayerZ)
|
2010-09-24 18:26:58 +00:00
|
|
|
: flinger(flinger), dpy(dpy),
|
2010-12-11 00:22:31 +00:00
|
|
|
heap(heap), w(w), h(h), f(f), sw(sw), sh(sh),
|
|
|
|
minLayerZ(minLayerZ), maxLayerZ(maxLayerZ),
|
|
|
|
result(PERMISSION_DENIED)
|
2010-09-24 18:26:58 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
status_t getResult() const {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
virtual bool handler() {
|
|
|
|
Mutex::Autolock _l(flinger->mStateLock);
|
|
|
|
|
|
|
|
// if we have secure windows, never allow the screen capture
|
|
|
|
if (flinger->mSecureFrameBuffer)
|
|
|
|
return true;
|
|
|
|
|
2010-09-29 20:02:36 +00:00
|
|
|
result = flinger->captureScreenImplLocked(dpy,
|
2010-12-11 00:22:31 +00:00
|
|
|
heap, w, h, f, sw, sh, minLayerZ, maxLayerZ);
|
2010-09-24 18:26:58 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
sp<MessageBase> msg = new MessageCaptureScreen(this,
|
2010-12-11 00:22:31 +00:00
|
|
|
dpy, heap, width, height, format, sw, sh, minLayerZ, maxLayerZ);
|
2010-09-24 18:26:58 +00:00
|
|
|
status_t res = postMessageSync(msg);
|
|
|
|
if (res == NO_ERROR) {
|
|
|
|
res = static_cast<MessageCaptureScreen*>( msg.get() )->getResult();
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
2010-06-01 22:12:58 +00:00
|
|
|
sp<Layer> SurfaceFlinger::getLayer(const sp<ISurface>& sur) const
|
2009-03-04 03:31:44 +00:00
|
|
|
{
|
2010-06-01 22:12:58 +00:00
|
|
|
sp<Layer> result;
|
|
|
|
Mutex::Autolock _l(mStateLock);
|
|
|
|
result = mLayerMap.valueFor( sur->asBinder() ).promote();
|
|
|
|
return result;
|
|
|
|
}
|
2009-07-03 01:11:53 +00:00
|
|
|
|
2010-06-01 22:12:58 +00:00
|
|
|
// ---------------------------------------------------------------------------
|
2010-06-03 06:28:45 +00:00
|
|
|
|
2010-06-01 22:12:58 +00:00
|
|
|
Client::Client(const sp<SurfaceFlinger>& flinger)
|
|
|
|
: mFlinger(flinger), mNameGenerator(1)
|
|
|
|
{
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
2010-06-03 06:28:45 +00:00
|
|
|
Client::~Client()
|
|
|
|
{
|
|
|
|
const size_t count = mLayers.size();
|
|
|
|
for (size_t i=0 ; i<count ; i++) {
|
|
|
|
sp<LayerBaseClient> layer(mLayers.valueAt(i).promote());
|
|
|
|
if (layer != 0) {
|
|
|
|
mFlinger->removeLayer(layer);
|
|
|
|
}
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
}
|
2009-04-10 21:24:30 +00:00
|
|
|
|
2010-06-03 06:28:45 +00:00
|
|
|
status_t Client::initCheck() const {
|
2010-06-01 22:12:58 +00:00
|
|
|
return NO_ERROR;
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
2009-04-10 21:24:30 +00:00
|
|
|
|
2011-06-17 00:15:51 +00:00
|
|
|
ssize_t Client::attachLayer(const sp<LayerBaseClient>& layer)
|
2009-03-04 03:31:44 +00:00
|
|
|
{
|
2011-06-17 00:15:51 +00:00
|
|
|
int32_t name = android_atomic_inc(&mNameGenerator);
|
2010-06-03 06:28:45 +00:00
|
|
|
mLayers.add(name, layer);
|
|
|
|
return name;
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
2010-06-01 22:12:58 +00:00
|
|
|
void Client::detachLayer(const LayerBaseClient* layer)
|
2010-06-03 06:28:45 +00:00
|
|
|
{
|
|
|
|
// we do a linear search here, because this doesn't happen often
|
|
|
|
const size_t count = mLayers.size();
|
|
|
|
for (size_t i=0 ; i<count ; i++) {
|
|
|
|
if (mLayers.valueAt(i) == layer) {
|
|
|
|
mLayers.removeItemsAt(i, 1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-06-17 00:15:51 +00:00
|
|
|
sp<LayerBaseClient> Client::getLayerUser(int32_t i) const {
|
2009-04-10 21:24:30 +00:00
|
|
|
sp<LayerBaseClient> lbc;
|
2011-06-17 00:15:51 +00:00
|
|
|
const wp<LayerBaseClient>& layer(mLayers.valueFor(i));
|
2010-06-03 06:28:45 +00:00
|
|
|
if (layer != 0) {
|
|
|
|
lbc = layer.promote();
|
|
|
|
LOGE_IF(lbc==0, "getLayerUser(name=%d) is dead", int(i));
|
2009-04-10 21:24:30 +00:00
|
|
|
}
|
|
|
|
return lbc;
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
2010-06-03 06:28:45 +00:00
|
|
|
sp<IMemoryHeap> Client::getControlBlock() const {
|
2010-06-01 22:12:58 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
ssize_t Client::getTokenForSurface(const sp<ISurface>& sur) const {
|
|
|
|
return -1;
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
2010-06-03 06:28:45 +00:00
|
|
|
sp<ISurface> Client::createSurface(
|
2010-06-01 22:12:58 +00:00
|
|
|
ISurfaceComposerClient::surface_data_t* params, int pid,
|
|
|
|
const String8& name,
|
|
|
|
DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
|
2009-03-04 03:31:44 +00:00
|
|
|
uint32_t flags)
|
|
|
|
{
|
2010-06-03 06:28:45 +00:00
|
|
|
return mFlinger->createSurface(this, pid, name, params,
|
|
|
|
display, w, h, format, flags);
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
2010-06-03 06:28:45 +00:00
|
|
|
status_t Client::destroySurface(SurfaceID sid) {
|
|
|
|
return mFlinger->removeSurface(this, sid);
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
2010-06-03 06:28:45 +00:00
|
|
|
status_t Client::setState(int32_t count, const layer_state_t* states) {
|
|
|
|
return mFlinger->setClientState(this, count, states);
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
2010-06-01 22:12:58 +00:00
|
|
|
|
|
|
|
UserClient::UserClient(const sp<SurfaceFlinger>& flinger)
|
|
|
|
: ctrlblk(0), mBitmap(0), mFlinger(flinger)
|
|
|
|
{
|
|
|
|
const int pgsize = getpagesize();
|
|
|
|
const int cblksize = ((sizeof(SharedClient)+(pgsize-1))&~(pgsize-1));
|
|
|
|
|
|
|
|
mCblkHeap = new MemoryHeapBase(cblksize, 0,
|
|
|
|
"SurfaceFlinger Client control-block");
|
|
|
|
|
|
|
|
ctrlblk = static_cast<SharedClient *>(mCblkHeap->getBase());
|
|
|
|
if (ctrlblk) { // construct the shared structure in-place.
|
|
|
|
new(ctrlblk) SharedClient;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
UserClient::~UserClient()
|
|
|
|
{
|
|
|
|
if (ctrlblk) {
|
|
|
|
ctrlblk->~SharedClient(); // destroy our shared-structure.
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* When a UserClient dies, it's unclear what to do exactly.
|
|
|
|
* We could go ahead and destroy all surfaces linked to that client
|
|
|
|
* however, it wouldn't be fair to the main Client
|
|
|
|
* (usually the the window-manager), which might want to re-target
|
|
|
|
* the layer to another UserClient.
|
|
|
|
* I think the best is to do nothing, or not much; in most cases the
|
|
|
|
* WM itself will go ahead and clean things up when it detects a client of
|
|
|
|
* his has died.
|
|
|
|
* The remaining question is what to display? currently we keep
|
|
|
|
* just keep the current buffer.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
status_t UserClient::initCheck() const {
|
|
|
|
return ctrlblk == 0 ? NO_INIT : NO_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
void UserClient::detachLayer(const Layer* layer)
|
|
|
|
{
|
|
|
|
int32_t name = layer->getToken();
|
|
|
|
if (name >= 0) {
|
2010-06-09 02:54:15 +00:00
|
|
|
int32_t mask = 1LU<<name;
|
|
|
|
if ((android_atomic_and(~mask, &mBitmap) & mask) == 0) {
|
|
|
|
LOGW("token %d wasn't marked as used %08x", name, int(mBitmap));
|
|
|
|
}
|
2010-06-01 22:12:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sp<IMemoryHeap> UserClient::getControlBlock() const {
|
|
|
|
return mCblkHeap;
|
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t UserClient::getTokenForSurface(const sp<ISurface>& sur) const
|
|
|
|
{
|
|
|
|
int32_t name = NAME_NOT_FOUND;
|
|
|
|
sp<Layer> layer(mFlinger->getLayer(sur));
|
2010-08-10 23:37:53 +00:00
|
|
|
if (layer == 0) {
|
|
|
|
return name;
|
|
|
|
}
|
2010-06-01 22:12:58 +00:00
|
|
|
|
2010-06-09 02:54:15 +00:00
|
|
|
// if this layer already has a token, just return it
|
2010-06-01 22:12:58 +00:00
|
|
|
name = layer->getToken();
|
2010-08-10 23:37:53 +00:00
|
|
|
if ((name >= 0) && (layer->getClient() == this)) {
|
2010-06-09 02:54:15 +00:00
|
|
|
return name;
|
2010-08-10 23:37:53 +00:00
|
|
|
}
|
2010-06-01 22:12:58 +00:00
|
|
|
|
|
|
|
name = 0;
|
|
|
|
do {
|
|
|
|
int32_t mask = 1LU<<name;
|
|
|
|
if ((android_atomic_or(mask, &mBitmap) & mask) == 0) {
|
|
|
|
// we found and locked that name
|
2010-06-09 02:54:15 +00:00
|
|
|
status_t err = layer->setToken(
|
|
|
|
const_cast<UserClient*>(this), ctrlblk, name);
|
|
|
|
if (err != NO_ERROR) {
|
|
|
|
// free the name
|
|
|
|
android_atomic_and(~mask, &mBitmap);
|
|
|
|
name = err;
|
|
|
|
}
|
2010-06-01 22:12:58 +00:00
|
|
|
break;
|
|
|
|
}
|
2011-02-11 00:18:36 +00:00
|
|
|
if (++name >= SharedBufferStack::NUM_LAYERS_MAX)
|
2010-06-01 22:12:58 +00:00
|
|
|
name = NO_MEMORY;
|
|
|
|
} while(name >= 0);
|
|
|
|
|
2010-06-08 22:40:56 +00:00
|
|
|
//LOGD("getTokenForSurface(%p) => %d (client=%p, bitmap=%08lx)",
|
|
|
|
// sur->asBinder().get(), name, this, mBitmap);
|
2010-06-01 22:12:58 +00:00
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
|
|
|
sp<ISurface> UserClient::createSurface(
|
|
|
|
ISurfaceComposerClient::surface_data_t* params, int pid,
|
|
|
|
const String8& name,
|
|
|
|
DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
|
|
|
|
uint32_t flags) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
status_t UserClient::destroySurface(SurfaceID sid) {
|
|
|
|
return INVALID_OPERATION;
|
|
|
|
}
|
|
|
|
status_t UserClient::setState(int32_t count, const layer_state_t* states) {
|
|
|
|
return INVALID_OPERATION;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
2009-03-04 03:31:44 +00:00
|
|
|
|
2011-01-13 02:30:40 +00:00
|
|
|
GraphicBufferAlloc::GraphicBufferAlloc() {}
|
|
|
|
|
|
|
|
GraphicBufferAlloc::~GraphicBufferAlloc() {}
|
|
|
|
|
|
|
|
sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t w, uint32_t h,
|
|
|
|
PixelFormat format, uint32_t usage) {
|
|
|
|
sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(w, h, format, usage));
|
|
|
|
status_t err = graphicBuffer->initCheck();
|
|
|
|
if (err != 0) {
|
|
|
|
LOGE("createGraphicBuffer: init check failed: %d", err);
|
|
|
|
return 0;
|
|
|
|
} else if (graphicBuffer->handle == 0) {
|
|
|
|
LOGE("createGraphicBuffer: unable to create GraphicBuffer");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
Mutex::Autolock _l(mLock);
|
|
|
|
mBuffers.add(graphicBuffer);
|
|
|
|
return graphicBuffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GraphicBufferAlloc::freeAllGraphicBuffersExcept(int bufIdx) {
|
|
|
|
Mutex::Autolock _l(mLock);
|
|
|
|
if (0 <= bufIdx && bufIdx < mBuffers.size()) {
|
|
|
|
sp<GraphicBuffer> b(mBuffers[bufIdx]);
|
|
|
|
mBuffers.clear();
|
|
|
|
mBuffers.add(b);
|
|
|
|
} else {
|
|
|
|
mBuffers.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
2009-03-04 03:31:44 +00:00
|
|
|
GraphicPlane::GraphicPlane()
|
|
|
|
: mHw(0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
GraphicPlane::~GraphicPlane() {
|
|
|
|
delete mHw;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool GraphicPlane::initialized() const {
|
|
|
|
return mHw ? true : false;
|
|
|
|
}
|
|
|
|
|
2010-02-08 23:49:35 +00:00
|
|
|
int GraphicPlane::getWidth() const {
|
|
|
|
return mWidth;
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
2010-02-08 23:49:35 +00:00
|
|
|
int GraphicPlane::getHeight() const {
|
|
|
|
return mHeight;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GraphicPlane::setDisplayHardware(DisplayHardware *hw)
|
|
|
|
{
|
|
|
|
mHw = hw;
|
|
|
|
|
|
|
|
// initialize the display orientation transform.
|
|
|
|
// it's a constant that should come from the display driver.
|
|
|
|
int displayOrientation = ISurfaceComposer::eOrientationDefault;
|
|
|
|
char property[PROPERTY_VALUE_MAX];
|
|
|
|
if (property_get("ro.sf.hwrotation", property, NULL) > 0) {
|
|
|
|
//displayOrientation
|
|
|
|
switch (atoi(property)) {
|
|
|
|
case 90:
|
|
|
|
displayOrientation = ISurfaceComposer::eOrientation90;
|
|
|
|
break;
|
|
|
|
case 270:
|
|
|
|
displayOrientation = ISurfaceComposer::eOrientation270;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const float w = hw->getWidth();
|
|
|
|
const float h = hw->getHeight();
|
|
|
|
GraphicPlane::orientationToTransfrom(displayOrientation, w, h,
|
|
|
|
&mDisplayTransform);
|
|
|
|
if (displayOrientation & ISurfaceComposer::eOrientationSwapMask) {
|
|
|
|
mDisplayWidth = h;
|
|
|
|
mDisplayHeight = w;
|
|
|
|
} else {
|
|
|
|
mDisplayWidth = w;
|
|
|
|
mDisplayHeight = h;
|
|
|
|
}
|
|
|
|
|
|
|
|
setOrientation(ISurfaceComposer::eOrientationDefault);
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
status_t GraphicPlane::orientationToTransfrom(
|
|
|
|
int orientation, int w, int h, Transform* tr)
|
2010-02-22 11:15:57 +00:00
|
|
|
{
|
|
|
|
uint32_t flags = 0;
|
2009-03-04 03:31:44 +00:00
|
|
|
switch (orientation) {
|
|
|
|
case ISurfaceComposer::eOrientationDefault:
|
2010-02-22 11:15:57 +00:00
|
|
|
flags = Transform::ROT_0;
|
|
|
|
break;
|
2009-03-04 03:31:44 +00:00
|
|
|
case ISurfaceComposer::eOrientation90:
|
2010-02-22 11:15:57 +00:00
|
|
|
flags = Transform::ROT_90;
|
2009-03-04 03:31:44 +00:00
|
|
|
break;
|
|
|
|
case ISurfaceComposer::eOrientation180:
|
2010-02-22 11:15:57 +00:00
|
|
|
flags = Transform::ROT_180;
|
2009-03-04 03:31:44 +00:00
|
|
|
break;
|
|
|
|
case ISurfaceComposer::eOrientation270:
|
2010-02-22 11:15:57 +00:00
|
|
|
flags = Transform::ROT_270;
|
2009-03-04 03:31:44 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return BAD_VALUE;
|
|
|
|
}
|
2010-02-22 11:15:57 +00:00
|
|
|
tr->set(flags, w, h);
|
2009-03-04 03:31:44 +00:00
|
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
status_t GraphicPlane::setOrientation(int orientation)
|
|
|
|
{
|
|
|
|
// If the rotation can be handled in hardware, this is where
|
|
|
|
// the magic should happen.
|
2010-02-08 23:49:35 +00:00
|
|
|
|
|
|
|
const DisplayHardware& hw(displayHardware());
|
|
|
|
const float w = mDisplayWidth;
|
|
|
|
const float h = mDisplayHeight;
|
|
|
|
mWidth = int(w);
|
|
|
|
mHeight = int(h);
|
|
|
|
|
|
|
|
Transform orientationTransform;
|
2010-02-22 11:15:57 +00:00
|
|
|
GraphicPlane::orientationToTransfrom(orientation, w, h,
|
|
|
|
&orientationTransform);
|
|
|
|
if (orientation & ISurfaceComposer::eOrientationSwapMask) {
|
|
|
|
mWidth = int(h);
|
|
|
|
mHeight = int(w);
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
2010-02-22 11:15:57 +00:00
|
|
|
|
2009-03-28 00:58:20 +00:00
|
|
|
mOrientation = orientation;
|
2010-02-08 23:49:35 +00:00
|
|
|
mGlobalTransform = mDisplayTransform * orientationTransform;
|
2009-03-04 03:31:44 +00:00
|
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
const DisplayHardware& GraphicPlane::displayHardware() const {
|
|
|
|
return *mHw;
|
|
|
|
}
|
|
|
|
|
2010-10-11 19:37:43 +00:00
|
|
|
DisplayHardware& GraphicPlane::editDisplayHardware() {
|
|
|
|
return *mHw;
|
|
|
|
}
|
|
|
|
|
2009-03-04 03:31:44 +00:00
|
|
|
const Transform& GraphicPlane::transform() const {
|
|
|
|
return mGlobalTransform;
|
|
|
|
}
|
|
|
|
|
2009-04-10 21:24:30 +00:00
|
|
|
EGLDisplay GraphicPlane::getEGLDisplay() const {
|
|
|
|
return mHw->getEGLDisplay();
|
|
|
|
}
|
|
|
|
|
2009-03-04 03:31:44 +00:00
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
}; // namespace android
|