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.
|
|
|
|
*/
|
|
|
|
|
2012-02-24 03:27:23 +00:00
|
|
|
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
|
|
|
|
|
2009-03-04 03:31:44 +00:00
|
|
|
#include <stdint.h>
|
2012-07-24 06:11:29 +00:00
|
|
|
#include <sys/types.h>
|
2009-03-04 03:31:44 +00:00
|
|
|
#include <errno.h>
|
|
|
|
#include <math.h>
|
2012-07-24 06:11:29 +00:00
|
|
|
|
|
|
|
#include <EGL/egl.h>
|
|
|
|
#include <GLES/gl.h>
|
2009-03-04 03:31:44 +00:00
|
|
|
|
|
|
|
#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>
|
2011-06-27 23:05:52 +00:00
|
|
|
#include <binder/PermissionCache.h>
|
2009-07-03 01:11:53 +00:00
|
|
|
|
2012-07-26 01:56:13 +00:00
|
|
|
#include <ui/DisplayInfo.h>
|
|
|
|
|
2011-11-18 01:49:17 +00:00
|
|
|
#include <gui/IDisplayEventConnection.h>
|
2012-07-24 06:11:29 +00:00
|
|
|
#include <gui/BitTube.h>
|
|
|
|
#include <gui/SurfaceTextureClient.h>
|
|
|
|
|
|
|
|
#include <ui/GraphicBufferAllocator.h>
|
|
|
|
#include <ui/PixelFormat.h>
|
2011-11-18 01:49:17 +00:00
|
|
|
|
2009-03-04 03:31:44 +00:00
|
|
|
#include <utils/String8.h>
|
|
|
|
#include <utils/String16.h>
|
|
|
|
#include <utils/StopWatch.h>
|
2012-02-24 03:27:23 +00:00
|
|
|
#include <utils/Trace.h>
|
2009-03-04 03:31:44 +00:00
|
|
|
|
2012-07-24 06:11:29 +00:00
|
|
|
#include <private/android_filesystem_config.h>
|
2009-03-04 03:31:44 +00:00
|
|
|
|
|
|
|
#include "clz.h"
|
2012-02-26 02:48:35 +00:00
|
|
|
#include "DdmConnection.h"
|
2012-06-21 00:51:20 +00:00
|
|
|
#include "DisplayHardware.h"
|
2012-06-18 23:47:56 +00:00
|
|
|
#include "Client.h"
|
2011-11-18 01:49:17 +00:00
|
|
|
#include "EventThread.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"
|
2011-10-13 23:02:48 +00:00
|
|
|
#include "LayerScreenshot.h"
|
2009-03-04 03:31:44 +00:00
|
|
|
#include "SurfaceFlinger.h"
|
|
|
|
|
2012-07-12 21:25:33 +00:00
|
|
|
#include "DisplayHardware/FramebufferSurface.h"
|
2010-08-11 00:14:02 +00:00
|
|
|
#include "DisplayHardware/HWComposer.h"
|
2009-03-04 03:31:44 +00:00
|
|
|
|
2011-04-20 21:20:59 +00:00
|
|
|
|
2011-11-30 01:55:46 +00:00
|
|
|
#define EGL_VERSION_HW_ANDROID 0x3143
|
|
|
|
|
2009-03-04 03:31:44 +00:00
|
|
|
#define DISPLAY_COUNT 1
|
|
|
|
|
|
|
|
namespace android {
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
2011-06-27 23:05:52 +00:00
|
|
|
const String16 sHardwareTest("android.permission.HARDWARE_TEST");
|
|
|
|
const String16 sAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER");
|
|
|
|
const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER");
|
|
|
|
const String16 sDump("android.permission.DUMP");
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
2009-03-04 03:31:44 +00:00
|
|
|
SurfaceFlinger::SurfaceFlinger()
|
|
|
|
: BnSurfaceComposer(), Thread(false),
|
|
|
|
mTransactionFlags(0),
|
2011-10-13 00:39:00 +00:00
|
|
|
mTransationPending(false),
|
2009-04-10 21:24:30 +00:00
|
|
|
mLayersRemoved(false),
|
2009-03-04 03:31:44 +00:00
|
|
|
mBootTime(systemTime()),
|
|
|
|
mVisibleRegionsDirty(false),
|
2010-08-11 00:14:02 +00:00
|
|
|
mHwWorkListDirty(false),
|
2010-10-14 21:54:06 +00:00
|
|
|
mElectronBeamAnimationMode(0),
|
2009-03-04 03:31:44 +00:00
|
|
|
mDebugRegion(0),
|
2011-08-16 03:44:40 +00:00
|
|
|
mDebugDDMS(0),
|
2010-09-23 01:58:01 +00:00
|
|
|
mDebugDisableHWC(0),
|
2011-08-24 01:03:18 +00:00
|
|
|
mDebugDisableTransformHint(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),
|
2012-06-19 01:06:45 +00:00
|
|
|
mExternalDisplaySurface(EGL_NO_SURFACE)
|
2009-03-04 03:31:44 +00:00
|
|
|
{
|
2012-01-04 20:05:49 +00:00
|
|
|
ALOGI("SurfaceFlinger is starting");
|
2009-03-04 03:31:44 +00:00
|
|
|
|
|
|
|
// debugging stuff...
|
|
|
|
char value[PROPERTY_VALUE_MAX];
|
2011-08-16 03:44:40 +00:00
|
|
|
|
2009-03-04 03:31:44 +00:00
|
|
|
property_get("debug.sf.showupdates", value, "0");
|
|
|
|
mDebugRegion = atoi(value);
|
2011-08-16 03:44:40 +00:00
|
|
|
|
2012-03-23 21:17:18 +00:00
|
|
|
#ifdef DDMS_DEBUGGING
|
2011-08-16 03:44:40 +00:00
|
|
|
property_get("debug.sf.ddms", value, "0");
|
|
|
|
mDebugDDMS = atoi(value);
|
|
|
|
if (mDebugDDMS) {
|
|
|
|
DdmConnection::start(getServiceName());
|
|
|
|
}
|
2012-06-19 00:27:56 +00:00
|
|
|
#else
|
|
|
|
#warning "DDMS_DEBUGGING disabled"
|
2012-03-23 21:17:18 +00:00
|
|
|
#endif
|
2011-08-16 03:44:40 +00:00
|
|
|
|
2012-01-04 20:05:49 +00:00
|
|
|
ALOGI_IF(mDebugRegion, "showupdates enabled");
|
|
|
|
ALOGI_IF(mDebugDDMS, "DDMS debugging enabled");
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
2012-02-01 02:24:27 +00:00
|
|
|
void SurfaceFlinger::onFirstRef()
|
|
|
|
{
|
|
|
|
mEventQueue.init(this);
|
|
|
|
|
|
|
|
run("SurfaceFlinger", PRIORITY_URGENT_DISPLAY);
|
|
|
|
|
|
|
|
// Wait for the main thread to be done with its initialization
|
|
|
|
mReadyToRunBarrier.wait();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-04 03:31:44 +00:00
|
|
|
SurfaceFlinger::~SurfaceFlinger()
|
|
|
|
{
|
|
|
|
glDeleteTextures(1, &mWormholeTexName);
|
2012-07-12 21:25:33 +00:00
|
|
|
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
|
|
|
eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
|
|
|
eglTerminate(display);
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
2012-02-01 02:24:27 +00:00
|
|
|
void SurfaceFlinger::binderDied(const wp<IBinder>& who)
|
|
|
|
{
|
|
|
|
// the window manager died on us. prepare its eulogy.
|
|
|
|
|
|
|
|
// reset screen orientation
|
|
|
|
Vector<ComposerState> state;
|
2012-07-25 03:43:54 +00:00
|
|
|
Vector<DisplayState> displays;
|
|
|
|
DisplayState d;
|
|
|
|
d.orientation = eOrientationDefault;
|
|
|
|
displays.add(d);
|
|
|
|
setTransactionState(state, displays, 0);
|
2012-02-01 02:24:27 +00:00
|
|
|
|
|
|
|
// restart the boot-animation
|
2012-06-20 00:26:12 +00:00
|
|
|
startBootAnim();
|
2012-02-01 02:24:27 +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;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
void SurfaceFlinger::bootFinished()
|
|
|
|
{
|
|
|
|
const nsecs_t now = systemTime();
|
|
|
|
const nsecs_t duration = now - mBootTime;
|
2012-01-04 20:05:49 +00:00
|
|
|
ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
|
2009-10-06 00:07:12 +00:00
|
|
|
mBootFinished = true;
|
2011-07-02 00:08:43 +00:00
|
|
|
|
|
|
|
// wait patiently for the window manager death
|
|
|
|
const String16 name("window");
|
|
|
|
sp<IBinder> window(defaultServiceManager()->getService(name));
|
|
|
|
if (window != 0) {
|
2012-07-24 06:11:29 +00:00
|
|
|
window->linkToDeath(static_cast<IBinder::DeathRecipient*>(this));
|
2011-07-02 00:08:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// stop boot animation
|
2012-06-20 00:26:12 +00:00
|
|
|
// formerly we would just kill the process, but we now ask it to exit so it
|
|
|
|
// can choose where to stop the animation.
|
|
|
|
property_set("service.bootanim.exit", "1");
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
2012-07-24 06:11:29 +00:00
|
|
|
void SurfaceFlinger::deleteTextureAsync(GLuint texture) {
|
|
|
|
class MessageDestroyGLTexture : public MessageBase {
|
|
|
|
GLuint texture;
|
|
|
|
public:
|
|
|
|
MessageDestroyGLTexture(GLuint texture)
|
|
|
|
: texture(texture) {
|
|
|
|
}
|
|
|
|
virtual bool handler() {
|
|
|
|
glDeleteTextures(1, &texture);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
postMessageAsync(new MessageDestroyGLTexture(texture));
|
|
|
|
}
|
|
|
|
|
2012-07-12 21:25:33 +00:00
|
|
|
status_t SurfaceFlinger::selectConfigForPixelFormat(
|
|
|
|
EGLDisplay dpy,
|
|
|
|
EGLint const* attrs,
|
|
|
|
PixelFormat format,
|
|
|
|
EGLConfig* outConfig)
|
|
|
|
{
|
|
|
|
EGLConfig config = NULL;
|
|
|
|
EGLint numConfigs = -1, n=0;
|
|
|
|
eglGetConfigs(dpy, NULL, 0, &numConfigs);
|
|
|
|
EGLConfig* const configs = new EGLConfig[numConfigs];
|
|
|
|
eglChooseConfig(dpy, attrs, configs, numConfigs, &n);
|
|
|
|
for (int i=0 ; i<n ; i++) {
|
|
|
|
EGLint nativeVisualId = 0;
|
|
|
|
eglGetConfigAttrib(dpy, configs[i], EGL_NATIVE_VISUAL_ID, &nativeVisualId);
|
|
|
|
if (nativeVisualId>0 && format == nativeVisualId) {
|
|
|
|
*outConfig = configs[i];
|
|
|
|
delete [] configs;
|
|
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
delete [] configs;
|
|
|
|
return NAME_NOT_FOUND;
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
2012-07-12 21:25:33 +00:00
|
|
|
EGLConfig SurfaceFlinger::selectEGLConfig(EGLDisplay display, EGLint nativeVisualId) {
|
|
|
|
// select our EGLConfig. It must support EGL_RECORDABLE_ANDROID if
|
|
|
|
// it is to be used with WIFI displays
|
|
|
|
EGLConfig config;
|
|
|
|
EGLint dummy;
|
|
|
|
status_t err;
|
|
|
|
EGLint attribs[] = {
|
|
|
|
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
|
|
|
|
EGL_RECORDABLE_ANDROID, EGL_TRUE,
|
|
|
|
EGL_NONE
|
|
|
|
};
|
|
|
|
err = selectConfigForPixelFormat(display, attribs, nativeVisualId, &config);
|
|
|
|
if (err) {
|
|
|
|
// maybe we failed because of EGL_RECORDABLE_ANDROID
|
|
|
|
ALOGW("couldn't find an EGLConfig with EGL_RECORDABLE_ANDROID");
|
|
|
|
attribs[2] = EGL_NONE;
|
|
|
|
err = selectConfigForPixelFormat(display, attribs, nativeVisualId, &config);
|
|
|
|
}
|
|
|
|
ALOGE_IF(err, "couldn't find an EGLConfig matching the screen format");
|
|
|
|
if (eglGetConfigAttrib(display, config, EGL_CONFIG_CAVEAT, &dummy) == EGL_TRUE) {
|
|
|
|
ALOGW_IF(dummy == EGL_SLOW_CONFIG, "EGL_SLOW_CONFIG selected!");
|
|
|
|
}
|
|
|
|
return config;
|
|
|
|
}
|
2009-03-04 03:31:44 +00:00
|
|
|
|
2012-07-12 21:25:33 +00:00
|
|
|
EGLContext SurfaceFlinger::createGLContext(EGLDisplay display, EGLConfig config) {
|
|
|
|
// Also create our EGLContext
|
|
|
|
EGLint contextAttributes[] = {
|
|
|
|
#ifdef EGL_IMG_context_priority
|
|
|
|
#ifdef HAS_CONTEXT_PRIORITY
|
|
|
|
#warning "using EGL_IMG_context_priority"
|
|
|
|
EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG,
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
EGL_NONE, EGL_NONE
|
|
|
|
};
|
|
|
|
EGLContext ctxt = eglCreateContext(display, config, NULL, contextAttributes);
|
|
|
|
ALOGE_IF(ctxt==EGL_NO_CONTEXT, "EGLContext creation failed");
|
|
|
|
return ctxt;
|
|
|
|
}
|
2009-03-04 03:31:44 +00:00
|
|
|
|
2012-07-12 21:25:33 +00:00
|
|
|
void SurfaceFlinger::initializeGL(EGLDisplay display, EGLSurface surface) {
|
|
|
|
EGLBoolean result = eglMakeCurrent(display, surface, surface, mEGLContext);
|
|
|
|
if (!result) {
|
|
|
|
ALOGE("Couldn't create a working GLES context. check logs. exiting...");
|
|
|
|
exit(0);
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
2012-07-12 21:25:33 +00:00
|
|
|
GLExtensions& extensions(GLExtensions::getInstance());
|
|
|
|
extensions.initWithGLStrings(
|
|
|
|
glGetString(GL_VENDOR),
|
|
|
|
glGetString(GL_RENDERER),
|
|
|
|
glGetString(GL_VERSION),
|
|
|
|
glGetString(GL_EXTENSIONS),
|
|
|
|
eglQueryString(display, EGL_VENDOR),
|
|
|
|
eglQueryString(display, EGL_VERSION),
|
|
|
|
eglQueryString(display, EGL_EXTENSIONS));
|
2010-08-16 15:49:37 +00:00
|
|
|
|
2012-07-12 21:25:33 +00:00
|
|
|
EGLint w, h;
|
|
|
|
eglQuerySurface(display, surface, EGL_WIDTH, &w);
|
|
|
|
eglQuerySurface(display, surface, EGL_HEIGHT, &h);
|
2010-08-16 15:49:37 +00:00
|
|
|
|
2012-07-12 21:25:33 +00:00
|
|
|
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
|
|
|
|
glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);
|
2009-07-03 01:11:53 +00:00
|
|
|
|
2009-03-04 03:31:44 +00:00
|
|
|
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);
|
|
|
|
glShadeModel(GL_FLAT);
|
|
|
|
glDisable(GL_DITHER);
|
|
|
|
glDisable(GL_CULL_FACE);
|
|
|
|
|
2012-07-12 21:25:33 +00:00
|
|
|
struct pack565 {
|
|
|
|
inline uint16_t operator() (int r, int g, int b) const {
|
|
|
|
return (r<<11)|(g<<5)|b;
|
|
|
|
}
|
|
|
|
} pack565;
|
|
|
|
|
2009-03-04 03:31:44 +00:00
|
|
|
const uint16_t g0 = pack565(0x0F,0x1F,0x0F);
|
|
|
|
const uint16_t g1 = pack565(0x17,0x2f,0x17);
|
2011-10-07 21:51:16 +00:00
|
|
|
const uint16_t wormholeTexData[4] = { g0, g1, g1, g0 };
|
2009-03-04 03:31:44 +00:00
|
|
|
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,
|
2011-10-07 21:51:16 +00:00
|
|
|
GL_RGB, GL_UNSIGNED_SHORT_5_6_5, wormholeTexData);
|
|
|
|
|
|
|
|
const uint16_t protTexData[] = { pack565(0x03, 0x03, 0x03) };
|
|
|
|
glGenTextures(1, &mProtectedTexName);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, mProtectedTexName);
|
|
|
|
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, 1, 1, 0,
|
|
|
|
GL_RGB, GL_UNSIGNED_SHORT_5_6_5, protTexData);
|
2009-03-04 03:31:44 +00:00
|
|
|
|
|
|
|
glViewport(0, 0, w, h);
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glLoadIdentity();
|
2011-07-08 00:30:31 +00:00
|
|
|
// put the origin in the left-bottom corner
|
|
|
|
glOrthof(0, w, 0, h, 0, 1); // l=0, r=w ; b=0, t=h
|
2009-03-04 03:31:44 +00:00
|
|
|
|
2012-07-12 21:25:33 +00:00
|
|
|
// print some debugging info
|
|
|
|
EGLint r,g,b,a;
|
|
|
|
eglGetConfigAttrib(display, mEGLConfig, EGL_RED_SIZE, &r);
|
|
|
|
eglGetConfigAttrib(display, mEGLConfig, EGL_GREEN_SIZE, &g);
|
|
|
|
eglGetConfigAttrib(display, mEGLConfig, EGL_BLUE_SIZE, &b);
|
|
|
|
eglGetConfigAttrib(display, mEGLConfig, EGL_ALPHA_SIZE, &a);
|
|
|
|
ALOGI("EGL informations:");
|
|
|
|
ALOGI("vendor : %s", extensions.getEglVendor());
|
|
|
|
ALOGI("version : %s", extensions.getEglVersion());
|
|
|
|
ALOGI("extensions: %s", extensions.getEglExtension());
|
|
|
|
ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported");
|
|
|
|
ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, mEGLConfig);
|
|
|
|
ALOGI("OpenGL ES informations:");
|
|
|
|
ALOGI("vendor : %s", extensions.getVendor());
|
|
|
|
ALOGI("renderer : %s", extensions.getRenderer());
|
|
|
|
ALOGI("version : %s", extensions.getVersion());
|
|
|
|
ALOGI("extensions: %s", extensions.getExtension());
|
|
|
|
ALOGI("GL_MAX_TEXTURE_SIZE = %d", mMaxTextureSize);
|
|
|
|
ALOGI("GL_MAX_VIEWPORT_DIMS = %d x %d", mMaxViewportDims[0], mMaxViewportDims[1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
status_t SurfaceFlinger::readyToRun()
|
|
|
|
{
|
|
|
|
ALOGI( "SurfaceFlinger's main thread ready to run. "
|
|
|
|
"Initializing graphics H/W...");
|
|
|
|
|
|
|
|
// initialize EGL
|
|
|
|
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
|
|
|
eglInitialize(display, NULL, NULL);
|
|
|
|
|
|
|
|
// Initialize the main display
|
|
|
|
// create native window to main display
|
|
|
|
sp<FramebufferSurface> anw = FramebufferSurface::create();
|
|
|
|
ANativeWindow* const window = anw.get();
|
|
|
|
if (!window) {
|
|
|
|
ALOGE("Display subsystem failed to initialize. check logs. exiting...");
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// initialize the config and context
|
|
|
|
int format;
|
|
|
|
window->query(window, NATIVE_WINDOW_FORMAT, &format);
|
|
|
|
mEGLConfig = selectEGLConfig(display, format);
|
|
|
|
mEGLContext = createGLContext(display, mEGLConfig);
|
|
|
|
|
|
|
|
// initialize our main display hardware
|
|
|
|
DisplayHardware* const hw = new DisplayHardware(this, 0, anw, mEGLConfig);
|
|
|
|
mDisplayHardwares[0] = hw;
|
|
|
|
|
|
|
|
// initialize OpenGL ES
|
|
|
|
EGLSurface surface = hw->getEGLSurface();
|
|
|
|
initializeGL(display, surface);
|
2011-11-18 01:49:17 +00:00
|
|
|
|
2012-07-26 04:12:12 +00:00
|
|
|
// start the EventThread
|
|
|
|
mEventThread = new EventThread(this);
|
|
|
|
mEventQueue.setEventThread(mEventThread);
|
|
|
|
|
2012-07-25 05:46:10 +00:00
|
|
|
// initialize the H/W composer
|
|
|
|
mHwc = new HWComposer(this,
|
|
|
|
*static_cast<HWComposer::EventHandler *>(this),
|
|
|
|
hw->getRefreshPeriod());
|
|
|
|
if (mHwc->initCheck() == NO_ERROR) {
|
|
|
|
mHwc->setFrameBuffer(display, surface);
|
|
|
|
}
|
|
|
|
|
2012-07-12 21:25:33 +00:00
|
|
|
// We're now ready to accept clients...
|
2011-11-18 01:49:17 +00:00
|
|
|
mReadyToRunBarrier.open();
|
|
|
|
|
2009-05-22 02:21:59 +00:00
|
|
|
// start boot animation
|
2012-06-20 00:26:12 +00:00
|
|
|
startBootAnim();
|
2010-08-16 15:49:37 +00:00
|
|
|
|
2009-03-04 03:31:44 +00:00
|
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
|
2012-06-20 00:26:12 +00:00
|
|
|
void SurfaceFlinger::startBootAnim() {
|
|
|
|
// start boot animation
|
|
|
|
property_set("service.bootanim.exit", "0");
|
|
|
|
property_set("ctl.start", "bootanim");
|
|
|
|
}
|
|
|
|
|
2012-07-12 21:25:33 +00:00
|
|
|
uint32_t SurfaceFlinger::getMaxTextureSize() const {
|
|
|
|
return mMaxTextureSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t SurfaceFlinger::getMaxViewportDims() const {
|
|
|
|
return mMaxViewportDims[0] < mMaxViewportDims[1] ?
|
|
|
|
mMaxViewportDims[0] : mMaxViewportDims[1];
|
|
|
|
}
|
|
|
|
|
2011-11-18 01:49:17 +00:00
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
2011-08-18 01:19:00 +00:00
|
|
|
bool SurfaceFlinger::authenticateSurfaceTexture(
|
|
|
|
const sp<ISurfaceTexture>& surfaceTexture) const {
|
2011-03-08 20:18:54 +00:00
|
|
|
Mutex::Autolock _l(mStateLock);
|
2011-08-18 01:19:00 +00:00
|
|
|
sp<IBinder> surfaceTextureBinder(surfaceTexture->asBinder());
|
2011-03-08 20:18:54 +00:00
|
|
|
|
|
|
|
// 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());
|
2011-08-18 01:19:00 +00:00
|
|
|
if (lbc != NULL) {
|
|
|
|
wp<IBinder> lbcBinder = lbc->getSurfaceTextureBinder();
|
|
|
|
if (lbcBinder == surfaceTextureBinder) {
|
|
|
|
return true;
|
|
|
|
}
|
2011-03-08 20:18:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check the layers in the purgatory. This check is here so that if a
|
2011-08-18 01:19:00 +00:00
|
|
|
// SurfaceTexture gets destroyed before all the clients are done using it,
|
|
|
|
// the error will not be reported as "surface XYZ is not authenticated", but
|
2011-03-08 20:18:54 +00:00
|
|
|
// 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());
|
2011-08-18 01:19:00 +00:00
|
|
|
if (lbc != NULL) {
|
|
|
|
wp<IBinder> lbcBinder = lbc->getSurfaceTextureBinder();
|
|
|
|
if (lbcBinder == surfaceTextureBinder) {
|
|
|
|
return true;
|
|
|
|
}
|
2011-03-08 20:18:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-07-26 01:56:13 +00:00
|
|
|
status_t SurfaceFlinger::getDisplayInfo(DisplayID dpy, DisplayInfo* info) {
|
|
|
|
if (uint32_t(dpy) >= 2) {
|
|
|
|
return BAD_INDEX;
|
|
|
|
}
|
|
|
|
const DisplayHardware& hw(getDefaultDisplayHardware());
|
|
|
|
return hw.getInfo(info);
|
|
|
|
}
|
|
|
|
|
2011-11-18 01:49:17 +00:00
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() {
|
2012-01-25 00:39:14 +00:00
|
|
|
return mEventThread->createEventConnection();
|
2010-05-19 00:06:55 +00:00
|
|
|
}
|
|
|
|
|
2012-06-19 01:06:45 +00:00
|
|
|
void SurfaceFlinger::connectDisplay(const sp<ISurfaceTexture> display) {
|
2012-06-21 00:51:20 +00:00
|
|
|
const DisplayHardware& hw(getDefaultDisplayHardware());
|
2012-06-19 01:06:45 +00:00
|
|
|
EGLSurface result = EGL_NO_SURFACE;
|
|
|
|
EGLSurface old_surface = EGL_NO_SURFACE;
|
|
|
|
sp<SurfaceTextureClient> stc;
|
|
|
|
|
|
|
|
if (display != NULL) {
|
|
|
|
stc = new SurfaceTextureClient(display);
|
|
|
|
result = eglCreateWindowSurface(hw.getEGLDisplay(),
|
2012-07-12 21:25:33 +00:00
|
|
|
mEGLConfig, (EGLNativeWindowType)stc.get(), NULL);
|
2012-06-19 01:06:45 +00:00
|
|
|
ALOGE_IF(result == EGL_NO_SURFACE,
|
|
|
|
"eglCreateWindowSurface failed (ISurfaceTexture=%p)",
|
|
|
|
display.get());
|
|
|
|
}
|
|
|
|
|
|
|
|
{ // scope for the lock
|
|
|
|
Mutex::Autolock _l(mStateLock);
|
|
|
|
old_surface = mExternalDisplaySurface;
|
|
|
|
mExternalDisplayNativeWindow = stc;
|
|
|
|
mExternalDisplaySurface = result;
|
|
|
|
ALOGD("mExternalDisplaySurface = %p", result);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (old_surface != EGL_NO_SURFACE) {
|
|
|
|
// Note: EGL allows to destroy an object while its current
|
|
|
|
// it will fail to become current next time though.
|
|
|
|
eglDestroySurface(hw.getEGLDisplay(), old_surface);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
EGLSurface SurfaceFlinger::getExternalDisplaySurface() const {
|
|
|
|
Mutex::Autolock _l(mStateLock);
|
|
|
|
return mExternalDisplaySurface;
|
|
|
|
}
|
|
|
|
|
2009-03-04 03:31:44 +00:00
|
|
|
// ----------------------------------------------------------------------------
|
2012-02-01 02:24:27 +00:00
|
|
|
|
|
|
|
void SurfaceFlinger::waitForEvent() {
|
|
|
|
mEventQueue.waitMessage();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SurfaceFlinger::signalTransaction() {
|
|
|
|
mEventQueue.invalidate();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SurfaceFlinger::signalLayerUpdate() {
|
|
|
|
mEventQueue.invalidate();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SurfaceFlinger::signalRefresh() {
|
|
|
|
mEventQueue.refresh();
|
|
|
|
}
|
|
|
|
|
|
|
|
status_t SurfaceFlinger::postMessageAsync(const sp<MessageBase>& msg,
|
|
|
|
nsecs_t reltime, uint32_t flags) {
|
|
|
|
return mEventQueue.postMessage(msg, reltime);
|
|
|
|
}
|
|
|
|
|
|
|
|
status_t SurfaceFlinger::postMessageSync(const sp<MessageBase>& msg,
|
|
|
|
nsecs_t reltime, uint32_t flags) {
|
|
|
|
status_t res = mEventQueue.postMessage(msg, reltime);
|
|
|
|
if (res == NO_ERROR) {
|
|
|
|
msg->wait();
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
2009-03-04 03:31:44 +00:00
|
|
|
|
2012-06-29 21:12:52 +00:00
|
|
|
bool SurfaceFlinger::threadLoop() {
|
2009-03-04 03:31:44 +00:00
|
|
|
waitForEvent();
|
2012-02-01 02:24:27 +00:00
|
|
|
return true;
|
|
|
|
}
|
2009-03-04 03:31:44 +00:00
|
|
|
|
2012-07-25 05:46:10 +00:00
|
|
|
void SurfaceFlinger::onVSyncReceived(int dpy, nsecs_t timestamp) {
|
|
|
|
DisplayHardware& hw(const_cast<DisplayHardware&>(getDisplayHardware(dpy)));
|
|
|
|
hw.onVSyncReceived(timestamp);
|
|
|
|
mEventThread->onVSyncReceived(dpy, timestamp);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SurfaceFlinger::eventControl(int event, int enabled) {
|
|
|
|
getHwComposer().eventControl(event, enabled);
|
|
|
|
}
|
|
|
|
|
2012-06-29 21:12:52 +00:00
|
|
|
void SurfaceFlinger::onMessageReceived(int32_t what) {
|
2012-02-24 03:27:23 +00:00
|
|
|
ATRACE_CALL();
|
2012-02-01 02:24:27 +00:00
|
|
|
switch (what) {
|
2012-06-29 21:12:52 +00:00
|
|
|
case MessageQueue::INVALIDATE:
|
|
|
|
handleMessageTransaction();
|
|
|
|
handleMessageInvalidate();
|
|
|
|
signalRefresh();
|
|
|
|
break;
|
|
|
|
case MessageQueue::REFRESH:
|
|
|
|
handleMessageRefresh();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2009-03-04 03:31:44 +00:00
|
|
|
|
2012-06-29 21:12:52 +00:00
|
|
|
void SurfaceFlinger::handleMessageTransaction() {
|
|
|
|
const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
|
|
|
|
uint32_t transactionFlags = peekTransactionFlags(mask);
|
|
|
|
if (transactionFlags) {
|
|
|
|
Region dirtyRegion;
|
|
|
|
dirtyRegion = handleTransaction(transactionFlags);
|
|
|
|
// XXX: dirtyRegion should be per screen
|
|
|
|
mDirtyRegion |= dirtyRegion;
|
|
|
|
}
|
|
|
|
}
|
2009-03-04 03:31:44 +00:00
|
|
|
|
2012-06-29 21:12:52 +00:00
|
|
|
void SurfaceFlinger::handleMessageInvalidate() {
|
|
|
|
Region dirtyRegion;
|
|
|
|
dirtyRegion = handlePageFlip();
|
|
|
|
// XXX: dirtyRegion should be per screen
|
|
|
|
mDirtyRegion |= dirtyRegion;
|
|
|
|
}
|
2011-10-19 00:36:28 +00:00
|
|
|
|
2012-06-29 21:12:52 +00:00
|
|
|
void SurfaceFlinger::handleMessageRefresh() {
|
|
|
|
handleRefresh();
|
2010-08-11 00:14:02 +00:00
|
|
|
|
2012-07-11 20:48:17 +00:00
|
|
|
if (mVisibleRegionsDirty) {
|
|
|
|
Region opaqueRegion;
|
|
|
|
Region dirtyRegion;
|
|
|
|
const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
|
|
|
|
computeVisibleRegions(currentLayers, dirtyRegion, opaqueRegion);
|
|
|
|
mDirtyRegion.orSelf(dirtyRegion);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* rebuild the visible layer list per screen
|
|
|
|
*/
|
|
|
|
|
|
|
|
// TODO: iterate through all displays
|
|
|
|
DisplayHardware& hw(const_cast<DisplayHardware&>(getDisplayHardware(0)));
|
|
|
|
|
|
|
|
Vector< sp<LayerBase> > layersSortedByZ;
|
|
|
|
const size_t count = currentLayers.size();
|
|
|
|
for (size_t i=0 ; i<count ; i++) {
|
|
|
|
if (!currentLayers[i]->visibleRegion.isEmpty()) {
|
|
|
|
// TODO: also check that this layer is associated to this display
|
|
|
|
layersSortedByZ.add(currentLayers[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
hw.setVisibleLayersSortedByZ(layersSortedByZ);
|
|
|
|
|
|
|
|
|
|
|
|
// FIXME: mWormholeRegion needs to be calculated per screen
|
|
|
|
//const DisplayHardware& hw(getDefaultDisplayHardware()); // XXX: we can't keep that here
|
|
|
|
mWormholeRegion = Region(hw.getBounds()).subtract(
|
|
|
|
hw.getTransform().transform(opaqueRegion) );
|
|
|
|
mVisibleRegionsDirty = false;
|
|
|
|
invalidateHwcGeometry();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-29 21:12:52 +00:00
|
|
|
// XXX: dirtyRegion should be per screen, we should check all of them
|
|
|
|
if (mDirtyRegion.isEmpty()) {
|
|
|
|
return;
|
|
|
|
}
|
2012-02-05 09:49:16 +00:00
|
|
|
|
2012-06-29 21:12:52 +00:00
|
|
|
// TODO: iterate through all displays
|
|
|
|
const DisplayHardware& hw(getDisplayHardware(0));
|
2012-04-12 03:43:19 +00:00
|
|
|
|
2012-06-29 21:12:52 +00:00
|
|
|
// XXX: dirtyRegion should be per screen
|
|
|
|
// transform the dirty region into this screen's coordinate space
|
|
|
|
const Transform& planeTransform(hw.getTransform());
|
|
|
|
mDirtyRegion = planeTransform.transform(mDirtyRegion);
|
|
|
|
mDirtyRegion.orSelf(getAndClearInvalidateRegion());
|
|
|
|
mDirtyRegion.andSelf(hw.bounds());
|
2012-02-05 09:49:16 +00:00
|
|
|
|
2012-02-04 23:44:04 +00:00
|
|
|
|
2012-06-29 21:12:52 +00:00
|
|
|
if (CC_UNLIKELY(mHwWorkListDirty)) {
|
|
|
|
// build the h/w work list
|
|
|
|
handleWorkList(hw);
|
|
|
|
}
|
2012-06-19 01:06:45 +00:00
|
|
|
|
2012-06-29 21:12:52 +00:00
|
|
|
if (CC_LIKELY(hw.canDraw())) {
|
|
|
|
// repaint the framebuffer (if needed)
|
|
|
|
handleRepaint(hw);
|
|
|
|
// inform the h/w that we're done compositing
|
|
|
|
hw.compositionComplete();
|
|
|
|
postFramebuffer();
|
|
|
|
} else {
|
|
|
|
// pretend we did the post
|
|
|
|
hw.compositionComplete();
|
|
|
|
}
|
2012-06-19 01:06:45 +00:00
|
|
|
|
2012-06-29 21:12:52 +00:00
|
|
|
// render to the external display if we have one
|
|
|
|
EGLSurface externalDisplaySurface = getExternalDisplaySurface();
|
|
|
|
if (externalDisplaySurface != EGL_NO_SURFACE) {
|
|
|
|
EGLSurface cur = eglGetCurrentSurface(EGL_DRAW);
|
|
|
|
EGLBoolean success = eglMakeCurrent(eglGetCurrentDisplay(),
|
|
|
|
externalDisplaySurface, externalDisplaySurface,
|
|
|
|
eglGetCurrentContext());
|
|
|
|
|
|
|
|
ALOGE_IF(!success, "eglMakeCurrent -> external failed");
|
|
|
|
|
|
|
|
if (success) {
|
|
|
|
// redraw the screen entirely...
|
|
|
|
glDisable(GL_TEXTURE_EXTERNAL_OES);
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
|
|
glClearColor(0,0,0,1);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
2012-07-11 20:48:17 +00:00
|
|
|
|
|
|
|
const Vector< sp<LayerBase> >& layers( hw.getVisibleLayersSortedByZ() );
|
2012-06-29 21:12:52 +00:00
|
|
|
const size_t count = layers.size();
|
|
|
|
for (size_t i=0 ; i<count ; ++i) {
|
|
|
|
const sp<LayerBase>& layer(layers[i]);
|
|
|
|
layer->drawForSreenShot(hw);
|
|
|
|
}
|
2012-06-19 01:06:45 +00:00
|
|
|
|
2012-06-29 21:12:52 +00:00
|
|
|
success = eglSwapBuffers(eglGetCurrentDisplay(), externalDisplaySurface);
|
|
|
|
ALOGE_IF(!success, "external display eglSwapBuffers failed");
|
2012-06-19 01:06:45 +00:00
|
|
|
|
2012-06-29 21:12:52 +00:00
|
|
|
hw.compositionComplete();
|
|
|
|
}
|
2012-06-19 01:06:45 +00:00
|
|
|
|
2012-06-29 21:12:52 +00:00
|
|
|
success = eglMakeCurrent(eglGetCurrentDisplay(),
|
|
|
|
cur, cur, eglGetCurrentContext());
|
|
|
|
|
|
|
|
ALOGE_IF(!success, "eglMakeCurrent -> internal failed");
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
2012-06-29 21:12:52 +00:00
|
|
|
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SurfaceFlinger::postFramebuffer()
|
|
|
|
{
|
2012-03-01 23:44:37 +00:00
|
|
|
ATRACE_CALL();
|
2012-02-04 23:44:04 +00:00
|
|
|
// mSwapRegion can be empty here is some cases, for instance if a hidden
|
|
|
|
// or fully transparent window is updating.
|
|
|
|
// in that case, we need to flip anyways to not risk a deadlock with
|
|
|
|
// h/w composer.
|
|
|
|
|
2012-06-21 00:51:20 +00:00
|
|
|
const DisplayHardware& hw(getDefaultDisplayHardware());
|
2012-07-25 05:46:10 +00:00
|
|
|
HWComposer& hwc(getHwComposer());
|
2012-07-11 20:48:17 +00:00
|
|
|
const Vector< sp<LayerBase> >& layers(hw.getVisibleLayersSortedByZ());
|
|
|
|
size_t numLayers = layers.size();
|
2011-10-17 01:46:35 +00:00
|
|
|
const nsecs_t now = systemTime();
|
|
|
|
mDebugInSwapBuffers = now;
|
2012-07-02 23:49:28 +00:00
|
|
|
|
|
|
|
if (hwc.initCheck() == NO_ERROR) {
|
|
|
|
HWComposer::LayerListIterator cur = hwc.begin();
|
|
|
|
const HWComposer::LayerListIterator end = hwc.end();
|
|
|
|
for (size_t i = 0; cur != end && i < numLayers; ++i, ++cur) {
|
|
|
|
if (cur->getCompositionType() == HWC_OVERLAY) {
|
2012-07-11 20:48:17 +00:00
|
|
|
layers[i]->setAcquireFence(*cur);
|
2012-07-02 23:49:28 +00:00
|
|
|
} else {
|
|
|
|
cur->setAcquireFenceFd(-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-17 01:46:35 +00:00
|
|
|
hw.flip(mSwapRegion);
|
2012-07-25 05:46:10 +00:00
|
|
|
hwc.commit();
|
2012-01-16 02:54:57 +00:00
|
|
|
|
2012-06-14 21:45:17 +00:00
|
|
|
if (hwc.initCheck() == NO_ERROR) {
|
|
|
|
HWComposer::LayerListIterator cur = hwc.begin();
|
|
|
|
const HWComposer::LayerListIterator end = hwc.end();
|
|
|
|
for (size_t i = 0; cur != end && i < numLayers; ++i, ++cur) {
|
2012-07-11 20:48:17 +00:00
|
|
|
layers[i]->onLayerDisplayed(&*cur);
|
2012-06-14 21:45:17 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (size_t i = 0; i < numLayers; i++) {
|
2012-07-11 20:48:17 +00:00
|
|
|
layers[i]->onLayerDisplayed(NULL);
|
2012-06-14 21:45:17 +00:00
|
|
|
}
|
2012-01-16 02:54:57 +00:00
|
|
|
}
|
|
|
|
|
2011-10-17 01:46:35 +00:00
|
|
|
mLastSwapBufferTime = systemTime() - now;
|
|
|
|
mDebugInSwapBuffers = 0;
|
|
|
|
mSwapRegion.clear();
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
2012-06-29 21:12:52 +00:00
|
|
|
Region SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
|
2009-03-04 03:31:44 +00:00
|
|
|
{
|
2012-03-01 23:44:37 +00:00
|
|
|
ATRACE_CALL();
|
|
|
|
|
2012-06-29 21:12:52 +00:00
|
|
|
Region dirtyRegion;
|
|
|
|
|
2011-05-19 22:38:14 +00:00
|
|
|
Mutex::Autolock _l(mStateLock);
|
|
|
|
const nsecs_t now = systemTime();
|
|
|
|
mDebugInTransaction = now;
|
|
|
|
|
|
|
|
// Here we're guaranteed that some transaction flags are set
|
|
|
|
// so we can call handleTransactionLocked() unconditionally.
|
|
|
|
// We call getTransactionFlags(), which will also clear the flags,
|
|
|
|
// with mStateLock held to guarantee that mCurrentState won't change
|
|
|
|
// until the transaction is committed.
|
|
|
|
|
|
|
|
const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
|
|
|
|
transactionFlags = getTransactionFlags(mask);
|
2012-06-29 21:12:52 +00:00
|
|
|
dirtyRegion = handleTransactionLocked(transactionFlags);
|
2011-05-19 22:38:14 +00:00
|
|
|
|
|
|
|
mLastTransactionTime = systemTime() - now;
|
|
|
|
mDebugInTransaction = 0;
|
|
|
|
invalidateHwcGeometry();
|
|
|
|
// here the transaction has been committed
|
2012-06-29 21:12:52 +00:00
|
|
|
|
|
|
|
return dirtyRegion;
|
2009-06-05 01:46:21 +00:00
|
|
|
}
|
2009-03-04 03:31:44 +00:00
|
|
|
|
2012-06-29 21:12:52 +00:00
|
|
|
Region SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
|
2009-06-05 01:46:21 +00:00
|
|
|
{
|
2012-06-29 21:12:52 +00:00
|
|
|
Region dirtyRegion;
|
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.
|
|
|
|
|
2012-06-21 00:51:20 +00:00
|
|
|
const int dpy = 0; // TODO: should be a parameter
|
|
|
|
DisplayHardware& hw(const_cast<DisplayHardware&>(getDisplayHardware(dpy)));
|
2012-07-25 04:08:59 +00:00
|
|
|
hw.setOrientation(mCurrentState.orientation);
|
2009-03-04 03:31:44 +00:00
|
|
|
|
2012-06-21 00:51:20 +00:00
|
|
|
// FIXME: mVisibleRegionsDirty & mDirtyRegion should this be per DisplayHardware?
|
2009-03-04 03:31:44 +00:00
|
|
|
mVisibleRegionsDirty = true;
|
|
|
|
mDirtyRegion.set(hw.bounds());
|
|
|
|
}
|
|
|
|
|
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
|
2012-06-29 21:12:52 +00:00
|
|
|
// TODO: we could traverse the tree from front to back and compute the actual visible region
|
|
|
|
// TODO: we could cache the transformed region
|
|
|
|
Layer::State front(layer->drawingState());
|
|
|
|
Region visibleReg = front.transform.transform(
|
|
|
|
Region(Rect(front.active.w, front.active.h)));
|
|
|
|
dirtyRegion.orSelf(visibleReg);
|
2009-04-22 22:23:34 +00:00
|
|
|
}
|
|
|
|
}
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
commitTransaction();
|
2012-06-29 21:12:52 +00:00
|
|
|
return dirtyRegion;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SurfaceFlinger::commitTransaction()
|
|
|
|
{
|
|
|
|
if (!mLayersPendingRemoval.isEmpty()) {
|
|
|
|
// Notify removed layers now that they can't be drawn from
|
|
|
|
for (size_t i = 0; i < mLayersPendingRemoval.size(); i++) {
|
|
|
|
mLayersPendingRemoval[i]->onRemoved();
|
|
|
|
}
|
|
|
|
mLayersPendingRemoval.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
mDrawingState = mCurrentState;
|
|
|
|
mTransationPending = false;
|
|
|
|
mTransactionCV.broadcast();
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SurfaceFlinger::computeVisibleRegions(
|
2011-03-12 00:54:47 +00:00
|
|
|
const LayerVector& currentLayers, Region& dirtyRegion, Region& opaqueRegion)
|
2009-03-04 03:31:44 +00:00
|
|
|
{
|
2012-03-01 23:44:37 +00:00
|
|
|
ATRACE_CALL();
|
|
|
|
|
2009-03-04 03:31:44 +00:00
|
|
|
Region aboveOpaqueLayers;
|
|
|
|
Region aboveCoveredLayers;
|
|
|
|
Region dirty;
|
|
|
|
|
2012-07-11 20:48:17 +00:00
|
|
|
dirtyRegion.clear();
|
2009-03-04 03:31:44 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
// 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
|
2011-12-15 17:51:17 +00:00
|
|
|
if (CC_LIKELY(!(s.flags & ISurfaceComposer::eLayerHidden) && s.alpha)) {
|
2011-04-20 21:20:59 +00:00
|
|
|
const bool translucent = !layer->isOpaque();
|
2012-06-29 21:12:52 +00:00
|
|
|
Rect bounds(layer->computeBounds());
|
2009-03-04 03:31:44 +00:00
|
|
|
visibleRegion.set(bounds);
|
2010-03-16 23:41:46 +00:00
|
|
|
if (!visibleRegion.isEmpty()) {
|
|
|
|
// Remove the transparent area from the visible region
|
|
|
|
if (translucent) {
|
2012-06-29 21:12:52 +00:00
|
|
|
Region transparentRegionScreen;
|
|
|
|
const Transform tr(s.transform);
|
|
|
|
if (tr.transformed()) {
|
|
|
|
if (tr.preserveRects()) {
|
|
|
|
// transform the transparent region
|
|
|
|
transparentRegionScreen = tr.transform(s.transparentRegion);
|
|
|
|
} else {
|
|
|
|
// transformation too complex, can't do the
|
|
|
|
// transparent region optimization.
|
|
|
|
transparentRegionScreen.clear();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
transparentRegionScreen = s.transparentRegion;
|
|
|
|
}
|
|
|
|
visibleRegion.subtractSelf(transparentRegionScreen);
|
2010-03-16 23:41:46 +00:00
|
|
|
}
|
2009-03-04 03:31:44 +00:00
|
|
|
|
2010-03-16 23:41:46 +00:00
|
|
|
// compute the opaque region
|
2012-06-29 21:12:52 +00:00
|
|
|
const int32_t layerOrientation = s.transform.getOrientation();
|
2010-03-16 23:41:46 +00:00
|
|
|
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
|
2012-06-29 21:12:52 +00:00
|
|
|
dirty.orSelf(layer->visibleRegion);
|
2009-03-04 03:31:44 +00:00
|
|
|
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;
|
2012-06-29 21:12:52 +00:00
|
|
|
const Region oldVisibleRegion = layer->visibleRegion;
|
|
|
|
const Region oldCoveredRegion = layer->coveredRegion;
|
2010-03-16 23:41:46 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
opaqueRegion = aboveOpaqueLayers;
|
|
|
|
}
|
|
|
|
|
2012-06-29 21:12:52 +00:00
|
|
|
Region SurfaceFlinger::handlePageFlip()
|
2009-03-04 03:31:44 +00:00
|
|
|
{
|
2012-02-24 03:27:23 +00:00
|
|
|
ATRACE_CALL();
|
2012-06-29 21:12:52 +00:00
|
|
|
Region dirtyRegion;
|
2012-02-01 02:24:27 +00:00
|
|
|
|
2011-03-12 00:54:47 +00:00
|
|
|
const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
|
2009-03-04 03:31:44 +00:00
|
|
|
|
2012-06-29 21:12:52 +00:00
|
|
|
bool visibleRegions = false;
|
|
|
|
const size_t count = currentLayers.size();
|
|
|
|
sp<LayerBase> const* layers = currentLayers.array();
|
|
|
|
for (size_t i=0 ; i<count ; i++) {
|
|
|
|
const sp<LayerBase>& layer(layers[i]);
|
|
|
|
dirtyRegion.orSelf( layer->latchBuffer(visibleRegions) );
|
|
|
|
}
|
2010-08-11 00:19:56 +00:00
|
|
|
|
2012-07-11 20:48:17 +00:00
|
|
|
mVisibleRegionsDirty |= visibleRegions;
|
2011-10-21 22:18:28 +00:00
|
|
|
|
2012-06-29 21:12:52 +00:00
|
|
|
return dirtyRegion;
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
2011-01-14 01:53:01 +00:00
|
|
|
void SurfaceFlinger::invalidateHwcGeometry()
|
|
|
|
{
|
|
|
|
mHwWorkListDirty = true;
|
|
|
|
}
|
|
|
|
|
2012-02-01 02:24:27 +00:00
|
|
|
void SurfaceFlinger::handleRefresh()
|
|
|
|
{
|
|
|
|
bool needInvalidate = false;
|
|
|
|
const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
|
|
|
|
const size_t count = currentLayers.size();
|
|
|
|
for (size_t i=0 ; i<count ; i++) {
|
|
|
|
const sp<LayerBase>& layer(currentLayers[i]);
|
|
|
|
if (layer->onPreComposition()) {
|
|
|
|
needInvalidate = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (needInvalidate) {
|
|
|
|
signalLayerUpdate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-21 00:51:20 +00:00
|
|
|
void SurfaceFlinger::handleWorkList(const DisplayHardware& hw)
|
2010-08-11 00:14:02 +00:00
|
|
|
{
|
|
|
|
mHwWorkListDirty = false;
|
2012-07-25 05:46:10 +00:00
|
|
|
HWComposer& hwc(getHwComposer());
|
2010-08-11 00:14:02 +00:00
|
|
|
if (hwc.initCheck() == NO_ERROR) {
|
2012-07-11 20:48:17 +00:00
|
|
|
const Vector< sp<LayerBase> >& currentLayers(hw.getVisibleLayersSortedByZ());
|
2010-08-11 00:14:02 +00:00
|
|
|
const size_t count = currentLayers.size();
|
|
|
|
hwc.createWorkList(count);
|
2012-05-14 03:42:01 +00:00
|
|
|
|
|
|
|
HWComposer::LayerListIterator cur = hwc.begin();
|
|
|
|
const HWComposer::LayerListIterator end = hwc.end();
|
|
|
|
for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
|
2012-06-29 21:12:52 +00:00
|
|
|
currentLayers[i]->setGeometry(hw, *cur);
|
2011-08-23 04:44:41 +00:00
|
|
|
if (mDebugDisableHWC || mDebugRegion) {
|
2012-05-14 03:42:01 +00:00
|
|
|
cur->setSkip(true);
|
2010-09-23 01:58:01 +00:00
|
|
|
}
|
2010-08-11 00:14:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-06-27 02:06:36 +00:00
|
|
|
|
2012-06-21 00:51:20 +00:00
|
|
|
void SurfaceFlinger::handleRepaint(const DisplayHardware& hw)
|
2009-03-04 03:31:44 +00:00
|
|
|
{
|
2012-03-01 23:44:37 +00:00
|
|
|
ATRACE_CALL();
|
|
|
|
|
2009-06-27 02:06:36 +00:00
|
|
|
// compute the invalid region
|
2011-09-21 00:22:44 +00:00
|
|
|
mSwapRegion.orSelf(mDirtyRegion);
|
2009-03-04 03:31:44 +00:00
|
|
|
|
2011-12-15 17:51:17 +00:00
|
|
|
if (CC_UNLIKELY(mDebugRegion)) {
|
2012-06-21 00:51:20 +00:00
|
|
|
debugFlashRegions(hw);
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
2009-06-27 02:06:36 +00:00
|
|
|
// set the frame buffer
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
2009-03-04 03:31:44 +00:00
|
|
|
|
|
|
|
uint32_t flags = hw.getFlags();
|
2012-04-16 06:34:59 +00:00
|
|
|
if (flags & DisplayHardware::SWAP_RECTANGLE) {
|
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
|
2012-04-16 06:34:59 +00:00
|
|
|
mDirtyRegion.set(mSwapRegion.bounds());
|
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())
|
2011-09-21 00:22:44 +00:00
|
|
|
mDirtyRegion.set(mSwapRegion.bounds());
|
2009-03-04 03:31:44 +00:00
|
|
|
} 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());
|
2011-09-21 00:22:44 +00:00
|
|
|
mSwapRegion = mDirtyRegion;
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-21 00:51:20 +00:00
|
|
|
setupHardwareComposer(hw);
|
|
|
|
composeSurfaces(hw, mDirtyRegion);
|
2009-03-04 03:31:44 +00:00
|
|
|
|
2011-09-21 00:21:56 +00:00
|
|
|
// update the swap region and clear the dirty region
|
|
|
|
mSwapRegion.orSelf(mDirtyRegion);
|
2009-03-04 03:31:44 +00:00
|
|
|
mDirtyRegion.clear();
|
|
|
|
}
|
|
|
|
|
2012-06-21 00:51:20 +00:00
|
|
|
void SurfaceFlinger::setupHardwareComposer(const DisplayHardware& hw)
|
2009-03-04 03:31:44 +00:00
|
|
|
{
|
2012-07-25 05:46:10 +00:00
|
|
|
HWComposer& hwc(getHwComposer());
|
2012-05-14 03:42:01 +00:00
|
|
|
HWComposer::LayerListIterator cur = hwc.begin();
|
|
|
|
const HWComposer::LayerListIterator end = hwc.end();
|
|
|
|
if (cur == end) {
|
2011-09-21 00:21:56 +00:00
|
|
|
return;
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
2010-08-11 00:14:02 +00:00
|
|
|
|
2012-07-11 20:48:17 +00:00
|
|
|
const Vector< sp<LayerBase> >& layers(hw.getVisibleLayersSortedByZ());
|
2010-08-12 22:03:26 +00:00
|
|
|
size_t count = layers.size();
|
2010-08-11 00:14:02 +00:00
|
|
|
|
2012-01-06 19:20:56 +00:00
|
|
|
ALOGE_IF(hwc.getNumLayers() != count,
|
2010-08-12 22:03:26 +00:00
|
|
|
"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
|
|
|
|
*/
|
2012-05-14 03:42:01 +00:00
|
|
|
for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
|
2011-09-09 01:31:55 +00:00
|
|
|
const sp<LayerBase>& layer(layers[i]);
|
2012-05-14 03:42:01 +00:00
|
|
|
layer->setPerFrameData(*cur);
|
2011-09-09 01:31:55 +00:00
|
|
|
}
|
|
|
|
status_t err = hwc.prepare();
|
2012-01-06 19:20:56 +00:00
|
|
|
ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
|
2011-09-09 01:31:55 +00:00
|
|
|
}
|
|
|
|
|
2012-06-21 00:51:20 +00:00
|
|
|
void SurfaceFlinger::composeSurfaces(const DisplayHardware& hw, const Region& dirty)
|
2011-09-09 01:31:55 +00:00
|
|
|
{
|
2012-07-25 05:46:10 +00:00
|
|
|
HWComposer& hwc(getHwComposer());
|
2012-05-14 03:42:01 +00:00
|
|
|
HWComposer::LayerListIterator cur = hwc.begin();
|
|
|
|
const HWComposer::LayerListIterator end = hwc.end();
|
2011-09-23 03:57:04 +00:00
|
|
|
|
|
|
|
const size_t fbLayerCount = hwc.getLayerCount(HWC_FRAMEBUFFER);
|
2012-05-14 03:42:01 +00:00
|
|
|
if (cur==end || fbLayerCount) {
|
2012-04-16 06:34:59 +00:00
|
|
|
// Never touch the framebuffer if we don't have any framebuffer layers
|
2010-08-12 22:03:26 +00:00
|
|
|
|
2012-04-18 09:28:45 +00:00
|
|
|
if (hwc.getLayerCount(HWC_OVERLAY)) {
|
|
|
|
// when using overlays, we assume a fully transparent framebuffer
|
|
|
|
// NOTE: we could reduce how much we need to clear, for instance
|
|
|
|
// remove where there are opaque FB layers. however, on some
|
|
|
|
// GPUs doing a "clean slate" glClear might be more efficient.
|
|
|
|
// We'll revisit later if needed.
|
|
|
|
glClearColor(0, 0, 0, 0);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
} else {
|
|
|
|
// screen is already cleared here
|
|
|
|
if (!mWormholeRegion.isEmpty()) {
|
|
|
|
// can happen with SurfaceView
|
|
|
|
drawWormhole();
|
|
|
|
}
|
2012-04-16 06:34:59 +00:00
|
|
|
}
|
2012-03-29 19:23:51 +00:00
|
|
|
|
2012-04-16 06:34:59 +00:00
|
|
|
/*
|
|
|
|
* and then, render the layers targeted at the framebuffer
|
|
|
|
*/
|
2012-03-29 19:23:51 +00:00
|
|
|
|
2012-07-11 20:48:17 +00:00
|
|
|
const Vector< sp<LayerBase> >& layers(hw.getVisibleLayersSortedByZ());
|
2012-04-16 06:34:59 +00:00
|
|
|
const size_t count = layers.size();
|
2012-06-29 21:12:52 +00:00
|
|
|
const Transform& tr = hw.getTransform();
|
2012-07-19 23:44:38 +00:00
|
|
|
for (size_t i=0 ; i<count ; ++i) {
|
2012-04-16 06:34:59 +00:00
|
|
|
const sp<LayerBase>& layer(layers[i]);
|
2012-06-29 21:12:52 +00:00
|
|
|
const Region clip(dirty.intersect(tr.transform(layer->visibleRegion)));
|
2012-04-16 06:34:59 +00:00
|
|
|
if (!clip.isEmpty()) {
|
2012-07-19 23:44:38 +00:00
|
|
|
if (cur != end && cur->getCompositionType() == HWC_OVERLAY) {
|
2012-05-14 03:42:01 +00:00
|
|
|
if (i && (cur->getHints() & HWC_HINT_CLEAR_FB)
|
2012-04-16 06:34:59 +00:00
|
|
|
&& layer->isOpaque()) {
|
2012-04-18 09:28:45 +00:00
|
|
|
// never clear the very first layer since we're
|
|
|
|
// guaranteed the FB is already cleared
|
2012-06-21 00:51:20 +00:00
|
|
|
layer->clearWithOpenGL(hw, clip);
|
2012-04-16 06:34:59 +00:00
|
|
|
}
|
2012-07-23 20:11:19 +00:00
|
|
|
++cur;
|
2012-04-16 06:34:59 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// render the layer
|
2012-06-21 00:51:20 +00:00
|
|
|
layer->draw(hw, clip);
|
2012-03-29 19:23:51 +00:00
|
|
|
}
|
2012-07-19 23:44:38 +00:00
|
|
|
if (cur != end) {
|
|
|
|
++cur;
|
|
|
|
}
|
2012-03-29 19:23:51 +00:00
|
|
|
}
|
|
|
|
}
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
2012-06-21 00:51:20 +00:00
|
|
|
void SurfaceFlinger::debugFlashRegions(const DisplayHardware& hw)
|
2009-03-04 03:31:44 +00:00
|
|
|
{
|
2010-06-15 04:20:00 +00:00
|
|
|
const uint32_t flags = hw.getFlags();
|
2011-08-23 04:44:41 +00:00
|
|
|
const int32_t height = hw.getHeight();
|
2011-09-21 00:22:44 +00:00
|
|
|
if (mSwapRegion.isEmpty()) {
|
2011-08-23 04:44:41 +00:00
|
|
|
return;
|
|
|
|
}
|
2010-06-15 04:20:00 +00:00
|
|
|
|
2012-04-16 06:34:59 +00:00
|
|
|
if (!(flags & DisplayHardware::SWAP_RECTANGLE)) {
|
2010-06-15 04:20:00 +00:00
|
|
|
const Region repaint((flags & DisplayHardware::PARTIAL_UPDATES) ?
|
|
|
|
mDirtyRegion.bounds() : hw.bounds());
|
2012-06-21 00:51:20 +00:00
|
|
|
composeSurfaces(hw, repaint);
|
2010-06-15 04:20:00 +00:00
|
|
|
}
|
|
|
|
|
2011-10-18 21:49:27 +00:00
|
|
|
glDisable(GL_TEXTURE_EXTERNAL_OES);
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
2009-03-04 03:31:44 +00:00
|
|
|
glDisable(GL_BLEND);
|
|
|
|
|
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] = {
|
2011-08-23 04:44:41 +00:00
|
|
|
{ r.left, height - r.top },
|
|
|
|
{ r.left, height - r.bottom },
|
|
|
|
{ r.right, height - r.bottom },
|
|
|
|
{ r.right, height - r.top }
|
2009-03-04 03:31:44 +00:00
|
|
|
};
|
|
|
|
glVertexPointer(2, GL_FLOAT, 0, vertices);
|
|
|
|
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
|
|
|
}
|
2010-06-15 04:20:00 +00:00
|
|
|
|
2011-09-21 00:22:44 +00:00
|
|
|
hw.flip(mSwapRegion);
|
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
|
|
|
}
|
|
|
|
|
|
|
|
void SurfaceFlinger::drawWormhole() const
|
|
|
|
{
|
|
|
|
const Region region(mWormholeRegion.intersect(mDirtyRegion));
|
|
|
|
if (region.isEmpty())
|
|
|
|
return;
|
|
|
|
|
2012-04-16 10:14:05 +00:00
|
|
|
glDisable(GL_TEXTURE_EXTERNAL_OES);
|
2012-04-18 09:28:45 +00:00
|
|
|
glDisable(GL_TEXTURE_2D);
|
2012-04-16 10:14:05 +00:00
|
|
|
glDisable(GL_BLEND);
|
2012-04-18 09:28:45 +00:00
|
|
|
glColor4f(0,0,0,0);
|
2012-04-16 10:14:05 +00:00
|
|
|
|
|
|
|
GLfloat vertices[4][2];
|
|
|
|
glVertexPointer(2, GL_FLOAT, 0, vertices);
|
|
|
|
Region::const_iterator it = region.begin();
|
|
|
|
Region::const_iterator const end = region.end();
|
|
|
|
while (it != end) {
|
|
|
|
const Rect& r = *it++;
|
|
|
|
vertices[0][0] = r.left;
|
|
|
|
vertices[0][1] = r.top;
|
|
|
|
vertices[1][0] = r.right;
|
|
|
|
vertices[1][1] = r.top;
|
|
|
|
vertices[2][0] = r.right;
|
|
|
|
vertices[2][1] = r.bottom;
|
|
|
|
vertices[3][0] = r.left;
|
|
|
|
vertices[3][1] = r.bottom;
|
|
|
|
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
|
|
|
}
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2010-06-03 06:28:45 +00:00
|
|
|
// attach this layer to the client
|
2011-05-03 23:21:41 +00:00
|
|
|
size_t name = client->attachLayer(lbc);
|
|
|
|
|
2010-06-03 06:28:45 +00:00
|
|
|
// add this layer to the current state list
|
2012-07-24 06:11:29 +00:00
|
|
|
Mutex::Autolock _l(mStateLock);
|
|
|
|
mCurrentState.layersSortedByZ.add(lbc);
|
2010-06-03 06:28:45 +00:00
|
|
|
|
2011-05-03 23:21:41 +00:00
|
|
|
return ssize_t(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
|
|
|
{
|
|
|
|
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
|
|
|
|
2011-12-02 18:00:00 +00:00
|
|
|
mLayersPendingRemoval.push(layerBase);
|
2009-10-03 01:12:30 +00:00
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2011-05-04 00:04:02 +00:00
|
|
|
uint32_t SurfaceFlinger::peekTransactionFlags(uint32_t flags)
|
|
|
|
{
|
|
|
|
return android_atomic_release_load(&mTransactionFlags);
|
|
|
|
}
|
|
|
|
|
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
|
2012-02-01 02:24:27 +00:00
|
|
|
signalTransaction();
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
return old;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-25 03:43:54 +00:00
|
|
|
void SurfaceFlinger::setTransactionState(
|
|
|
|
const Vector<ComposerState>& state,
|
|
|
|
const Vector<DisplayState>& displays,
|
|
|
|
uint32_t flags)
|
|
|
|
{
|
2011-06-29 02:09:31 +00:00
|
|
|
Mutex::Autolock _l(mStateLock);
|
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
|
|
|
|
2012-07-25 03:43:54 +00:00
|
|
|
int orientation = eOrientationUnchanged;
|
|
|
|
if (displays.size()) {
|
|
|
|
// TODO: handle all displays
|
|
|
|
orientation = displays[0].orientation;
|
|
|
|
}
|
|
|
|
|
2011-10-13 00:39:00 +00:00
|
|
|
uint32_t transactionFlags = 0;
|
2011-10-10 22:48:06 +00:00
|
|
|
if (mCurrentState.orientation != orientation) {
|
|
|
|
if (uint32_t(orientation)<=eOrientation270 || orientation==42) {
|
|
|
|
mCurrentState.orientation = orientation;
|
2011-10-13 00:39:00 +00:00
|
|
|
transactionFlags |= eTransactionNeeded;
|
2011-10-10 22:48:06 +00:00
|
|
|
} else if (orientation != eOrientationUnchanged) {
|
2012-01-05 23:22:43 +00:00
|
|
|
ALOGW("setTransactionState: ignoring unrecognized orientation: %d",
|
2011-10-10 22:48:06 +00:00
|
|
|
orientation);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-29 02:09:31 +00:00
|
|
|
const size_t count = state.size();
|
|
|
|
for (size_t i=0 ; i<count ; i++) {
|
|
|
|
const ComposerState& s(state[i]);
|
|
|
|
sp<Client> client( static_cast<Client *>(s.client.get()) );
|
2011-10-13 00:39:00 +00:00
|
|
|
transactionFlags |= setClientStateLocked(client, s.state);
|
2011-06-29 02:09:31 +00:00
|
|
|
}
|
2011-11-08 05:58:03 +00:00
|
|
|
|
2011-10-13 00:39:00 +00:00
|
|
|
if (transactionFlags) {
|
2011-11-08 05:58:03 +00:00
|
|
|
// this triggers the transaction
|
2011-10-13 00:39:00 +00:00
|
|
|
setTransactionFlags(transactionFlags);
|
2011-06-29 02:09:31 +00:00
|
|
|
|
2011-11-08 05:58:03 +00:00
|
|
|
// if this is a synchronous transaction, wait for it to take effect
|
|
|
|
// before returning.
|
|
|
|
if (flags & eSynchronous) {
|
|
|
|
mTransationPending = true;
|
|
|
|
}
|
|
|
|
while (mTransationPending) {
|
|
|
|
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.
|
2012-01-05 23:22:43 +00:00
|
|
|
ALOGW_IF(err == TIMED_OUT, "closeGlobalTransaction timed out!");
|
2011-11-08 05:58:03 +00:00
|
|
|
mTransationPending = 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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-24 06:11:29 +00:00
|
|
|
sp<ISurface> SurfaceFlinger::createLayer(
|
2011-04-20 21:19:32 +00:00
|
|
|
ISurfaceComposerClient::surface_data_t* params,
|
|
|
|
const String8& name,
|
|
|
|
const sp<Client>& client,
|
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;
|
2011-04-20 21:20:59 +00:00
|
|
|
sp<ISurface> surfaceHandle;
|
2009-07-10 01:16:43 +00:00
|
|
|
|
|
|
|
if (int32_t(w|h) < 0) {
|
2012-07-24 06:11:29 +00:00
|
|
|
ALOGE("createLayer() failed, w or h is negative (w=%d, h=%d)",
|
2009-07-10 01:16:43 +00:00
|
|
|
int(w), int(h));
|
|
|
|
return surfaceHandle;
|
|
|
|
}
|
2010-08-16 15:49:37 +00:00
|
|
|
|
2012-07-24 06:11:29 +00:00
|
|
|
//ALOGD("createLayer for (%d x %d), name=%s", w, h, name.string());
|
2009-03-04 03:31:44 +00:00
|
|
|
switch (flags & eFXSurfaceMask) {
|
|
|
|
case eFXSurfaceNormal:
|
2012-07-24 06:11:29 +00:00
|
|
|
layer = createNormalLayer(client, d, w, h, flags, format);
|
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:
|
2012-07-24 06:11:29 +00:00
|
|
|
layer = createDimLayer(client, d, w, h, flags);
|
2009-03-04 03:31:44 +00:00
|
|
|
break;
|
2011-10-13 23:02:48 +00:00
|
|
|
case eFXSurfaceScreenshot:
|
2012-07-24 06:11:29 +00:00
|
|
|
layer = createScreenshotLayer(client, d, w, h, flags);
|
2011-10-13 23:02:48 +00:00
|
|
|
break;
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
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);
|
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;
|
2011-04-20 21:20:59 +00:00
|
|
|
params->identity = layer->getIdentity();
|
2009-08-20 00:46:26 +00:00
|
|
|
}
|
2010-06-03 06:28:45 +00:00
|
|
|
setTransactionFlags(eTransactionNeeded);
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return surfaceHandle;
|
|
|
|
}
|
|
|
|
|
2012-07-24 06:11:29 +00:00
|
|
|
sp<Layer> SurfaceFlinger::createNormalLayer(
|
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);
|
2011-12-15 17:51:17 +00:00
|
|
|
if (CC_LIKELY(err != NO_ERROR)) {
|
2012-07-24 06:11:29 +00:00
|
|
|
ALOGE("createNormalLayer() failed (%s)", strerror(-err));
|
2009-04-10 21:24:30 +00:00
|
|
|
layer.clear();
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
return layer;
|
|
|
|
}
|
|
|
|
|
2012-07-24 06:11:29 +00:00
|
|
|
sp<LayerDim> SurfaceFlinger::createDimLayer(
|
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);
|
2011-10-13 23:02:48 +00:00
|
|
|
return layer;
|
|
|
|
}
|
|
|
|
|
2012-07-24 06:11:29 +00:00
|
|
|
sp<LayerScreenshot> SurfaceFlinger::createScreenshotLayer(
|
2011-10-13 23:02:48 +00:00
|
|
|
const sp<Client>& client, DisplayID display,
|
|
|
|
uint32_t w, uint32_t h, uint32_t flags)
|
|
|
|
{
|
|
|
|
sp<LayerScreenshot> layer = new LayerScreenshot(this, display, client);
|
2009-03-04 03:31:44 +00:00
|
|
|
return layer;
|
|
|
|
}
|
|
|
|
|
2012-07-24 06:11:29 +00:00
|
|
|
status_t SurfaceFlinger::onLayerRemoved(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);
|
2012-02-23 22:35:13 +00:00
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-07-24 06:11:29 +00:00
|
|
|
status_t SurfaceFlinger::onLayerDestroyed(const wp<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-05-19 22:38:14 +00:00
|
|
|
status_t err = NO_ERROR;
|
|
|
|
sp<LayerBaseClient> l(layer.promote());
|
|
|
|
if (l != NULL) {
|
|
|
|
Mutex::Autolock _l(mStateLock);
|
|
|
|
err = 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.
|
|
|
|
ssize_t idx = mLayerPurgatory.remove(l);
|
2012-01-06 19:20:56 +00:00
|
|
|
ALOGE_IF(idx < 0,
|
2011-05-19 22:38:14 +00:00
|
|
|
"layer=%p is not in the purgatory list", l.get());
|
2009-04-21 02:39:12 +00:00
|
|
|
}
|
2012-01-06 19:20:56 +00:00
|
|
|
ALOGE_IF(err<0 && err != NAME_NOT_FOUND,
|
2011-05-19 22:38:14 +00:00
|
|
|
"error removing layer=%p (%s)", l.get(), strerror(-err));
|
|
|
|
}
|
|
|
|
return err;
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
2011-06-29 02:09:31 +00:00
|
|
|
uint32_t SurfaceFlinger::setClientStateLocked(
|
2010-06-03 06:28:45 +00:00
|
|
|
const sp<Client>& client,
|
2011-06-29 02:09:31 +00:00
|
|
|
const layer_state_t& s)
|
2009-03-04 03:31:44 +00:00
|
|
|
{
|
|
|
|
uint32_t flags = 0;
|
2011-06-29 02:09:31 +00:00
|
|
|
sp<LayerBaseClient> layer(client->getLayerUser(s.surface));
|
|
|
|
if (layer != 0) {
|
|
|
|
const uint32_t what = s.what;
|
|
|
|
if (what & ePositionChanged) {
|
|
|
|
if (layer->setPosition(s.x, s.y))
|
|
|
|
flags |= eTraversalNeeded;
|
|
|
|
}
|
|
|
|
if (what & eLayerChanged) {
|
|
|
|
ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
|
|
|
|
if (layer->setLayer(s.z)) {
|
|
|
|
mCurrentState.layersSortedByZ.removeAt(idx);
|
|
|
|
mCurrentState.layersSortedByZ.add(layer);
|
|
|
|
// we need traversal (state changed)
|
|
|
|
// AND transaction (list changed)
|
|
|
|
flags |= eTransactionNeeded|eTraversalNeeded;
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
2011-06-29 02:09:31 +00:00
|
|
|
}
|
|
|
|
if (what & eSizeChanged) {
|
|
|
|
if (layer->setSize(s.w, s.h)) {
|
|
|
|
flags |= eTraversalNeeded;
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
}
|
2011-06-29 02:09:31 +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;
|
|
|
|
}
|
2012-05-11 03:43:55 +00:00
|
|
|
if (what & eCropChanged) {
|
|
|
|
if (layer->setCrop(s.crop))
|
|
|
|
flags |= eTraversalNeeded;
|
|
|
|
}
|
2012-07-25 04:41:09 +00:00
|
|
|
if (what & eLayerStackChanged) {
|
|
|
|
if (layer->setLayerStack(s.layerStack))
|
|
|
|
flags |= eTraversalNeeded;
|
|
|
|
}
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
2011-06-29 02:09:31 +00:00
|
|
|
return flags;
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
2012-04-11 05:09:54 +00:00
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
void SurfaceFlinger::onScreenAcquired() {
|
2012-06-07 20:17:52 +00:00
|
|
|
ALOGD("Screen about to return, flinger = %p", this);
|
2012-06-21 00:51:20 +00:00
|
|
|
const DisplayHardware& hw(getDefaultDisplayHardware()); // XXX: this should be per DisplayHardware
|
2012-07-25 05:46:10 +00:00
|
|
|
getHwComposer().acquire();
|
2012-04-11 05:09:54 +00:00
|
|
|
hw.acquireScreen();
|
2012-04-11 04:04:02 +00:00
|
|
|
mEventThread->onScreenAcquired();
|
2012-04-11 05:09:54 +00:00
|
|
|
// this is a temporary work-around, eventually this should be called
|
|
|
|
// by the power-manager
|
|
|
|
SurfaceFlinger::turnElectronBeamOn(mElectronBeamAnimationMode);
|
2012-04-11 04:04:02 +00:00
|
|
|
// from this point on, SF will process updates again
|
2012-04-13 23:18:55 +00:00
|
|
|
repaintEverything();
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
2012-04-11 05:09:54 +00:00
|
|
|
void SurfaceFlinger::onScreenReleased() {
|
2012-06-07 20:17:52 +00:00
|
|
|
ALOGD("About to give-up screen, flinger = %p", this);
|
2012-06-21 00:51:20 +00:00
|
|
|
const DisplayHardware& hw(getDefaultDisplayHardware()); // XXX: this should be per DisplayHardware
|
2012-04-11 05:09:54 +00:00
|
|
|
if (hw.isScreenAcquired()) {
|
2012-04-11 04:04:02 +00:00
|
|
|
mEventThread->onScreenReleased();
|
2012-04-11 05:09:54 +00:00
|
|
|
hw.releaseScreen();
|
2012-07-25 05:46:10 +00:00
|
|
|
getHwComposer().release();
|
2012-04-11 05:09:54 +00:00
|
|
|
// from this point on, SF will stop drawing
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-07 20:17:52 +00:00
|
|
|
void SurfaceFlinger::unblank() {
|
2012-04-11 05:09:54 +00:00
|
|
|
class MessageScreenAcquired : public MessageBase {
|
|
|
|
SurfaceFlinger* flinger;
|
|
|
|
public:
|
|
|
|
MessageScreenAcquired(SurfaceFlinger* flinger) : flinger(flinger) { }
|
|
|
|
virtual bool handler() {
|
|
|
|
flinger->onScreenAcquired();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
sp<MessageBase> msg = new MessageScreenAcquired(this);
|
|
|
|
postMessageSync(msg);
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
2012-06-07 20:17:52 +00:00
|
|
|
void SurfaceFlinger::blank() {
|
2012-04-11 05:09:54 +00:00
|
|
|
class MessageScreenReleased : public MessageBase {
|
|
|
|
SurfaceFlinger* flinger;
|
|
|
|
public:
|
|
|
|
MessageScreenReleased(SurfaceFlinger* flinger) : flinger(flinger) { }
|
|
|
|
virtual bool handler() {
|
|
|
|
flinger->onScreenReleased();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
sp<MessageBase> msg = new MessageScreenReleased(this);
|
|
|
|
postMessageSync(msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
2009-03-04 03:31:44 +00:00
|
|
|
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;
|
2011-06-27 23:05:52 +00:00
|
|
|
|
|
|
|
if (!PermissionCache::checkCallingPermission(sDump)) {
|
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
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
|
2012-01-20 02:34:40 +00:00
|
|
|
bool dumpAll = true;
|
|
|
|
size_t index = 0;
|
2012-01-29 06:31:55 +00:00
|
|
|
size_t numArgs = args.size();
|
|
|
|
if (numArgs) {
|
|
|
|
if ((index < numArgs) &&
|
|
|
|
(args[index] == String16("--list"))) {
|
|
|
|
index++;
|
|
|
|
listLayersLocked(args, index, result, buffer, SIZE);
|
2012-03-09 06:01:51 +00:00
|
|
|
dumpAll = false;
|
2012-01-29 06:31:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((index < numArgs) &&
|
|
|
|
(args[index] == String16("--latency"))) {
|
2012-01-20 02:34:40 +00:00
|
|
|
index++;
|
|
|
|
dumpStatsLocked(args, index, result, buffer, SIZE);
|
2012-03-09 06:01:51 +00:00
|
|
|
dumpAll = false;
|
2012-01-20 02:34:40 +00:00
|
|
|
}
|
2012-01-29 06:31:55 +00:00
|
|
|
|
|
|
|
if ((index < numArgs) &&
|
|
|
|
(args[index] == String16("--latency-clear"))) {
|
|
|
|
index++;
|
|
|
|
clearStatsLocked(args, index, result, buffer, SIZE);
|
2012-03-09 06:01:51 +00:00
|
|
|
dumpAll = false;
|
2012-01-29 06:31:55 +00:00
|
|
|
}
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
2010-04-21 00:55:49 +00:00
|
|
|
|
2012-01-20 02:34:40 +00:00
|
|
|
if (dumpAll) {
|
|
|
|
dumpAllLocked(result, buffer, SIZE);
|
|
|
|
}
|
2011-01-20 00:15:53 +00:00
|
|
|
|
2012-01-20 02:34:40 +00:00
|
|
|
if (locked) {
|
|
|
|
mStateLock.unlock();
|
2011-01-20 00:15:53 +00:00
|
|
|
}
|
2012-01-20 02:34:40 +00:00
|
|
|
}
|
|
|
|
write(fd, result.string(), result.size());
|
|
|
|
return NO_ERROR;
|
|
|
|
}
|
2011-01-20 00:15:53 +00:00
|
|
|
|
2012-01-29 06:31:55 +00:00
|
|
|
void SurfaceFlinger::listLayersLocked(const Vector<String16>& args, size_t& index,
|
|
|
|
String8& result, char* buffer, size_t SIZE) const
|
|
|
|
{
|
|
|
|
const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
|
|
|
|
const size_t count = currentLayers.size();
|
|
|
|
for (size_t i=0 ; i<count ; i++) {
|
|
|
|
const sp<LayerBase>& layer(currentLayers[i]);
|
|
|
|
snprintf(buffer, SIZE, "%s\n", layer->getName().string());
|
|
|
|
result.append(buffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-20 02:34:40 +00:00
|
|
|
void SurfaceFlinger::dumpStatsLocked(const Vector<String16>& args, size_t& index,
|
|
|
|
String8& result, char* buffer, size_t SIZE) const
|
|
|
|
{
|
|
|
|
String8 name;
|
|
|
|
if (index < args.size()) {
|
|
|
|
name = String8(args[index]);
|
|
|
|
index++;
|
|
|
|
}
|
2011-01-20 00:15:53 +00:00
|
|
|
|
2012-01-20 02:34:40 +00:00
|
|
|
const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
|
|
|
|
const size_t count = currentLayers.size();
|
|
|
|
for (size_t i=0 ; i<count ; i++) {
|
|
|
|
const sp<LayerBase>& layer(currentLayers[i]);
|
|
|
|
if (name.isEmpty()) {
|
|
|
|
snprintf(buffer, SIZE, "%s\n", layer->getName().string());
|
|
|
|
result.append(buffer);
|
|
|
|
}
|
|
|
|
if (name.isEmpty() || (name == layer->getName())) {
|
|
|
|
layer->dumpStats(result, buffer, SIZE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-07-15 01:01:49 +00:00
|
|
|
|
2012-01-29 06:31:55 +00:00
|
|
|
void SurfaceFlinger::clearStatsLocked(const Vector<String16>& args, size_t& index,
|
|
|
|
String8& result, char* buffer, size_t SIZE) const
|
|
|
|
{
|
|
|
|
String8 name;
|
|
|
|
if (index < args.size()) {
|
|
|
|
name = String8(args[index]);
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
|
|
|
|
const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
|
|
|
|
const size_t count = currentLayers.size();
|
|
|
|
for (size_t i=0 ; i<count ; i++) {
|
|
|
|
const sp<LayerBase>& layer(currentLayers[i]);
|
|
|
|
if (name.isEmpty() || (name == layer->getName())) {
|
|
|
|
layer->clearStats();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-20 02:34:40 +00:00
|
|
|
void SurfaceFlinger::dumpAllLocked(
|
|
|
|
String8& result, char* buffer, size_t SIZE) const
|
|
|
|
{
|
|
|
|
// 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;
|
2011-11-30 01:55:46 +00:00
|
|
|
|
2012-01-20 02:34:40 +00:00
|
|
|
/*
|
|
|
|
* Dump the visible layer list
|
|
|
|
*/
|
|
|
|
const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
|
|
|
|
const size_t count = currentLayers.size();
|
|
|
|
snprintf(buffer, SIZE, "Visible layers (count = %d)\n", count);
|
|
|
|
result.append(buffer);
|
|
|
|
for (size_t i=0 ; i<count ; i++) {
|
|
|
|
const sp<LayerBase>& layer(currentLayers[i]);
|
|
|
|
layer->dump(result, buffer, SIZE);
|
|
|
|
}
|
2011-11-30 01:55:46 +00:00
|
|
|
|
2012-01-20 02:34:40 +00:00
|
|
|
/*
|
|
|
|
* Dump the layers in the purgatory
|
|
|
|
*/
|
2011-07-15 01:01:49 +00:00
|
|
|
|
2012-01-20 02:34:40 +00:00
|
|
|
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);
|
|
|
|
}
|
2010-04-21 00:55:49 +00:00
|
|
|
|
2012-01-20 02:34:40 +00:00
|
|
|
/*
|
|
|
|
* Dump SurfaceFlinger global state
|
|
|
|
*/
|
2010-04-21 00:55:49 +00:00
|
|
|
|
2012-01-20 02:34:40 +00:00
|
|
|
snprintf(buffer, SIZE, "SurfaceFlinger global state:\n");
|
|
|
|
result.append(buffer);
|
2010-04-21 00:55:49 +00:00
|
|
|
|
2012-06-21 00:51:20 +00:00
|
|
|
const DisplayHardware& hw(getDefaultDisplayHardware());
|
2012-01-20 02:34:40 +00:00
|
|
|
const GLExtensions& extensions(GLExtensions::getInstance());
|
|
|
|
snprintf(buffer, SIZE, "GLES: %s, %s, %s\n",
|
|
|
|
extensions.getVendor(),
|
|
|
|
extensions.getRenderer(),
|
|
|
|
extensions.getVersion());
|
|
|
|
result.append(buffer);
|
2011-11-18 01:49:17 +00:00
|
|
|
|
2012-01-20 02:34:40 +00:00
|
|
|
snprintf(buffer, SIZE, "EGL : %s\n",
|
2012-06-21 00:51:20 +00:00
|
|
|
eglQueryString(hw.getEGLDisplay(),
|
2012-01-20 02:34:40 +00:00
|
|
|
EGL_VERSION_HW_ANDROID));
|
|
|
|
result.append(buffer);
|
2010-09-23 01:58:01 +00:00
|
|
|
|
2012-01-20 02:34:40 +00:00
|
|
|
snprintf(buffer, SIZE, "EXTS: %s\n", extensions.getExtension());
|
|
|
|
result.append(buffer);
|
2009-08-26 23:36:26 +00:00
|
|
|
|
2012-01-20 02:34:40 +00:00
|
|
|
mWormholeRegion.dump(result, "WormholeRegion");
|
|
|
|
snprintf(buffer, SIZE,
|
|
|
|
" orientation=%d, canDraw=%d\n",
|
|
|
|
mCurrentState.orientation, hw.canDraw());
|
|
|
|
result.append(buffer);
|
|
|
|
snprintf(buffer, SIZE,
|
|
|
|
" last eglSwapBuffers() time: %f us\n"
|
|
|
|
" last transaction time : %f us\n"
|
2012-02-05 08:19:27 +00:00
|
|
|
" transaction-flags : %08x\n"
|
2012-01-20 02:34:40 +00:00
|
|
|
" refresh-rate : %f fps\n"
|
|
|
|
" x-dpi : %f\n"
|
2012-03-22 19:15:54 +00:00
|
|
|
" y-dpi : %f\n"
|
|
|
|
" density : %f\n",
|
2012-01-20 02:34:40 +00:00
|
|
|
mLastSwapBufferTime/1000.0,
|
|
|
|
mLastTransactionTime/1000.0,
|
2012-02-05 08:19:27 +00:00
|
|
|
mTransactionFlags,
|
2012-01-20 02:34:40 +00:00
|
|
|
hw.getRefreshRate(),
|
|
|
|
hw.getDpiX(),
|
2012-03-22 19:15:54 +00:00
|
|
|
hw.getDpiY(),
|
|
|
|
hw.getDensity());
|
2012-01-20 02:34:40 +00:00
|
|
|
result.append(buffer);
|
|
|
|
|
|
|
|
snprintf(buffer, SIZE, " eglSwapBuffers time: %f us\n",
|
|
|
|
inSwapBuffersDuration/1000.0);
|
|
|
|
result.append(buffer);
|
|
|
|
|
|
|
|
snprintf(buffer, SIZE, " transaction time: %f us\n",
|
|
|
|
inTransactionDuration/1000.0);
|
|
|
|
result.append(buffer);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* VSYNC state
|
|
|
|
*/
|
|
|
|
mEventThread->dump(result, buffer, SIZE);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Dump HWComposer state
|
|
|
|
*/
|
2012-07-25 05:46:10 +00:00
|
|
|
HWComposer& hwc(getHwComposer());
|
2012-01-20 02:34:40 +00:00
|
|
|
snprintf(buffer, SIZE, "h/w composer state:\n");
|
|
|
|
result.append(buffer);
|
|
|
|
snprintf(buffer, SIZE, " h/w composer %s and %s\n",
|
|
|
|
hwc.initCheck()==NO_ERROR ? "present" : "not present",
|
|
|
|
(mDebugDisableHWC || mDebugRegion) ? "disabled" : "enabled");
|
|
|
|
result.append(buffer);
|
2012-07-11 20:48:17 +00:00
|
|
|
hwc.dump(result, buffer, SIZE, hw.getVisibleLayersSortedByZ());
|
2012-01-20 02:34:40 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Dump gralloc state
|
|
|
|
*/
|
|
|
|
const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
|
|
|
|
alloc.dump(result);
|
|
|
|
hw.dump(result);
|
2009-03-04 03:31:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
status_t SurfaceFlinger::onTransact(
|
|
|
|
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
|
|
|
|
{
|
|
|
|
switch (code) {
|
|
|
|
case CREATE_CONNECTION:
|
2011-06-29 02:09:31 +00:00
|
|
|
case SET_TRANSACTION_STATE:
|
2009-03-04 03:31:44 +00:00
|
|
|
case SET_ORIENTATION:
|
|
|
|
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:
|
2012-06-07 20:17:52 +00:00
|
|
|
case BLANK:
|
|
|
|
case UNBLANK:
|
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();
|
2011-06-27 23:05:52 +00:00
|
|
|
if ((uid != AID_GRAPHICS) &&
|
|
|
|
!PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid)) {
|
2012-01-06 19:20:56 +00:00
|
|
|
ALOGE("Permission Denial: "
|
2009-06-16 01:24:59 +00:00
|
|
|
"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();
|
2011-06-27 23:05:52 +00:00
|
|
|
if ((uid != AID_GRAPHICS) &&
|
|
|
|
!PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) {
|
2012-01-06 19:20:56 +00:00
|
|
|
ALOGE("Permission Denial: "
|
2010-09-24 18:26:58 +00:00
|
|
|
"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);
|
2011-12-15 17:51:17 +00:00
|
|
|
if (CC_UNLIKELY(!PermissionCache::checkCallingPermission(sHardwareTest))) {
|
2009-06-16 01:24:59 +00:00
|
|
|
IPCThreadState* ipc = IPCThreadState::self();
|
|
|
|
const int pid = ipc->getCallingPid();
|
|
|
|
const int uid = ipc->getCallingUid();
|
2012-01-06 19:20:56 +00:00
|
|
|
ALOGE("Permission Denial: "
|
2009-06-16 01:24:59 +00:00
|
|
|
"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);
|
2011-08-23 04:44:41 +00:00
|
|
|
invalidateHwcGeometry();
|
|
|
|
repaintEverything();
|
2009-03-04 03:31:44 +00:00
|
|
|
return NO_ERROR;
|
|
|
|
case 1004:{ // repaint everything
|
2011-08-23 04:44:41 +00:00
|
|
|
repaintEverything();
|
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
|
|
|
}
|
2012-02-24 04:05:39 +00:00
|
|
|
case 1006:{ // send empty update
|
|
|
|
signalRefresh();
|
|
|
|
return NO_ERROR;
|
|
|
|
}
|
2011-08-23 04:44:41 +00:00
|
|
|
case 1008: // toggle use of hw composer
|
|
|
|
n = data.readInt32();
|
|
|
|
mDebugDisableHWC = n ? 1 : 0;
|
|
|
|
invalidateHwcGeometry();
|
|
|
|
repaintEverything();
|
|
|
|
return NO_ERROR;
|
2011-08-24 01:03:18 +00:00
|
|
|
case 1009: // toggle use of transform hint
|
|
|
|
n = data.readInt32();
|
|
|
|
mDebugDisableTransformHint = n ? 1 : 0;
|
|
|
|
invalidateHwcGeometry();
|
|
|
|
repaintEverything();
|
|
|
|
return NO_ERROR;
|
2009-03-04 03:31:44 +00:00
|
|
|
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);
|
2012-04-18 09:28:45 +00:00
|
|
|
reply->writeInt32(0);
|
2012-02-07 05:21:05 +00:00
|
|
|
reply->writeInt32(mDebugDisableHWC);
|
2009-03-04 03:31:44 +00:00
|
|
|
return NO_ERROR;
|
|
|
|
case 1013: {
|
|
|
|
Mutex::Autolock _l(mStateLock);
|
2012-06-21 00:51:20 +00:00
|
|
|
const DisplayHardware& hw(getDefaultDisplayHardware());
|
2009-03-04 03:31:44 +00:00
|
|
|
reply->writeInt32(hw.getPageFlipCount());
|
|
|
|
}
|
|
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2011-08-23 04:44:41 +00:00
|
|
|
void SurfaceFlinger::repaintEverything() {
|
2012-06-21 00:51:20 +00:00
|
|
|
const DisplayHardware& hw(getDefaultDisplayHardware()); // FIXME: this cannot be bound the default display
|
2011-10-21 22:18:28 +00:00
|
|
|
const Rect bounds(hw.getBounds());
|
|
|
|
setInvalidateRegion(Region(bounds));
|
2012-02-01 02:24:27 +00:00
|
|
|
signalTransaction();
|
2011-08-23 04:44:41 +00:00
|
|
|
}
|
|
|
|
|
2011-10-21 22:18:28 +00:00
|
|
|
void SurfaceFlinger::setInvalidateRegion(const Region& reg) {
|
|
|
|
Mutex::Autolock _l(mInvalidateLock);
|
|
|
|
mInvalidateRegion = reg;
|
|
|
|
}
|
|
|
|
|
|
|
|
Region SurfaceFlinger::getAndClearInvalidateRegion() {
|
|
|
|
Mutex::Autolock _l(mInvalidateLock);
|
|
|
|
Region reg(mInvalidateRegion);
|
|
|
|
mInvalidateRegion.clear();
|
|
|
|
return reg;
|
|
|
|
}
|
|
|
|
|
2010-10-11 19:37:43 +00:00
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
2011-10-13 23:02:48 +00:00
|
|
|
status_t SurfaceFlinger::renderScreenToTexture(DisplayID dpy,
|
|
|
|
GLuint* textureName, GLfloat* uOut, GLfloat* vOut)
|
|
|
|
{
|
|
|
|
Mutex::Autolock _l(mStateLock);
|
|
|
|
return renderScreenToTextureLocked(dpy, textureName, uOut, vOut);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2012-04-11 04:04:02 +00:00
|
|
|
ATRACE_CALL();
|
|
|
|
|
2010-10-11 19:37:43 +00:00
|
|
|
if (!GLExtensions::getInstance().haveFramebufferObject())
|
|
|
|
return INVALID_OPERATION;
|
|
|
|
|
|
|
|
// get screen geometry
|
2012-06-21 00:51:20 +00:00
|
|
|
const DisplayHardware& hw(getDisplayHardware(dpy));
|
2010-10-11 19:37:43 +00:00
|
|
|
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);
|
2012-04-16 06:34:59 +00:00
|
|
|
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
|
|
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
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...
|
2011-10-18 21:49:27 +00:00
|
|
|
glDisable(GL_TEXTURE_EXTERNAL_OES);
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
2010-10-12 23:05:48 +00:00
|
|
|
glClearColor(0,0,0,1);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
2011-10-11 02:02:07 +00:00
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
2012-07-11 20:48:17 +00:00
|
|
|
const Vector< sp<LayerBase> >& layers(hw.getVisibleLayersSortedByZ());
|
2010-10-12 23:05:48 +00:00
|
|
|
const size_t count = layers.size();
|
|
|
|
for (size_t i=0 ; i<count ; ++i) {
|
|
|
|
const sp<LayerBase>& layer(layers[i]);
|
2012-06-21 00:51:20 +00:00
|
|
|
layer->drawForSreenShot(hw);
|
2010-10-12 23:05:48 +00:00
|
|
|
}
|
2010-10-11 19:37:43 +00:00
|
|
|
|
2011-10-13 23:02:48 +00:00
|
|
|
hw.compositionComplete();
|
|
|
|
|
2010-10-12 23:05:48 +00:00
|
|
|
// back to main framebuffer
|
|
|
|
glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
|
|
|
|
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
|
|
|
|
2012-05-18 21:18:08 +00:00
|
|
|
class VSyncWaiter {
|
|
|
|
DisplayEventReceiver::Event buffer[4];
|
|
|
|
sp<Looper> looper;
|
|
|
|
sp<IDisplayEventConnection> events;
|
|
|
|
sp<BitTube> eventTube;
|
|
|
|
public:
|
|
|
|
VSyncWaiter(const sp<EventThread>& eventThread) {
|
|
|
|
looper = new Looper(true);
|
|
|
|
events = eventThread->createEventConnection();
|
|
|
|
eventTube = events->getDataChannel();
|
|
|
|
looper->addFd(eventTube->getFd(), 0, ALOOPER_EVENT_INPUT, 0, 0);
|
|
|
|
events->requestNextVsync();
|
|
|
|
}
|
|
|
|
|
|
|
|
void wait() {
|
|
|
|
ssize_t n;
|
|
|
|
|
|
|
|
looper->pollOnce(-1);
|
|
|
|
// we don't handle any errors here, it doesn't matter
|
|
|
|
// and we don't want to take the risk to get stuck.
|
|
|
|
|
|
|
|
// drain the events...
|
|
|
|
while ((n = DisplayEventReceiver::getEvents(
|
|
|
|
eventTube, buffer, 4)) > 0) ;
|
|
|
|
|
|
|
|
events->requestNextVsync();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2010-10-12 23:05:48 +00:00
|
|
|
status_t SurfaceFlinger::electronBeamOffAnimationImplLocked()
|
|
|
|
{
|
|
|
|
// get screen geometry
|
2012-06-21 00:51:20 +00:00
|
|
|
const DisplayHardware& hw(getDefaultDisplayHardware());
|
2010-10-12 23:05:48 +00:00
|
|
|
const uint32_t hw_w = hw.getWidth();
|
|
|
|
const uint32_t hw_h = hw.getHeight();
|
2011-10-11 02:02:07 +00:00
|
|
|
const Region screenBounds(hw.getBounds());
|
2010-10-11 19:37:43 +00:00
|
|
|
|
2010-10-12 23:05:48 +00:00
|
|
|
GLfloat u, v;
|
|
|
|
GLuint tname;
|
2011-10-13 23:02:48 +00:00
|
|
|
status_t result = renderScreenToTextureLocked(0, &tname, &u, &v);
|
2010-10-12 23:05:48 +00:00
|
|
|
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];
|
2011-10-11 02:02:07 +00:00
|
|
|
const GLfloat texCoords[4][2] = { {0,0}, {0,v}, {u,v}, {u,0} };
|
2010-10-12 23:05:48 +00:00
|
|
|
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);
|
2012-01-13 08:36:45 +00:00
|
|
|
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
|
|
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
2010-10-12 23:05:48 +00:00
|
|
|
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
|
|
|
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
|
|
glVertexPointer(2, GL_FLOAT, 0, vtx);
|
|
|
|
|
2011-07-08 00:30:31 +00:00
|
|
|
/*
|
|
|
|
* Texture coordinate mapping
|
|
|
|
*
|
|
|
|
* u
|
|
|
|
* 1 +----------+---+
|
|
|
|
* | | | | image is inverted
|
|
|
|
* | V | | w.r.t. the texture
|
|
|
|
* 1-v +----------+ | coordinates
|
|
|
|
* | |
|
|
|
|
* | |
|
|
|
|
* | |
|
|
|
|
* 0 +--------------+
|
|
|
|
* 0 1
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2010-10-12 23:05:48 +00:00
|
|
|
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;
|
2011-07-08 00:30:31 +00:00
|
|
|
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-12 23:05:48 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
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;
|
2011-07-08 00:30:31 +00:00
|
|
|
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-12 23:05:48 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-05-18 21:18:08 +00:00
|
|
|
VSyncWaiter vsync(mEventThread);
|
|
|
|
|
2010-10-12 23:05:48 +00:00
|
|
|
// the full animation is 24 frames
|
2011-07-08 00:30:31 +00:00
|
|
|
char value[PROPERTY_VALUE_MAX];
|
|
|
|
property_get("debug.sf.electron_frames", value, "24");
|
|
|
|
int nbFrames = (atoi(value) + 1) >> 1;
|
|
|
|
if (nbFrames <= 0) // just in case
|
|
|
|
nbFrames = 24;
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
v_stretch vverts(hw_w, hw_h);
|
2011-10-11 02:02:07 +00:00
|
|
|
|
|
|
|
glMatrixMode(GL_TEXTURE);
|
|
|
|
glLoadIdentity();
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
|
|
|
|
2010-10-12 23:05:48 +00:00
|
|
|
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);
|
|
|
|
|
2012-05-18 21:18:08 +00:00
|
|
|
// wait for vsync
|
|
|
|
vsync.wait();
|
|
|
|
|
2010-10-12 23:05:48 +00:00
|
|
|
// 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);
|
2012-05-18 21:18:08 +00:00
|
|
|
|
|
|
|
// wait for vsync
|
|
|
|
vsync.wait();
|
|
|
|
|
2010-10-12 23:05:48 +00:00
|
|
|
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);
|
|
|
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
|
|
glDeleteTextures(1, &tname);
|
2011-04-20 21:20:59 +00:00
|
|
|
glDisable(GL_TEXTURE_2D);
|
2011-10-18 21:49:27 +00:00
|
|
|
glDisable(GL_BLEND);
|
2010-10-12 23:05:48 +00:00
|
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
status_t SurfaceFlinger::electronBeamOnAnimationImplLocked()
|
|
|
|
{
|
|
|
|
status_t result = PERMISSION_DENIED;
|
|
|
|
|
|
|
|
if (!GLExtensions::getInstance().haveFramebufferObject())
|
|
|
|
return INVALID_OPERATION;
|
|
|
|
|
|
|
|
|
|
|
|
// get screen geometry
|
2012-06-21 00:51:20 +00:00
|
|
|
const DisplayHardware& hw(getDefaultDisplayHardware());
|
2010-10-12 23:05:48 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
GLfloat vtx[8];
|
|
|
|
const GLfloat texCoords[4][2] = { {0,v}, {0,0}, {u,0}, {u,v} };
|
|
|
|
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);
|
2012-01-13 08:36:45 +00:00
|
|
|
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
|
|
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
2010-10-12 23:05:48 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-05-18 21:18:08 +00:00
|
|
|
VSyncWaiter vsync(mEventThread);
|
|
|
|
|
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);
|
2012-05-18 21:18:08 +00:00
|
|
|
|
|
|
|
// wait for vsync
|
|
|
|
vsync.wait();
|
|
|
|
|
2010-10-12 23:05:48 +00:00
|
|
|
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
|
|
|
|
2012-05-18 21:18:08 +00:00
|
|
|
// wait for vsync
|
|
|
|
vsync.wait();
|
|
|
|
|
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);
|
|
|
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
2010-10-11 19:37:43 +00:00
|
|
|
glDeleteTextures(1, &tname);
|
2011-04-20 21:20:59 +00:00
|
|
|
glDisable(GL_TEXTURE_2D);
|
2011-10-18 21:49:27 +00:00
|
|
|
glDisable(GL_BLEND);
|
2010-10-11 19:37:43 +00:00
|
|
|
|
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
|
|
|
{
|
2012-04-11 04:04:02 +00:00
|
|
|
ATRACE_CALL();
|
|
|
|
|
2012-06-21 00:51:20 +00:00
|
|
|
DisplayHardware& hw(const_cast<DisplayHardware&>(getDefaultDisplayHardware()));
|
2010-10-12 23:05:48 +00:00
|
|
|
if (!hw.canDraw()) {
|
|
|
|
// we're already off
|
|
|
|
return NO_ERROR;
|
|
|
|
}
|
2011-09-02 19:22:39 +00:00
|
|
|
|
|
|
|
// turn off hwc while we're doing the animation
|
2012-07-25 05:46:10 +00:00
|
|
|
getHwComposer().disable();
|
2011-09-02 19:22:39 +00:00
|
|
|
// and make sure to turn it back on (if needed) next time we compose
|
|
|
|
invalidateHwcGeometry();
|
|
|
|
|
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);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
hw.flip( Region(hw.bounds()) );
|
|
|
|
|
2010-10-14 19:19:37 +00:00
|
|
|
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
|
|
|
{
|
2012-06-21 00:51:20 +00:00
|
|
|
DisplayHardware& hw(const_cast<DisplayHardware&>(getDefaultDisplayHardware()));
|
2010-10-12 23:05:48 +00:00
|
|
|
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:46:24 +00:00
|
|
|
|
|
|
|
// make sure to redraw the whole screen when the animation is done
|
|
|
|
mDirtyRegion.set(hw.bounds());
|
2012-02-01 02:24:27 +00:00
|
|
|
signalTransaction();
|
2010-10-14 19:46:24 +00:00
|
|
|
|
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
|
|
|
{
|
2012-03-12 19:18:42 +00:00
|
|
|
ATRACE_CALL();
|
|
|
|
|
2010-09-29 20:02:36 +00:00
|
|
|
status_t result = PERMISSION_DENIED;
|
|
|
|
|
|
|
|
// only one display supported for now
|
2012-07-11 20:48:17 +00:00
|
|
|
if (CC_UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT)) {
|
2010-09-29 20:02:36 +00:00
|
|
|
return BAD_VALUE;
|
2012-07-11 20:48:17 +00:00
|
|
|
}
|
2010-09-29 20:02:36 +00:00
|
|
|
|
2012-07-11 20:48:17 +00:00
|
|
|
if (!GLExtensions::getInstance().haveFramebufferObject()) {
|
2010-09-29 20:02:36 +00:00
|
|
|
return INVALID_OPERATION;
|
2012-07-11 20:48:17 +00:00
|
|
|
}
|
2010-09-29 20:02:36 +00:00
|
|
|
|
|
|
|
// get screen geometry
|
2012-06-21 00:51:20 +00:00
|
|
|
const DisplayHardware& hw(getDisplayHardware(dpy));
|
2010-09-29 20:02:36 +00:00
|
|
|
const uint32_t hw_w = hw.getWidth();
|
|
|
|
const uint32_t hw_h = hw.getHeight();
|
|
|
|
|
2012-07-11 20:48:17 +00:00
|
|
|
// if we have secure windows on this display, never allow the screen capture
|
|
|
|
if (hw.getSecureLayerVisible()) {
|
|
|
|
return PERMISSION_DENIED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((sw > hw_w) || (sh > hw_h)) {
|
2010-09-29 20:02:36 +00:00
|
|
|
return BAD_VALUE;
|
2012-07-11 20:48:17 +00:00
|
|
|
}
|
2010-09-29 20:02:36 +00:00
|
|
|
|
|
|
|
sw = (!sw) ? hw_w : sw;
|
|
|
|
sh = (!sh) ? hw_h : sh;
|
|
|
|
const size_t size = sw * sh * 4;
|
|
|
|
|
2011-12-20 16:23:08 +00:00
|
|
|
//ALOGD("screenshot: sw=%d, sh=%d, minZ=%d, maxZ=%d",
|
2011-03-03 02:45:50 +00:00
|
|
|
// 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);
|
2012-03-12 19:18:42 +00:00
|
|
|
|
2010-09-29 20:02:36 +00:00
|
|
|
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);
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glPushMatrix();
|
|
|
|
glLoadIdentity();
|
2011-07-08 00:30:31 +00:00
|
|
|
glOrthof(0, hw_w, hw_h, 0, 0, 1);
|
2010-09-29 20:02:36 +00:00
|
|
|
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
|
|
|
|
2011-10-07 21:51:16 +00:00
|
|
|
const LayerVector& layers(mDrawingState.layersSortedByZ);
|
|
|
|
const size_t count = layers.size();
|
2010-09-29 20:02:36 +00:00
|
|
|
for (size_t i=0 ; i<count ; ++i) {
|
|
|
|
const sp<LayerBase>& layer(layers[i]);
|
2011-08-25 21:36:43 +00:00
|
|
|
const uint32_t flags = layer->drawingState().flags;
|
|
|
|
if (!(flags & ISurfaceComposer::eLayerHidden)) {
|
|
|
|
const uint32_t z = layer->drawingState().z;
|
|
|
|
if (z >= minLayerZ && z <= maxLayerZ) {
|
2012-06-21 00:51:20 +00:00
|
|
|
layer->drawForSreenShot(hw);
|
2011-08-25 21:36:43 +00:00
|
|
|
}
|
2010-12-11 00:22:31 +00:00
|
|
|
}
|
2010-09-29 20:02:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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()
|
2012-03-12 19:18:42 +00:00
|
|
|
ScopedTrace _t(ATRACE_TAG, "glReadPixels");
|
2010-09-29 20:02:36 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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-12-20 16:23:08 +00:00
|
|
|
// ALOGD("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
|
2011-12-15 17:51:17 +00:00
|
|
|
if (CC_UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
|
2010-09-24 18:26:58 +00:00
|
|
|
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);
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
2012-07-24 06:11:29 +00:00
|
|
|
SurfaceFlinger::LayerVector::LayerVector() {
|
|
|
|
}
|
|
|
|
|
|
|
|
SurfaceFlinger::LayerVector::LayerVector(const LayerVector& rhs)
|
|
|
|
: SortedVector<sp<LayerBase> >(rhs) {
|
|
|
|
}
|
|
|
|
|
|
|
|
int SurfaceFlinger::LayerVector::do_compare(const void* lhs,
|
|
|
|
const void* rhs) const
|
2009-03-04 03:31:44 +00:00
|
|
|
{
|
2012-07-24 06:11:29 +00:00
|
|
|
const sp<LayerBase>& l(*reinterpret_cast<const sp<LayerBase>*>(lhs));
|
|
|
|
const sp<LayerBase>& r(*reinterpret_cast<const sp<LayerBase>*>(rhs));
|
|
|
|
// sort layers by Z order
|
|
|
|
uint32_t lz = l->currentState().z;
|
|
|
|
uint32_t rz = r->currentState().z;
|
|
|
|
// then by sequence, so we get a stable ordering
|
|
|
|
return (lz != rz) ? (lz - rz) : (l->sequence - r->sequence);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
SurfaceFlinger::State::State()
|
|
|
|
: orientation(ISurfaceComposer::eOrientationDefault),
|
|
|
|
orientationFlags(0) {
|
2010-06-01 22:12:58 +00:00
|
|
|
}
|
2009-07-03 01:11:53 +00:00
|
|
|
|
2010-06-01 22:12:58 +00:00
|
|
|
// ---------------------------------------------------------------------------
|
2010-06-03 06:28:45 +00:00
|
|
|
|
2011-01-13 02:30:40 +00:00
|
|
|
GraphicBufferAlloc::GraphicBufferAlloc() {}
|
|
|
|
|
|
|
|
GraphicBufferAlloc::~GraphicBufferAlloc() {}
|
|
|
|
|
|
|
|
sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t w, uint32_t h,
|
2011-07-01 21:53:49 +00:00
|
|
|
PixelFormat format, uint32_t usage, status_t* error) {
|
2011-01-13 02:30:40 +00:00
|
|
|
sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(w, h, format, usage));
|
|
|
|
status_t err = graphicBuffer->initCheck();
|
2011-07-01 21:53:49 +00:00
|
|
|
*error = err;
|
2011-04-20 21:20:59 +00:00
|
|
|
if (err != 0 || graphicBuffer->handle == 0) {
|
2011-07-01 21:53:49 +00:00
|
|
|
if (err == NO_MEMORY) {
|
|
|
|
GraphicBuffer::dumpAllocationsToSystemLog();
|
|
|
|
}
|
2012-01-06 19:20:56 +00:00
|
|
|
ALOGE("GraphicBufferAlloc::createGraphicBuffer(w=%d, h=%d) "
|
2011-04-20 21:20:59 +00:00
|
|
|
"failed (%s), handle=%p",
|
|
|
|
w, h, strerror(-err), graphicBuffer->handle);
|
2011-01-13 02:30:40 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return graphicBuffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
2009-03-04 03:31:44 +00:00
|
|
|
}; // namespace android
|