summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorMathias Agopian <mathias@google.com>2010-07-14 17:59:35 -0700
committerMathias Agopian <mathias@google.com>2010-07-14 17:59:35 -0700
commit81bac09fa6b01dd1495644d9c825c3666762fced (patch)
tree346e826932eef1b4402dfa98796075e63d3c90e8 /services
parente1ea0811de760256cee3b1ffca227251e1cf52c5 (diff)
downloadframeworks_native-81bac09fa6b01dd1495644d9c825c3666762fced.zip
frameworks_native-81bac09fa6b01dd1495644d9c825c3666762fced.tar.gz
frameworks_native-81bac09fa6b01dd1495644d9c825c3666762fced.tar.bz2
move native services under services/
moved surfaceflinger, audioflinger, cameraservice all native services should now reside in this location. Change-Id: Iee42b83dd2a94c3bf5107ab0895fe2dfcd5337a8
Diffstat (limited to 'services')
-rw-r--r--services/surfaceflinger/Android.mk52
-rw-r--r--services/surfaceflinger/Barrier.h55
-rw-r--r--services/surfaceflinger/BlurFilter.cpp376
-rw-r--r--services/surfaceflinger/BlurFilter.h35
-rw-r--r--services/surfaceflinger/DisplayHardware/DisplayHardware.cpp336
-rw-r--r--services/surfaceflinger/DisplayHardware/DisplayHardware.h116
-rw-r--r--services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp401
-rw-r--r--services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h96
-rw-r--r--services/surfaceflinger/GLExtensions.cpp133
-rw-r--r--services/surfaceflinger/GLExtensions.h94
-rw-r--r--services/surfaceflinger/Layer.cpp875
-rw-r--r--services/surfaceflinger/Layer.h239
-rw-r--r--services/surfaceflinger/LayerBase.cpp593
-rw-r--r--services/surfaceflinger/LayerBase.h333
-rw-r--r--services/surfaceflinger/LayerBlur.cpp249
-rw-r--r--services/surfaceflinger/LayerBlur.h65
-rw-r--r--services/surfaceflinger/LayerBuffer.cpp682
-rw-r--r--services/surfaceflinger/LayerBuffer.h220
-rw-r--r--services/surfaceflinger/LayerDim.cpp103
-rw-r--r--services/surfaceflinger/LayerDim.h56
-rw-r--r--services/surfaceflinger/MODULE_LICENSE_APACHE20
-rw-r--r--services/surfaceflinger/MessageQueue.cpp193
-rw-r--r--services/surfaceflinger/MessageQueue.h126
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp1909
-rw-r--r--services/surfaceflinger/SurfaceFlinger.h420
-rw-r--r--services/surfaceflinger/TextureManager.cpp342
-rw-r--r--services/surfaceflinger/TextureManager.h94
-rw-r--r--services/surfaceflinger/Transform.cpp391
-rw-r--r--services/surfaceflinger/Transform.h126
-rw-r--r--services/surfaceflinger/clz.cpp37
-rw-r--r--services/surfaceflinger/clz.h37
-rw-r--r--services/surfaceflinger/tests/Android.mk1
-rw-r--r--services/surfaceflinger/tests/overlays/Android.mk17
-rw-r--r--services/surfaceflinger/tests/overlays/overlays.cpp59
-rw-r--r--services/surfaceflinger/tests/resize/Android.mk17
-rw-r--r--services/surfaceflinger/tests/resize/resize.cpp62
36 files changed, 8940 insertions, 0 deletions
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
new file mode 100644
index 0000000..a14bfb5
--- /dev/null
+++ b/services/surfaceflinger/Android.mk
@@ -0,0 +1,52 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ clz.cpp.arm \
+ DisplayHardware/DisplayHardware.cpp \
+ DisplayHardware/DisplayHardwareBase.cpp \
+ BlurFilter.cpp.arm \
+ GLExtensions.cpp \
+ Layer.cpp \
+ LayerBase.cpp \
+ LayerBuffer.cpp \
+ LayerBlur.cpp \
+ LayerDim.cpp \
+ MessageQueue.cpp \
+ SurfaceFlinger.cpp \
+ TextureManager.cpp \
+ Transform.cpp
+
+LOCAL_CFLAGS:= -DLOG_TAG=\"SurfaceFlinger\"
+LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+
+ifeq ($(TARGET_BOARD_PLATFORM), omap3)
+ LOCAL_CFLAGS += -DNO_RGBX_8888
+endif
+
+# need "-lrt" on Linux simulator to pick up clock_gettime
+ifeq ($(TARGET_SIMULATOR),true)
+ ifeq ($(HOST_OS),linux)
+ LOCAL_LDLIBS += -lrt -lpthread
+ endif
+endif
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libpixelflinger \
+ libhardware \
+ libutils \
+ libEGL \
+ libGLESv1_CM \
+ libbinder \
+ libui \
+ libsurfaceflinger_client
+
+LOCAL_C_INCLUDES := \
+ $(call include-path-for, corecg graphics)
+
+LOCAL_C_INCLUDES += hardware/libhardware/modules/gralloc
+
+LOCAL_MODULE:= libsurfaceflinger
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/services/surfaceflinger/Barrier.h b/services/surfaceflinger/Barrier.h
new file mode 100644
index 0000000..6f8507e
--- /dev/null
+++ b/services/surfaceflinger/Barrier.h
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_BARRIER_H
+#define ANDROID_BARRIER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class Barrier
+{
+public:
+ inline Barrier() : state(CLOSED) { }
+ inline ~Barrier() { }
+ void open() {
+ Mutex::Autolock _l(lock);
+ state = OPENED;
+ cv.broadcast();
+ }
+ void close() {
+ Mutex::Autolock _l(lock);
+ state = CLOSED;
+ }
+ void wait() const {
+ Mutex::Autolock _l(lock);
+ while (state == CLOSED) {
+ cv.wait(lock);
+ }
+ }
+private:
+ enum { OPENED, CLOSED };
+ mutable Mutex lock;
+ mutable Condition cv;
+ volatile int state;
+};
+
+}; // namespace android
+
+#endif // ANDROID_BARRIER_H
diff --git a/services/surfaceflinger/BlurFilter.cpp b/services/surfaceflinger/BlurFilter.cpp
new file mode 100644
index 0000000..1ffbd5b
--- /dev/null
+++ b/services/surfaceflinger/BlurFilter.cpp
@@ -0,0 +1,376 @@
+/*
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <utils/Errors.h>
+
+#include <pixelflinger/pixelflinger.h>
+
+#include "clz.h"
+
+#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
+#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
+
+namespace android {
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+inline uint32_t BLUR_RGBA_TO_HOST(uint32_t v) {
+ return v;
+}
+inline uint32_t BLUR_HOST_TO_RGBA(uint32_t v) {
+ return v;
+}
+#else
+inline uint32_t BLUR_RGBA_TO_HOST(uint32_t v) {
+ return (v<<24) | (v>>24) | ((v<<8)&0xff0000) | ((v>>8)&0xff00);
+}
+inline uint32_t BLUR_HOST_TO_RGBA(uint32_t v) {
+ return (v<<24) | (v>>24) | ((v<<8)&0xff0000) | ((v>>8)&0xff00);
+}
+#endif
+
+const int BLUR_DITHER_BITS = 6; // dither weights stored on 6 bits
+const int BLUR_DITHER_ORDER_SHIFT= 3;
+const int BLUR_DITHER_ORDER = (1<<BLUR_DITHER_ORDER_SHIFT);
+const int BLUR_DITHER_SIZE = BLUR_DITHER_ORDER * BLUR_DITHER_ORDER;
+const int BLUR_DITHER_MASK = BLUR_DITHER_ORDER-1;
+
+static const uint8_t gDitherMatrix[BLUR_DITHER_SIZE] = {
+ 0, 32, 8, 40, 2, 34, 10, 42,
+ 48, 16, 56, 24, 50, 18, 58, 26,
+ 12, 44, 4, 36, 14, 46, 6, 38,
+ 60, 28, 52, 20, 62, 30, 54, 22,
+ 3, 35, 11, 43, 1, 33, 9, 41,
+ 51, 19, 59, 27, 49, 17, 57, 25,
+ 15, 47, 7, 39, 13, 45, 5, 37,
+ 63, 31, 55, 23, 61, 29, 53, 21
+};
+
+
+template <int FACTOR = 0>
+struct BlurColor565
+{
+ typedef uint16_t type;
+ int r, g, b;
+ inline BlurColor565() { }
+ inline BlurColor565(uint16_t v) {
+ r = v >> 11;
+ g = (v >> 5) & 0x3E;
+ b = v & 0x1F;
+ }
+ inline void clear() { r=g=b=0; }
+ inline uint16_t to(int shift, int last, int dither) const {
+ int R = r;
+ int G = g;
+ int B = b;
+ if (UNLIKELY(last)) {
+ if (FACTOR>0) {
+ int L = (R+G+B)>>1;
+ R += (((L>>1) - R) * FACTOR) >> 8;
+ G += (((L ) - G) * FACTOR) >> 8;
+ B += (((L>>1) - B) * FACTOR) >> 8;
+ }
+ R += (dither << shift) >> BLUR_DITHER_BITS;
+ G += (dither << shift) >> BLUR_DITHER_BITS;
+ B += (dither << shift) >> BLUR_DITHER_BITS;
+ }
+ R >>= shift;
+ G >>= shift;
+ B >>= shift;
+ return (R<<11) | (G<<5) | B;
+ }
+ inline BlurColor565& operator += (const BlurColor565& rhs) {
+ r += rhs.r;
+ g += rhs.g;
+ b += rhs.b;
+ return *this;
+ }
+ inline BlurColor565& operator -= (const BlurColor565& rhs) {
+ r -= rhs.r;
+ g -= rhs.g;
+ b -= rhs.b;
+ return *this;
+ }
+};
+
+template <int FACTOR = 0>
+struct BlurColor888X
+{
+ typedef uint32_t type;
+ int r, g, b;
+ inline BlurColor888X() { }
+ inline BlurColor888X(uint32_t v) {
+ v = BLUR_RGBA_TO_HOST(v);
+ r = v & 0xFF;
+ g = (v >> 8) & 0xFF;
+ b = (v >> 16) & 0xFF;
+ }
+ inline void clear() { r=g=b=0; }
+ inline uint32_t to(int shift, int last, int dither) const {
+ int R = r;
+ int G = g;
+ int B = b;
+ if (UNLIKELY(last)) {
+ if (FACTOR>0) {
+ int L = (R+G+G+B)>>2;
+ R += ((L - R) * FACTOR) >> 8;
+ G += ((L - G) * FACTOR) >> 8;
+ B += ((L - B) * FACTOR) >> 8;
+ }
+ }
+ R >>= shift;
+ G >>= shift;
+ B >>= shift;
+ return BLUR_HOST_TO_RGBA((0xFF<<24) | (B<<16) | (G<<8) | R);
+ }
+ inline BlurColor888X& operator += (const BlurColor888X& rhs) {
+ r += rhs.r;
+ g += rhs.g;
+ b += rhs.b;
+ return *this;
+ }
+ inline BlurColor888X& operator -= (const BlurColor888X& rhs) {
+ r -= rhs.r;
+ g -= rhs.g;
+ b -= rhs.b;
+ return *this;
+ }
+};
+
+struct BlurGray565
+{
+ typedef uint16_t type;
+ int l;
+ inline BlurGray565() { }
+ inline BlurGray565(uint16_t v) {
+ int r = v >> 11;
+ int g = (v >> 5) & 0x3F;
+ int b = v & 0x1F;
+ l = (r + g + b + 1)>>1;
+ }
+ inline void clear() { l=0; }
+ inline uint16_t to(int shift, int last, int dither) const {
+ int L = l;
+ if (UNLIKELY(last)) {
+ L += (dither << shift) >> BLUR_DITHER_BITS;
+ }
+ L >>= shift;
+ return ((L>>1)<<11) | (L<<5) | (L>>1);
+ }
+ inline BlurGray565& operator += (const BlurGray565& rhs) {
+ l += rhs.l;
+ return *this;
+ }
+ inline BlurGray565& operator -= (const BlurGray565& rhs) {
+ l -= rhs.l;
+ return *this;
+ }
+};
+
+struct BlurGray8888
+{
+ typedef uint32_t type;
+ int l, a;
+ inline BlurGray8888() { }
+ inline BlurGray8888(uint32_t v) {
+ v = BLUR_RGBA_TO_HOST(v);
+ int r = v & 0xFF;
+ int g = (v >> 8) & 0xFF;
+ int b = (v >> 16) & 0xFF;
+ a = v >> 24;
+ l = r + g + g + b;
+ }
+ inline void clear() { l=a=0; }
+ inline uint32_t to(int shift, int last, int dither) const {
+ int L = l;
+ int A = a;
+ if (UNLIKELY(last)) {
+ L += (dither << (shift+2)) >> BLUR_DITHER_BITS;
+ A += (dither << shift) >> BLUR_DITHER_BITS;
+ }
+ L >>= (shift+2);
+ A >>= shift;
+ return BLUR_HOST_TO_RGBA((A<<24) | (L<<16) | (L<<8) | L);
+ }
+ inline BlurGray8888& operator += (const BlurGray8888& rhs) {
+ l += rhs.l;
+ a += rhs.a;
+ return *this;
+ }
+ inline BlurGray8888& operator -= (const BlurGray8888& rhs) {
+ l -= rhs.l;
+ a -= rhs.a;
+ return *this;
+ }
+};
+
+
+template<typename PIXEL>
+static status_t blurFilter(
+ GGLSurface const* dst,
+ GGLSurface const* src,
+ int kernelSizeUser,
+ int repeat)
+{
+ typedef typename PIXEL::type TYPE;
+
+ const int shift = 31 - clz(kernelSizeUser);
+ const int areaShift = shift*2;
+ const int kernelSize = 1<<shift;
+ const int kernelHalfSize = kernelSize/2;
+ const int mask = kernelSize-1;
+ const int w = src->width;
+ const int h = src->height;
+ const uint8_t* ditherMatrix = gDitherMatrix;
+
+ // we need a temporary buffer to store one line of blurred columns
+ // as well as kernelSize lines of source pixels organized as a ring buffer.
+ void* const temporary_buffer = malloc(
+ (w + kernelSize) * sizeof(PIXEL) +
+ (src->stride * kernelSize) * sizeof(TYPE));
+ if (!temporary_buffer)
+ return NO_MEMORY;
+
+ PIXEL* const sums = (PIXEL*)temporary_buffer;
+ TYPE* const scratch = (TYPE*)(sums + w + kernelSize);
+
+ // Apply the blur 'repeat' times, this is used to approximate
+ // gaussian blurs. 3 times gives good results.
+ for (int k=0 ; k<repeat ; k++) {
+
+ // Clear the columns sums for this round
+ memset(sums, 0, (w + kernelSize) * sizeof(PIXEL));
+ TYPE* head;
+ TYPE pixel;
+ PIXEL current;
+
+ // Since we're going to override the source data we need
+ // to copy it in a temporary buffer. Only kernelSize lines are
+ // required. But since we start in the center of the kernel,
+ // we only copy half of the data, and fill the rest with zeros
+ // (assuming black/transparent pixels).
+ memcpy( scratch + src->stride*kernelHalfSize,
+ src->data,
+ src->stride*kernelHalfSize*sizeof(TYPE));
+
+ // sum half of each column, because we assume the first half is
+ // zeros (black/transparent).
+ for (int y=0 ; y<kernelHalfSize ; y++) {
+ head = (TYPE*)src->data + y*src->stride;
+ for (int x=0 ; x<w ; x++)
+ sums[x] += PIXEL( *head++ );
+ }
+
+ for (int y=0 ; y<h ; y++) {
+ TYPE* fb = (TYPE*)dst->data + y*dst->stride;
+
+ // compute the dither matrix line
+ uint8_t const * ditherY = ditherMatrix
+ + (y & BLUR_DITHER_MASK)*BLUR_DITHER_ORDER;
+
+ // Horizontal blur pass on the columns sums
+ int count, dither, x=0;
+ PIXEL const * out= sums;
+ PIXEL const * in = sums;
+ current.clear();
+
+ count = kernelHalfSize;
+ do {
+ current += *in;
+ in++;
+ } while (--count);
+
+ count = kernelHalfSize;
+ do {
+ current += *in;
+ dither = *(ditherY + ((x++)&BLUR_DITHER_MASK));
+ *fb++ = current.to(areaShift, k==repeat-1, dither);
+ in++;
+ } while (--count);
+
+ count = w-kernelSize;
+ do {
+ current += *in;
+ current -= *out;
+ dither = *(ditherY + ((x++)&BLUR_DITHER_MASK));
+ *fb++ = current.to(areaShift, k==repeat-1, dither);
+ in++, out++;
+ } while (--count);
+
+ count = kernelHalfSize;
+ do {
+ current -= *out;
+ dither = *(ditherY + ((x++)&BLUR_DITHER_MASK));
+ *fb++ = current.to(areaShift, k==repeat-1, dither);
+ out++;
+ } while (--count);
+
+ // vertical blur pass, subtract the oldest line from each columns
+ // and add a new line. Subtract or add zeros at the top
+ // and bottom edges.
+ TYPE* const tail = scratch + (y & mask) * src->stride;
+ if (y >= kernelHalfSize) {
+ for (int x=0 ; x<w ; x++)
+ sums[x] -= PIXEL( tail[x] );
+ }
+ if (y < h-kernelSize) {
+ memcpy( tail,
+ (TYPE*)src->data + (y+kernelHalfSize)*src->stride,
+ src->stride*sizeof(TYPE));
+ for (int x=0 ; x<w ; x++)
+ sums[x] += PIXEL( tail[x] );
+ }
+ }
+
+ // The subsequent passes are always done in-place.
+ src = dst;
+ }
+
+ free(temporary_buffer);
+
+ return NO_ERROR;
+}
+
+template status_t blurFilter< BlurColor565<0x80> >(
+ GGLSurface const* dst,
+ GGLSurface const* src,
+ int kernelSizeUser,
+ int repeat);
+
+status_t blurFilter(
+ GGLSurface const* image,
+ int kernelSizeUser,
+ int repeat)
+{
+ status_t err = BAD_VALUE;
+ if (image->format == GGL_PIXEL_FORMAT_RGB_565) {
+ err = blurFilter< BlurColor565<0x80> >(image, image, kernelSizeUser, repeat);
+ } else if (image->format == GGL_PIXEL_FORMAT_RGBX_8888) {
+ err = blurFilter< BlurColor888X<0x80> >(image, image, kernelSizeUser, repeat);
+ }
+ return err;
+}
+
+} // namespace android
+
+//err = blur< BlurColor565<0x80> >(dst, src, kernelSizeUser, repeat);
+//err = blur<BlurGray565>(dst, src, kernelSizeUser, repeat);
+//err = blur<BlurGray8888>(dst, src, kernelSizeUser, repeat);
diff --git a/services/surfaceflinger/BlurFilter.h b/services/surfaceflinger/BlurFilter.h
new file mode 100644
index 0000000..294db43
--- /dev/null
+++ b/services/surfaceflinger/BlurFilter.h
@@ -0,0 +1,35 @@
+/*
+**
+** Copyright 2006, 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.
+*/
+
+#ifndef ANDROID_BLUR_FILTER_H
+#define ANDROID_BLUR_FILTER_H
+
+#include <stdint.h>
+#include <utils/Errors.h>
+
+#include <pixelflinger/pixelflinger.h>
+
+namespace android {
+
+status_t blurFilter(
+ GGLSurface const* image,
+ int kernelSizeUser,
+ int repeat);
+
+} // namespace android
+
+#endif // ANDROID_BLUR_FILTER_H
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
new file mode 100644
index 0000000..2eac0a8
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -0,0 +1,336 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#include <cutils/properties.h>
+
+#include <utils/RefBase.h>
+#include <utils/Log.h>
+
+#include <ui/PixelFormat.h>
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
+#include <GLES/gl.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <pixelflinger/pixelflinger.h>
+
+#include "DisplayHardware/DisplayHardware.h"
+
+#include <hardware/copybit.h>
+#include <hardware/overlay.h>
+#include <hardware/gralloc.h>
+
+#include "GLExtensions.h"
+
+using namespace android;
+
+
+static __attribute__((noinline))
+void checkGLErrors()
+{
+ do {
+ // there could be more than one error flag
+ GLenum error = glGetError();
+ if (error == GL_NO_ERROR)
+ break;
+ LOGE("GL error 0x%04x", int(error));
+ } while(true);
+}
+
+static __attribute__((noinline))
+void checkEGLErrors(const char* token)
+{
+ EGLint error = eglGetError();
+ if (error && error != EGL_SUCCESS) {
+ LOGE("%s: EGL error 0x%04x (%s)",
+ token, int(error), EGLUtils::strerror(error));
+ }
+}
+
+/*
+ * Initialize the display to the specified values.
+ *
+ */
+
+DisplayHardware::DisplayHardware(
+ const sp<SurfaceFlinger>& flinger,
+ uint32_t dpy)
+ : DisplayHardwareBase(flinger, dpy),
+ mFlags(0)
+{
+ init(dpy);
+}
+
+DisplayHardware::~DisplayHardware()
+{
+ fini();
+}
+
+float DisplayHardware::getDpiX() const { return mDpiX; }
+float DisplayHardware::getDpiY() const { return mDpiY; }
+float DisplayHardware::getDensity() const { return mDensity; }
+float DisplayHardware::getRefreshRate() const { return mRefreshRate; }
+int DisplayHardware::getWidth() const { return mWidth; }
+int DisplayHardware::getHeight() const { return mHeight; }
+PixelFormat DisplayHardware::getFormat() const { return mFormat; }
+uint32_t DisplayHardware::getMaxTextureSize() const { return mMaxTextureSize; }
+uint32_t DisplayHardware::getMaxViewportDims() const { return mMaxViewportDims; }
+
+void DisplayHardware::init(uint32_t dpy)
+{
+ mNativeWindow = new FramebufferNativeWindow();
+ framebuffer_device_t const * fbDev = mNativeWindow->getDevice();
+ mDpiX = mNativeWindow->xdpi;
+ mDpiY = mNativeWindow->ydpi;
+ mRefreshRate = fbDev->fps;
+
+ mOverlayEngine = NULL;
+ hw_module_t const* module;
+ if (hw_get_module(OVERLAY_HARDWARE_MODULE_ID, &module) == 0) {
+ overlay_control_open(module, &mOverlayEngine);
+ }
+
+ EGLint w, h, dummy;
+ EGLint numConfigs=0;
+ EGLSurface surface;
+ EGLContext context;
+
+ // initialize EGL
+ EGLint attribs[] = {
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_NONE, 0,
+ EGL_NONE
+ };
+
+ // debug: disable h/w rendering
+ char property[PROPERTY_VALUE_MAX];
+ if (property_get("debug.sf.hw", property, NULL) > 0) {
+ if (atoi(property) == 0) {
+ LOGW("H/W composition disabled");
+ attribs[2] = EGL_CONFIG_CAVEAT;
+ attribs[3] = EGL_SLOW_CONFIG;
+ }
+ }
+
+ // TODO: all the extensions below should be queried through
+ // eglGetProcAddress().
+
+ EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ eglInitialize(display, NULL, NULL);
+ eglGetConfigs(display, NULL, 0, &numConfigs);
+
+ EGLConfig config;
+ status_t err = EGLUtils::selectConfigForNativeWindow(
+ display, attribs, mNativeWindow.get(), &config);
+ LOGE_IF(err, "couldn't find an EGLConfig matching the screen format");
+
+ EGLint r,g,b,a;
+ eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r);
+ eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g);
+ eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b);
+ eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a);
+
+ if (mNativeWindow->isUpdateOnDemand()) {
+ mFlags |= PARTIAL_UPDATES;
+ }
+
+ if (eglGetConfigAttrib(display, config, EGL_CONFIG_CAVEAT, &dummy) == EGL_TRUE) {
+ if (dummy == EGL_SLOW_CONFIG)
+ mFlags |= SLOW_CONFIG;
+ }
+
+ /*
+ * Create our main surface
+ */
+
+ surface = eglCreateWindowSurface(display, config, mNativeWindow.get(), NULL);
+ eglQuerySurface(display, surface, EGL_WIDTH, &mWidth);
+ eglQuerySurface(display, surface, EGL_HEIGHT, &mHeight);
+
+ if (mFlags & PARTIAL_UPDATES) {
+ // if we have partial updates, we definitely don't need to
+ // preserve the backbuffer, which may be costly.
+ eglSurfaceAttrib(display, surface,
+ EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED);
+ }
+
+ if (eglQuerySurface(display, surface, EGL_SWAP_BEHAVIOR, &dummy) == EGL_TRUE) {
+ if (dummy == EGL_BUFFER_PRESERVED) {
+ mFlags |= BUFFER_PRESERVED;
+ }
+ }
+
+ /* Read density from build-specific ro.sf.lcd_density property
+ * except if it is overridden by qemu.sf.lcd_density.
+ */
+ if (property_get("qemu.sf.lcd_density", property, NULL) <= 0) {
+ if (property_get("ro.sf.lcd_density", property, NULL) <= 0) {
+ LOGW("ro.sf.lcd_density not defined, using 160 dpi by default.");
+ strcpy(property, "160");
+ }
+ } else {
+ /* for the emulator case, reset the dpi values too */
+ mDpiX = mDpiY = atoi(property);
+ }
+ mDensity = atoi(property) * (1.0f/160.0f);
+
+
+ /*
+ * Create our OpenGL ES context
+ */
+
+ context = eglCreateContext(display, config, NULL, NULL);
+
+ mDisplay = display;
+ mConfig = config;
+ mSurface = surface;
+ mContext = context;
+ mFormat = fbDev->format;
+ mPageFlipCount = 0;
+
+ /*
+ * Gather OpenGL ES extensions
+ */
+
+ eglMakeCurrent(display, surface, surface, context);
+
+ 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));
+
+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
+ glGetIntegerv(GL_MAX_VIEWPORT_DIMS, &mMaxViewportDims);
+
+
+#ifdef EGL_ANDROID_swap_rectangle
+ if (extensions.hasExtension("EGL_ANDROID_swap_rectangle")) {
+ if (eglSetSwapRectangleANDROID(display, surface,
+ 0, 0, mWidth, mHeight) == EGL_TRUE) {
+ // This could fail if this extension is not supported by this
+ // specific surface (of config)
+ mFlags |= SWAP_RECTANGLE;
+ }
+ }
+ // when we have the choice between PARTIAL_UPDATES and SWAP_RECTANGLE
+ // choose PARTIAL_UPDATES, which should be more efficient
+ if (mFlags & PARTIAL_UPDATES)
+ mFlags &= ~SWAP_RECTANGLE;
+#endif
+
+ LOGI("EGL informations:");
+ LOGI("# of configs : %d", numConfigs);
+ LOGI("vendor : %s", extensions.getEglVendor());
+ LOGI("version : %s", extensions.getEglVersion());
+ LOGI("extensions: %s", extensions.getEglExtension());
+ LOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported");
+ LOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config);
+
+ LOGI("OpenGL informations:");
+ LOGI("vendor : %s", extensions.getVendor());
+ LOGI("renderer : %s", extensions.getRenderer());
+ LOGI("version : %s", extensions.getVersion());
+ LOGI("extensions: %s", extensions.getExtension());
+ LOGI("GL_MAX_TEXTURE_SIZE = %d", mMaxTextureSize);
+ LOGI("GL_MAX_VIEWPORT_DIMS = %d", mMaxViewportDims);
+ LOGI("flags = %08x", mFlags);
+
+ // Unbind the context from this thread
+ eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+}
+
+/*
+ * Clean up. Throw out our local state.
+ *
+ * (It's entirely possible we'll never get here, since this is meant
+ * for real hardware, which doesn't restart.)
+ */
+
+void DisplayHardware::fini()
+{
+ eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ eglTerminate(mDisplay);
+ overlay_control_close(mOverlayEngine);
+}
+
+void DisplayHardware::releaseScreen() const
+{
+ DisplayHardwareBase::releaseScreen();
+}
+
+void DisplayHardware::acquireScreen() const
+{
+ DisplayHardwareBase::acquireScreen();
+}
+
+uint32_t DisplayHardware::getPageFlipCount() const {
+ return mPageFlipCount;
+}
+
+status_t DisplayHardware::compositionComplete() const {
+ return mNativeWindow->compositionComplete();
+}
+
+void DisplayHardware::flip(const Region& dirty) const
+{
+ checkGLErrors();
+
+ EGLDisplay dpy = mDisplay;
+ EGLSurface surface = mSurface;
+
+#ifdef EGL_ANDROID_swap_rectangle
+ if (mFlags & SWAP_RECTANGLE) {
+ const Region newDirty(dirty.intersect(bounds()));
+ const Rect b(newDirty.getBounds());
+ eglSetSwapRectangleANDROID(dpy, surface,
+ b.left, b.top, b.width(), b.height());
+ }
+#endif
+
+ if (mFlags & PARTIAL_UPDATES) {
+ mNativeWindow->setUpdateRectangle(dirty.getBounds());
+ }
+
+ mPageFlipCount++;
+ eglSwapBuffers(dpy, surface);
+ checkEGLErrors("eglSwapBuffers");
+
+ // for debugging
+ //glClearColor(1,0,0,0);
+ //glClear(GL_COLOR_BUFFER_BIT);
+}
+
+uint32_t DisplayHardware::getFlags() const
+{
+ return mFlags;
+}
+
+void DisplayHardware::makeCurrent() const
+{
+ eglMakeCurrent(mDisplay, mSurface, mSurface, mContext);
+}
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
new file mode 100644
index 0000000..66bf521
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_DISPLAY_HARDWARE_H
+#define ANDROID_DISPLAY_HARDWARE_H
+
+#include <stdlib.h>
+
+#include <ui/PixelFormat.h>
+#include <ui/Region.h>
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <pixelflinger/pixelflinger.h>
+
+#include "GLExtensions.h"
+
+#include "DisplayHardware/DisplayHardwareBase.h"
+
+struct overlay_control_device_t;
+struct framebuffer_device_t;
+struct copybit_image_t;
+
+namespace android {
+
+class FramebufferNativeWindow;
+
+class DisplayHardware : public DisplayHardwareBase
+{
+public:
+ enum {
+ COPY_BITS_EXTENSION = 0x00000008,
+ BUFFER_PRESERVED = 0x00010000,
+ PARTIAL_UPDATES = 0x00020000, // video driver feature
+ SLOW_CONFIG = 0x00040000, // software
+ SWAP_RECTANGLE = 0x00080000,
+ };
+
+ DisplayHardware(
+ const sp<SurfaceFlinger>& flinger,
+ uint32_t displayIndex);
+
+ ~DisplayHardware();
+
+ void releaseScreen() const;
+ void acquireScreen() const;
+
+ // Flip the front and back buffers if the back buffer is "dirty". Might
+ // be instantaneous, might involve copying the frame buffer around.
+ void flip(const Region& dirty) const;
+
+ float getDpiX() const;
+ float getDpiY() const;
+ float getRefreshRate() const;
+ float getDensity() const;
+ int getWidth() const;
+ int getHeight() const;
+ PixelFormat getFormat() const;
+ uint32_t getFlags() const;
+ void makeCurrent() const;
+ uint32_t getMaxTextureSize() const;
+ uint32_t getMaxViewportDims() const;
+
+ uint32_t getPageFlipCount() const;
+ EGLDisplay getEGLDisplay() const { return mDisplay; }
+ overlay_control_device_t* getOverlayEngine() const { return mOverlayEngine; }
+
+ status_t compositionComplete() const;
+
+ Rect bounds() const {
+ return Rect(mWidth, mHeight);
+ }
+
+private:
+ void init(uint32_t displayIndex) __attribute__((noinline));
+ void fini() __attribute__((noinline));
+
+ EGLDisplay mDisplay;
+ EGLSurface mSurface;
+ EGLContext mContext;
+ EGLConfig mConfig;
+ float mDpiX;
+ float mDpiY;
+ float mRefreshRate;
+ float mDensity;
+ int mWidth;
+ int mHeight;
+ PixelFormat mFormat;
+ uint32_t mFlags;
+ mutable uint32_t mPageFlipCount;
+ GLint mMaxViewportDims;
+ GLint mMaxTextureSize;
+
+ sp<FramebufferNativeWindow> mNativeWindow;
+ overlay_control_device_t* mOverlayEngine;
+};
+
+}; // namespace android
+
+#endif // ANDROID_DISPLAY_HARDWARE_H
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
new file mode 100644
index 0000000..1d09f84
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
@@ -0,0 +1,401 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+
+#include <linux/unistd.h>
+
+#include <utils/Log.h>
+
+#include "DisplayHardware/DisplayHardwareBase.h"
+#include "SurfaceFlinger.h"
+
+// ----------------------------------------------------------------------------
+// the sim build doesn't have gettid
+
+#ifndef HAVE_GETTID
+# define gettid getpid
+#endif
+
+// ----------------------------------------------------------------------------
+namespace android {
+
+static char const * kSleepFileName = "/sys/power/wait_for_fb_sleep";
+static char const * kWakeFileName = "/sys/power/wait_for_fb_wake";
+static char const * const kOldSleepFileName = "/sys/android_power/wait_for_fb_sleep";
+static char const * const kOldWakeFileName = "/sys/android_power/wait_for_fb_wake";
+
+// This dir exists if the framebuffer console is present, either built into
+// the kernel or loaded as a module.
+static char const * const kFbconSysDir = "/sys/class/graphics/fbcon";
+
+// ----------------------------------------------------------------------------
+
+DisplayHardwareBase::DisplayEventThreadBase::DisplayEventThreadBase(
+ const sp<SurfaceFlinger>& flinger)
+ : Thread(false), mFlinger(flinger) {
+}
+
+DisplayHardwareBase::DisplayEventThreadBase::~DisplayEventThreadBase() {
+}
+
+// ----------------------------------------------------------------------------
+
+DisplayHardwareBase::DisplayEventThread::DisplayEventThread(
+ const sp<SurfaceFlinger>& flinger)
+ : DisplayEventThreadBase(flinger)
+{
+}
+
+DisplayHardwareBase::DisplayEventThread::~DisplayEventThread()
+{
+}
+
+bool DisplayHardwareBase::DisplayEventThread::threadLoop()
+{
+ int err = 0;
+ char buf;
+ int fd;
+
+ fd = open(kSleepFileName, O_RDONLY, 0);
+ do {
+ err = read(fd, &buf, 1);
+ } while (err < 0 && errno == EINTR);
+ close(fd);
+ LOGW_IF(err<0, "ANDROID_WAIT_FOR_FB_SLEEP failed (%s)", strerror(errno));
+ if (err >= 0) {
+ sp<SurfaceFlinger> flinger = mFlinger.promote();
+ LOGD("About to give-up screen, flinger = %p", flinger.get());
+ if (flinger != 0) {
+ mBarrier.close();
+ flinger->screenReleased(0);
+ mBarrier.wait();
+ }
+ }
+ fd = open(kWakeFileName, O_RDONLY, 0);
+ do {
+ err = read(fd, &buf, 1);
+ } while (err < 0 && errno == EINTR);
+ close(fd);
+ LOGW_IF(err<0, "ANDROID_WAIT_FOR_FB_WAKE failed (%s)", strerror(errno));
+ if (err >= 0) {
+ sp<SurfaceFlinger> flinger = mFlinger.promote();
+ LOGD("Screen about to return, flinger = %p", flinger.get());
+ if (flinger != 0)
+ flinger->screenAcquired(0);
+ }
+ return true;
+}
+
+status_t DisplayHardwareBase::DisplayEventThread::releaseScreen() const
+{
+ mBarrier.open();
+ return NO_ERROR;
+}
+
+status_t DisplayHardwareBase::DisplayEventThread::readyToRun()
+{
+ if (access(kSleepFileName, R_OK) || access(kWakeFileName, R_OK)) {
+ if (access(kOldSleepFileName, R_OK) || access(kOldWakeFileName, R_OK)) {
+ LOGE("Couldn't open %s or %s", kSleepFileName, kWakeFileName);
+ return NO_INIT;
+ }
+ kSleepFileName = kOldSleepFileName;
+ kWakeFileName = kOldWakeFileName;
+ }
+ return NO_ERROR;
+}
+
+status_t DisplayHardwareBase::DisplayEventThread::initCheck() const
+{
+ return (((access(kSleepFileName, R_OK) == 0 &&
+ access(kWakeFileName, R_OK) == 0) ||
+ (access(kOldSleepFileName, R_OK) == 0 &&
+ access(kOldWakeFileName, R_OK) == 0)) &&
+ access(kFbconSysDir, F_OK) != 0) ? NO_ERROR : NO_INIT;
+}
+
+// ----------------------------------------------------------------------------
+
+pid_t DisplayHardwareBase::ConsoleManagerThread::sSignalCatcherPid = 0;
+
+DisplayHardwareBase::ConsoleManagerThread::ConsoleManagerThread(
+ const sp<SurfaceFlinger>& flinger)
+ : DisplayEventThreadBase(flinger), consoleFd(-1)
+{
+ sSignalCatcherPid = 0;
+
+ // create a new console
+ char const * const ttydev = "/dev/tty0";
+ int fd = open(ttydev, O_RDWR | O_SYNC);
+ if (fd<0) {
+ LOGE("Can't open %s", ttydev);
+ this->consoleFd = -errno;
+ return;
+ }
+
+ // to make sure that we are in text mode
+ int res = ioctl(fd, KDSETMODE, (void*) KD_TEXT);
+ if (res<0) {
+ LOGE("ioctl(%d, KDSETMODE, ...) failed, res %d (%s)",
+ fd, res, strerror(errno));
+ }
+
+ // get the current console
+ struct vt_stat vs;
+ res = ioctl(fd, VT_GETSTATE, &vs);
+ if (res<0) {
+ LOGE("ioctl(%d, VT_GETSTATE, ...) failed, res %d (%s)",
+ fd, res, strerror(errno));
+ this->consoleFd = -errno;
+ return;
+ }
+
+ // switch to console 7 (which is what X normaly uses)
+ int vtnum = 7;
+ do {
+ res = ioctl(fd, VT_ACTIVATE, (void*)vtnum);
+ } while(res < 0 && errno == EINTR);
+ if (res<0) {
+ LOGE("ioctl(%d, VT_ACTIVATE, ...) failed, %d (%s) for %d",
+ fd, errno, strerror(errno), vtnum);
+ this->consoleFd = -errno;
+ return;
+ }
+
+ do {
+ res = ioctl(fd, VT_WAITACTIVE, (void*)vtnum);
+ } while(res < 0 && errno == EINTR);
+ if (res<0) {
+ LOGE("ioctl(%d, VT_WAITACTIVE, ...) failed, %d %d %s for %d",
+ fd, res, errno, strerror(errno), vtnum);
+ this->consoleFd = -errno;
+ return;
+ }
+
+ // open the new console
+ close(fd);
+ fd = open(ttydev, O_RDWR | O_SYNC);
+ if (fd<0) {
+ LOGE("Can't open new console %s", ttydev);
+ this->consoleFd = -errno;
+ return;
+ }
+
+ /* disable console line buffer, echo, ... */
+ struct termios ttyarg;
+ ioctl(fd, TCGETS , &ttyarg);
+ ttyarg.c_iflag = 0;
+ ttyarg.c_lflag = 0;
+ ioctl(fd, TCSETS , &ttyarg);
+
+ // set up signals so we're notified when the console changes
+ // we can't use SIGUSR1 because it's used by the java-vm
+ vm.mode = VT_PROCESS;
+ vm.waitv = 0;
+ vm.relsig = SIGUSR2;
+ vm.acqsig = SIGUNUSED;
+ vm.frsig = 0;
+
+ struct sigaction act;
+ sigemptyset(&act.sa_mask);
+ act.sa_handler = sigHandler;
+ act.sa_flags = 0;
+ sigaction(vm.relsig, &act, NULL);
+
+ sigemptyset(&act.sa_mask);
+ act.sa_handler = sigHandler;
+ act.sa_flags = 0;
+ sigaction(vm.acqsig, &act, NULL);
+
+ sigset_t mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, vm.relsig);
+ sigaddset(&mask, vm.acqsig);
+ sigprocmask(SIG_BLOCK, &mask, NULL);
+
+ // switch to graphic mode
+ res = ioctl(fd, KDSETMODE, (void*)KD_GRAPHICS);
+ LOGW_IF(res<0,
+ "ioctl(%d, KDSETMODE, KD_GRAPHICS) failed, res %d", fd, res);
+
+ this->prev_vt_num = vs.v_active;
+ this->vt_num = vtnum;
+ this->consoleFd = fd;
+}
+
+DisplayHardwareBase::ConsoleManagerThread::~ConsoleManagerThread()
+{
+ if (this->consoleFd >= 0) {
+ int fd = this->consoleFd;
+ int prev_vt_num = this->prev_vt_num;
+ int res;
+ ioctl(fd, KDSETMODE, (void*)KD_TEXT);
+ do {
+ res = ioctl(fd, VT_ACTIVATE, (void*)prev_vt_num);
+ } while(res < 0 && errno == EINTR);
+ do {
+ res = ioctl(fd, VT_WAITACTIVE, (void*)prev_vt_num);
+ } while(res < 0 && errno == EINTR);
+ close(fd);
+ char const * const ttydev = "/dev/tty0";
+ fd = open(ttydev, O_RDWR | O_SYNC);
+ ioctl(fd, VT_DISALLOCATE, 0);
+ close(fd);
+ }
+}
+
+status_t DisplayHardwareBase::ConsoleManagerThread::readyToRun()
+{
+ if (this->consoleFd >= 0) {
+ sSignalCatcherPid = gettid();
+
+ sigset_t mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, vm.relsig);
+ sigaddset(&mask, vm.acqsig);
+ sigprocmask(SIG_BLOCK, &mask, NULL);
+
+ int res = ioctl(this->consoleFd, VT_SETMODE, &vm);
+ if (res<0) {
+ LOGE("ioctl(%d, VT_SETMODE, ...) failed, %d (%s)",
+ this->consoleFd, errno, strerror(errno));
+ }
+ return NO_ERROR;
+ }
+ return this->consoleFd;
+}
+
+void DisplayHardwareBase::ConsoleManagerThread::requestExit()
+{
+ Thread::requestExit();
+ if (sSignalCatcherPid != 0) {
+ // wake the thread up
+ kill(sSignalCatcherPid, SIGINT);
+ // wait for it...
+ }
+}
+
+void DisplayHardwareBase::ConsoleManagerThread::sigHandler(int sig)
+{
+ // resend the signal to our signal catcher thread
+ LOGW("received signal %d in thread %d, resending to %d",
+ sig, gettid(), sSignalCatcherPid);
+
+ // we absolutely need the delays below because without them
+ // our main thread never gets a chance to handle the signal.
+ usleep(10000);
+ kill(sSignalCatcherPid, sig);
+ usleep(10000);
+}
+
+status_t DisplayHardwareBase::ConsoleManagerThread::releaseScreen() const
+{
+ int fd = this->consoleFd;
+ int err = ioctl(fd, VT_RELDISP, (void*)1);
+ LOGE_IF(err<0, "ioctl(%d, VT_RELDISP, 1) failed %d (%s)",
+ fd, errno, strerror(errno));
+ return (err<0) ? (-errno) : status_t(NO_ERROR);
+}
+
+bool DisplayHardwareBase::ConsoleManagerThread::threadLoop()
+{
+ sigset_t mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, vm.relsig);
+ sigaddset(&mask, vm.acqsig);
+
+ int sig = 0;
+ sigwait(&mask, &sig);
+
+ if (sig == vm.relsig) {
+ sp<SurfaceFlinger> flinger = mFlinger.promote();
+ //LOGD("About to give-up screen, flinger = %p", flinger.get());
+ if (flinger != 0)
+ flinger->screenReleased(0);
+ } else if (sig == vm.acqsig) {
+ sp<SurfaceFlinger> flinger = mFlinger.promote();
+ //LOGD("Screen about to return, flinger = %p", flinger.get());
+ if (flinger != 0)
+ flinger->screenAcquired(0);
+ }
+
+ return true;
+}
+
+status_t DisplayHardwareBase::ConsoleManagerThread::initCheck() const
+{
+ return consoleFd >= 0 ? NO_ERROR : NO_INIT;
+}
+
+// ----------------------------------------------------------------------------
+
+DisplayHardwareBase::DisplayHardwareBase(const sp<SurfaceFlinger>& flinger,
+ uint32_t displayIndex)
+ : mCanDraw(true)
+{
+ mDisplayEventThread = new DisplayEventThread(flinger);
+ if (mDisplayEventThread->initCheck() != NO_ERROR) {
+ // fall-back on the console
+ mDisplayEventThread = new ConsoleManagerThread(flinger);
+ }
+}
+
+DisplayHardwareBase::~DisplayHardwareBase()
+{
+ // request exit
+ mDisplayEventThread->requestExitAndWait();
+}
+
+
+bool DisplayHardwareBase::canDraw() const
+{
+ return mCanDraw;
+}
+
+void DisplayHardwareBase::releaseScreen() const
+{
+ status_t err = mDisplayEventThread->releaseScreen();
+ if (err >= 0) {
+ //LOGD("screen given-up");
+ mCanDraw = false;
+ }
+}
+
+void DisplayHardwareBase::acquireScreen() const
+{
+ status_t err = mDisplayEventThread->acquireScreen();
+ if (err >= 0) {
+ //LOGD("screen returned");
+ mCanDraw = true;
+ }
+}
+
+}; // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
new file mode 100644
index 0000000..8369bb8
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_DISPLAY_HARDWARE_BASE_H
+#define ANDROID_DISPLAY_HARDWARE_BASE_H
+
+#include <stdint.h>
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+#include <linux/kd.h>
+#include <linux/vt.h>
+#include "Barrier.h"
+
+namespace android {
+
+class SurfaceFlinger;
+
+class DisplayHardwareBase
+{
+public:
+ DisplayHardwareBase(
+ const sp<SurfaceFlinger>& flinger,
+ uint32_t displayIndex);
+
+ ~DisplayHardwareBase();
+
+ // console managment
+ void releaseScreen() const;
+ void acquireScreen() const;
+ bool canDraw() const;
+
+private:
+ class DisplayEventThreadBase : public Thread {
+ protected:
+ wp<SurfaceFlinger> mFlinger;
+ public:
+ DisplayEventThreadBase(const sp<SurfaceFlinger>& flinger);
+ virtual ~DisplayEventThreadBase();
+ virtual void onFirstRef() {
+ run("DisplayEventThread", PRIORITY_URGENT_DISPLAY);
+ }
+ virtual status_t acquireScreen() const { return NO_ERROR; };
+ virtual status_t releaseScreen() const { return NO_ERROR; };
+ virtual status_t initCheck() const = 0;
+ };
+
+ class DisplayEventThread : public DisplayEventThreadBase
+ {
+ mutable Barrier mBarrier;
+ public:
+ DisplayEventThread(const sp<SurfaceFlinger>& flinger);
+ virtual ~DisplayEventThread();
+ virtual bool threadLoop();
+ virtual status_t readyToRun();
+ virtual status_t releaseScreen() const;
+ virtual status_t initCheck() const;
+ };
+
+ class ConsoleManagerThread : public DisplayEventThreadBase
+ {
+ int consoleFd;
+ int vt_num;
+ int prev_vt_num;
+ vt_mode vm;
+ static void sigHandler(int sig);
+ static pid_t sSignalCatcherPid;
+ public:
+ ConsoleManagerThread(const sp<SurfaceFlinger>& flinger);
+ virtual ~ConsoleManagerThread();
+ virtual bool threadLoop();
+ virtual status_t readyToRun();
+ virtual void requestExit();
+ virtual status_t releaseScreen() const;
+ virtual status_t initCheck() const;
+ };
+
+ sp<DisplayEventThreadBase> mDisplayEventThread;
+ mutable int mCanDraw;
+};
+
+}; // namespace android
+
+#endif // ANDROID_DISPLAY_HARDWARE_BASE_H
diff --git a/services/surfaceflinger/GLExtensions.cpp b/services/surfaceflinger/GLExtensions.cpp
new file mode 100644
index 0000000..7f4f9fc
--- /dev/null
+++ b/services/surfaceflinger/GLExtensions.cpp
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+
+#include "GLExtensions.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+ANDROID_SINGLETON_STATIC_INSTANCE( GLExtensions )
+
+GLExtensions::GLExtensions()
+ : mHaveTextureExternal(false),
+ mHaveNpot(false),
+ mHaveDirectTexture(false)
+{
+}
+
+void GLExtensions::initWithGLStrings(
+ GLubyte const* vendor,
+ GLubyte const* renderer,
+ GLubyte const* version,
+ GLubyte const* extensions,
+ char const* egl_vendor,
+ char const* egl_version,
+ char const* egl_extensions)
+{
+ mVendor = (char const*)vendor;
+ mRenderer = (char const*)renderer;
+ mVersion = (char const*)version;
+ mExtensions = (char const*)extensions;
+ mEglVendor = egl_vendor;
+ mEglVersion = egl_version;
+ mEglExtensions = egl_extensions;
+
+ char const* curr = (char const*)extensions;
+ char const* head = curr;
+ do {
+ head = strchr(curr, ' ');
+ String8 s(curr, head ? head-curr : strlen(curr));
+ if (s.length()) {
+ mExtensionList.add(s);
+ }
+ curr = head+1;
+ } while (head);
+
+ curr = egl_extensions;
+ head = curr;
+ do {
+ head = strchr(curr, ' ');
+ String8 s(curr, head ? head-curr : strlen(curr));
+ if (s.length()) {
+ mExtensionList.add(s);
+ }
+ curr = head+1;
+ } while (head);
+
+#ifdef EGL_ANDROID_image_native_buffer
+ if (hasExtension("GL_OES_EGL_image") &&
+ (hasExtension("EGL_KHR_image_base") || hasExtension("EGL_KHR_image")) &&
+ hasExtension("EGL_ANDROID_image_native_buffer"))
+ {
+ mHaveDirectTexture = true;
+ }
+#else
+#warning "EGL_ANDROID_image_native_buffer not supported"
+#endif
+
+ if (hasExtension("GL_ARB_texture_non_power_of_two")) {
+ mHaveNpot = true;
+ }
+
+ if (hasExtension("GL_OES_texture_external")) {
+ mHaveTextureExternal = true;
+ } else if (strstr(mRenderer.string(), "Adreno")) {
+ // hack for Adreno 200
+ mHaveTextureExternal = true;
+ }
+}
+
+bool GLExtensions::hasExtension(char const* extension) const
+{
+ const String8 s(extension);
+ return mExtensionList.indexOf(s) >= 0;
+}
+
+char const* GLExtensions::getVendor() const {
+ return mVendor.string();
+}
+
+char const* GLExtensions::getRenderer() const {
+ return mRenderer.string();
+}
+
+char const* GLExtensions::getVersion() const {
+ return mVersion.string();
+}
+
+char const* GLExtensions::getExtension() const {
+ return mExtensions.string();
+}
+
+char const* GLExtensions::getEglVendor() const {
+ return mEglVendor.string();
+}
+
+char const* GLExtensions::getEglVersion() const {
+ return mEglVersion.string();
+}
+
+char const* GLExtensions::getEglExtension() const {
+ return mEglExtensions.string();
+}
+
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/services/surfaceflinger/GLExtensions.h b/services/surfaceflinger/GLExtensions.h
new file mode 100644
index 0000000..bbb284e
--- /dev/null
+++ b/services/surfaceflinger/GLExtensions.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef ANDROID_SF_GLEXTENSION_H
+#define ANDROID_SF_GLEXTENSION_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/String8.h>
+#include <utils/SortedVector.h>
+#include <utils/Singleton.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+class GLExtensions : public Singleton<GLExtensions>
+{
+ friend class Singleton<GLExtensions>;
+
+ bool mHaveTextureExternal : 1;
+ bool mHaveNpot : 1;
+ bool mHaveDirectTexture : 1;
+
+ String8 mVendor;
+ String8 mRenderer;
+ String8 mVersion;
+ String8 mExtensions;
+ String8 mEglVendor;
+ String8 mEglVersion;
+ String8 mEglExtensions;
+ SortedVector<String8> mExtensionList;
+
+ GLExtensions(const GLExtensions&);
+ GLExtensions& operator = (const GLExtensions&);
+
+protected:
+ GLExtensions();
+
+public:
+ inline bool haveTextureExternal() const {
+ return mHaveTextureExternal;
+ }
+ inline bool haveNpot() const {
+ return mHaveNpot;
+ }
+ inline bool haveDirectTexture() const {
+ return mHaveDirectTexture;
+ }
+
+ void initWithGLStrings(
+ GLubyte const* vendor,
+ GLubyte const* renderer,
+ GLubyte const* version,
+ GLubyte const* extensions,
+ char const* egl_vendor,
+ char const* egl_version,
+ char const* egl_extensions);
+
+ char const* getVendor() const;
+ char const* getRenderer() const;
+ char const* getVersion() const;
+ char const* getExtension() const;
+
+ char const* getEglVendor() const;
+ char const* getEglVersion() const;
+ char const* getEglExtension() const;
+
+ bool hasExtension(char const* extension) const;
+};
+
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_SF_GLEXTENSION_H
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
new file mode 100644
index 0000000..758da4e
--- /dev/null
+++ b/services/surfaceflinger/Layer.cpp
@@ -0,0 +1,875 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <cutils/properties.h>
+#include <cutils/native_handle.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/StopWatch.h>
+
+#include <ui/GraphicBuffer.h>
+#include <ui/PixelFormat.h>
+
+#include <surfaceflinger/Surface.h>
+
+#include "clz.h"
+#include "GLExtensions.h"
+#include "Layer.h"
+#include "SurfaceFlinger.h"
+#include "DisplayHardware/DisplayHardware.h"
+
+
+#define DEBUG_RESIZE 0
+
+
+namespace android {
+
+template <typename T> inline T min(T a, T b) {
+ return a<b ? a : b;
+}
+
+// ---------------------------------------------------------------------------
+
+Layer::Layer(SurfaceFlinger* flinger,
+ DisplayID display, const sp<Client>& client)
+ : LayerBaseClient(flinger, display, client),
+ mGLExtensions(GLExtensions::getInstance()),
+ mNeedsBlending(true),
+ mNeedsDithering(false),
+ mSecure(false),
+ mTextureManager(),
+ mBufferManager(mTextureManager),
+ mWidth(0), mHeight(0), mFixedSize(false)
+{
+}
+
+Layer::~Layer()
+{
+ // FIXME: must be called from the main UI thread
+ EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
+ mBufferManager.destroy(dpy);
+
+ // we can use getUserClientUnsafe here because we know we're
+ // single-threaded at that point.
+ sp<UserClient> ourClient(mUserClientRef.getUserClientUnsafe());
+ if (ourClient != 0) {
+ ourClient->detachLayer(this);
+ }
+}
+
+status_t Layer::setToken(const sp<UserClient>& userClient,
+ SharedClient* sharedClient, int32_t token)
+{
+ sp<SharedBufferServer> lcblk = new SharedBufferServer(
+ sharedClient, token, mBufferManager.getDefaultBufferCount(),
+ getIdentity());
+
+ status_t err = mUserClientRef.setToken(userClient, lcblk, token);
+
+ LOGE_IF(err != NO_ERROR,
+ "ClientRef::setToken(%p, %p, %u) failed",
+ userClient.get(), lcblk.get(), token);
+
+ if (err == NO_ERROR) {
+ // we need to free the buffers associated with this surface
+ }
+
+ return err;
+}
+
+int32_t Layer::getToken() const
+{
+ return mUserClientRef.getToken();
+}
+
+sp<UserClient> Layer::getClient() const
+{
+ return mUserClientRef.getClient();
+}
+
+// called with SurfaceFlinger::mStateLock as soon as the layer is entered
+// in the purgatory list
+void Layer::onRemoved()
+{
+ ClientRef::Access sharedClient(mUserClientRef);
+ SharedBufferServer* lcblk(sharedClient.get());
+ if (lcblk) {
+ // wake up the condition
+ lcblk->setStatus(NO_INIT);
+ }
+}
+
+sp<LayerBaseClient::Surface> Layer::createSurface() const
+{
+ return mSurface;
+}
+
+status_t Layer::ditch()
+{
+ // NOTE: Called from the main UI thread
+
+ // the layer is not on screen anymore. free as much resources as possible
+ mFreezeLock.clear();
+
+ EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
+ mBufferManager.destroy(dpy);
+ mSurface.clear();
+
+ Mutex::Autolock _l(mLock);
+ mWidth = mHeight = 0;
+ return NO_ERROR;
+}
+
+status_t Layer::setBuffers( uint32_t w, uint32_t h,
+ PixelFormat format, uint32_t flags)
+{
+ // this surfaces pixel format
+ PixelFormatInfo info;
+ status_t err = getPixelFormatInfo(format, &info);
+ if (err) return err;
+
+ // the display's pixel format
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ uint32_t const maxSurfaceDims = min(
+ hw.getMaxTextureSize(), hw.getMaxViewportDims());
+
+ // never allow a surface larger than what our underlying GL implementation
+ // can handle.
+ if ((uint32_t(w)>maxSurfaceDims) || (uint32_t(h)>maxSurfaceDims)) {
+ return BAD_VALUE;
+ }
+
+ PixelFormatInfo displayInfo;
+ getPixelFormatInfo(hw.getFormat(), &displayInfo);
+ const uint32_t hwFlags = hw.getFlags();
+
+ mFormat = format;
+ mReqFormat = format;
+ mWidth = w;
+ mHeight = h;
+ mSecure = (flags & ISurfaceComposer::eSecure) ? true : false;
+ mNeedsBlending = (info.h_alpha - info.l_alpha) > 0;
+
+ // we use the red index
+ int displayRedSize = displayInfo.getSize(PixelFormatInfo::INDEX_RED);
+ int layerRedsize = info.getSize(PixelFormatInfo::INDEX_RED);
+ mNeedsDithering = layerRedsize > displayRedSize;
+
+ mSurface = new SurfaceLayer(mFlinger, this);
+ return NO_ERROR;
+}
+
+void Layer::reloadTexture(const Region& dirty)
+{
+ sp<GraphicBuffer> buffer(mBufferManager.getActiveBuffer());
+ if (buffer == NULL) {
+ // this situation can happen if we ran out of memory for instance.
+ // not much we can do. continue to use whatever texture was bound
+ // to this context.
+ return;
+ }
+
+ if (mGLExtensions.haveDirectTexture()) {
+ EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
+ if (mBufferManager.initEglImage(dpy, buffer) != NO_ERROR) {
+ // not sure what we can do here...
+ goto slowpath;
+ }
+ } else {
+slowpath:
+ GGLSurface t;
+ status_t res = buffer->lock(&t, GRALLOC_USAGE_SW_READ_OFTEN);
+ LOGE_IF(res, "error %d (%s) locking buffer %p",
+ res, strerror(res), buffer.get());
+ if (res == NO_ERROR) {
+ mBufferManager.loadTexture(dirty, t);
+ buffer->unlock();
+ }
+ }
+}
+
+void Layer::onDraw(const Region& clip) const
+{
+ Texture tex(mBufferManager.getActiveTexture());
+ if (tex.name == -1LU) {
+ // the texture has not been created yet, this Layer has
+ // in fact never been drawn into. This happens frequently with
+ // SurfaceView because the WindowManager can't know when the client
+ // has drawn the first time.
+
+ // If there is nothing under us, we paint the screen in black, otherwise
+ // we just skip this update.
+
+ // figure out if there is something below us
+ Region under;
+ const SurfaceFlinger::LayerVector& drawingLayers(mFlinger->mDrawingState.layersSortedByZ);
+ const size_t count = drawingLayers.size();
+ for (size_t i=0 ; i<count ; ++i) {
+ const sp<LayerBase>& layer(drawingLayers[i]);
+ if (layer.get() == static_cast<LayerBase const*>(this))
+ break;
+ under.orSelf(layer->visibleRegionScreen);
+ }
+ // if not everything below us is covered, we plug the holes!
+ Region holes(clip.subtract(under));
+ if (!holes.isEmpty()) {
+ clearWithOpenGL(holes, 0, 0, 0, 1);
+ }
+ return;
+ }
+ drawWithOpenGL(clip, tex);
+}
+
+bool Layer::needsFiltering() const
+{
+ if (!(mFlags & DisplayHardware::SLOW_CONFIG)) {
+ // NOTE: there is a race here, because mFixedSize is updated in a
+ // binder transaction. however, it doesn't really matter since it is
+ // evaluated each time we draw. To be perfectly correct, this flag
+ // would have to be associated with a buffer.
+ if (mFixedSize)
+ return true;
+ }
+ return LayerBase::needsFiltering();
+}
+
+
+status_t Layer::setBufferCount(int bufferCount)
+{
+ ClientRef::Access sharedClient(mUserClientRef);
+ SharedBufferServer* lcblk(sharedClient.get());
+ if (!lcblk) {
+ // oops, the client is already gone
+ return DEAD_OBJECT;
+ }
+
+ // NOTE: lcblk->resize() is protected by an internal lock
+ status_t err = lcblk->resize(bufferCount);
+ if (err == NO_ERROR)
+ mBufferManager.resize(bufferCount);
+
+ return err;
+}
+
+sp<GraphicBuffer> Layer::requestBuffer(int index,
+ uint32_t reqWidth, uint32_t reqHeight, uint32_t reqFormat,
+ uint32_t usage)
+{
+ sp<GraphicBuffer> buffer;
+
+ if (int32_t(reqWidth | reqHeight | reqFormat) < 0)
+ return buffer;
+
+ if ((!reqWidth && reqHeight) || (reqWidth && !reqHeight))
+ return buffer;
+
+ // this ensures our client doesn't go away while we're accessing
+ // the shared area.
+ ClientRef::Access sharedClient(mUserClientRef);
+ SharedBufferServer* lcblk(sharedClient.get());
+ if (!lcblk) {
+ // oops, the client is already gone
+ return buffer;
+ }
+
+ /*
+ * This is called from the client's Surface::dequeue(). This can happen
+ * at any time, especially while we're in the middle of using the
+ * buffer 'index' as our front buffer.
+ *
+ * Make sure the buffer we're resizing is not the front buffer and has been
+ * dequeued. Once this condition is asserted, we are guaranteed that this
+ * buffer cannot become the front buffer under our feet, since we're called
+ * from Surface::dequeue()
+ */
+ status_t err = lcblk->assertReallocate(index);
+ LOGE_IF(err, "assertReallocate(%d) failed (%s)", index, strerror(-err));
+ if (err != NO_ERROR) {
+ // the surface may have died
+ return buffer;
+ }
+
+ uint32_t w, h, f;
+ { // scope for the lock
+ Mutex::Autolock _l(mLock);
+ const bool fixedSizeChanged = mFixedSize != (reqWidth && reqHeight);
+ const bool formatChanged = mReqFormat != reqFormat;
+ mReqWidth = reqWidth;
+ mReqHeight = reqHeight;
+ mReqFormat = reqFormat;
+ mFixedSize = reqWidth && reqHeight;
+ w = reqWidth ? reqWidth : mWidth;
+ h = reqHeight ? reqHeight : mHeight;
+ f = reqFormat ? reqFormat : mFormat;
+ buffer = mBufferManager.detachBuffer(index);
+ if (fixedSizeChanged || formatChanged) {
+ lcblk->reallocateAllExcept(index);
+ }
+ }
+
+ const uint32_t effectiveUsage = getEffectiveUsage(usage);
+ if (buffer!=0 && buffer->getStrongCount() == 1) {
+ err = buffer->reallocate(w, h, f, effectiveUsage);
+ } else {
+ // here we have to reallocate a new buffer because we could have a
+ // client in our process with a reference to it (eg: status bar),
+ // and we can't release the handle under its feet.
+ buffer.clear();
+ buffer = new GraphicBuffer(w, h, f, effectiveUsage);
+ err = buffer->initCheck();
+ }
+
+ if (err || buffer->handle == 0) {
+ LOGE_IF(err || buffer->handle == 0,
+ "Layer::requestBuffer(this=%p), index=%d, w=%d, h=%d failed (%s)",
+ this, index, w, h, strerror(-err));
+ } else {
+ LOGD_IF(DEBUG_RESIZE,
+ "Layer::requestBuffer(this=%p), index=%d, w=%d, h=%d, handle=%p",
+ this, index, w, h, buffer->handle);
+ }
+
+ if (err == NO_ERROR && buffer->handle != 0) {
+ Mutex::Autolock _l(mLock);
+ mBufferManager.attachBuffer(index, buffer);
+ }
+ return buffer;
+}
+
+uint32_t Layer::getEffectiveUsage(uint32_t usage) const
+{
+ /*
+ * buffers used for software rendering, but h/w composition
+ * are allocated with SW_READ_OFTEN | SW_WRITE_OFTEN | HW_TEXTURE
+ *
+ * buffers used for h/w rendering and h/w composition
+ * are allocated with HW_RENDER | HW_TEXTURE
+ *
+ * buffers used with h/w rendering and either NPOT or no egl_image_ext
+ * are allocated with SW_READ_RARELY | HW_RENDER
+ *
+ */
+
+ if (mSecure) {
+ // secure buffer, don't store it into the GPU
+ usage = GraphicBuffer::USAGE_SW_READ_OFTEN |
+ GraphicBuffer::USAGE_SW_WRITE_OFTEN;
+ } else {
+ // it's allowed to modify the usage flags here, but generally
+ // the requested flags should be honored.
+ // request EGLImage for all buffers
+ usage |= GraphicBuffer::USAGE_HW_TEXTURE;
+ }
+ return usage;
+}
+
+uint32_t Layer::doTransaction(uint32_t flags)
+{
+ const Layer::State& front(drawingState());
+ const Layer::State& temp(currentState());
+
+ const bool sizeChanged = (front.requested_w != temp.requested_w) ||
+ (front.requested_h != temp.requested_h);
+
+ if (sizeChanged) {
+ // the size changed, we need to ask our client to request a new buffer
+ LOGD_IF(DEBUG_RESIZE,
+ "resize (layer=%p), requested (%dx%d), drawing (%d,%d)",
+ this,
+ int(temp.requested_w), int(temp.requested_h),
+ int(front.requested_w), int(front.requested_h));
+
+ if (!isFixedSize()) {
+ // we're being resized and there is a freeze display request,
+ // acquire a freeze lock, so that the screen stays put
+ // until we've redrawn at the new size; this is to avoid
+ // glitches upon orientation changes.
+ if (mFlinger->hasFreezeRequest()) {
+ // if the surface is hidden, don't try to acquire the
+ // freeze lock, since hidden surfaces may never redraw
+ if (!(front.flags & ISurfaceComposer::eLayerHidden)) {
+ mFreezeLock = mFlinger->getFreezeLock();
+ }
+ }
+
+ // this will make sure LayerBase::doTransaction doesn't update
+ // the drawing state's size
+ Layer::State& editDraw(mDrawingState);
+ editDraw.requested_w = temp.requested_w;
+ editDraw.requested_h = temp.requested_h;
+
+ // record the new size, form this point on, when the client request
+ // a buffer, it'll get the new size.
+ setBufferSize(temp.requested_w, temp.requested_h);
+
+ ClientRef::Access sharedClient(mUserClientRef);
+ SharedBufferServer* lcblk(sharedClient.get());
+ if (lcblk) {
+ // all buffers need reallocation
+ lcblk->reallocateAll();
+ }
+ } else {
+ // record the new size
+ setBufferSize(temp.requested_w, temp.requested_h);
+ }
+ }
+
+ if (temp.sequence != front.sequence) {
+ if (temp.flags & ISurfaceComposer::eLayerHidden || temp.alpha == 0) {
+ // this surface is now hidden, so it shouldn't hold a freeze lock
+ // (it may never redraw, which is fine if it is hidden)
+ mFreezeLock.clear();
+ }
+ }
+
+ return LayerBase::doTransaction(flags);
+}
+
+void Layer::setBufferSize(uint32_t w, uint32_t h) {
+ Mutex::Autolock _l(mLock);
+ mWidth = w;
+ mHeight = h;
+}
+
+bool Layer::isFixedSize() const {
+ Mutex::Autolock _l(mLock);
+ return mFixedSize;
+}
+
+// ----------------------------------------------------------------------------
+// pageflip handling...
+// ----------------------------------------------------------------------------
+
+void Layer::lockPageFlip(bool& recomputeVisibleRegions)
+{
+ ClientRef::Access sharedClient(mUserClientRef);
+ SharedBufferServer* lcblk(sharedClient.get());
+ if (!lcblk) {
+ // client died
+ recomputeVisibleRegions = true;
+ return;
+ }
+
+ ssize_t buf = lcblk->retireAndLock();
+ if (buf == NOT_ENOUGH_DATA) {
+ // NOTE: This is not an error, it simply means there is nothing to
+ // retire. The buffer is locked because we will use it
+ // for composition later in the loop
+ return;
+ }
+
+ if (buf < NO_ERROR) {
+ LOGE("retireAndLock() buffer index (%d) out of range", int(buf));
+ mPostedDirtyRegion.clear();
+ return;
+ }
+
+ // we retired a buffer, which becomes the new front buffer
+ if (mBufferManager.setActiveBufferIndex(buf) < NO_ERROR) {
+ LOGE("retireAndLock() buffer index (%d) out of range", int(buf));
+ mPostedDirtyRegion.clear();
+ return;
+ }
+
+ // get the dirty region
+ sp<GraphicBuffer> newFrontBuffer(getBuffer(buf));
+ if (newFrontBuffer != NULL) {
+ // compute the posted region
+ const Region dirty(lcblk->getDirtyRegion(buf));
+ mPostedDirtyRegion = dirty.intersect( newFrontBuffer->getBounds() );
+
+ // update the layer size and release freeze-lock
+ const Layer::State& front(drawingState());
+ if (newFrontBuffer->getWidth() == front.requested_w &&
+ newFrontBuffer->getHeight() == front.requested_h)
+ {
+ if ((front.w != front.requested_w) ||
+ (front.h != front.requested_h))
+ {
+ // Here we pretend the transaction happened by updating the
+ // current and drawing states. Drawing state is only accessed
+ // in this thread, no need to have it locked
+ Layer::State& editDraw(mDrawingState);
+ editDraw.w = editDraw.requested_w;
+ editDraw.h = editDraw.requested_h;
+
+ // We also need to update the current state so that we don't
+ // end-up doing too much work during the next transaction.
+ // NOTE: We actually don't need hold the transaction lock here
+ // because State::w and State::h are only accessed from
+ // this thread
+ Layer::State& editTemp(currentState());
+ editTemp.w = editDraw.w;
+ editTemp.h = editDraw.h;
+
+ // recompute visible region
+ recomputeVisibleRegions = true;
+ }
+
+ // we now have the correct size, unfreeze the screen
+ mFreezeLock.clear();
+ }
+ } else {
+ // this should not happen unless we ran out of memory while
+ // allocating the buffer. we're hoping that things will get back
+ // to normal the next time the app tries to draw into this buffer.
+ // meanwhile, pretend the screen didn't update.
+ mPostedDirtyRegion.clear();
+ }
+
+ if (lcblk->getQueuedCount()) {
+ // signal an event if we have more buffers waiting
+ mFlinger->signalEvent();
+ }
+
+ /* a buffer was posted, so we need to call reloadTexture(), which
+ * will update our internal data structures (eg: EGLImageKHR or
+ * texture names). we need to do this even if mPostedDirtyRegion is
+ * empty -- it's orthogonal to the fact that a new buffer was posted,
+ * for instance, a degenerate case could be that the user did an empty
+ * update but repainted the buffer with appropriate content (after a
+ * resize for instance).
+ */
+ reloadTexture( mPostedDirtyRegion );
+}
+
+void Layer::unlockPageFlip(
+ const Transform& planeTransform, Region& outDirtyRegion)
+{
+ Region dirtyRegion(mPostedDirtyRegion);
+ if (!dirtyRegion.isEmpty()) {
+ mPostedDirtyRegion.clear();
+ // The dirty region is given in the layer's coordinate space
+ // transform the dirty region by the surface's transformation
+ // and the global transformation.
+ const Layer::State& s(drawingState());
+ const Transform tr(planeTransform * s.transform);
+ dirtyRegion = tr.transform(dirtyRegion);
+
+ // At this point, the dirty region is in screen space.
+ // Make sure it's constrained by the visible region (which
+ // is in screen space as well).
+ dirtyRegion.andSelf(visibleRegionScreen);
+ outDirtyRegion.orSelf(dirtyRegion);
+ }
+ if (visibleRegionScreen.isEmpty()) {
+ // an invisible layer should not hold a freeze-lock
+ // (because it may never be updated and therefore never release it)
+ mFreezeLock.clear();
+ }
+}
+
+void Layer::finishPageFlip()
+{
+ ClientRef::Access sharedClient(mUserClientRef);
+ SharedBufferServer* lcblk(sharedClient.get());
+ if (lcblk) {
+ int buf = mBufferManager.getActiveBufferIndex();
+ if (buf >= 0) {
+ status_t err = lcblk->unlock( buf );
+ LOGE_IF(err!=NO_ERROR,
+ "layer %p, buffer=%d wasn't locked!",
+ this, buf);
+ }
+ }
+}
+
+
+void Layer::dump(String8& result, char* buffer, size_t SIZE) const
+{
+ LayerBaseClient::dump(result, buffer, SIZE);
+
+ ClientRef::Access sharedClient(mUserClientRef);
+ SharedBufferServer* lcblk(sharedClient.get());
+ uint32_t totalTime = 0;
+ if (lcblk) {
+ SharedBufferStack::Statistics stats = lcblk->getStats();
+ totalTime= stats.totalTime;
+ result.append( lcblk->dump(" ") );
+ }
+
+ sp<const GraphicBuffer> buf0(getBuffer(0));
+ sp<const GraphicBuffer> buf1(getBuffer(1));
+ uint32_t w0=0, h0=0, s0=0;
+ uint32_t w1=0, h1=0, s1=0;
+ if (buf0 != 0) {
+ w0 = buf0->getWidth();
+ h0 = buf0->getHeight();
+ s0 = buf0->getStride();
+ }
+ if (buf1 != 0) {
+ w1 = buf1->getWidth();
+ h1 = buf1->getHeight();
+ s1 = buf1->getStride();
+ }
+ snprintf(buffer, SIZE,
+ " "
+ "format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u],"
+ " freezeLock=%p, dq-q-time=%u us\n",
+ mFormat, w0, h0, s0, w1, h1, s1,
+ getFreezeLock().get(), totalTime);
+
+ result.append(buffer);
+}
+
+// ---------------------------------------------------------------------------
+
+Layer::ClientRef::ClientRef()
+ : mControlBlock(0), mToken(-1) {
+}
+
+Layer::ClientRef::~ClientRef() {
+}
+
+int32_t Layer::ClientRef::getToken() const {
+ Mutex::Autolock _l(mLock);
+ return mToken;
+}
+
+sp<UserClient> Layer::ClientRef::getClient() const {
+ Mutex::Autolock _l(mLock);
+ return mUserClient.promote();
+}
+
+status_t Layer::ClientRef::setToken(const sp<UserClient>& uc,
+ const sp<SharedBufferServer>& sharedClient, int32_t token) {
+ Mutex::Autolock _l(mLock);
+
+ { // scope for strong mUserClient reference
+ sp<UserClient> userClient(mUserClient.promote());
+ if (mUserClient != 0 && mControlBlock != 0) {
+ mControlBlock->setStatus(NO_INIT);
+ }
+ }
+
+ mUserClient = uc;
+ mToken = token;
+ mControlBlock = sharedClient;
+ return NO_ERROR;
+}
+
+sp<UserClient> Layer::ClientRef::getUserClientUnsafe() const {
+ return mUserClient.promote();
+}
+
+// this class gives us access to SharedBufferServer safely
+// it makes sure the UserClient (and its associated shared memory)
+// won't go away while we're accessing it.
+Layer::ClientRef::Access::Access(const ClientRef& ref)
+ : mControlBlock(0)
+{
+ Mutex::Autolock _l(ref.mLock);
+ mUserClientStrongRef = ref.mUserClient.promote();
+ if (mUserClientStrongRef != 0)
+ mControlBlock = ref.mControlBlock;
+}
+
+Layer::ClientRef::Access::~Access()
+{
+}
+
+// ---------------------------------------------------------------------------
+
+Layer::BufferManager::BufferManager(TextureManager& tm)
+ : mNumBuffers(NUM_BUFFERS), mTextureManager(tm),
+ mActiveBuffer(-1), mFailover(false)
+{
+}
+
+Layer::BufferManager::~BufferManager()
+{
+}
+
+status_t Layer::BufferManager::resize(size_t size)
+{
+ Mutex::Autolock _l(mLock);
+ mNumBuffers = size;
+ return NO_ERROR;
+}
+
+// only for debugging
+sp<GraphicBuffer> Layer::BufferManager::getBuffer(size_t index) const {
+ return mBufferData[index].buffer;
+}
+
+status_t Layer::BufferManager::setActiveBufferIndex(size_t index) {
+ mActiveBuffer = index;
+ return NO_ERROR;
+}
+
+size_t Layer::BufferManager::getActiveBufferIndex() const {
+ return mActiveBuffer;
+}
+
+Texture Layer::BufferManager::getActiveTexture() const {
+ Texture res;
+ if (mFailover || mActiveBuffer<0) {
+ res = mFailoverTexture;
+ } else {
+ static_cast<Image&>(res) = mBufferData[mActiveBuffer].texture;
+ }
+ return res;
+}
+
+sp<GraphicBuffer> Layer::BufferManager::getActiveBuffer() const {
+ sp<GraphicBuffer> result;
+ const ssize_t activeBuffer = mActiveBuffer;
+ if (activeBuffer >= 0) {
+ BufferData const * const buffers = mBufferData;
+ Mutex::Autolock _l(mLock);
+ result = buffers[activeBuffer].buffer;
+ }
+ return result;
+}
+
+sp<GraphicBuffer> Layer::BufferManager::detachBuffer(size_t index)
+{
+ BufferData* const buffers = mBufferData;
+ sp<GraphicBuffer> buffer;
+ Mutex::Autolock _l(mLock);
+ buffer = buffers[index].buffer;
+ buffers[index].buffer = 0;
+ return buffer;
+}
+
+status_t Layer::BufferManager::attachBuffer(size_t index,
+ const sp<GraphicBuffer>& buffer)
+{
+ BufferData* const buffers = mBufferData;
+ Mutex::Autolock _l(mLock);
+ buffers[index].buffer = buffer;
+ buffers[index].texture.dirty = true;
+ return NO_ERROR;
+}
+
+status_t Layer::BufferManager::destroy(EGLDisplay dpy)
+{
+ BufferData* const buffers = mBufferData;
+ size_t num;
+ { // scope for the lock
+ Mutex::Autolock _l(mLock);
+ num = mNumBuffers;
+ for (size_t i=0 ; i<num ; i++) {
+ buffers[i].buffer = 0;
+ }
+ }
+ for (size_t i=0 ; i<num ; i++) {
+ destroyTexture(&buffers[i].texture, dpy);
+ }
+ destroyTexture(&mFailoverTexture, dpy);
+ return NO_ERROR;
+}
+
+status_t Layer::BufferManager::initEglImage(EGLDisplay dpy,
+ const sp<GraphicBuffer>& buffer)
+{
+ status_t err = NO_INIT;
+ ssize_t index = mActiveBuffer;
+ if (index >= 0) {
+ if (!mFailover) {
+ Image& texture(mBufferData[index].texture);
+ err = mTextureManager.initEglImage(&texture, dpy, buffer);
+ // if EGLImage fails, we switch to regular texture mode, and we
+ // free all resources associated with using EGLImages.
+ if (err == NO_ERROR) {
+ mFailover = false;
+ destroyTexture(&mFailoverTexture, dpy);
+ } else {
+ mFailover = true;
+ const size_t num = mNumBuffers;
+ for (size_t i=0 ; i<num ; i++) {
+ destroyTexture(&mBufferData[i].texture, dpy);
+ }
+ }
+ } else {
+ // we failed once, don't try again
+ err = BAD_VALUE;
+ }
+ }
+ return err;
+}
+
+status_t Layer::BufferManager::loadTexture(
+ const Region& dirty, const GGLSurface& t)
+{
+ return mTextureManager.loadTexture(&mFailoverTexture, dirty, t);
+}
+
+status_t Layer::BufferManager::destroyTexture(Image* tex, EGLDisplay dpy)
+{
+ if (tex->name != -1U) {
+ glDeleteTextures(1, &tex->name);
+ tex->name = -1U;
+ }
+ if (tex->image != EGL_NO_IMAGE_KHR) {
+ eglDestroyImageKHR(dpy, tex->image);
+ tex->image = EGL_NO_IMAGE_KHR;
+ }
+ return NO_ERROR;
+}
+
+// ---------------------------------------------------------------------------
+
+Layer::SurfaceLayer::SurfaceLayer(const sp<SurfaceFlinger>& flinger,
+ const sp<Layer>& owner)
+ : Surface(flinger, owner->getIdentity(), owner)
+{
+}
+
+Layer::SurfaceLayer::~SurfaceLayer()
+{
+}
+
+sp<GraphicBuffer> Layer::SurfaceLayer::requestBuffer(int index,
+ uint32_t w, uint32_t h, uint32_t format, uint32_t usage)
+{
+ sp<GraphicBuffer> buffer;
+ sp<Layer> owner(getOwner());
+ if (owner != 0) {
+ /*
+ * requestBuffer() cannot be called from the main thread
+ * as it could cause a dead-lock, since it may have to wait
+ * on conditions updated my the main thread.
+ */
+ buffer = owner->requestBuffer(index, w, h, format, usage);
+ }
+ return buffer;
+}
+
+status_t Layer::SurfaceLayer::setBufferCount(int bufferCount)
+{
+ status_t err = DEAD_OBJECT;
+ sp<Layer> owner(getOwner());
+ if (owner != 0) {
+ /*
+ * setBufferCount() cannot be called from the main thread
+ * as it could cause a dead-lock, since it may have to wait
+ * on conditions updated my the main thread.
+ */
+ err = owner->setBufferCount(bufferCount);
+ }
+ return err;
+}
+
+// ---------------------------------------------------------------------------
+
+
+}; // namespace android
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
new file mode 100644
index 0000000..e1d283b
--- /dev/null
+++ b/services/surfaceflinger/Layer.h
@@ -0,0 +1,239 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_LAYER_H
+#define ANDROID_LAYER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <ui/GraphicBuffer.h>
+#include <ui/PixelFormat.h>
+#include <pixelflinger/pixelflinger.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include "LayerBase.h"
+#include "Transform.h"
+#include "TextureManager.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class FreezeLock;
+class Client;
+class GLExtensions;
+class UserClient;
+
+// ---------------------------------------------------------------------------
+
+class Layer : public LayerBaseClient
+{
+public:
+ Layer(SurfaceFlinger* flinger, DisplayID display,
+ const sp<Client>& client);
+
+ virtual ~Layer();
+
+ virtual const char* getTypeId() const { return "Layer"; }
+
+ // the this layer's size and format
+ status_t setBuffers(uint32_t w, uint32_t h,
+ PixelFormat format, uint32_t flags=0);
+
+ // associate a UserClient to this Layer
+ status_t setToken(const sp<UserClient>& uc, SharedClient* sc, int32_t idx);
+ int32_t getToken() const;
+ sp<UserClient> getClient() const;
+
+ // Set this Layer's buffers size
+ void setBufferSize(uint32_t w, uint32_t h);
+ bool isFixedSize() const;
+
+ // LayerBase interface
+ virtual void onDraw(const Region& clip) const;
+ virtual uint32_t doTransaction(uint32_t transactionFlags);
+ virtual void lockPageFlip(bool& recomputeVisibleRegions);
+ virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
+ virtual void finishPageFlip();
+ virtual bool needsBlending() const { return mNeedsBlending; }
+ virtual bool needsDithering() const { return mNeedsDithering; }
+ virtual bool needsFiltering() const;
+ virtual bool isSecure() const { return mSecure; }
+ virtual sp<Surface> createSurface() const;
+ virtual status_t ditch();
+ virtual void onRemoved();
+
+ // only for debugging
+ inline sp<GraphicBuffer> getBuffer(int i) const {
+ return mBufferManager.getBuffer(i); }
+ // only for debugging
+ inline const sp<FreezeLock>& getFreezeLock() const {
+ return mFreezeLock; }
+
+protected:
+ virtual void dump(String8& result, char* scratch, size_t size) const;
+
+private:
+ void reloadTexture(const Region& dirty);
+ uint32_t getEffectiveUsage(uint32_t usage) const;
+ sp<GraphicBuffer> requestBuffer(int bufferIdx,
+ uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
+ status_t setBufferCount(int bufferCount);
+
+ // -----------------------------------------------------------------------
+
+ class SurfaceLayer : public LayerBaseClient::Surface {
+ public:
+ SurfaceLayer(const sp<SurfaceFlinger>& flinger, const sp<Layer>& owner);
+ ~SurfaceLayer();
+ private:
+ virtual sp<GraphicBuffer> requestBuffer(int bufferIdx,
+ uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
+ virtual status_t setBufferCount(int bufferCount);
+ sp<Layer> getOwner() const {
+ return static_cast<Layer*>(Surface::getOwner().get());
+ }
+ };
+ friend class SurfaceLayer;
+
+ // -----------------------------------------------------------------------
+
+ class ClientRef {
+ ClientRef(const ClientRef& rhs);
+ ClientRef& operator = (const ClientRef& rhs);
+ mutable Mutex mLock;
+ // binder thread, page-flip thread
+ sp<SharedBufferServer> mControlBlock;
+ wp<UserClient> mUserClient;
+ int32_t mToken;
+ public:
+ ClientRef();
+ ~ClientRef();
+ int32_t getToken() const;
+ sp<UserClient> getClient() const;
+ status_t setToken(const sp<UserClient>& uc,
+ const sp<SharedBufferServer>& sharedClient, int32_t token);
+ sp<UserClient> getUserClientUnsafe() const;
+ class Access {
+ Access(const Access& rhs);
+ Access& operator = (const Access& rhs);
+ sp<UserClient> mUserClientStrongRef;
+ sp<SharedBufferServer> mControlBlock;
+ public:
+ Access(const ClientRef& ref);
+ ~Access();
+ inline SharedBufferServer* get() const { return mControlBlock.get(); }
+ };
+ friend class Access;
+ };
+
+ // -----------------------------------------------------------------------
+
+ class BufferManager {
+ static const size_t NUM_BUFFERS = 2;
+ struct BufferData {
+ sp<GraphicBuffer> buffer;
+ Image texture;
+ };
+ // this lock protect mBufferData[].buffer but since there
+ // is very little contention, we have only one like for
+ // the whole array, we also use it to protect mNumBuffers.
+ mutable Mutex mLock;
+ BufferData mBufferData[SharedBufferStack::NUM_BUFFER_MAX];
+ size_t mNumBuffers;
+ Texture mFailoverTexture;
+ TextureManager& mTextureManager;
+ ssize_t mActiveBuffer;
+ bool mFailover;
+ static status_t destroyTexture(Image* tex, EGLDisplay dpy);
+
+ public:
+ static size_t getDefaultBufferCount() { return NUM_BUFFERS; }
+ BufferManager(TextureManager& tm);
+ ~BufferManager();
+
+ // detach/attach buffer from/to given index
+ sp<GraphicBuffer> detachBuffer(size_t index);
+ status_t attachBuffer(size_t index, const sp<GraphicBuffer>& buffer);
+ // resize the number of active buffers
+ status_t resize(size_t size);
+
+ // ----------------------------------------------
+ // must be called from GL thread
+
+ // set/get active buffer index
+ status_t setActiveBufferIndex(size_t index);
+ size_t getActiveBufferIndex() const;
+ // return the active buffer
+ sp<GraphicBuffer> getActiveBuffer() const;
+ // return the active texture (or fail-over)
+ Texture getActiveTexture() const;
+ // frees resources associated with all buffers
+ status_t destroy(EGLDisplay dpy);
+ // load bitmap data into the active buffer
+ status_t loadTexture(const Region& dirty, const GGLSurface& t);
+ // make active buffer an EGLImage if needed
+ status_t initEglImage(EGLDisplay dpy,
+ const sp<GraphicBuffer>& buffer);
+
+ // ----------------------------------------------
+ // only for debugging
+ sp<GraphicBuffer> getBuffer(size_t index) const;
+ };
+
+ // -----------------------------------------------------------------------
+
+ // thread-safe
+ ClientRef mUserClientRef;
+
+ // constants
+ sp<Surface> mSurface;
+ PixelFormat mFormat;
+ const GLExtensions& mGLExtensions;
+ bool mNeedsBlending;
+ bool mNeedsDithering;
+
+ // page-flip thread (currently main thread)
+ bool mSecure;
+ Region mPostedDirtyRegion;
+
+ // page-flip thread and transaction thread (currently main thread)
+ sp<FreezeLock> mFreezeLock;
+
+ // see threading usage in declaration
+ TextureManager mTextureManager;
+ BufferManager mBufferManager;
+
+ // binder thread, transaction thread
+ mutable Mutex mLock;
+ uint32_t mWidth;
+ uint32_t mHeight;
+ uint32_t mReqWidth;
+ uint32_t mReqHeight;
+ uint32_t mReqFormat;
+ bool mFixedSize;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_LAYER_H
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
new file mode 100644
index 0000000..d5aa53f
--- /dev/null
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -0,0 +1,593 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <hardware/hardware.h>
+
+#include "clz.h"
+#include "LayerBase.h"
+#include "SurfaceFlinger.h"
+#include "DisplayHardware/DisplayHardware.h"
+#include "TextureManager.h"
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+LayerBase::LayerBase(SurfaceFlinger* flinger, DisplayID display)
+ : dpy(display), contentDirty(false),
+ mFlinger(flinger),
+ mNeedsFiltering(false),
+ mOrientation(0),
+ mLeft(0), mTop(0),
+ mTransactionFlags(0),
+ mPremultipliedAlpha(true), mName("unnamed"), mDebug(false),
+ mInvalidate(0)
+{
+ const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware());
+ mFlags = hw.getFlags();
+}
+
+LayerBase::~LayerBase()
+{
+}
+
+void LayerBase::setName(const String8& name) {
+ mName = name;
+}
+
+String8 LayerBase::getName() const {
+ return mName;
+}
+
+const GraphicPlane& LayerBase::graphicPlane(int dpy) const
+{
+ return mFlinger->graphicPlane(dpy);
+}
+
+GraphicPlane& LayerBase::graphicPlane(int dpy)
+{
+ return mFlinger->graphicPlane(dpy);
+}
+
+void LayerBase::initStates(uint32_t w, uint32_t h, uint32_t flags)
+{
+ uint32_t layerFlags = 0;
+ if (flags & ISurfaceComposer::eHidden)
+ layerFlags = ISurfaceComposer::eLayerHidden;
+
+ if (flags & ISurfaceComposer::eNonPremultiplied)
+ mPremultipliedAlpha = false;
+
+ mCurrentState.z = 0;
+ mCurrentState.w = w;
+ mCurrentState.h = h;
+ mCurrentState.requested_w = w;
+ mCurrentState.requested_h = h;
+ mCurrentState.alpha = 0xFF;
+ mCurrentState.flags = layerFlags;
+ mCurrentState.sequence = 0;
+ mCurrentState.transform.set(0, 0);
+
+ // drawing state & current state are identical
+ mDrawingState = mCurrentState;
+}
+
+void LayerBase::commitTransaction() {
+ mDrawingState = mCurrentState;
+}
+void LayerBase::forceVisibilityTransaction() {
+ // this can be called without SurfaceFlinger.mStateLock, but if we
+ // can atomically increment the sequence number, it doesn't matter.
+ android_atomic_inc(&mCurrentState.sequence);
+ requestTransaction();
+}
+bool LayerBase::requestTransaction() {
+ int32_t old = setTransactionFlags(eTransactionNeeded);
+ return ((old & eTransactionNeeded) == 0);
+}
+uint32_t LayerBase::getTransactionFlags(uint32_t flags) {
+ return android_atomic_and(~flags, &mTransactionFlags) & flags;
+}
+uint32_t LayerBase::setTransactionFlags(uint32_t flags) {
+ return android_atomic_or(flags, &mTransactionFlags);
+}
+
+bool LayerBase::setPosition(int32_t x, int32_t y) {
+ if (mCurrentState.transform.tx() == x && mCurrentState.transform.ty() == y)
+ return false;
+ mCurrentState.sequence++;
+ mCurrentState.transform.set(x, y);
+ requestTransaction();
+ return true;
+}
+bool LayerBase::setLayer(uint32_t z) {
+ if (mCurrentState.z == z)
+ return false;
+ mCurrentState.sequence++;
+ mCurrentState.z = z;
+ requestTransaction();
+ return true;
+}
+bool LayerBase::setSize(uint32_t w, uint32_t h) {
+ if (mCurrentState.requested_w == w && mCurrentState.requested_h == h)
+ return false;
+ mCurrentState.requested_w = w;
+ mCurrentState.requested_h = h;
+ requestTransaction();
+ return true;
+}
+bool LayerBase::setAlpha(uint8_t alpha) {
+ if (mCurrentState.alpha == alpha)
+ return false;
+ mCurrentState.sequence++;
+ mCurrentState.alpha = alpha;
+ requestTransaction();
+ return true;
+}
+bool LayerBase::setMatrix(const layer_state_t::matrix22_t& matrix) {
+ mCurrentState.sequence++;
+ mCurrentState.transform.set(
+ matrix.dsdx, matrix.dsdy, matrix.dtdx, matrix.dtdy);
+ requestTransaction();
+ return true;
+}
+bool LayerBase::setTransparentRegionHint(const Region& transparent) {
+ mCurrentState.sequence++;
+ mCurrentState.transparentRegion = transparent;
+ requestTransaction();
+ return true;
+}
+bool LayerBase::setFlags(uint8_t flags, uint8_t mask) {
+ const uint32_t newFlags = (mCurrentState.flags & ~mask) | (flags & mask);
+ if (mCurrentState.flags == newFlags)
+ return false;
+ mCurrentState.sequence++;
+ mCurrentState.flags = newFlags;
+ requestTransaction();
+ return true;
+}
+
+Rect LayerBase::visibleBounds() const
+{
+ return mTransformedBounds;
+}
+
+void LayerBase::setVisibleRegion(const Region& visibleRegion) {
+ // always called from main thread
+ visibleRegionScreen = visibleRegion;
+}
+
+void LayerBase::setCoveredRegion(const Region& coveredRegion) {
+ // always called from main thread
+ coveredRegionScreen = coveredRegion;
+}
+
+uint32_t LayerBase::doTransaction(uint32_t flags)
+{
+ const Layer::State& front(drawingState());
+ const Layer::State& temp(currentState());
+
+ if ((front.requested_w != temp.requested_w) ||
+ (front.requested_h != temp.requested_h)) {
+ // resize the layer, set the physical size to the requested size
+ Layer::State& editTemp(currentState());
+ editTemp.w = temp.requested_w;
+ editTemp.h = temp.requested_h;
+ }
+
+ if ((front.w != temp.w) || (front.h != temp.h)) {
+ // invalidate and recompute the visible regions if needed
+ flags |= Layer::eVisibleRegion;
+ }
+
+ if (temp.sequence != front.sequence) {
+ // invalidate and recompute the visible regions if needed
+ flags |= eVisibleRegion;
+ this->contentDirty = true;
+
+ mNeedsFiltering = false;
+ if (!(mFlags & DisplayHardware::SLOW_CONFIG)) {
+ // we may use linear filtering, if the matrix scales us
+ const uint8_t type = temp.transform.getType();
+ if (!temp.transform.preserveRects() || (type >= Transform::SCALE)) {
+ mNeedsFiltering = true;
+ }
+ }
+ }
+
+ // Commit the transaction
+ commitTransaction();
+ return flags;
+}
+
+void LayerBase::validateVisibility(const Transform& planeTransform)
+{
+ const Layer::State& s(drawingState());
+ const Transform tr(planeTransform * s.transform);
+ const bool transformed = tr.transformed();
+
+ uint32_t w = s.w;
+ uint32_t h = s.h;
+ tr.transform(mVertices[0], 0, 0);
+ tr.transform(mVertices[1], 0, h);
+ tr.transform(mVertices[2], w, h);
+ tr.transform(mVertices[3], w, 0);
+ if (UNLIKELY(transformed)) {
+ // NOTE: here we could also punt if we have too many rectangles
+ // in the transparent region
+ 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;
+ }
+
+ // cache a few things...
+ mOrientation = tr.getOrientation();
+ mTransformedBounds = tr.makeBounds(w, h);
+ mLeft = tr.tx();
+ mTop = tr.ty();
+}
+
+void LayerBase::lockPageFlip(bool& recomputeVisibleRegions)
+{
+}
+
+void LayerBase::unlockPageFlip(
+ const Transform& planeTransform, Region& outDirtyRegion)
+{
+ if ((android_atomic_and(~1, &mInvalidate)&1) == 1) {
+ outDirtyRegion.orSelf(visibleRegionScreen);
+ }
+}
+
+void LayerBase::finishPageFlip()
+{
+}
+
+void LayerBase::invalidate()
+{
+ if ((android_atomic_or(1, &mInvalidate)&1) == 0) {
+ mFlinger->signalEvent();
+ }
+}
+
+void LayerBase::drawRegion(const Region& reg) const
+{
+ Region::const_iterator it = reg.begin();
+ Region::const_iterator const end = reg.end();
+ if (it != end) {
+ Rect r;
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ const int32_t fbWidth = hw.getWidth();
+ const int32_t fbHeight = hw.getHeight();
+ const GLshort vertices[][2] = { { 0, 0 }, { fbWidth, 0 },
+ { fbWidth, fbHeight }, { 0, fbHeight } };
+ glVertexPointer(2, GL_SHORT, 0, vertices);
+ while (it != end) {
+ const Rect& r = *it++;
+ const GLint sy = fbHeight - (r.top + r.height());
+ glScissor(r.left, sy, r.width(), r.height());
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ }
+ }
+}
+
+void LayerBase::draw(const Region& inClip) const
+{
+ // invalidate the region we'll update
+ Region clip(inClip); // copy-on-write, so no-op most of the time
+
+ // Remove the transparent area from the clipping region
+ const State& s = drawingState();
+ if (LIKELY(!s.transparentRegion.isEmpty())) {
+ clip.subtract(transparentRegionScreen);
+ if (clip.isEmpty()) {
+ // usually this won't happen because this should be taken care of
+ // by SurfaceFlinger::computeVisibleRegions()
+ return;
+ }
+ }
+
+ // reset GL state
+ glEnable(GL_SCISSOR_TEST);
+
+ onDraw(clip);
+}
+
+void LayerBase::clearWithOpenGL(const Region& clip, GLclampf red,
+ GLclampf green, GLclampf blue,
+ GLclampf alpha) const
+{
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ const uint32_t fbHeight = hw.getHeight();
+ glColor4f(red,green,blue,alpha);
+
+ TextureManager::deactivateTextures();
+
+ glDisable(GL_BLEND);
+ glDisable(GL_DITHER);
+
+ Region::const_iterator it = clip.begin();
+ Region::const_iterator const end = clip.end();
+ glEnable(GL_SCISSOR_TEST);
+ glVertexPointer(2, GL_FLOAT, 0, mVertices);
+ while (it != end) {
+ const Rect& r = *it++;
+ const GLint sy = fbHeight - (r.top + r.height());
+ glScissor(r.left, sy, r.width(), r.height());
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ }
+}
+
+void LayerBase::clearWithOpenGL(const Region& clip) const
+{
+ clearWithOpenGL(clip,0,0,0,0);
+}
+
+void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const
+{
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ const uint32_t fbHeight = hw.getHeight();
+ const State& s(drawingState());
+
+ // bind our texture
+ TextureManager::activateTexture(texture, needsFiltering());
+ uint32_t width = texture.width;
+ uint32_t height = texture.height;
+
+ GLenum src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
+ if (UNLIKELY(s.alpha < 0xFF)) {
+ const GLfloat alpha = s.alpha * (1.0f/255.0f);
+ if (mPremultipliedAlpha) {
+ glColor4f(alpha, alpha, alpha, alpha);
+ } else {
+ glColor4f(1, 1, 1, alpha);
+ }
+ glEnable(GL_BLEND);
+ glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ } else {
+ glColor4f(1, 1, 1, 1);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ if (needsBlending()) {
+ glEnable(GL_BLEND);
+ glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
+ } else {
+ glDisable(GL_BLEND);
+ }
+ }
+
+ Region::const_iterator it = clip.begin();
+ Region::const_iterator const end = clip.end();
+ const GLfloat texCoords[4][2] = {
+ { 0, 0 },
+ { 0, 1 },
+ { 1, 1 },
+ { 1, 0 }
+ };
+
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+
+ // the texture's source is rotated
+ switch (texture.transform) {
+ case HAL_TRANSFORM_ROT_90:
+ glTranslatef(0, 1, 0);
+ glRotatef(-90, 0, 0, 1);
+ break;
+ case HAL_TRANSFORM_ROT_180:
+ glTranslatef(1, 1, 0);
+ glRotatef(-180, 0, 0, 1);
+ break;
+ case HAL_TRANSFORM_ROT_270:
+ glTranslatef(1, 0, 0);
+ glRotatef(-270, 0, 0, 1);
+ break;
+ }
+
+ if (texture.NPOTAdjust) {
+ glScalef(texture.wScale, texture.hScale, 1.0f);
+ }
+
+ if (needsDithering()) {
+ glEnable(GL_DITHER);
+ } else {
+ glDisable(GL_DITHER);
+ }
+
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glVertexPointer(2, GL_FLOAT, 0, mVertices);
+ glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
+
+ while (it != end) {
+ const Rect& r = *it++;
+ const GLint sy = fbHeight - (r.top + r.height());
+ glScissor(r.left, sy, r.width(), r.height());
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ }
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+}
+
+void LayerBase::dump(String8& result, char* buffer, size_t SIZE) const
+{
+ const Layer::State& s(drawingState());
+ snprintf(buffer, SIZE,
+ "+ %s %p\n"
+ " "
+ "z=%9d, pos=(%4d,%4d), size=(%4d,%4d), "
+ "needsBlending=%1d, needsDithering=%1d, invalidate=%1d, "
+ "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n",
+ getTypeId(), this, s.z, tx(), ty(), s.w, s.h,
+ needsBlending(), needsDithering(), contentDirty,
+ s.alpha, s.flags,
+ s.transform[0][0], s.transform[0][1],
+ s.transform[1][0], s.transform[1][1]);
+ result.append(buffer);
+}
+
+// ---------------------------------------------------------------------------
+
+int32_t LayerBaseClient::sIdentity = 1;
+
+LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,
+ const sp<Client>& client)
+ : LayerBase(flinger, display), mClientRef(client),
+ mIdentity(uint32_t(android_atomic_inc(&sIdentity)))
+{
+}
+
+LayerBaseClient::~LayerBaseClient()
+{
+ sp<Client> c(mClientRef.promote());
+ if (c != 0) {
+ c->detachLayer(this);
+ }
+}
+
+sp<LayerBaseClient::Surface> LayerBaseClient::getSurface()
+{
+ sp<Surface> s;
+ Mutex::Autolock _l(mLock);
+ s = mClientSurface.promote();
+ if (s == 0) {
+ s = createSurface();
+ mClientSurface = s;
+ }
+ return s;
+}
+
+sp<LayerBaseClient::Surface> LayerBaseClient::createSurface() const
+{
+ return new Surface(mFlinger, mIdentity,
+ const_cast<LayerBaseClient *>(this));
+}
+
+void LayerBaseClient::dump(String8& result, char* buffer, size_t SIZE) const
+{
+ LayerBase::dump(result, buffer, SIZE);
+
+ sp<Client> client(mClientRef.promote());
+ snprintf(buffer, SIZE,
+ " name=%s\n"
+ " client=%p, identity=%u\n",
+ getName().string(),
+ client.get(), getIdentity());
+
+ result.append(buffer);
+}
+
+// ---------------------------------------------------------------------------
+
+LayerBaseClient::Surface::Surface(
+ const sp<SurfaceFlinger>& flinger,
+ int identity,
+ const sp<LayerBaseClient>& owner)
+ : mFlinger(flinger), mIdentity(identity), mOwner(owner)
+{
+}
+
+LayerBaseClient::Surface::~Surface()
+{
+ /*
+ * This is a good place to clean-up all client resources
+ */
+
+ // destroy client resources
+ sp<LayerBaseClient> layer = getOwner();
+ if (layer != 0) {
+ mFlinger->destroySurface(layer);
+ }
+}
+
+sp<LayerBaseClient> LayerBaseClient::Surface::getOwner() const {
+ sp<LayerBaseClient> owner(mOwner.promote());
+ return owner;
+}
+
+status_t LayerBaseClient::Surface::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch (code) {
+ case REGISTER_BUFFERS:
+ case UNREGISTER_BUFFERS:
+ case CREATE_OVERLAY:
+ {
+ if (!mFlinger->mAccessSurfaceFlinger.checkCalling()) {
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ LOGE("Permission Denial: "
+ "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
+ return PERMISSION_DENIED;
+ }
+ }
+ }
+ return BnSurface::onTransact(code, data, reply, flags);
+}
+
+sp<GraphicBuffer> LayerBaseClient::Surface::requestBuffer(int bufferIdx,
+ uint32_t w, uint32_t h, uint32_t format, uint32_t usage)
+{
+ return NULL;
+}
+
+status_t LayerBaseClient::Surface::setBufferCount(int bufferCount)
+{
+ return INVALID_OPERATION;
+}
+
+status_t LayerBaseClient::Surface::registerBuffers(
+ const ISurface::BufferHeap& buffers)
+{
+ return INVALID_OPERATION;
+}
+
+void LayerBaseClient::Surface::postBuffer(ssize_t offset)
+{
+}
+
+void LayerBaseClient::Surface::unregisterBuffers()
+{
+}
+
+sp<OverlayRef> LayerBaseClient::Surface::createOverlay(
+ uint32_t w, uint32_t h, int32_t format, int32_t orientation)
+{
+ return NULL;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
new file mode 100644
index 0000000..4288cf7
--- /dev/null
+++ b/services/surfaceflinger/LayerBase.h
@@ -0,0 +1,333 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_LAYER_BASE_H
+#define ANDROID_LAYER_BASE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES/gl.h>
+
+#include <utils/RefBase.h>
+
+#include <ui/Region.h>
+#include <ui/Overlay.h>
+
+#include <surfaceflinger/ISurfaceComposerClient.h>
+#include <private/surfaceflinger/SharedBufferStack.h>
+#include <private/surfaceflinger/LayerState.h>
+
+#include <pixelflinger/pixelflinger.h>
+
+#include "Transform.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class DisplayHardware;
+class Client;
+class GraphicBuffer;
+class GraphicPlane;
+class LayerBaseClient;
+class SurfaceFlinger;
+class Texture;
+
+// ---------------------------------------------------------------------------
+
+class LayerBase : public RefBase
+{
+public:
+ LayerBase(SurfaceFlinger* flinger, DisplayID display);
+
+ DisplayID dpy;
+ mutable bool contentDirty;
+ Region visibleRegionScreen;
+ Region transparentRegionScreen;
+ Region coveredRegionScreen;
+
+ struct State {
+ uint32_t w;
+ uint32_t h;
+ uint32_t requested_w;
+ uint32_t requested_h;
+ uint32_t z;
+ uint8_t alpha;
+ uint8_t flags;
+ uint8_t reserved[2];
+ int32_t sequence; // changes when visible regions can change
+ uint32_t tint;
+ Transform transform;
+ Region transparentRegion;
+ };
+
+ void setName(const String8& name);
+ String8 getName() const;
+
+ // modify current state
+ bool setPosition(int32_t x, int32_t y);
+ bool setLayer(uint32_t z);
+ bool setSize(uint32_t w, uint32_t h);
+ bool setAlpha(uint8_t alpha);
+ bool setMatrix(const layer_state_t::matrix22_t& matrix);
+ bool setTransparentRegionHint(const Region& opaque);
+ bool setFlags(uint8_t flags, uint8_t mask);
+
+ void commitTransaction();
+ bool requestTransaction();
+ void forceVisibilityTransaction();
+
+ uint32_t getTransactionFlags(uint32_t flags);
+ uint32_t setTransactionFlags(uint32_t flags);
+
+ Rect visibleBounds() const;
+ void drawRegion(const Region& reg) const;
+
+ void invalidate();
+
+ virtual sp<LayerBaseClient> getLayerBaseClient() const { return 0; }
+
+ virtual const char* getTypeId() const { return "LayerBase"; }
+
+ /**
+ * draw - performs some global clipping optimizations
+ * and calls onDraw().
+ * Typically this method is not overridden, instead implement onDraw()
+ * to perform the actual drawing.
+ */
+ virtual void draw(const Region& clip) const;
+
+ /**
+ * onDraw - draws the surface.
+ */
+ virtual void onDraw(const Region& clip) const = 0;
+
+ /**
+ * initStates - called just after construction
+ */
+ virtual void initStates(uint32_t w, uint32_t h, uint32_t flags);
+
+ /**
+ * doTransaction - process the transaction. This is a good place to figure
+ * out which attributes of the surface have changed.
+ */
+ virtual uint32_t doTransaction(uint32_t transactionFlags);
+
+ /**
+ * setVisibleRegion - called to set the new visible region. This gives
+ * a chance to update the new visible region or record the fact it changed.
+ */
+ virtual void setVisibleRegion(const Region& visibleRegion);
+
+ /**
+ * setCoveredRegion - called when the covered region changes. The covered
+ * region corresponds to any area of the surface that is covered
+ * (transparently or not) by another surface.
+ */
+ virtual void setCoveredRegion(const Region& coveredRegion);
+
+ /**
+ * validateVisibility - cache a bunch of things
+ */
+ virtual void validateVisibility(const Transform& globalTransform);
+
+ /**
+ * lockPageFlip - called each time the screen is redrawn and returns whether
+ * the visible regions need to be recomputed (this is a fairly heavy
+ * operation, so this should be set only if needed). Typically this is used
+ * to figure out if the content or size of a surface has changed.
+ */
+ virtual void lockPageFlip(bool& recomputeVisibleRegions);
+
+ /**
+ * unlockPageFlip - called each time the screen is redrawn. updates the
+ * final dirty region wrt the planeTransform.
+ * At this point, all visible regions, surface position and size, etc... are
+ * correct.
+ */
+ virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
+
+ /**
+ * finishPageFlip - called after all surfaces have drawn.
+ */
+ virtual void finishPageFlip();
+
+ /**
+ * needsBlending - true if this surface needs blending
+ */
+ virtual bool needsBlending() const { return false; }
+
+ /**
+ * needsDithering - true if this surface needs dithering
+ */
+ virtual bool needsDithering() const { return false; }
+
+ /**
+ * needsLinearFiltering - true if this surface needs filtering
+ */
+ virtual bool needsFiltering() const { return mNeedsFiltering; }
+
+ /**
+ * isSecure - true if this surface is secure, that is if it prevents
+ * screenshots or VNC servers.
+ */
+ virtual bool isSecure() const { return false; }
+
+ /** Called from the main thread, when the surface is removed from the
+ * draw list */
+ virtual status_t ditch() { return NO_ERROR; }
+
+ /** called with the state lock when the surface is removed from the
+ * current list */
+ virtual void onRemoved() { };
+
+ /** always call base class first */
+ virtual void dump(String8& result, char* scratch, size_t size) const;
+
+
+ enum { // flags for doTransaction()
+ eVisibleRegion = 0x00000002,
+ };
+
+
+ inline const State& drawingState() const { return mDrawingState; }
+ inline const State& currentState() const { return mCurrentState; }
+ inline State& currentState() { return mCurrentState; }
+
+ static int compareCurrentStateZ(
+ sp<LayerBase> const * layerA,
+ sp<LayerBase> const * layerB) {
+ return layerA[0]->currentState().z - layerB[0]->currentState().z;
+ }
+
+ int32_t getOrientation() const { return mOrientation; }
+ int tx() const { return mLeft; }
+ int ty() const { return mTop; }
+
+protected:
+ const GraphicPlane& graphicPlane(int dpy) const;
+ GraphicPlane& graphicPlane(int dpy);
+
+ void clearWithOpenGL(const Region& clip, GLclampf r, GLclampf g,
+ GLclampf b, GLclampf alpha) const;
+ void clearWithOpenGL(const Region& clip) const;
+ void drawWithOpenGL(const Region& clip, const Texture& texture) const;
+
+ sp<SurfaceFlinger> mFlinger;
+ uint32_t mFlags;
+
+ // cached during validateVisibility()
+ bool mNeedsFiltering;
+ int32_t mOrientation;
+ GLfloat mVertices[4][2];
+ Rect mTransformedBounds;
+ int mLeft;
+ int mTop;
+
+ // these are protected by an external lock
+ State mCurrentState;
+ State mDrawingState;
+ volatile int32_t mTransactionFlags;
+
+ // don't change, don't need a lock
+ bool mPremultipliedAlpha;
+ String8 mName;
+ mutable bool mDebug;
+
+
+ // atomic
+ volatile int32_t mInvalidate;
+
+
+protected:
+ virtual ~LayerBase();
+
+private:
+ LayerBase(const LayerBase& rhs);
+};
+
+
+// ---------------------------------------------------------------------------
+
+class LayerBaseClient : public LayerBase
+{
+public:
+ class Surface;
+
+ LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,
+ const sp<Client>& client);
+ virtual ~LayerBaseClient();
+
+ sp<Surface> getSurface();
+ virtual sp<Surface> createSurface() const;
+ virtual sp<LayerBaseClient> getLayerBaseClient() const {
+ return const_cast<LayerBaseClient*>(this); }
+ virtual const char* getTypeId() const { return "LayerBaseClient"; }
+
+ uint32_t getIdentity() const { return mIdentity; }
+
+ class Surface : public BnSurface {
+ public:
+ int32_t getIdentity() const { return mIdentity; }
+
+ protected:
+ Surface(const sp<SurfaceFlinger>& flinger, int identity,
+ const sp<LayerBaseClient>& owner);
+ virtual ~Surface();
+ virtual status_t onTransact(uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags);
+ sp<LayerBaseClient> getOwner() const;
+
+ private:
+ virtual sp<GraphicBuffer> requestBuffer(int bufferIdx,
+ uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
+ virtual status_t setBufferCount(int bufferCount);
+
+ virtual status_t registerBuffers(const ISurface::BufferHeap& buffers);
+ virtual void postBuffer(ssize_t offset);
+ virtual void unregisterBuffers();
+ virtual sp<OverlayRef> createOverlay(uint32_t w, uint32_t h,
+ int32_t format, int32_t orientation);
+
+ protected:
+ friend class LayerBaseClient;
+ sp<SurfaceFlinger> mFlinger;
+ int32_t mIdentity;
+ wp<LayerBaseClient> mOwner;
+ };
+
+ friend class Surface;
+
+protected:
+ virtual void dump(String8& result, char* scratch, size_t size) const;
+
+private:
+ mutable Mutex mLock;
+ mutable wp<Surface> mClientSurface;
+ const wp<Client> mClientRef;
+ // only read
+ const uint32_t mIdentity;
+ static int32_t sIdentity;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_LAYER_BASE_H
diff --git a/services/surfaceflinger/LayerBlur.cpp b/services/surfaceflinger/LayerBlur.cpp
new file mode 100644
index 0000000..64a43c7
--- /dev/null
+++ b/services/surfaceflinger/LayerBlur.cpp
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include "clz.h"
+#include "BlurFilter.h"
+#include "LayerBlur.h"
+#include "SurfaceFlinger.h"
+#include "DisplayHardware/DisplayHardware.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+LayerBlur::LayerBlur(SurfaceFlinger* flinger, DisplayID display,
+ const sp<Client>& client)
+ : LayerBaseClient(flinger, display, client), mCacheDirty(true),
+ mRefreshCache(true), mCacheAge(0), mTextureName(-1U),
+ mWidthScale(1.0f), mHeightScale(1.0f),
+ mBlurFormat(GGL_PIXEL_FORMAT_RGB_565)
+{
+}
+
+LayerBlur::~LayerBlur()
+{
+ if (mTextureName != -1U) {
+ glDeleteTextures(1, &mTextureName);
+ }
+}
+
+void LayerBlur::setVisibleRegion(const Region& visibleRegion)
+{
+ LayerBaseClient::setVisibleRegion(visibleRegion);
+ if (visibleRegionScreen.isEmpty()) {
+ if (mTextureName != -1U) {
+ // We're not visible, free the texture up.
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glDeleteTextures(1, &mTextureName);
+ mTextureName = -1U;
+ }
+ }
+}
+
+uint32_t LayerBlur::doTransaction(uint32_t flags)
+{
+ // we're doing a transaction, refresh the cache!
+ if (!mFlinger->isFrozen()) {
+ mRefreshCache = true;
+ mCacheDirty = true;
+ flags |= eVisibleRegion;
+ this->contentDirty = true;
+ }
+ return LayerBase::doTransaction(flags);
+}
+
+void LayerBlur::unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion)
+{
+ // this code-path must be as tight as possible, it's called each time
+ // the screen is composited.
+ if (UNLIKELY(!visibleRegionScreen.isEmpty())) {
+ // if anything visible below us is invalidated, the cache becomes dirty
+ if (!mCacheDirty &&
+ !visibleRegionScreen.intersect(outDirtyRegion).isEmpty()) {
+ mCacheDirty = true;
+ }
+ if (mCacheDirty) {
+ if (!mFlinger->isFrozen()) {
+ // update everything below us that is visible
+ outDirtyRegion.orSelf(visibleRegionScreen);
+ nsecs_t now = systemTime();
+ if ((now - mCacheAge) >= ms2ns(500)) {
+ mCacheAge = now;
+ mRefreshCache = true;
+ mCacheDirty = false;
+ } else {
+ if (!mAutoRefreshPending) {
+ mFlinger->postMessageAsync(
+ new MessageBase(MessageQueue::INVALIDATE),
+ ms2ns(500));
+ mAutoRefreshPending = true;
+ }
+ }
+ }
+ }
+ }
+ LayerBase::unlockPageFlip(planeTransform, outDirtyRegion);
+}
+
+void LayerBlur::onDraw(const Region& clip) const
+{
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ const uint32_t fbHeight = hw.getHeight();
+ int x = mTransformedBounds.left;
+ int y = mTransformedBounds.top;
+ int w = mTransformedBounds.width();
+ int h = mTransformedBounds.height();
+ GLint X = x;
+ GLint Y = fbHeight - (y + h);
+ if (X < 0) {
+ w += X;
+ X = 0;
+ }
+ if (Y < 0) {
+ h += Y;
+ Y = 0;
+ }
+ if (w<0 || h<0) {
+ // we're outside of the framebuffer
+ return;
+ }
+
+ if (mTextureName == -1U) {
+ // create the texture name the first time
+ // can't do that in the ctor, because it runs in another thread.
+ glGenTextures(1, &mTextureName);
+ glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES, &mReadFormat);
+ glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE_OES, &mReadType);
+ if (mReadFormat != GL_RGB || mReadType != GL_UNSIGNED_SHORT_5_6_5) {
+ mReadFormat = GL_RGBA;
+ mReadType = GL_UNSIGNED_BYTE;
+ mBlurFormat = GGL_PIXEL_FORMAT_RGBX_8888;
+ }
+ }
+
+ Region::const_iterator it = clip.begin();
+ Region::const_iterator const end = clip.end();
+ if (it != end) {
+#if defined(GL_OES_texture_external)
+ if (GLExtensions::getInstance().haveTextureExternal()) {
+ glDisable(GL_TEXTURE_EXTERNAL_OES);
+ }
+#endif
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, mTextureName);
+
+ if (mRefreshCache) {
+ mRefreshCache = false;
+ mAutoRefreshPending = false;
+
+ int32_t pixelSize = 4;
+ int32_t s = w;
+ if (mReadType == GL_UNSIGNED_SHORT_5_6_5) {
+ // allocate enough memory for 4-bytes (2 pixels) aligned data
+ s = (w + 1) & ~1;
+ pixelSize = 2;
+ }
+
+ uint16_t* const pixels = (uint16_t*)malloc(s*h*pixelSize);
+
+ // This reads the frame-buffer, so a h/w GL would have to
+ // finish() its rendering first. we don't want to do that
+ // too often. Read data is 4-bytes aligned.
+ glReadPixels(X, Y, w, h, mReadFormat, mReadType, pixels);
+
+ // blur that texture.
+ GGLSurface bl;
+ bl.version = sizeof(GGLSurface);
+ bl.width = w;
+ bl.height = h;
+ bl.stride = s;
+ bl.format = mBlurFormat;
+ bl.data = (GGLubyte*)pixels;
+ blurFilter(&bl, 8, 2);
+
+ if (GLExtensions::getInstance().haveNpot()) {
+ glTexImage2D(GL_TEXTURE_2D, 0, mReadFormat, w, h, 0,
+ mReadFormat, mReadType, pixels);
+ mWidthScale = 1.0f / w;
+ mHeightScale =-1.0f / h;
+ mYOffset = 0;
+ } else {
+ GLuint tw = 1 << (31 - clz(w));
+ GLuint th = 1 << (31 - clz(h));
+ if (tw < GLuint(w)) tw <<= 1;
+ if (th < GLuint(h)) th <<= 1;
+ glTexImage2D(GL_TEXTURE_2D, 0, mReadFormat, tw, th, 0,
+ mReadFormat, mReadType, NULL);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h,
+ mReadFormat, mReadType, pixels);
+ mWidthScale = 1.0f / tw;
+ mHeightScale =-1.0f / th;
+ mYOffset = th-h;
+ }
+
+ free((void*)pixels);
+ }
+
+ const State& s = drawingState();
+ if (UNLIKELY(s.alpha < 0xFF)) {
+ const GLfloat alpha = s.alpha * (1.0f/255.0f);
+ glColor4f(0, 0, 0, alpha);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ } else {
+ glDisable(GL_BLEND);
+ }
+
+ if (mFlags & DisplayHardware::SLOW_CONFIG) {
+ glDisable(GL_DITHER);
+ } else {
+ glEnable(GL_DITHER);
+ }
+
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+ glScalef(mWidthScale, mHeightScale, 1);
+ glTranslatef(-x, mYOffset - y, 0);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glVertexPointer(2, GL_FLOAT, 0, mVertices);
+ glTexCoordPointer(2, GL_FLOAT, 0, mVertices);
+ while (it != end) {
+ const Rect& r = *it++;
+ const GLint sy = fbHeight - (r.top + r.height());
+ glScissor(r.left, sy, r.width(), r.height());
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ }
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/services/surfaceflinger/LayerBlur.h b/services/surfaceflinger/LayerBlur.h
new file mode 100644
index 0000000..4c9ec64
--- /dev/null
+++ b/services/surfaceflinger/LayerBlur.h
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_LAYER_BLUR_H
+#define ANDROID_LAYER_BLUR_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <ui/Region.h>
+
+#include "LayerBase.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class LayerBlur : public LayerBaseClient
+{
+public:
+ LayerBlur(SurfaceFlinger* flinger, DisplayID display,
+ const sp<Client>& client);
+ virtual ~LayerBlur();
+
+ virtual void onDraw(const Region& clip) const;
+ virtual bool needsBlending() const { return true; }
+ virtual bool isSecure() const { return false; }
+ virtual const char* getTypeId() const { return "LayerBlur"; }
+
+ virtual uint32_t doTransaction(uint32_t flags);
+ virtual void setVisibleRegion(const Region& visibleRegion);
+ virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
+
+private:
+ bool mCacheDirty;
+ mutable bool mRefreshCache;
+ mutable bool mAutoRefreshPending;
+ nsecs_t mCacheAge;
+ mutable GLuint mTextureName;
+ mutable GLfloat mWidthScale;
+ mutable GLfloat mHeightScale;
+ mutable GLfloat mYOffset;
+ mutable GLint mReadFormat;
+ mutable GLint mReadType;
+ mutable uint32_t mBlurFormat;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_LAYER_BLUR_H
diff --git a/services/surfaceflinger/LayerBuffer.cpp b/services/surfaceflinger/LayerBuffer.cpp
new file mode 100644
index 0000000..5f83636
--- /dev/null
+++ b/services/surfaceflinger/LayerBuffer.cpp
@@ -0,0 +1,682 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <math.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/StopWatch.h>
+
+#include <ui/GraphicBuffer.h>
+#include <ui/PixelFormat.h>
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+
+#include <hardware/copybit.h>
+
+#include "LayerBuffer.h"
+#include "SurfaceFlinger.h"
+#include "DisplayHardware/DisplayHardware.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+gralloc_module_t const* LayerBuffer::sGrallocModule = 0;
+
+// ---------------------------------------------------------------------------
+
+LayerBuffer::LayerBuffer(SurfaceFlinger* flinger, DisplayID display,
+ const sp<Client>& client)
+ : LayerBaseClient(flinger, display, client),
+ mNeedsBlending(false), mBlitEngine(0)
+{
+}
+
+LayerBuffer::~LayerBuffer()
+{
+ if (mBlitEngine) {
+ copybit_close(mBlitEngine);
+ }
+}
+
+void LayerBuffer::onFirstRef()
+{
+ LayerBaseClient::onFirstRef();
+ mSurface = new SurfaceLayerBuffer(mFlinger, this);
+
+ hw_module_t const* module = (hw_module_t const*)sGrallocModule;
+ if (!module) {
+ // NOTE: technically there is a race here, but it shouldn't
+ // cause any problem since hw_get_module() always returns
+ // the same value.
+ if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
+ sGrallocModule = (gralloc_module_t const *)module;
+ }
+ }
+
+ if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
+ copybit_open(module, &mBlitEngine);
+ }
+}
+
+sp<LayerBaseClient::Surface> LayerBuffer::createSurface() const
+{
+ return mSurface;
+}
+
+status_t LayerBuffer::ditch()
+{
+ mSurface.clear();
+ return NO_ERROR;
+}
+
+bool LayerBuffer::needsBlending() const {
+ return mNeedsBlending;
+}
+
+void LayerBuffer::setNeedsBlending(bool blending) {
+ mNeedsBlending = blending;
+}
+
+void LayerBuffer::postBuffer(ssize_t offset)
+{
+ sp<Source> source(getSource());
+ if (source != 0)
+ source->postBuffer(offset);
+}
+
+void LayerBuffer::unregisterBuffers()
+{
+ sp<Source> source(clearSource());
+ if (source != 0)
+ source->unregisterBuffers();
+}
+
+uint32_t LayerBuffer::doTransaction(uint32_t flags)
+{
+ sp<Source> source(getSource());
+ if (source != 0)
+ source->onTransaction(flags);
+ uint32_t res = LayerBase::doTransaction(flags);
+ // we always want filtering for these surfaces
+ mNeedsFiltering = !(mFlags & DisplayHardware::SLOW_CONFIG);
+ return res;
+}
+
+void LayerBuffer::unlockPageFlip(const Transform& planeTransform,
+ Region& outDirtyRegion)
+{
+ // this code-path must be as tight as possible, it's called each time
+ // the screen is composited.
+ sp<Source> source(getSource());
+ if (source != 0)
+ source->onVisibilityResolved(planeTransform);
+ LayerBase::unlockPageFlip(planeTransform, outDirtyRegion);
+}
+
+void LayerBuffer::onDraw(const Region& clip) const
+{
+ sp<Source> source(getSource());
+ if (LIKELY(source != 0)) {
+ source->onDraw(clip);
+ } else {
+ clearWithOpenGL(clip);
+ }
+}
+
+void LayerBuffer::serverDestroy()
+{
+ sp<Source> source(clearSource());
+ if (source != 0) {
+ source->destroy();
+ }
+}
+
+/**
+ * This creates a "buffer" source for this surface
+ */
+status_t LayerBuffer::registerBuffers(const ISurface::BufferHeap& buffers)
+{
+ Mutex::Autolock _l(mLock);
+ if (mSource != 0)
+ return INVALID_OPERATION;
+
+ sp<BufferSource> source = new BufferSource(*this, buffers);
+
+ status_t result = source->getStatus();
+ if (result == NO_ERROR) {
+ mSource = source;
+ }
+ return result;
+}
+
+/**
+ * This creates an "overlay" source for this surface
+ */
+sp<OverlayRef> LayerBuffer::createOverlay(uint32_t w, uint32_t h, int32_t f,
+ int32_t orientation)
+{
+ sp<OverlayRef> result;
+ Mutex::Autolock _l(mLock);
+ if (mSource != 0)
+ return result;
+
+ sp<OverlaySource> source = new OverlaySource(*this, &result, w, h, f, orientation);
+ if (result != 0) {
+ mSource = source;
+ }
+ return result;
+}
+
+sp<LayerBuffer::Source> LayerBuffer::getSource() const {
+ Mutex::Autolock _l(mLock);
+ return mSource;
+}
+
+sp<LayerBuffer::Source> LayerBuffer::clearSource() {
+ sp<Source> source;
+ Mutex::Autolock _l(mLock);
+ source = mSource;
+ mSource.clear();
+ return source;
+}
+
+// ============================================================================
+// LayerBuffer::SurfaceLayerBuffer
+// ============================================================================
+
+LayerBuffer::SurfaceLayerBuffer::SurfaceLayerBuffer(
+ const sp<SurfaceFlinger>& flinger, const sp<LayerBuffer>& owner)
+ : LayerBaseClient::Surface(flinger, owner->getIdentity(), owner)
+{
+}
+
+LayerBuffer::SurfaceLayerBuffer::~SurfaceLayerBuffer()
+{
+ unregisterBuffers();
+}
+
+status_t LayerBuffer::SurfaceLayerBuffer::registerBuffers(
+ const ISurface::BufferHeap& buffers)
+{
+ sp<LayerBuffer> owner(getOwner());
+ if (owner != 0)
+ return owner->registerBuffers(buffers);
+ return NO_INIT;
+}
+
+void LayerBuffer::SurfaceLayerBuffer::postBuffer(ssize_t offset)
+{
+ sp<LayerBuffer> owner(getOwner());
+ if (owner != 0)
+ owner->postBuffer(offset);
+}
+
+void LayerBuffer::SurfaceLayerBuffer::unregisterBuffers()
+{
+ sp<LayerBuffer> owner(getOwner());
+ if (owner != 0)
+ owner->unregisterBuffers();
+}
+
+sp<OverlayRef> LayerBuffer::SurfaceLayerBuffer::createOverlay(
+ uint32_t w, uint32_t h, int32_t format, int32_t orientation) {
+ sp<OverlayRef> result;
+ sp<LayerBuffer> owner(getOwner());
+ if (owner != 0)
+ result = owner->createOverlay(w, h, format, orientation);
+ return result;
+}
+
+// ============================================================================
+// LayerBuffer::Buffer
+// ============================================================================
+
+LayerBuffer::Buffer::Buffer(const ISurface::BufferHeap& buffers,
+ ssize_t offset, size_t bufferSize)
+ : mBufferHeap(buffers), mSupportsCopybit(false)
+{
+ NativeBuffer& src(mNativeBuffer);
+ src.crop.l = 0;
+ src.crop.t = 0;
+ src.crop.r = buffers.w;
+ src.crop.b = buffers.h;
+
+ src.img.w = buffers.hor_stride ?: buffers.w;
+ src.img.h = buffers.ver_stride ?: buffers.h;
+ src.img.format = buffers.format;
+ src.img.base = (void*)(intptr_t(buffers.heap->base()) + offset);
+ src.img.handle = 0;
+
+ gralloc_module_t const * module = LayerBuffer::getGrallocModule();
+ if (module && module->perform) {
+ int err = module->perform(module,
+ GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER,
+ buffers.heap->heapID(), bufferSize,
+ offset, buffers.heap->base(),
+ &src.img.handle);
+
+ // we can fail here is the passed buffer is purely software
+ mSupportsCopybit = (err == NO_ERROR);
+ }
+ }
+
+LayerBuffer::Buffer::~Buffer()
+{
+ NativeBuffer& src(mNativeBuffer);
+ if (src.img.handle) {
+ native_handle_delete(src.img.handle);
+ }
+}
+
+// ============================================================================
+// LayerBuffer::Source
+// LayerBuffer::BufferSource
+// LayerBuffer::OverlaySource
+// ============================================================================
+
+LayerBuffer::Source::Source(LayerBuffer& layer)
+ : mLayer(layer)
+{
+}
+LayerBuffer::Source::~Source() {
+}
+void LayerBuffer::Source::onDraw(const Region& clip) const {
+}
+void LayerBuffer::Source::onTransaction(uint32_t flags) {
+}
+void LayerBuffer::Source::onVisibilityResolved(
+ const Transform& planeTransform) {
+}
+void LayerBuffer::Source::postBuffer(ssize_t offset) {
+}
+void LayerBuffer::Source::unregisterBuffers() {
+}
+
+// ---------------------------------------------------------------------------
+
+LayerBuffer::BufferSource::BufferSource(LayerBuffer& layer,
+ const ISurface::BufferHeap& buffers)
+ : Source(layer), mStatus(NO_ERROR), mBufferSize(0)
+{
+ if (buffers.heap == NULL) {
+ // this is allowed, but in this case, it is illegal to receive
+ // postBuffer(). The surface just erases the framebuffer with
+ // fully transparent pixels.
+ mBufferHeap = buffers;
+ mLayer.setNeedsBlending(false);
+ return;
+ }
+
+ status_t err = (buffers.heap->heapID() >= 0) ? NO_ERROR : NO_INIT;
+ if (err != NO_ERROR) {
+ LOGE("LayerBuffer::BufferSource: invalid heap (%s)", strerror(err));
+ mStatus = err;
+ return;
+ }
+
+ PixelFormatInfo info;
+ err = getPixelFormatInfo(buffers.format, &info);
+ if (err != NO_ERROR) {
+ LOGE("LayerBuffer::BufferSource: invalid format %d (%s)",
+ buffers.format, strerror(err));
+ mStatus = err;
+ return;
+ }
+
+ if (buffers.hor_stride<0 || buffers.ver_stride<0) {
+ LOGE("LayerBuffer::BufferSource: invalid parameters "
+ "(w=%d, h=%d, xs=%d, ys=%d)",
+ buffers.w, buffers.h, buffers.hor_stride, buffers.ver_stride);
+ mStatus = BAD_VALUE;
+ return;
+ }
+
+ mBufferHeap = buffers;
+ mLayer.setNeedsBlending((info.h_alpha - info.l_alpha) > 0);
+ mBufferSize = info.getScanlineSize(buffers.hor_stride)*buffers.ver_stride;
+ mLayer.forceVisibilityTransaction();
+}
+
+LayerBuffer::BufferSource::~BufferSource()
+{
+ class MessageDestroyTexture : public MessageBase {
+ SurfaceFlinger* flinger;
+ GLuint name;
+ public:
+ MessageDestroyTexture(
+ SurfaceFlinger* flinger, GLuint name)
+ : flinger(flinger), name(name) { }
+ virtual bool handler() {
+ glDeleteTextures(1, &name);
+ return true;
+ }
+ };
+
+ if (mTexture.name != -1U) {
+ // GL textures can only be destroyed from the GL thread
+ getFlinger()->mEventQueue.postMessage(
+ new MessageDestroyTexture(getFlinger(), mTexture.name) );
+ }
+ if (mTexture.image != EGL_NO_IMAGE_KHR) {
+ EGLDisplay dpy(getFlinger()->graphicPlane(0).getEGLDisplay());
+ eglDestroyImageKHR(dpy, mTexture.image);
+ }
+}
+
+void LayerBuffer::BufferSource::postBuffer(ssize_t offset)
+{
+ ISurface::BufferHeap buffers;
+ { // scope for the lock
+ Mutex::Autolock _l(mBufferSourceLock);
+ buffers = mBufferHeap;
+ if (buffers.heap != 0) {
+ const size_t memorySize = buffers.heap->getSize();
+ if ((size_t(offset) + mBufferSize) > memorySize) {
+ LOGE("LayerBuffer::BufferSource::postBuffer() "
+ "invalid buffer (offset=%d, size=%d, heap-size=%d",
+ int(offset), int(mBufferSize), int(memorySize));
+ return;
+ }
+ }
+ }
+
+ sp<Buffer> buffer;
+ if (buffers.heap != 0) {
+ buffer = new LayerBuffer::Buffer(buffers, offset, mBufferSize);
+ if (buffer->getStatus() != NO_ERROR)
+ buffer.clear();
+ setBuffer(buffer);
+ mLayer.invalidate();
+ }
+}
+
+void LayerBuffer::BufferSource::unregisterBuffers()
+{
+ Mutex::Autolock _l(mBufferSourceLock);
+ mBufferHeap.heap.clear();
+ mBuffer.clear();
+ mLayer.invalidate();
+}
+
+sp<LayerBuffer::Buffer> LayerBuffer::BufferSource::getBuffer() const
+{
+ Mutex::Autolock _l(mBufferSourceLock);
+ return mBuffer;
+}
+
+void LayerBuffer::BufferSource::setBuffer(const sp<LayerBuffer::Buffer>& buffer)
+{
+ Mutex::Autolock _l(mBufferSourceLock);
+ mBuffer = buffer;
+}
+
+void LayerBuffer::BufferSource::onDraw(const Region& clip) const
+{
+ sp<Buffer> ourBuffer(getBuffer());
+ if (UNLIKELY(ourBuffer == 0)) {
+ // nothing to do, we don't have a buffer
+ mLayer.clearWithOpenGL(clip);
+ return;
+ }
+
+ status_t err = NO_ERROR;
+ NativeBuffer src(ourBuffer->getBuffer());
+ const Rect transformedBounds(mLayer.getTransformedBounds());
+
+#if defined(EGL_ANDROID_image_native_buffer)
+ if (GLExtensions::getInstance().haveDirectTexture()) {
+ err = INVALID_OPERATION;
+ if (ourBuffer->supportsCopybit()) {
+ copybit_device_t* copybit = mLayer.mBlitEngine;
+ if (copybit && err != NO_ERROR) {
+ // create our EGLImageKHR the first time
+ err = initTempBuffer();
+ if (err == NO_ERROR) {
+ // NOTE: Assume the buffer is allocated with the proper USAGE flags
+ const NativeBuffer& dst(mTempBuffer);
+ region_iterator clip(Region(Rect(dst.crop.r, dst.crop.b)));
+ copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
+ copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
+ copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
+ err = copybit->stretch(copybit, &dst.img, &src.img,
+ &dst.crop, &src.crop, &clip);
+ if (err != NO_ERROR) {
+ clearTempBufferImage();
+ }
+ }
+ }
+ }
+ }
+#endif
+ else {
+ err = INVALID_OPERATION;
+ }
+
+ if (err != NO_ERROR) {
+ // slower fallback
+ GGLSurface t;
+ t.version = sizeof(GGLSurface);
+ t.width = src.crop.r;
+ t.height = src.crop.b;
+ t.stride = src.img.w;
+ t.vstride= src.img.h;
+ t.format = src.img.format;
+ t.data = (GGLubyte*)src.img.base;
+ const Region dirty(Rect(t.width, t.height));
+ mTextureManager.loadTexture(&mTexture, dirty, t);
+ }
+
+ mTexture.transform = mBufferHeap.transform;
+ mLayer.drawWithOpenGL(clip, mTexture);
+}
+
+status_t LayerBuffer::BufferSource::initTempBuffer() const
+{
+ // figure out the size we need now
+ const ISurface::BufferHeap& buffers(mBufferHeap);
+ uint32_t w = mLayer.mTransformedBounds.width();
+ uint32_t h = mLayer.mTransformedBounds.height();
+ if (buffers.w * h != buffers.h * w) {
+ int t = w; w = h; h = t;
+ }
+
+ // we're in the copybit case, so make sure we can handle this blit
+ // we don't have to keep the aspect ratio here
+ copybit_device_t* copybit = mLayer.mBlitEngine;
+ const int down = copybit->get(copybit, COPYBIT_MINIFICATION_LIMIT);
+ const int up = copybit->get(copybit, COPYBIT_MAGNIFICATION_LIMIT);
+ if (buffers.w > w*down) w = buffers.w / down;
+ else if (w > buffers.w*up) w = buffers.w*up;
+ if (buffers.h > h*down) h = buffers.h / down;
+ else if (h > buffers.h*up) h = buffers.h*up;
+
+ if (mTexture.image != EGL_NO_IMAGE_KHR) {
+ // we have an EGLImage, make sure the needed size didn't change
+ if (w!=mTexture.width || h!= mTexture.height) {
+ // delete the EGLImage and texture
+ clearTempBufferImage();
+ } else {
+ // we're good, we have an EGLImageKHR and it's (still) the
+ // right size
+ return NO_ERROR;
+ }
+ }
+
+ // figure out if we need linear filtering
+ if (buffers.w * h == buffers.h * w) {
+ // same pixel area, don't use filtering
+ mLayer.mNeedsFiltering = false;
+ }
+
+ // Allocate a temporary buffer and create the corresponding EGLImageKHR
+ // once the EGLImage has been created we don't need the
+ // graphic buffer reference anymore.
+ sp<GraphicBuffer> buffer = new GraphicBuffer(
+ w, h, HAL_PIXEL_FORMAT_RGB_565,
+ GraphicBuffer::USAGE_HW_TEXTURE |
+ GraphicBuffer::USAGE_HW_2D);
+
+ status_t err = buffer->initCheck();
+ if (err == NO_ERROR) {
+ NativeBuffer& dst(mTempBuffer);
+ dst.img.w = buffer->getStride();
+ dst.img.h = h;
+ dst.img.format = buffer->getPixelFormat();
+ dst.img.handle = (native_handle_t *)buffer->handle;
+ dst.img.base = 0;
+ dst.crop.l = 0;
+ dst.crop.t = 0;
+ dst.crop.r = w;
+ dst.crop.b = h;
+
+ EGLDisplay dpy(getFlinger()->graphicPlane(0).getEGLDisplay());
+ err = mTextureManager.initEglImage(&mTexture, dpy, buffer);
+ }
+
+ return err;
+}
+
+void LayerBuffer::BufferSource::clearTempBufferImage() const
+{
+ // delete the image
+ EGLDisplay dpy(getFlinger()->graphicPlane(0).getEGLDisplay());
+ eglDestroyImageKHR(dpy, mTexture.image);
+
+ // and the associated texture (recreate a name)
+ glDeleteTextures(1, &mTexture.name);
+ Texture defaultTexture;
+ mTexture = defaultTexture;
+}
+
+// ---------------------------------------------------------------------------
+
+LayerBuffer::OverlaySource::OverlaySource(LayerBuffer& layer,
+ sp<OverlayRef>* overlayRef,
+ uint32_t w, uint32_t h, int32_t format, int32_t orientation)
+ : Source(layer), mVisibilityChanged(false),
+ mOverlay(0), mOverlayHandle(0), mOverlayDevice(0), mOrientation(orientation)
+{
+ overlay_control_device_t* overlay_dev = getFlinger()->getOverlayEngine();
+ if (overlay_dev == NULL) {
+ // overlays not supported
+ return;
+ }
+
+ mOverlayDevice = overlay_dev;
+ overlay_t* overlay = overlay_dev->createOverlay(overlay_dev, w, h, format);
+ if (overlay == NULL) {
+ // couldn't create the overlay (no memory? no more overlays?)
+ return;
+ }
+
+ // enable dithering...
+ overlay_dev->setParameter(overlay_dev, overlay,
+ OVERLAY_DITHER, OVERLAY_ENABLE);
+
+ mOverlay = overlay;
+ mWidth = overlay->w;
+ mHeight = overlay->h;
+ mFormat = overlay->format;
+ mWidthStride = overlay->w_stride;
+ mHeightStride = overlay->h_stride;
+ mInitialized = false;
+
+ mOverlayHandle = overlay->getHandleRef(overlay);
+
+ sp<OverlayChannel> channel = new OverlayChannel( &layer );
+
+ *overlayRef = new OverlayRef(mOverlayHandle, channel,
+ mWidth, mHeight, mFormat, mWidthStride, mHeightStride);
+ getFlinger()->signalEvent();
+}
+
+LayerBuffer::OverlaySource::~OverlaySource()
+{
+ if (mOverlay && mOverlayDevice) {
+ overlay_control_device_t* overlay_dev = mOverlayDevice;
+ overlay_dev->destroyOverlay(overlay_dev, mOverlay);
+ }
+}
+
+void LayerBuffer::OverlaySource::onDraw(const Region& clip) const
+{
+ // this would be where the color-key would be set, should we need it.
+ GLclampf red = 0;
+ GLclampf green = 0;
+ GLclampf blue = 0;
+ mLayer.clearWithOpenGL(clip, red, green, blue, 0);
+}
+
+void LayerBuffer::OverlaySource::onTransaction(uint32_t flags)
+{
+ const Layer::State& front(mLayer.drawingState());
+ const Layer::State& temp(mLayer.currentState());
+ if (temp.sequence != front.sequence) {
+ mVisibilityChanged = true;
+ }
+}
+
+void LayerBuffer::OverlaySource::onVisibilityResolved(
+ const Transform& planeTransform)
+{
+ // this code-path must be as tight as possible, it's called each time
+ // the screen is composited.
+ if (UNLIKELY(mOverlay != 0)) {
+ if (mVisibilityChanged || !mInitialized) {
+ mVisibilityChanged = false;
+ mInitialized = true;
+ const Rect bounds(mLayer.getTransformedBounds());
+ int x = bounds.left;
+ int y = bounds.top;
+ int w = bounds.width();
+ int h = bounds.height();
+
+ // we need a lock here to protect "destroy"
+ Mutex::Autolock _l(mOverlaySourceLock);
+ if (mOverlay) {
+ overlay_control_device_t* overlay_dev = mOverlayDevice;
+ overlay_dev->setPosition(overlay_dev, mOverlay, x,y,w,h);
+ // we need to combine the layer orientation and the
+ // user-requested orientation.
+ Transform finalTransform = Transform(mOrientation) *
+ Transform(mLayer.getOrientation());
+ overlay_dev->setParameter(overlay_dev, mOverlay,
+ OVERLAY_TRANSFORM, finalTransform.getOrientation());
+ overlay_dev->commit(overlay_dev, mOverlay);
+ }
+ }
+ }
+}
+
+void LayerBuffer::OverlaySource::destroy()
+{
+ // we need a lock here to protect "onVisibilityResolved"
+ Mutex::Autolock _l(mOverlaySourceLock);
+ if (mOverlay && mOverlayDevice) {
+ overlay_control_device_t* overlay_dev = mOverlayDevice;
+ overlay_dev->destroyOverlay(overlay_dev, mOverlay);
+ mOverlay = 0;
+ }
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/services/surfaceflinger/LayerBuffer.h b/services/surfaceflinger/LayerBuffer.h
new file mode 100644
index 0000000..1c0bf83
--- /dev/null
+++ b/services/surfaceflinger/LayerBuffer.h
@@ -0,0 +1,220 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_LAYER_BUFFER_H
+#define ANDROID_LAYER_BUFFER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "LayerBase.h"
+#include "TextureManager.h"
+
+struct copybit_device_t;
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class Buffer;
+class Region;
+class OverlayRef;
+
+// ---------------------------------------------------------------------------
+
+class LayerBuffer : public LayerBaseClient
+{
+ class Source : public LightRefBase<Source> {
+ public:
+ Source(LayerBuffer& layer);
+ virtual ~Source();
+ virtual void onDraw(const Region& clip) const;
+ virtual void onTransaction(uint32_t flags);
+ virtual void onVisibilityResolved(const Transform& planeTransform);
+ virtual void postBuffer(ssize_t offset);
+ virtual void unregisterBuffers();
+ virtual void destroy() { }
+ SurfaceFlinger* getFlinger() const { return mLayer.mFlinger.get(); }
+ protected:
+ LayerBuffer& mLayer;
+ };
+
+public:
+ LayerBuffer(SurfaceFlinger* flinger, DisplayID display,
+ const sp<Client>& client);
+ virtual ~LayerBuffer();
+
+ virtual void onFirstRef();
+ virtual bool needsBlending() const;
+ virtual const char* getTypeId() const { return "LayerBuffer"; }
+
+ virtual sp<LayerBaseClient::Surface> createSurface() const;
+ virtual status_t ditch();
+ virtual void onDraw(const Region& clip) const;
+ virtual uint32_t doTransaction(uint32_t flags);
+ virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
+
+ status_t registerBuffers(const ISurface::BufferHeap& buffers);
+ void postBuffer(ssize_t offset);
+ void unregisterBuffers();
+ sp<OverlayRef> createOverlay(uint32_t w, uint32_t h, int32_t format,
+ int32_t orientation);
+
+ sp<Source> getSource() const;
+ sp<Source> clearSource();
+ void setNeedsBlending(bool blending);
+ Rect getTransformedBounds() const {
+ return mTransformedBounds;
+ }
+
+ void serverDestroy();
+
+private:
+ struct NativeBuffer {
+ copybit_image_t img;
+ copybit_rect_t crop;
+ };
+
+ static gralloc_module_t const* sGrallocModule;
+ static gralloc_module_t const* getGrallocModule() {
+ return sGrallocModule;
+ }
+
+ class Buffer : public LightRefBase<Buffer> {
+ public:
+ Buffer(const ISurface::BufferHeap& buffers,
+ ssize_t offset, size_t bufferSize);
+ inline bool supportsCopybit() const {
+ return mSupportsCopybit;
+ }
+ inline status_t getStatus() const {
+ return mBufferHeap.heap!=0 ? NO_ERROR : NO_INIT;
+ }
+ inline const NativeBuffer& getBuffer() const {
+ return mNativeBuffer;
+ }
+ protected:
+ friend class LightRefBase<Buffer>;
+ Buffer& operator = (const Buffer& rhs);
+ Buffer(const Buffer& rhs);
+ ~Buffer();
+ private:
+ ISurface::BufferHeap mBufferHeap;
+ NativeBuffer mNativeBuffer;
+ bool mSupportsCopybit;
+ };
+
+ class BufferSource : public Source {
+ public:
+ BufferSource(LayerBuffer& layer, const ISurface::BufferHeap& buffers);
+ virtual ~BufferSource();
+
+ status_t getStatus() const { return mStatus; }
+ sp<Buffer> getBuffer() const;
+ void setBuffer(const sp<Buffer>& buffer);
+
+ virtual void onDraw(const Region& clip) const;
+ virtual void postBuffer(ssize_t offset);
+ virtual void unregisterBuffers();
+ virtual void destroy() { }
+ private:
+ status_t initTempBuffer() const;
+ void clearTempBufferImage() const;
+ mutable Mutex mBufferSourceLock;
+ sp<Buffer> mBuffer;
+ status_t mStatus;
+ ISurface::BufferHeap mBufferHeap;
+ size_t mBufferSize;
+ mutable Texture mTexture;
+ mutable NativeBuffer mTempBuffer;
+ mutable TextureManager mTextureManager;
+ };
+
+ class OverlaySource : public Source {
+ public:
+ OverlaySource(LayerBuffer& layer,
+ sp<OverlayRef>* overlayRef,
+ uint32_t w, uint32_t h, int32_t format, int32_t orientation);
+ virtual ~OverlaySource();
+ virtual void onDraw(const Region& clip) const;
+ virtual void onTransaction(uint32_t flags);
+ virtual void onVisibilityResolved(const Transform& planeTransform);
+ virtual void destroy();
+ private:
+
+ class OverlayChannel : public BnOverlay {
+ wp<LayerBuffer> mLayer;
+ virtual void destroy() {
+ sp<LayerBuffer> layer(mLayer.promote());
+ if (layer != 0) {
+ layer->serverDestroy();
+ }
+ }
+ public:
+ OverlayChannel(const sp<LayerBuffer>& layer)
+ : mLayer(layer) {
+ }
+ };
+
+ friend class OverlayChannel;
+ bool mVisibilityChanged;
+
+ overlay_t* mOverlay;
+ overlay_handle_t mOverlayHandle;
+ overlay_control_device_t* mOverlayDevice;
+ uint32_t mWidth;
+ uint32_t mHeight;
+ int32_t mFormat;
+ int32_t mWidthStride;
+ int32_t mHeightStride;
+ int32_t mOrientation;
+ mutable Mutex mOverlaySourceLock;
+ bool mInitialized;
+ };
+
+
+ class SurfaceLayerBuffer : public LayerBaseClient::Surface
+ {
+ public:
+ SurfaceLayerBuffer(const sp<SurfaceFlinger>& flinger,
+ const sp<LayerBuffer>& owner);
+ virtual ~SurfaceLayerBuffer();
+
+ virtual status_t registerBuffers(const ISurface::BufferHeap& buffers);
+ virtual void postBuffer(ssize_t offset);
+ virtual void unregisterBuffers();
+
+ virtual sp<OverlayRef> createOverlay(
+ uint32_t w, uint32_t h, int32_t format, int32_t orientation);
+ private:
+ sp<LayerBuffer> getOwner() const {
+ return static_cast<LayerBuffer*>(Surface::getOwner().get());
+ }
+ };
+
+ mutable Mutex mLock;
+ sp<Source> mSource;
+ sp<Surface> mSurface;
+ bool mInvalidate;
+ bool mNeedsBlending;
+ copybit_device_t* mBlitEngine;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_LAYER_BUFFER_H
diff --git a/services/surfaceflinger/LayerDim.cpp b/services/surfaceflinger/LayerDim.cpp
new file mode 100644
index 0000000..a1f339e
--- /dev/null
+++ b/services/surfaceflinger/LayerDim.cpp
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include <ui/GraphicBuffer.h>
+
+#include "LayerDim.h"
+#include "SurfaceFlinger.h"
+#include "DisplayHardware/DisplayHardware.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+bool LayerDim::sUseTexture;
+GLuint LayerDim::sTexId;
+EGLImageKHR LayerDim::sImage;
+int32_t LayerDim::sWidth;
+int32_t LayerDim::sHeight;
+
+// ---------------------------------------------------------------------------
+
+LayerDim::LayerDim(SurfaceFlinger* flinger, DisplayID display,
+ const sp<Client>& client)
+ : LayerBaseClient(flinger, display, client)
+{
+}
+
+void LayerDim::initDimmer(SurfaceFlinger* flinger, uint32_t w, uint32_t h)
+{
+ sTexId = -1;
+ sImage = EGL_NO_IMAGE_KHR;
+ sWidth = w;
+ sHeight = h;
+ sUseTexture = false;
+}
+
+LayerDim::~LayerDim()
+{
+}
+
+void LayerDim::onDraw(const Region& clip) const
+{
+ const State& s(drawingState());
+ Region::const_iterator it = clip.begin();
+ Region::const_iterator const end = clip.end();
+ if (s.alpha>0 && (it != end)) {
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ const GLfloat alpha = s.alpha/255.0f;
+ const uint32_t fbHeight = hw.getHeight();
+ glDisable(GL_DITHER);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ glColor4f(0, 0, 0, alpha);
+
+#if defined(GL_OES_texture_external)
+ if (GLExtensions::getInstance().haveTextureExternal()) {
+ glDisable(GL_TEXTURE_EXTERNAL_OES);
+ }
+#endif
+ glDisable(GL_TEXTURE_2D);
+
+ GLshort w = sWidth;
+ GLshort h = sHeight;
+ const GLshort vertices[4][2] = {
+ { 0, 0 },
+ { 0, h },
+ { w, h },
+ { w, 0 }
+ };
+ glVertexPointer(2, GL_SHORT, 0, vertices);
+
+ while (it != end) {
+ const Rect& r = *it++;
+ const GLint sy = fbHeight - (r.top + r.height());
+ glScissor(r.left, sy, r.width(), r.height());
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ }
+ }
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/services/surfaceflinger/LayerDim.h b/services/surfaceflinger/LayerDim.h
new file mode 100644
index 0000000..f032314
--- /dev/null
+++ b/services/surfaceflinger/LayerDim.h
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_LAYER_DIM_H
+#define ANDROID_LAYER_DIM_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include "LayerBase.h"
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+class LayerDim : public LayerBaseClient
+{
+ static bool sUseTexture;
+ static GLuint sTexId;
+ static EGLImageKHR sImage;
+ static int32_t sWidth;
+ static int32_t sHeight;
+public:
+ LayerDim(SurfaceFlinger* flinger, DisplayID display,
+ const sp<Client>& client);
+ virtual ~LayerDim();
+
+ virtual void onDraw(const Region& clip) const;
+ virtual bool needsBlending() const { return true; }
+ virtual bool isSecure() const { return false; }
+ virtual const char* getTypeId() const { return "LayerDim"; }
+
+ static void initDimmer(SurfaceFlinger* flinger, uint32_t w, uint32_t h);
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_LAYER_DIM_H
diff --git a/services/surfaceflinger/MODULE_LICENSE_APACHE2 b/services/surfaceflinger/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/services/surfaceflinger/MODULE_LICENSE_APACHE2
diff --git a/services/surfaceflinger/MessageQueue.cpp b/services/surfaceflinger/MessageQueue.cpp
new file mode 100644
index 0000000..d668e88
--- /dev/null
+++ b/services/surfaceflinger/MessageQueue.cpp
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#include <utils/threads.h>
+#include <utils/Timers.h>
+#include <utils/Log.h>
+#include <binder/IPCThreadState.h>
+
+#include "MessageQueue.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+void MessageList::insert(const sp<MessageBase>& node)
+{
+ LIST::iterator cur(mList.begin());
+ LIST::iterator end(mList.end());
+ while (cur != end) {
+ if (*node < **cur) {
+ mList.insert(cur, node);
+ return;
+ }
+ ++cur;
+ }
+ mList.insert(++end, node);
+}
+
+void MessageList::remove(MessageList::LIST::iterator pos)
+{
+ mList.erase(pos);
+}
+
+// ---------------------------------------------------------------------------
+
+MessageQueue::MessageQueue()
+ : mInvalidate(false)
+{
+ mInvalidateMessage = new MessageBase(INVALIDATE);
+}
+
+MessageQueue::~MessageQueue()
+{
+}
+
+sp<MessageBase> MessageQueue::waitMessage(nsecs_t timeout)
+{
+ sp<MessageBase> result;
+
+ bool again;
+ do {
+ const nsecs_t timeoutTime = systemTime() + timeout;
+ while (true) {
+ Mutex::Autolock _l(mLock);
+ nsecs_t now = systemTime();
+ nsecs_t nextEventTime = -1;
+
+ // invalidate messages are always handled first
+ if (mInvalidate) {
+ mInvalidate = false;
+ mInvalidateMessage->when = now;
+ result = mInvalidateMessage;
+ break;
+ }
+
+ LIST::iterator cur(mMessages.begin());
+ if (cur != mMessages.end()) {
+ result = *cur;
+ }
+
+ if (result != 0) {
+ if (result->when <= now) {
+ // there is a message to deliver
+ mMessages.remove(cur);
+ break;
+ }
+ if (timeout>=0 && timeoutTime < now) {
+ // we timed-out, return a NULL message
+ result = 0;
+ break;
+ }
+ nextEventTime = result->when;
+ result = 0;
+ }
+
+ if (timeout >= 0 && nextEventTime > 0) {
+ if (nextEventTime > timeoutTime) {
+ nextEventTime = timeoutTime;
+ }
+ }
+
+ if (nextEventTime >= 0) {
+ //LOGD("nextEventTime = %lld ms", nextEventTime);
+ if (nextEventTime > 0) {
+ // we're about to wait, flush the binder command buffer
+ IPCThreadState::self()->flushCommands();
+ const nsecs_t reltime = nextEventTime - systemTime();
+ if (reltime > 0) {
+ mCondition.waitRelative(mLock, reltime);
+ }
+ }
+ } else {
+ //LOGD("going to wait");
+ // we're about to wait, flush the binder command buffer
+ IPCThreadState::self()->flushCommands();
+ mCondition.wait(mLock);
+ }
+ }
+ // here we're not holding the lock anymore
+
+ if (result == 0)
+ break;
+
+ again = result->handler();
+ if (again) {
+ // the message has been processed. release our reference to it
+ // without holding the lock.
+ result->notify();
+ result = 0;
+ }
+
+ } while (again);
+
+ return result;
+}
+
+status_t MessageQueue::postMessage(
+ const sp<MessageBase>& message, nsecs_t relTime, uint32_t flags)
+{
+ return queueMessage(message, relTime, flags);
+}
+
+status_t MessageQueue::invalidate() {
+ Mutex::Autolock _l(mLock);
+ mInvalidate = true;
+ mCondition.signal();
+ return NO_ERROR;
+}
+
+status_t MessageQueue::queueMessage(
+ const sp<MessageBase>& message, nsecs_t relTime, uint32_t flags)
+{
+ Mutex::Autolock _l(mLock);
+ message->when = systemTime() + relTime;
+ mMessages.insert(message);
+
+ //LOGD("MessageQueue::queueMessage time = %lld ms", message->when);
+ //dumpLocked(message);
+
+ mCondition.signal();
+ return NO_ERROR;
+}
+
+void MessageQueue::dump(const sp<MessageBase>& message)
+{
+ Mutex::Autolock _l(mLock);
+ dumpLocked(message);
+}
+
+void MessageQueue::dumpLocked(const sp<MessageBase>& message)
+{
+ LIST::const_iterator cur(mMessages.begin());
+ LIST::const_iterator end(mMessages.end());
+ int c = 0;
+ while (cur != end) {
+ const char tick = (*cur == message) ? '>' : ' ';
+ LOGD("%c %d: msg{.what=%08x, when=%lld}",
+ tick, c, (*cur)->what, (*cur)->when);
+ ++cur;
+ c++;
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/services/surfaceflinger/MessageQueue.h b/services/surfaceflinger/MessageQueue.h
new file mode 100644
index 0000000..890f809
--- /dev/null
+++ b/services/surfaceflinger/MessageQueue.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+#ifndef ANDROID_MESSAGE_QUEUE_H
+#define ANDROID_MESSAGE_QUEUE_H
+
+#include <stdint.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#include <utils/threads.h>
+#include <utils/Timers.h>
+#include <utils/List.h>
+
+#include "Barrier.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class MessageBase;
+
+class MessageList
+{
+ List< sp<MessageBase> > mList;
+ typedef List< sp<MessageBase> > LIST;
+public:
+ inline LIST::iterator begin() { return mList.begin(); }
+ inline LIST::const_iterator begin() const { return mList.begin(); }
+ inline LIST::iterator end() { return mList.end(); }
+ inline LIST::const_iterator end() const { return mList.end(); }
+ inline bool isEmpty() const { return mList.empty(); }
+ void insert(const sp<MessageBase>& node);
+ void remove(LIST::iterator pos);
+};
+
+// ============================================================================
+
+class MessageBase :
+ public LightRefBase<MessageBase>
+{
+public:
+ nsecs_t when;
+ uint32_t what;
+ int32_t arg0;
+
+ MessageBase() : when(0), what(0), arg0(0) { }
+ MessageBase(uint32_t what, int32_t arg0=0)
+ : when(0), what(what), arg0(arg0) { }
+
+ // return true if message has a handler
+ virtual bool handler() { return false; }
+
+ // waits for the handler to be processed
+ void wait() const { barrier.wait(); }
+
+ // releases all waiters. this is done automatically if
+ // handler returns true
+ void notify() const { barrier.open(); }
+
+protected:
+ virtual ~MessageBase() { }
+
+private:
+ mutable Barrier barrier;
+ friend class LightRefBase<MessageBase>;
+};
+
+inline bool operator < (const MessageBase& lhs, const MessageBase& rhs) {
+ return lhs.when < rhs.when;
+}
+
+// ---------------------------------------------------------------------------
+
+class MessageQueue
+{
+ typedef List< sp<MessageBase> > LIST;
+public:
+
+ MessageQueue();
+ ~MessageQueue();
+
+ // pre-defined messages
+ enum {
+ INVALIDATE = '_upd'
+ };
+
+ sp<MessageBase> waitMessage(nsecs_t timeout = -1);
+
+ status_t postMessage(const sp<MessageBase>& message,
+ nsecs_t reltime=0, uint32_t flags = 0);
+
+ status_t invalidate();
+
+ void dump(const sp<MessageBase>& message);
+
+private:
+ status_t queueMessage(const sp<MessageBase>& message,
+ nsecs_t reltime, uint32_t flags);
+ void dumpLocked(const sp<MessageBase>& message);
+
+ Mutex mLock;
+ Condition mCondition;
+ MessageList mMessages;
+ bool mInvalidate;
+ sp<MessageBase> mInvalidateMessage;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif /* ANDROID_MESSAGE_QUEUE_H */
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
new file mode 100644
index 0000000..68e8f19
--- /dev/null
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -0,0 +1,1909 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <math.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/MemoryHeapBase.h>
+
+#include <utils/String8.h>
+#include <utils/String16.h>
+#include <utils/StopWatch.h>
+
+#include <ui/GraphicBufferAllocator.h>
+#include <ui/PixelFormat.h>
+
+#include <pixelflinger/pixelflinger.h>
+#include <GLES/gl.h>
+
+#include "clz.h"
+#include "GLExtensions.h"
+#include "Layer.h"
+#include "LayerBlur.h"
+#include "LayerBuffer.h"
+#include "LayerDim.h"
+#include "SurfaceFlinger.h"
+
+#include "DisplayHardware/DisplayHardware.h"
+
+/* ideally AID_GRAPHICS would be in a semi-public header
+ * or there would be a way to map a user/group name to its id
+ */
+#ifndef AID_GRAPHICS
+#define AID_GRAPHICS 1003
+#endif
+
+#define DISPLAY_COUNT 1
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+void SurfaceFlinger::instantiate() {
+ defaultServiceManager()->addService(
+ String16("SurfaceFlinger"), new SurfaceFlinger());
+}
+
+void SurfaceFlinger::shutdown() {
+ // we should unregister here, but not really because
+ // when (if) the service manager goes away, all the services
+ // it has a reference to will leave too.
+}
+
+// ---------------------------------------------------------------------------
+
+SurfaceFlinger::LayerVector::LayerVector(const SurfaceFlinger::LayerVector& rhs)
+ : lookup(rhs.lookup), layers(rhs.layers)
+{
+}
+
+ssize_t SurfaceFlinger::LayerVector::indexOf(
+ const sp<LayerBase>& key, size_t guess) const
+{
+ if (guess<size() && lookup.keyAt(guess) == key)
+ return guess;
+ const ssize_t i = lookup.indexOfKey(key);
+ if (i>=0) {
+ const size_t idx = lookup.valueAt(i);
+ LOGE_IF(layers[idx]!=key,
+ "LayerVector[%p]: layers[%d]=%p, key=%p",
+ this, int(idx), layers[idx].get(), key.get());
+ return idx;
+ }
+ return i;
+}
+
+ssize_t SurfaceFlinger::LayerVector::add(
+ const sp<LayerBase>& layer,
+ Vector< sp<LayerBase> >::compar_t cmp)
+{
+ size_t count = layers.size();
+ ssize_t l = 0;
+ ssize_t h = count-1;
+ ssize_t mid;
+ sp<LayerBase> const* a = layers.array();
+ while (l <= h) {
+ mid = l + (h - l)/2;
+ const int c = cmp(a+mid, &layer);
+ if (c == 0) { l = mid; break; }
+ else if (c<0) { l = mid+1; }
+ else { h = mid-1; }
+ }
+ size_t order = l;
+ while (order<count && !cmp(&layer, a+order)) {
+ order++;
+ }
+ count = lookup.size();
+ for (size_t i=0 ; i<count ; i++) {
+ if (lookup.valueAt(i) >= order) {
+ lookup.editValueAt(i)++;
+ }
+ }
+ layers.insertAt(layer, order);
+ lookup.add(layer, order);
+ return order;
+}
+
+ssize_t SurfaceFlinger::LayerVector::remove(const sp<LayerBase>& layer)
+{
+ const ssize_t keyIndex = lookup.indexOfKey(layer);
+ if (keyIndex >= 0) {
+ const size_t index = lookup.valueAt(keyIndex);
+ LOGE_IF(layers[index]!=layer,
+ "LayerVector[%p]: layers[%u]=%p, layer=%p",
+ this, int(index), layers[index].get(), layer.get());
+ layers.removeItemsAt(index);
+ lookup.removeItemsAt(keyIndex);
+ const size_t count = lookup.size();
+ for (size_t i=0 ; i<count ; i++) {
+ if (lookup.valueAt(i) >= size_t(index)) {
+ lookup.editValueAt(i)--;
+ }
+ }
+ return index;
+ }
+ return NAME_NOT_FOUND;
+}
+
+ssize_t SurfaceFlinger::LayerVector::reorder(
+ const sp<LayerBase>& layer,
+ Vector< sp<LayerBase> >::compar_t cmp)
+{
+ // XXX: it's a little lame. but oh well...
+ ssize_t err = remove(layer);
+ if (err >=0)
+ err = add(layer, cmp);
+ return err;
+}
+
+// ---------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#endif
+
+SurfaceFlinger::SurfaceFlinger()
+ : BnSurfaceComposer(), Thread(false),
+ mTransactionFlags(0),
+ mTransactionCount(0),
+ mResizeTransationPending(false),
+ mLayersRemoved(false),
+ mBootTime(systemTime()),
+ mHardwareTest("android.permission.HARDWARE_TEST"),
+ mAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"),
+ mDump("android.permission.DUMP"),
+ mVisibleRegionsDirty(false),
+ mDeferReleaseConsole(false),
+ mFreezeDisplay(false),
+ mFreezeCount(0),
+ mFreezeDisplayTime(0),
+ mDebugRegion(0),
+ mDebugBackground(0),
+ mDebugInSwapBuffers(0),
+ mLastSwapBufferTime(0),
+ mDebugInTransaction(0),
+ mLastTransactionTime(0),
+ mBootFinished(false),
+ mConsoleSignals(0),
+ mSecureFrameBuffer(0)
+{
+ init();
+}
+
+void SurfaceFlinger::init()
+{
+ LOGI("SurfaceFlinger is starting");
+
+ // debugging stuff...
+ char value[PROPERTY_VALUE_MAX];
+ property_get("debug.sf.showupdates", value, "0");
+ mDebugRegion = atoi(value);
+ property_get("debug.sf.showbackground", value, "0");
+ mDebugBackground = atoi(value);
+
+ LOGI_IF(mDebugRegion, "showupdates enabled");
+ LOGI_IF(mDebugBackground, "showbackground enabled");
+}
+
+SurfaceFlinger::~SurfaceFlinger()
+{
+ glDeleteTextures(1, &mWormholeTexName);
+}
+
+overlay_control_device_t* SurfaceFlinger::getOverlayEngine() const
+{
+ return graphicPlane(0).displayHardware().getOverlayEngine();
+}
+
+sp<IMemoryHeap> SurfaceFlinger::getCblk() const
+{
+ return mServerHeap;
+}
+
+sp<ISurfaceComposerClient> SurfaceFlinger::createConnection()
+{
+ sp<ISurfaceComposerClient> bclient;
+ sp<Client> client(new Client(this));
+ status_t err = client->initCheck();
+ if (err == NO_ERROR) {
+ bclient = client;
+ }
+ return bclient;
+}
+
+sp<ISurfaceComposerClient> SurfaceFlinger::createClientConnection()
+{
+ sp<ISurfaceComposerClient> bclient;
+ sp<UserClient> client(new UserClient(this));
+ status_t err = client->initCheck();
+ if (err == NO_ERROR) {
+ bclient = client;
+ }
+ return bclient;
+}
+
+
+const GraphicPlane& SurfaceFlinger::graphicPlane(int dpy) const
+{
+ LOGE_IF(uint32_t(dpy) >= DISPLAY_COUNT, "Invalid DisplayID %d", dpy);
+ const GraphicPlane& plane(mGraphicPlanes[dpy]);
+ return plane;
+}
+
+GraphicPlane& SurfaceFlinger::graphicPlane(int dpy)
+{
+ return const_cast<GraphicPlane&>(
+ const_cast<SurfaceFlinger const *>(this)->graphicPlane(dpy));
+}
+
+void SurfaceFlinger::bootFinished()
+{
+ const nsecs_t now = systemTime();
+ const nsecs_t duration = now - mBootTime;
+ LOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
+ mBootFinished = true;
+ property_set("ctl.stop", "bootanim");
+}
+
+void SurfaceFlinger::onFirstRef()
+{
+ run("SurfaceFlinger", PRIORITY_URGENT_DISPLAY);
+
+ // Wait for the main thread to be done with its initialization
+ mReadyToRunBarrier.wait();
+}
+
+static inline uint16_t pack565(int r, int g, int b) {
+ return (r<<11)|(g<<5)|b;
+}
+
+status_t SurfaceFlinger::readyToRun()
+{
+ LOGI( "SurfaceFlinger's main thread ready to run. "
+ "Initializing graphics H/W...");
+
+ // we only support one display currently
+ int dpy = 0;
+
+ {
+ // initialize the main display
+ GraphicPlane& plane(graphicPlane(dpy));
+ DisplayHardware* const hw = new DisplayHardware(this, dpy);
+ plane.setDisplayHardware(hw);
+ }
+
+ // create the shared control-block
+ mServerHeap = new MemoryHeapBase(4096,
+ MemoryHeapBase::READ_ONLY, "SurfaceFlinger read-only heap");
+ LOGE_IF(mServerHeap==0, "can't create shared memory dealer");
+
+ mServerCblk = static_cast<surface_flinger_cblk_t*>(mServerHeap->getBase());
+ LOGE_IF(mServerCblk==0, "can't get to shared control block's address");
+
+ new(mServerCblk) surface_flinger_cblk_t;
+
+ // initialize primary screen
+ // (other display should be initialized in the same manner, but
+ // asynchronously, as they could come and go. None of this is supported
+ // yet).
+ const GraphicPlane& plane(graphicPlane(dpy));
+ const DisplayHardware& hw = plane.displayHardware();
+ const uint32_t w = hw.getWidth();
+ const uint32_t h = hw.getHeight();
+ const uint32_t f = hw.getFormat();
+ hw.makeCurrent();
+
+ // initialize the shared control block
+ mServerCblk->connected |= 1<<dpy;
+ display_cblk_t* dcblk = mServerCblk->displays + dpy;
+ memset(dcblk, 0, sizeof(display_cblk_t));
+ dcblk->w = plane.getWidth();
+ dcblk->h = plane.getHeight();
+ dcblk->format = f;
+ dcblk->orientation = ISurfaceComposer::eOrientationDefault;
+ dcblk->xdpi = hw.getDpiX();
+ dcblk->ydpi = hw.getDpiY();
+ dcblk->fps = hw.getRefreshRate();
+ dcblk->density = hw.getDensity();
+
+ // Initialize OpenGL|ES
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+ glPixelStorei(GL_PACK_ALIGNMENT, 4);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnable(GL_SCISSOR_TEST);
+ glShadeModel(GL_FLAT);
+ glDisable(GL_DITHER);
+ glDisable(GL_CULL_FACE);
+
+ const uint16_t g0 = pack565(0x0F,0x1F,0x0F);
+ const uint16_t g1 = pack565(0x17,0x2f,0x17);
+ const uint16_t textureData[4] = { g0, g1, g1, g0 };
+ glGenTextures(1, &mWormholeTexName);
+ glBindTexture(GL_TEXTURE_2D, mWormholeTexName);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0,
+ GL_RGB, GL_UNSIGNED_SHORT_5_6_5, textureData);
+
+ glViewport(0, 0, w, h);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrthof(0, w, h, 0, 0, 1);
+
+ LayerDim::initDimmer(this, w, h);
+
+ mReadyToRunBarrier.open();
+
+ /*
+ * We're now ready to accept clients...
+ */
+
+ // start boot animation
+ property_set("ctl.start", "bootanim");
+
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark Events Handler
+#endif
+
+void SurfaceFlinger::waitForEvent()
+{
+ while (true) {
+ nsecs_t timeout = -1;
+ const nsecs_t freezeDisplayTimeout = ms2ns(5000);
+ if (UNLIKELY(isFrozen())) {
+ // wait 5 seconds
+ const nsecs_t now = systemTime();
+ if (mFreezeDisplayTime == 0) {
+ mFreezeDisplayTime = now;
+ }
+ nsecs_t waitTime = freezeDisplayTimeout - (now - mFreezeDisplayTime);
+ timeout = waitTime>0 ? waitTime : 0;
+ }
+
+ sp<MessageBase> msg = mEventQueue.waitMessage(timeout);
+
+ // see if we timed out
+ if (isFrozen()) {
+ const nsecs_t now = systemTime();
+ nsecs_t frozenTime = (now - mFreezeDisplayTime);
+ if (frozenTime >= freezeDisplayTimeout) {
+ // we timed out and are still frozen
+ LOGW("timeout expired mFreezeDisplay=%d, mFreezeCount=%d",
+ mFreezeDisplay, mFreezeCount);
+ mFreezeDisplayTime = 0;
+ mFreezeCount = 0;
+ mFreezeDisplay = false;
+ }
+ }
+
+ if (msg != 0) {
+ switch (msg->what) {
+ case MessageQueue::INVALIDATE:
+ // invalidate message, just return to the main loop
+ return;
+ }
+ }
+ }
+}
+
+void SurfaceFlinger::signalEvent() {
+ mEventQueue.invalidate();
+}
+
+void SurfaceFlinger::signal() const {
+ // this is the IPC call
+ const_cast<SurfaceFlinger*>(this)->signalEvent();
+}
+
+status_t SurfaceFlinger::postMessageAsync(const sp<MessageBase>& msg,
+ nsecs_t reltime, uint32_t flags)
+{
+ return mEventQueue.postMessage(msg, reltime, flags);
+}
+
+status_t SurfaceFlinger::postMessageSync(const sp<MessageBase>& msg,
+ nsecs_t reltime, uint32_t flags)
+{
+ status_t res = mEventQueue.postMessage(msg, reltime, flags);
+ if (res == NO_ERROR) {
+ msg->wait();
+ }
+ return res;
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark Main loop
+#endif
+
+bool SurfaceFlinger::threadLoop()
+{
+ waitForEvent();
+
+ // check for transactions
+ if (UNLIKELY(mConsoleSignals)) {
+ handleConsoleEvents();
+ }
+
+ if (LIKELY(mTransactionCount == 0)) {
+ // if we're in a global transaction, don't do anything.
+ const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
+ uint32_t transactionFlags = getTransactionFlags(mask);
+ if (LIKELY(transactionFlags)) {
+ handleTransaction(transactionFlags);
+ }
+ }
+
+ // post surfaces (if needed)
+ handlePageFlip();
+
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ if (LIKELY(hw.canDraw() && !isFrozen())) {
+ // repaint the framebuffer (if needed)
+ handleRepaint();
+
+ // inform the h/w that we're done compositing
+ hw.compositionComplete();
+
+ // release the clients before we flip ('cause flip might block)
+ unlockClients();
+
+ postFramebuffer();
+ } else {
+ // pretend we did the post
+ unlockClients();
+ usleep(16667); // 60 fps period
+ }
+ return true;
+}
+
+void SurfaceFlinger::postFramebuffer()
+{
+ if (!mInvalidRegion.isEmpty()) {
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ const nsecs_t now = systemTime();
+ mDebugInSwapBuffers = now;
+ hw.flip(mInvalidRegion);
+ mLastSwapBufferTime = systemTime() - now;
+ mDebugInSwapBuffers = 0;
+ mInvalidRegion.clear();
+ }
+}
+
+void SurfaceFlinger::handleConsoleEvents()
+{
+ // something to do with the console
+ const DisplayHardware& hw = graphicPlane(0).displayHardware();
+
+ int what = android_atomic_and(0, &mConsoleSignals);
+ if (what & eConsoleAcquired) {
+ hw.acquireScreen();
+ }
+
+ if (mDeferReleaseConsole && hw.canDraw()) {
+ // We got the release signal before the acquire signal
+ mDeferReleaseConsole = false;
+ hw.releaseScreen();
+ }
+
+ if (what & eConsoleReleased) {
+ if (hw.canDraw()) {
+ hw.releaseScreen();
+ } else {
+ mDeferReleaseConsole = true;
+ }
+ }
+
+ mDirtyRegion.set(hw.bounds());
+}
+
+void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
+{
+ Vector< sp<LayerBase> > ditchedLayers;
+
+ { // scope for the lock
+ Mutex::Autolock _l(mStateLock);
+ const nsecs_t now = systemTime();
+ mDebugInTransaction = now;
+ handleTransactionLocked(transactionFlags, ditchedLayers);
+ mLastTransactionTime = systemTime() - now;
+ mDebugInTransaction = 0;
+ }
+
+ // do this without lock held
+ const size_t count = ditchedLayers.size();
+ for (size_t i=0 ; i<count ; i++) {
+ if (ditchedLayers[i] != 0) {
+ //LOGD("ditching layer %p", ditchedLayers[i].get());
+ ditchedLayers[i]->ditch();
+ }
+ }
+}
+
+void SurfaceFlinger::handleTransactionLocked(
+ uint32_t transactionFlags, Vector< sp<LayerBase> >& ditchedLayers)
+{
+ const LayerVector& currentLayers(mCurrentState.layersSortedByZ);
+ 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++) {
+ const sp<LayerBase>& layer = currentLayers[i];
+ uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
+ if (!trFlags) continue;
+
+ const uint32_t flags = layer->doTransaction(0);
+ if (flags & Layer::eVisibleRegion)
+ mVisibleRegionsDirty = true;
+ }
+ }
+
+ /*
+ * Perform our own transaction if needed
+ */
+
+ if (transactionFlags & eTransactionNeeded) {
+ if (mCurrentState.orientation != mDrawingState.orientation) {
+ // the orientation has changed, recompute all visible regions
+ // and invalidate everything.
+
+ const int dpy = 0;
+ const int orientation = mCurrentState.orientation;
+ const uint32_t type = mCurrentState.orientationType;
+ GraphicPlane& plane(graphicPlane(dpy));
+ plane.setOrientation(orientation);
+
+ // update the shared control block
+ const DisplayHardware& hw(plane.displayHardware());
+ volatile display_cblk_t* dcblk = mServerCblk->displays + dpy;
+ dcblk->orientation = orientation;
+ dcblk->w = plane.getWidth();
+ dcblk->h = plane.getHeight();
+
+ mVisibleRegionsDirty = true;
+ mDirtyRegion.set(hw.bounds());
+ }
+
+ if (mCurrentState.freezeDisplay != mDrawingState.freezeDisplay) {
+ // freezing or unfreezing the display -> trigger animation if needed
+ mFreezeDisplay = mCurrentState.freezeDisplay;
+ if (mFreezeDisplay)
+ mFreezeDisplayTime = 0;
+ }
+
+ if (currentLayers.size() > mDrawingState.layersSortedByZ.size()) {
+ // layers have been added
+ mVisibleRegionsDirty = true;
+ }
+
+ // some layers might have been removed, so
+ // we need to update the regions they're exposing.
+ if (mLayersRemoved) {
+ mLayersRemoved = false;
+ mVisibleRegionsDirty = true;
+ const LayerVector& previousLayers(mDrawingState.layersSortedByZ);
+ const size_t count = previousLayers.size();
+ for (size_t i=0 ; i<count ; i++) {
+ const sp<LayerBase>& layer(previousLayers[i]);
+ if (currentLayers.indexOf( layer ) < 0) {
+ // this layer is not visible anymore
+ ditchedLayers.add(layer);
+ mDirtyRegionRemovedLayer.orSelf(layer->visibleRegionScreen);
+ }
+ }
+ }
+ }
+
+ commitTransaction();
+}
+
+sp<FreezeLock> SurfaceFlinger::getFreezeLock() const
+{
+ return new FreezeLock(const_cast<SurfaceFlinger *>(this));
+}
+
+void SurfaceFlinger::computeVisibleRegions(
+ LayerVector& currentLayers, Region& dirtyRegion, Region& opaqueRegion)
+{
+ const GraphicPlane& plane(graphicPlane(0));
+ const Transform& planeTransform(plane.transform());
+ const DisplayHardware& hw(plane.displayHardware());
+ const Region screenRegion(hw.bounds());
+
+ Region aboveOpaqueLayers;
+ Region aboveCoveredLayers;
+ Region dirty;
+
+ bool secureFrameBuffer = false;
+
+ size_t i = currentLayers.size();
+ while (i--) {
+ const sp<LayerBase>& layer = currentLayers[i];
+ layer->validateVisibility(planeTransform);
+
+ // start with the whole surface at its current location
+ const Layer::State& s(layer->drawingState());
+
+ /*
+ * opaqueRegion: area of a surface that is fully opaque.
+ */
+ Region opaqueRegion;
+
+ /*
+ * 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.
+ */
+ Region visibleRegion;
+
+ /*
+ * coveredRegion: area of a surface that is covered by all
+ * visible regions above it (which includes the translucent areas).
+ */
+ Region coveredRegion;
+
+
+ // handle hidden surfaces by setting the visible region to empty
+ if (LIKELY(!(s.flags & ISurfaceComposer::eLayerHidden) && s.alpha)) {
+ const bool translucent = layer->needsBlending();
+ const Rect bounds(layer->visibleBounds());
+ visibleRegion.set(bounds);
+ visibleRegion.andSelf(screenRegion);
+ if (!visibleRegion.isEmpty()) {
+ // Remove the transparent area from the visible region
+ if (translucent) {
+ visibleRegion.subtractSelf(layer->transparentRegionScreen);
+ }
+
+ // compute the opaque region
+ const int32_t layerOrientation = layer->getOrientation();
+ if (s.alpha==255 && !translucent &&
+ ((layerOrientation & Transform::ROT_INVALID) == false)) {
+ // the opaque region is the layer's footprint
+ opaqueRegion = visibleRegion;
+ }
+ }
+ }
+
+ // Clip the covered region to the visible region
+ coveredRegion = aboveCoveredLayers.intersect(visibleRegion);
+
+ // Update aboveCoveredLayers for next (lower) layer
+ aboveCoveredLayers.orSelf(visibleRegion);
+
+ // subtract the opaque region covered by the layers above us
+ visibleRegion.subtractSelf(aboveOpaqueLayers);
+
+ // compute this layer's dirty region
+ if (layer->contentDirty) {
+ // we need to invalidate the whole region
+ dirty = visibleRegion;
+ // as well, as the old visible region
+ dirty.orSelf(layer->visibleRegionScreen);
+ layer->contentDirty = false;
+ } else {
+ /* compute the exposed region:
+ * 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.
+ */
+ const Region newExposed = visibleRegion - coveredRegion;
+ const Region oldVisibleRegion = layer->visibleRegionScreen;
+ const Region oldCoveredRegion = layer->coveredRegionScreen;
+ const Region oldExposed = oldVisibleRegion - oldCoveredRegion;
+ dirty = (visibleRegion&oldCoveredRegion) | (newExposed-oldExposed);
+ }
+ dirty.subtractSelf(aboveOpaqueLayers);
+
+ // accumulate to the screen dirty region
+ dirtyRegion.orSelf(dirty);
+
+ // Update aboveOpaqueLayers for next (lower) layer
+ aboveOpaqueLayers.orSelf(opaqueRegion);
+
+ // Store the visible region is screen space
+ layer->setVisibleRegion(visibleRegion);
+ layer->setCoveredRegion(coveredRegion);
+
+ // If a secure layer is partially visible, lock-down the screen!
+ if (layer->isSecure() && !visibleRegion.isEmpty()) {
+ secureFrameBuffer = true;
+ }
+ }
+
+ // invalidate the areas where a layer was removed
+ dirtyRegion.orSelf(mDirtyRegionRemovedLayer);
+ mDirtyRegionRemovedLayer.clear();
+
+ mSecureFrameBuffer = secureFrameBuffer;
+ opaqueRegion = aboveOpaqueLayers;
+}
+
+
+void SurfaceFlinger::commitTransaction()
+{
+ mDrawingState = mCurrentState;
+ mResizeTransationPending = false;
+ mTransactionCV.broadcast();
+}
+
+void SurfaceFlinger::handlePageFlip()
+{
+ bool visibleRegions = mVisibleRegionsDirty;
+ LayerVector& currentLayers = const_cast<LayerVector&>(
+ mDrawingState.layersSortedByZ);
+ visibleRegions |= lockPageFlip(currentLayers);
+
+ const DisplayHardware& hw = graphicPlane(0).displayHardware();
+ const Region screenRegion(hw.bounds());
+ if (visibleRegions) {
+ Region opaqueRegion;
+ computeVisibleRegions(currentLayers, mDirtyRegion, opaqueRegion);
+ mWormholeRegion = screenRegion.subtract(opaqueRegion);
+ mVisibleRegionsDirty = false;
+ }
+
+ unlockPageFlip(currentLayers);
+ mDirtyRegion.andSelf(screenRegion);
+}
+
+bool SurfaceFlinger::lockPageFlip(const LayerVector& currentLayers)
+{
+ bool recomputeVisibleRegions = false;
+ 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]);
+ layer->lockPageFlip(recomputeVisibleRegions);
+ }
+ return recomputeVisibleRegions;
+}
+
+void SurfaceFlinger::unlockPageFlip(const LayerVector& currentLayers)
+{
+ const GraphicPlane& plane(graphicPlane(0));
+ const Transform& planeTransform(plane.transform());
+ size_t count = currentLayers.size();
+ sp<LayerBase> const* layers = currentLayers.array();
+ for (size_t i=0 ; i<count ; i++) {
+ const sp<LayerBase>& layer(layers[i]);
+ layer->unlockPageFlip(planeTransform, mDirtyRegion);
+ }
+}
+
+
+void SurfaceFlinger::handleRepaint()
+{
+ // compute the invalid region
+ mInvalidRegion.orSelf(mDirtyRegion);
+ if (mInvalidRegion.isEmpty()) {
+ // nothing to do
+ return;
+ }
+
+ if (UNLIKELY(mDebugRegion)) {
+ debugFlashRegions();
+ }
+
+ // set the frame buffer
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ uint32_t flags = hw.getFlags();
+ if ((flags & DisplayHardware::SWAP_RECTANGLE) ||
+ (flags & DisplayHardware::BUFFER_PRESERVED))
+ {
+ // we can redraw only what's dirty, but since SWAP_RECTANGLE only
+ // takes a rectangle, we must make sure to update that whole
+ // rectangle in that case
+ if (flags & DisplayHardware::SWAP_RECTANGLE) {
+ // TODO: we really should be able to pass a region to
+ // SWAP_RECTANGLE so that we don't have to redraw all this.
+ mDirtyRegion.set(mInvalidRegion.bounds());
+ } else {
+ // in the BUFFER_PRESERVED case, obviously, we can update only
+ // what's needed and nothing more.
+ // NOTE: this is NOT a common case, as preserving the backbuffer
+ // is costly and usually involves copying the whole update back.
+ }
+ } else {
+ if (flags & DisplayHardware::PARTIAL_UPDATES) {
+ // We need to redraw the rectangle that will be updated
+ // (pushed to the framebuffer).
+ // This is needed because PARTIAL_UPDATES only takes one
+ // rectangle instead of a region (see DisplayHardware::flip())
+ mDirtyRegion.set(mInvalidRegion.bounds());
+ } else {
+ // we need to redraw everything (the whole screen)
+ mDirtyRegion.set(hw.bounds());
+ mInvalidRegion = mDirtyRegion;
+ }
+ }
+
+ // compose all surfaces
+ composeSurfaces(mDirtyRegion);
+
+ // clear the dirty regions
+ mDirtyRegion.clear();
+}
+
+void SurfaceFlinger::composeSurfaces(const Region& dirty)
+{
+ if (UNLIKELY(!mWormholeRegion.isEmpty())) {
+ // should never happen unless the window manager has a bug
+ // draw something...
+ drawWormhole();
+ }
+ const SurfaceFlinger& flinger(*this);
+ const LayerVector& drawingLayers(mDrawingState.layersSortedByZ);
+ const size_t count = drawingLayers.size();
+ sp<LayerBase> const* const layers = drawingLayers.array();
+ for (size_t i=0 ; i<count ; ++i) {
+ const sp<LayerBase>& layer = layers[i];
+ const Region& visibleRegion(layer->visibleRegionScreen);
+ if (!visibleRegion.isEmpty()) {
+ const Region clip(dirty.intersect(visibleRegion));
+ if (!clip.isEmpty()) {
+ layer->draw(clip);
+ }
+ }
+ }
+}
+
+void SurfaceFlinger::unlockClients()
+{
+ const LayerVector& drawingLayers(mDrawingState.layersSortedByZ);
+ const size_t count = drawingLayers.size();
+ sp<LayerBase> const* const layers = drawingLayers.array();
+ for (size_t i=0 ; i<count ; ++i) {
+ const sp<LayerBase>& layer = layers[i];
+ layer->finishPageFlip();
+ }
+}
+
+void SurfaceFlinger::debugFlashRegions()
+{
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ const uint32_t flags = hw.getFlags();
+
+ if (!((flags & DisplayHardware::SWAP_RECTANGLE) ||
+ (flags & DisplayHardware::BUFFER_PRESERVED))) {
+ const Region repaint((flags & DisplayHardware::PARTIAL_UPDATES) ?
+ mDirtyRegion.bounds() : hw.bounds());
+ composeSurfaces(repaint);
+ }
+
+ TextureManager::deactivateTextures();
+
+ glDisable(GL_BLEND);
+ glDisable(GL_DITHER);
+ glDisable(GL_SCISSOR_TEST);
+
+ static int toggle = 0;
+ toggle = 1 - toggle;
+ if (toggle) {
+ glColor4f(1, 0, 1, 1);
+ } else {
+ glColor4f(1, 1, 0, 1);
+ }
+
+ Region::const_iterator it = mDirtyRegion.begin();
+ Region::const_iterator const end = mDirtyRegion.end();
+ while (it != end) {
+ const Rect& r = *it++;
+ GLfloat vertices[][2] = {
+ { r.left, r.top },
+ { r.left, r.bottom },
+ { r.right, r.bottom },
+ { r.right, r.top }
+ };
+ glVertexPointer(2, GL_FLOAT, 0, vertices);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ }
+
+ if (mInvalidRegion.isEmpty()) {
+ mDirtyRegion.dump("mDirtyRegion");
+ mInvalidRegion.dump("mInvalidRegion");
+ }
+ hw.flip(mInvalidRegion);
+
+ if (mDebugRegion > 1)
+ usleep(mDebugRegion * 1000);
+
+ glEnable(GL_SCISSOR_TEST);
+ //mDirtyRegion.dump("mDirtyRegion");
+}
+
+void SurfaceFlinger::drawWormhole() const
+{
+ const Region region(mWormholeRegion.intersect(mDirtyRegion));
+ if (region.isEmpty())
+ return;
+
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ const int32_t width = hw.getWidth();
+ const int32_t height = hw.getHeight();
+
+ glDisable(GL_BLEND);
+ glDisable(GL_DITHER);
+
+ if (LIKELY(!mDebugBackground)) {
+ glClearColor(0,0,0,0);
+ Region::const_iterator it = region.begin();
+ Region::const_iterator const end = region.end();
+ while (it != end) {
+ const Rect& r = *it++;
+ const GLint sy = height - (r.top + r.height());
+ glScissor(r.left, sy, r.width(), r.height());
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
+ } else {
+ const GLshort vertices[][2] = { { 0, 0 }, { width, 0 },
+ { width, height }, { 0, height } };
+ const GLshort tcoords[][2] = { { 0, 0 }, { 1, 0 }, { 1, 1 }, { 0, 1 } };
+ glVertexPointer(2, GL_SHORT, 0, vertices);
+ glTexCoordPointer(2, GL_SHORT, 0, tcoords);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+#if defined(GL_OES_texture_external)
+ if (GLExtensions::getInstance().haveTextureExternal()) {
+ glDisable(GL_TEXTURE_EXTERNAL_OES);
+ }
+#endif
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, mWormholeTexName);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+ glScalef(width*(1.0f/32.0f), height*(1.0f/32.0f), 1);
+ Region::const_iterator it = region.begin();
+ Region::const_iterator const end = region.end();
+ while (it != end) {
+ const Rect& r = *it++;
+ const GLint sy = height - (r.top + r.height());
+ glScissor(r.left, sy, r.width(), r.height());
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ }
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ }
+}
+
+void SurfaceFlinger::debugShowFPS() const
+{
+ static int mFrameCount;
+ static int mLastFrameCount = 0;
+ static nsecs_t mLastFpsTime = 0;
+ static float mFps = 0;
+ mFrameCount++;
+ nsecs_t now = systemTime();
+ nsecs_t diff = now - mLastFpsTime;
+ if (diff > ms2ns(250)) {
+ mFps = ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff;
+ mLastFpsTime = now;
+ mLastFrameCount = mFrameCount;
+ }
+ // XXX: mFPS has the value we want
+ }
+
+status_t SurfaceFlinger::addLayer(const sp<LayerBase>& layer)
+{
+ Mutex::Autolock _l(mStateLock);
+ addLayer_l(layer);
+ setTransactionFlags(eTransactionNeeded|eTraversalNeeded);
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::addLayer_l(const sp<LayerBase>& layer)
+{
+ ssize_t i = mCurrentState.layersSortedByZ.add(
+ layer, &LayerBase::compareCurrentStateZ);
+ return (i < 0) ? status_t(i) : status_t(NO_ERROR);
+}
+
+ssize_t SurfaceFlinger::addClientLayer(const sp<Client>& client,
+ const sp<LayerBaseClient>& lbc)
+{
+ Mutex::Autolock _l(mStateLock);
+
+ // attach this layer to the client
+ ssize_t name = client->attachLayer(lbc);
+
+ // add this layer to the current state list
+ addLayer_l(lbc);
+
+ return name;
+}
+
+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;
+}
+
+status_t SurfaceFlinger::removeLayer_l(const sp<LayerBase>& layerBase)
+{
+ sp<LayerBaseClient> lbc(layerBase->getLayerBaseClient());
+ if (lbc != 0) {
+ mLayerMap.removeItem( lbc->getSurface()->asBinder() );
+ }
+ ssize_t index = mCurrentState.layersSortedByZ.remove(layerBase);
+ if (index >= 0) {
+ mLayersRemoved = true;
+ return NO_ERROR;
+ }
+ return status_t(index);
+}
+
+status_t SurfaceFlinger::purgatorizeLayer_l(const sp<LayerBase>& layerBase)
+{
+ // remove the layer from the main list (through a transaction).
+ ssize_t err = removeLayer_l(layerBase);
+
+ layerBase->onRemoved();
+
+ // it's possible that we don't find a layer, because it might
+ // have been destroyed already -- this is not technically an error
+ // from the user because there is a race between Client::destroySurface(),
+ // ~Client() and ~ISurface().
+ return (err == NAME_NOT_FOUND) ? status_t(NO_ERROR) : err;
+}
+
+status_t SurfaceFlinger::invalidateLayerVisibility(const sp<LayerBase>& layer)
+{
+ layer->forceVisibilityTransaction();
+ setTransactionFlags(eTraversalNeeded);
+ return NO_ERROR;
+}
+
+uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags)
+{
+ return android_atomic_and(~flags, &mTransactionFlags) & flags;
+}
+
+uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags)
+{
+ uint32_t old = android_atomic_or(flags, &mTransactionFlags);
+ if ((old & flags)==0) { // wake the server up
+ signalEvent();
+ }
+ return old;
+}
+
+void SurfaceFlinger::openGlobalTransaction()
+{
+ android_atomic_inc(&mTransactionCount);
+}
+
+void SurfaceFlinger::closeGlobalTransaction()
+{
+ if (android_atomic_dec(&mTransactionCount) == 1) {
+ signalEvent();
+
+ // if there is a transaction with a resize, wait for it to
+ // take effect before returning.
+ Mutex::Autolock _l(mStateLock);
+ while (mResizeTransationPending) {
+ status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
+ if (CC_UNLIKELY(err != NO_ERROR)) {
+ // just in case something goes wrong in SF, return to the
+ // called after a few seconds.
+ LOGW_IF(err == TIMED_OUT, "closeGlobalTransaction timed out!");
+ mResizeTransationPending = false;
+ break;
+ }
+ }
+ }
+}
+
+status_t SurfaceFlinger::freezeDisplay(DisplayID dpy, uint32_t flags)
+{
+ if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
+ return BAD_VALUE;
+
+ Mutex::Autolock _l(mStateLock);
+ mCurrentState.freezeDisplay = 1;
+ setTransactionFlags(eTransactionNeeded);
+
+ // flags is intended to communicate some sort of animation behavior
+ // (for instance fading)
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::unfreezeDisplay(DisplayID dpy, uint32_t flags)
+{
+ if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
+ return BAD_VALUE;
+
+ Mutex::Autolock _l(mStateLock);
+ mCurrentState.freezeDisplay = 0;
+ setTransactionFlags(eTransactionNeeded);
+
+ // flags is intended to communicate some sort of animation behavior
+ // (for instance fading)
+ return NO_ERROR;
+}
+
+int SurfaceFlinger::setOrientation(DisplayID dpy,
+ int orientation, uint32_t flags)
+{
+ if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
+ return BAD_VALUE;
+
+ Mutex::Autolock _l(mStateLock);
+ if (mCurrentState.orientation != orientation) {
+ if (uint32_t(orientation)<=eOrientation270 || orientation==42) {
+ mCurrentState.orientationType = flags;
+ mCurrentState.orientation = orientation;
+ setTransactionFlags(eTransactionNeeded);
+ mTransactionCV.wait(mStateLock);
+ } else {
+ orientation = BAD_VALUE;
+ }
+ }
+ return orientation;
+}
+
+sp<ISurface> SurfaceFlinger::createSurface(const sp<Client>& client, int pid,
+ const String8& name, ISurfaceComposerClient::surface_data_t* params,
+ DisplayID d, uint32_t w, uint32_t h, PixelFormat format,
+ uint32_t flags)
+{
+ sp<LayerBaseClient> layer;
+ sp<LayerBaseClient::Surface> surfaceHandle;
+
+ if (int32_t(w|h) < 0) {
+ LOGE("createSurface() failed, w or h is negative (w=%d, h=%d)",
+ int(w), int(h));
+ return surfaceHandle;
+ }
+
+ //LOGD("createSurface for pid %d (%d x %d)", pid, w, h);
+ sp<Layer> normalLayer;
+ switch (flags & eFXSurfaceMask) {
+ case eFXSurfaceNormal:
+ if (UNLIKELY(flags & ePushBuffers)) {
+ layer = createPushBuffersSurface(client, d, w, h, flags);
+ } else {
+ normalLayer = createNormalSurface(client, d, w, h, flags, format);
+ layer = normalLayer;
+ }
+ break;
+ case eFXSurfaceBlur:
+ layer = createBlurSurface(client, d, w, h, flags);
+ break;
+ case eFXSurfaceDim:
+ layer = createDimSurface(client, d, w, h, flags);
+ break;
+ }
+
+ if (layer != 0) {
+ layer->initStates(w, h, flags);
+ layer->setName(name);
+ ssize_t token = addClientLayer(client, layer);
+
+ surfaceHandle = layer->getSurface();
+ if (surfaceHandle != 0) {
+ params->token = token;
+ params->identity = surfaceHandle->getIdentity();
+ params->width = w;
+ params->height = h;
+ params->format = format;
+ if (normalLayer != 0) {
+ Mutex::Autolock _l(mStateLock);
+ mLayerMap.add(surfaceHandle->asBinder(), normalLayer);
+ }
+ }
+
+ setTransactionFlags(eTransactionNeeded);
+ }
+
+ return surfaceHandle;
+}
+
+sp<Layer> SurfaceFlinger::createNormalSurface(
+ const sp<Client>& client, DisplayID display,
+ uint32_t w, uint32_t h, uint32_t flags,
+ PixelFormat& format)
+{
+ // 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:
+#ifdef NO_RGBX_8888
+ format = PIXEL_FORMAT_RGB_565;
+#else
+ format = PIXEL_FORMAT_RGBX_8888;
+#endif
+ break;
+ }
+
+#ifdef NO_RGBX_8888
+ if (format == PIXEL_FORMAT_RGBX_8888)
+ format = PIXEL_FORMAT_RGBA_8888;
+#endif
+
+ sp<Layer> layer = new Layer(this, display, client);
+ status_t err = layer->setBuffers(w, h, format, flags);
+ if (LIKELY(err != NO_ERROR)) {
+ LOGE("createNormalSurfaceLocked() failed (%s)", strerror(-err));
+ layer.clear();
+ }
+ return layer;
+}
+
+sp<LayerBlur> SurfaceFlinger::createBlurSurface(
+ const sp<Client>& client, DisplayID display,
+ uint32_t w, uint32_t h, uint32_t flags)
+{
+ sp<LayerBlur> layer = new LayerBlur(this, display, client);
+ layer->initStates(w, h, flags);
+ return layer;
+}
+
+sp<LayerDim> SurfaceFlinger::createDimSurface(
+ const sp<Client>& client, DisplayID display,
+ uint32_t w, uint32_t h, uint32_t flags)
+{
+ sp<LayerDim> layer = new LayerDim(this, display, client);
+ layer->initStates(w, h, flags);
+ return layer;
+}
+
+sp<LayerBuffer> SurfaceFlinger::createPushBuffersSurface(
+ const sp<Client>& client, DisplayID display,
+ uint32_t w, uint32_t h, uint32_t flags)
+{
+ sp<LayerBuffer> layer = new LayerBuffer(this, display, client);
+ layer->initStates(w, h, flags);
+ return layer;
+}
+
+status_t SurfaceFlinger::removeSurface(const sp<Client>& client, SurfaceID sid)
+{
+ /*
+ * called by the window manager, when a surface should be marked for
+ * destruction.
+ *
+ * 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).
+ */
+
+ status_t err = NAME_NOT_FOUND;
+ Mutex::Autolock _l(mStateLock);
+ sp<LayerBaseClient> layer = client->getLayerUser(sid);
+ if (layer != 0) {
+ err = purgatorizeLayer_l(layer);
+ if (err == NO_ERROR) {
+ setTransactionFlags(eTransactionNeeded);
+ }
+ }
+ return err;
+}
+
+status_t SurfaceFlinger::destroySurface(const sp<LayerBaseClient>& layer)
+{
+ // called by ~ISurface() when all references are gone
+
+ class MessageDestroySurface : public MessageBase {
+ SurfaceFlinger* flinger;
+ sp<LayerBaseClient> layer;
+ public:
+ MessageDestroySurface(
+ SurfaceFlinger* flinger, const sp<LayerBaseClient>& layer)
+ : flinger(flinger), layer(layer) { }
+ virtual bool handler() {
+ sp<LayerBaseClient> l(layer);
+ layer.clear(); // clear it outside of the lock;
+ Mutex::Autolock _l(flinger->mStateLock);
+ /*
+ * remove the layer from the current list -- chances are that it's
+ * not in the list anyway, because it should have been removed
+ * already upon request of the client (eg: window manager).
+ * However, a buggy client could have not done that.
+ * Since we know we don't have any more clients, we don't need
+ * to use the purgatory.
+ */
+ status_t err = flinger->removeLayer_l(l);
+ LOGE_IF(err<0 && err != NAME_NOT_FOUND,
+ "error removing layer=%p (%s)", l.get(), strerror(-err));
+ return true;
+ }
+ };
+
+ postMessageAsync( new MessageDestroySurface(this, layer) );
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::setClientState(
+ const sp<Client>& client,
+ int32_t count,
+ const layer_state_t* states)
+{
+ Mutex::Autolock _l(mStateLock);
+ uint32_t flags = 0;
+ for (int i=0 ; i<count ; i++) {
+ const layer_state_t& s(states[i]);
+ 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) {
+ if (layer->setLayer(s.z)) {
+ mCurrentState.layersSortedByZ.reorder(
+ layer, &Layer::compareCurrentStateZ);
+ // we need traversal (state changed)
+ // AND transaction (list changed)
+ flags |= eTransactionNeeded|eTraversalNeeded;
+ }
+ }
+ if (what & eSizeChanged) {
+ if (layer->setSize(s.w, s.h)) {
+ flags |= eTraversalNeeded;
+ mResizeTransationPending = true;
+ }
+ }
+ if (what & eAlphaChanged) {
+ if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f)))
+ flags |= eTraversalNeeded;
+ }
+ if (what & eMatrixChanged) {
+ if (layer->setMatrix(s.matrix))
+ flags |= eTraversalNeeded;
+ }
+ if (what & eTransparentRegionChanged) {
+ if (layer->setTransparentRegionHint(s.transparentRegion))
+ flags |= eTraversalNeeded;
+ }
+ if (what & eVisibilityChanged) {
+ if (layer->setFlags(s.flags, s.mask))
+ flags |= eTraversalNeeded;
+ }
+ }
+ }
+ if (flags) {
+ setTransactionFlags(flags);
+ }
+ return NO_ERROR;
+}
+
+void SurfaceFlinger::screenReleased(int dpy)
+{
+ // this may be called by a signal handler, we can't do too much in here
+ android_atomic_or(eConsoleReleased, &mConsoleSignals);
+ signalEvent();
+}
+
+void SurfaceFlinger::screenAcquired(int dpy)
+{
+ // this may be called by a signal handler, we can't do too much in here
+ android_atomic_or(eConsoleAcquired, &mConsoleSignals);
+ signalEvent();
+}
+
+status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 1024;
+ char buffer[SIZE];
+ String8 result;
+ if (!mDump.checkCalling()) {
+ 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 {
+
+ // figure out if we're stuck somewhere
+ const nsecs_t now = systemTime();
+ const nsecs_t inSwapBuffers(mDebugInSwapBuffers);
+ const nsecs_t inTransaction(mDebugInTransaction);
+ nsecs_t inSwapBuffersDuration = (inSwapBuffers) ? now-inSwapBuffers : 0;
+ nsecs_t inTransactionDuration = (inTransaction) ? now-inTransaction : 0;
+
+ // Try to get the main lock, but don't insist if we can't
+ // (this would indicate SF is stuck, but we want to be able to
+ // print something in dumpsys).
+ int retry = 3;
+ while (mStateLock.tryLock()<0 && --retry>=0) {
+ usleep(1000000);
+ }
+ const bool locked(retry >= 0);
+ if (!locked) {
+ snprintf(buffer, SIZE,
+ "SurfaceFlinger appears to be unresponsive, "
+ "dumping anyways (no locks held)\n");
+ result.append(buffer);
+ }
+
+ 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]);
+ layer->dump(result, buffer, SIZE);
+ const Layer::State& s(layer->drawingState());
+ s.transparentRegion.dump(result, "transparentRegion");
+ layer->transparentRegionScreen.dump(result, "transparentRegionScreen");
+ layer->visibleRegionScreen.dump(result, "visibleRegionScreen");
+ }
+
+ mWormholeRegion.dump(result, "WormholeRegion");
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ snprintf(buffer, SIZE,
+ " display frozen: %s, freezeCount=%d, orientation=%d, canDraw=%d\n",
+ mFreezeDisplay?"yes":"no", mFreezeCount,
+ mCurrentState.orientation, hw.canDraw());
+ result.append(buffer);
+ snprintf(buffer, SIZE,
+ " last eglSwapBuffers() time: %f us\n"
+ " last transaction time : %f us\n",
+ mLastSwapBufferTime/1000.0, mLastTransactionTime/1000.0);
+ result.append(buffer);
+
+ if (inSwapBuffersDuration || !locked) {
+ snprintf(buffer, SIZE, " eglSwapBuffers time: %f us\n",
+ inSwapBuffersDuration/1000.0);
+ result.append(buffer);
+ }
+
+ if (inTransactionDuration || !locked) {
+ snprintf(buffer, SIZE, " transaction time: %f us\n",
+ inTransactionDuration/1000.0);
+ result.append(buffer);
+ }
+
+ const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
+ alloc.dump(result);
+
+ if (locked) {
+ mStateLock.unlock();
+ }
+ }
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch (code) {
+ case CREATE_CONNECTION:
+ case OPEN_GLOBAL_TRANSACTION:
+ case CLOSE_GLOBAL_TRANSACTION:
+ case SET_ORIENTATION:
+ case FREEZE_DISPLAY:
+ case UNFREEZE_DISPLAY:
+ case BOOT_FINISHED:
+ {
+ // codes that require permission check
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ if ((uid != AID_GRAPHICS) && !mAccessSurfaceFlinger.check(pid, uid)) {
+ LOGE("Permission Denial: "
+ "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
+ return PERMISSION_DENIED;
+ }
+ }
+ }
+ status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags);
+ if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ if (UNLIKELY(!mHardwareTest.checkCalling())) {
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ LOGE("Permission Denial: "
+ "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
+ return PERMISSION_DENIED;
+ }
+ int n;
+ switch (code) {
+ case 1000: // SHOW_CPU, NOT SUPPORTED ANYMORE
+ return NO_ERROR;
+ case 1001: // SHOW_FPS, NOT SUPPORTED ANYMORE
+ return NO_ERROR;
+ case 1002: // SHOW_UPDATES
+ n = data.readInt32();
+ mDebugRegion = n ? n : (mDebugRegion ? 0 : 1);
+ return NO_ERROR;
+ case 1003: // SHOW_BACKGROUND
+ n = data.readInt32();
+ mDebugBackground = n ? 1 : 0;
+ return NO_ERROR;
+ case 1004:{ // repaint everything
+ Mutex::Autolock _l(mStateLock);
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ mDirtyRegion.set(hw.bounds()); // careful that's not thread-safe
+ signalEvent();
+ return NO_ERROR;
+ }
+ case 1005:{ // force transaction
+ setTransactionFlags(eTransactionNeeded|eTraversalNeeded);
+ return NO_ERROR;
+ }
+ case 1007: // set mFreezeCount
+ mFreezeCount = data.readInt32();
+ mFreezeDisplayTime = 0;
+ return NO_ERROR;
+ case 1010: // interrogate.
+ reply->writeInt32(0);
+ reply->writeInt32(0);
+ reply->writeInt32(mDebugRegion);
+ reply->writeInt32(mDebugBackground);
+ return NO_ERROR;
+ case 1013: {
+ Mutex::Autolock _l(mStateLock);
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ reply->writeInt32(hw.getPageFlipCount());
+ }
+ return NO_ERROR;
+ }
+ }
+ return err;
+}
+
+// ---------------------------------------------------------------------------
+
+sp<Layer> SurfaceFlinger::getLayer(const sp<ISurface>& sur) const
+{
+ sp<Layer> result;
+ Mutex::Autolock _l(mStateLock);
+ result = mLayerMap.valueFor( sur->asBinder() ).promote();
+ return result;
+}
+
+// ---------------------------------------------------------------------------
+
+Client::Client(const sp<SurfaceFlinger>& flinger)
+ : mFlinger(flinger), mNameGenerator(1)
+{
+}
+
+Client::~Client()
+{
+ const size_t count = mLayers.size();
+ for (size_t i=0 ; i<count ; i++) {
+ sp<LayerBaseClient> layer(mLayers.valueAt(i).promote());
+ if (layer != 0) {
+ mFlinger->removeLayer(layer);
+ }
+ }
+}
+
+status_t Client::initCheck() const {
+ return NO_ERROR;
+}
+
+ssize_t Client::attachLayer(const sp<LayerBaseClient>& layer)
+{
+ int32_t name = android_atomic_inc(&mNameGenerator);
+ mLayers.add(name, layer);
+ return name;
+}
+
+void Client::detachLayer(const LayerBaseClient* layer)
+{
+ // we do a linear search here, because this doesn't happen often
+ const size_t count = mLayers.size();
+ for (size_t i=0 ; i<count ; i++) {
+ if (mLayers.valueAt(i) == layer) {
+ mLayers.removeItemsAt(i, 1);
+ break;
+ }
+ }
+}
+sp<LayerBaseClient> Client::getLayerUser(int32_t i) const {
+ sp<LayerBaseClient> lbc;
+ const wp<LayerBaseClient>& layer(mLayers.valueFor(i));
+ if (layer != 0) {
+ lbc = layer.promote();
+ LOGE_IF(lbc==0, "getLayerUser(name=%d) is dead", int(i));
+ }
+ return lbc;
+}
+
+sp<IMemoryHeap> Client::getControlBlock() const {
+ return 0;
+}
+ssize_t Client::getTokenForSurface(const sp<ISurface>& sur) const {
+ return -1;
+}
+sp<ISurface> Client::createSurface(
+ ISurfaceComposerClient::surface_data_t* params, int pid,
+ const String8& name,
+ DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
+ uint32_t flags)
+{
+ return mFlinger->createSurface(this, pid, name, params,
+ display, w, h, format, flags);
+}
+status_t Client::destroySurface(SurfaceID sid) {
+ return mFlinger->removeSurface(this, sid);
+}
+status_t Client::setState(int32_t count, const layer_state_t* states) {
+ return mFlinger->setClientState(this, count, states);
+}
+
+// ---------------------------------------------------------------------------
+
+UserClient::UserClient(const sp<SurfaceFlinger>& flinger)
+ : ctrlblk(0), mBitmap(0), mFlinger(flinger)
+{
+ const int pgsize = getpagesize();
+ const int cblksize = ((sizeof(SharedClient)+(pgsize-1))&~(pgsize-1));
+
+ mCblkHeap = new MemoryHeapBase(cblksize, 0,
+ "SurfaceFlinger Client control-block");
+
+ ctrlblk = static_cast<SharedClient *>(mCblkHeap->getBase());
+ if (ctrlblk) { // construct the shared structure in-place.
+ new(ctrlblk) SharedClient;
+ }
+}
+
+UserClient::~UserClient()
+{
+ if (ctrlblk) {
+ ctrlblk->~SharedClient(); // destroy our shared-structure.
+ }
+
+ /*
+ * When a UserClient dies, it's unclear what to do exactly.
+ * We could go ahead and destroy all surfaces linked to that client
+ * however, it wouldn't be fair to the main Client
+ * (usually the the window-manager), which might want to re-target
+ * the layer to another UserClient.
+ * I think the best is to do nothing, or not much; in most cases the
+ * WM itself will go ahead and clean things up when it detects a client of
+ * his has died.
+ * The remaining question is what to display? currently we keep
+ * just keep the current buffer.
+ */
+}
+
+status_t UserClient::initCheck() const {
+ return ctrlblk == 0 ? NO_INIT : NO_ERROR;
+}
+
+void UserClient::detachLayer(const Layer* layer)
+{
+ int32_t name = layer->getToken();
+ if (name >= 0) {
+ int32_t mask = 1LU<<name;
+ if ((android_atomic_and(~mask, &mBitmap) & mask) == 0) {
+ LOGW("token %d wasn't marked as used %08x", name, int(mBitmap));
+ }
+ }
+}
+
+sp<IMemoryHeap> UserClient::getControlBlock() const {
+ return mCblkHeap;
+}
+
+ssize_t UserClient::getTokenForSurface(const sp<ISurface>& sur) const
+{
+ int32_t name = NAME_NOT_FOUND;
+ sp<Layer> layer(mFlinger->getLayer(sur));
+ if (layer == 0) return name;
+
+ // if this layer already has a token, just return it
+ name = layer->getToken();
+ if ((name >= 0) && (layer->getClient() == this))
+ return name;
+
+ name = 0;
+ do {
+ int32_t mask = 1LU<<name;
+ if ((android_atomic_or(mask, &mBitmap) & mask) == 0) {
+ // we found and locked that name
+ status_t err = layer->setToken(
+ const_cast<UserClient*>(this), ctrlblk, name);
+ if (err != NO_ERROR) {
+ // free the name
+ android_atomic_and(~mask, &mBitmap);
+ name = err;
+ }
+ break;
+ }
+ if (++name > 31)
+ name = NO_MEMORY;
+ } while(name >= 0);
+
+ //LOGD("getTokenForSurface(%p) => %d (client=%p, bitmap=%08lx)",
+ // sur->asBinder().get(), name, this, mBitmap);
+ return name;
+}
+
+sp<ISurface> UserClient::createSurface(
+ ISurfaceComposerClient::surface_data_t* params, int pid,
+ const String8& name,
+ DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
+ uint32_t flags) {
+ return 0;
+}
+status_t UserClient::destroySurface(SurfaceID sid) {
+ return INVALID_OPERATION;
+}
+status_t UserClient::setState(int32_t count, const layer_state_t* states) {
+ return INVALID_OPERATION;
+}
+
+// ---------------------------------------------------------------------------
+
+GraphicPlane::GraphicPlane()
+ : mHw(0)
+{
+}
+
+GraphicPlane::~GraphicPlane() {
+ delete mHw;
+}
+
+bool GraphicPlane::initialized() const {
+ return mHw ? true : false;
+}
+
+int GraphicPlane::getWidth() const {
+ return mWidth;
+}
+
+int GraphicPlane::getHeight() const {
+ return mHeight;
+}
+
+void GraphicPlane::setDisplayHardware(DisplayHardware *hw)
+{
+ mHw = hw;
+
+ // initialize the display orientation transform.
+ // it's a constant that should come from the display driver.
+ int displayOrientation = ISurfaceComposer::eOrientationDefault;
+ char property[PROPERTY_VALUE_MAX];
+ if (property_get("ro.sf.hwrotation", property, NULL) > 0) {
+ //displayOrientation
+ switch (atoi(property)) {
+ case 90:
+ displayOrientation = ISurfaceComposer::eOrientation90;
+ break;
+ case 270:
+ displayOrientation = ISurfaceComposer::eOrientation270;
+ break;
+ }
+ }
+
+ const float w = hw->getWidth();
+ const float h = hw->getHeight();
+ GraphicPlane::orientationToTransfrom(displayOrientation, w, h,
+ &mDisplayTransform);
+ if (displayOrientation & ISurfaceComposer::eOrientationSwapMask) {
+ mDisplayWidth = h;
+ mDisplayHeight = w;
+ } else {
+ mDisplayWidth = w;
+ mDisplayHeight = h;
+ }
+
+ setOrientation(ISurfaceComposer::eOrientationDefault);
+}
+
+status_t GraphicPlane::orientationToTransfrom(
+ int orientation, int w, int h, Transform* tr)
+{
+ uint32_t flags = 0;
+ switch (orientation) {
+ case ISurfaceComposer::eOrientationDefault:
+ flags = Transform::ROT_0;
+ break;
+ case ISurfaceComposer::eOrientation90:
+ flags = Transform::ROT_90;
+ break;
+ case ISurfaceComposer::eOrientation180:
+ flags = Transform::ROT_180;
+ break;
+ case ISurfaceComposer::eOrientation270:
+ flags = Transform::ROT_270;
+ break;
+ default:
+ return BAD_VALUE;
+ }
+ tr->set(flags, w, h);
+ return NO_ERROR;
+}
+
+status_t GraphicPlane::setOrientation(int orientation)
+{
+ // If the rotation can be handled in hardware, this is where
+ // the magic should happen.
+
+ const DisplayHardware& hw(displayHardware());
+ const float w = mDisplayWidth;
+ const float h = mDisplayHeight;
+ mWidth = int(w);
+ mHeight = int(h);
+
+ Transform orientationTransform;
+ GraphicPlane::orientationToTransfrom(orientation, w, h,
+ &orientationTransform);
+ if (orientation & ISurfaceComposer::eOrientationSwapMask) {
+ mWidth = int(h);
+ mHeight = int(w);
+ }
+
+ mOrientation = orientation;
+ mGlobalTransform = mDisplayTransform * orientationTransform;
+ return NO_ERROR;
+}
+
+const DisplayHardware& GraphicPlane::displayHardware() const {
+ return *mHw;
+}
+
+const Transform& GraphicPlane::transform() const {
+ return mGlobalTransform;
+}
+
+EGLDisplay GraphicPlane::getEGLDisplay() const {
+ return mHw->getEGLDisplay();
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
new file mode 100644
index 0000000..0bfc170
--- /dev/null
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -0,0 +1,420 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_SURFACE_FLINGER_H
+#define ANDROID_SURFACE_FLINGER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/SortedVector.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+#include <utils/Atomic.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+#include <binder/IMemory.h>
+#include <binder/Permission.h>
+
+#include <ui/PixelFormat.h>
+#include <surfaceflinger/ISurfaceComposer.h>
+#include <surfaceflinger/ISurfaceComposerClient.h>
+
+#include "Barrier.h"
+#include "Layer.h"
+
+#include "MessageQueue.h"
+
+struct copybit_device_t;
+struct overlay_device_t;
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class Client;
+class DisplayHardware;
+class FreezeLock;
+class Layer;
+class LayerBlur;
+class LayerDim;
+class LayerBuffer;
+
+#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
+#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
+
+// ---------------------------------------------------------------------------
+
+class Client : public BnSurfaceComposerClient
+{
+public:
+ Client(const sp<SurfaceFlinger>& flinger);
+ ~Client();
+
+ status_t initCheck() const;
+
+ // protected by SurfaceFlinger::mStateLock
+ ssize_t attachLayer(const sp<LayerBaseClient>& layer);
+ void detachLayer(const LayerBaseClient* layer);
+ sp<LayerBaseClient> getLayerUser(int32_t i) const;
+
+private:
+
+ // ISurfaceComposerClient interface
+ virtual sp<IMemoryHeap> getControlBlock() const;
+ virtual ssize_t getTokenForSurface(const sp<ISurface>& sur) const;
+ virtual sp<ISurface> createSurface(
+ surface_data_t* params, int pid, const String8& name,
+ DisplayID display, uint32_t w, uint32_t h,PixelFormat format,
+ uint32_t flags);
+ virtual status_t destroySurface(SurfaceID surfaceId);
+ virtual status_t setState(int32_t count, const layer_state_t* states);
+
+ DefaultKeyedVector< size_t, wp<LayerBaseClient> > mLayers;
+ sp<SurfaceFlinger> mFlinger;
+ int32_t mNameGenerator;
+};
+
+class UserClient : public BnSurfaceComposerClient
+{
+public:
+ // pointer to this client's control block
+ SharedClient* ctrlblk;
+
+public:
+ UserClient(const sp<SurfaceFlinger>& flinger);
+ ~UserClient();
+
+ status_t initCheck() const;
+
+ // protected by SurfaceFlinger::mStateLock
+ void detachLayer(const Layer* layer);
+
+private:
+
+ // ISurfaceComposerClient interface
+ virtual sp<IMemoryHeap> getControlBlock() const;
+ virtual ssize_t getTokenForSurface(const sp<ISurface>& sur) const;
+ virtual sp<ISurface> createSurface(
+ surface_data_t* params, int pid, const String8& name,
+ DisplayID display, uint32_t w, uint32_t h,PixelFormat format,
+ uint32_t flags);
+ virtual status_t destroySurface(SurfaceID surfaceId);
+ virtual status_t setState(int32_t count, const layer_state_t* states);
+
+ // atomic-ops
+ mutable volatile int32_t mBitmap;
+
+ sp<IMemoryHeap> mCblkHeap;
+ sp<SurfaceFlinger> mFlinger;
+};
+
+// ---------------------------------------------------------------------------
+
+class GraphicPlane
+{
+public:
+ static status_t orientationToTransfrom(int orientation, int w, int h,
+ Transform* tr);
+
+ GraphicPlane();
+ ~GraphicPlane();
+
+ bool initialized() const;
+
+ void setDisplayHardware(DisplayHardware *);
+ status_t setOrientation(int orientation);
+ int getOrientation() const { return mOrientation; }
+ int getWidth() const;
+ int getHeight() const;
+
+ const DisplayHardware& displayHardware() const;
+ const Transform& transform() const;
+ EGLDisplay getEGLDisplay() const;
+
+private:
+ GraphicPlane(const GraphicPlane&);
+ GraphicPlane operator = (const GraphicPlane&);
+
+ DisplayHardware* mHw;
+ Transform mGlobalTransform;
+ Transform mDisplayTransform;
+ int mOrientation;
+ float mDisplayWidth;
+ float mDisplayHeight;
+ int mWidth;
+ int mHeight;
+};
+
+// ---------------------------------------------------------------------------
+
+enum {
+ eTransactionNeeded = 0x01,
+ eTraversalNeeded = 0x02
+};
+
+class SurfaceFlinger : public BnSurfaceComposer, protected Thread
+{
+public:
+ static void instantiate();
+ static void shutdown();
+
+ SurfaceFlinger();
+ virtual ~SurfaceFlinger();
+ void init();
+
+ virtual status_t onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
+
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+ // ISurfaceComposer interface
+ virtual sp<ISurfaceComposerClient> createConnection();
+ virtual sp<ISurfaceComposerClient> createClientConnection();
+ virtual sp<IMemoryHeap> getCblk() const;
+ virtual void bootFinished();
+ virtual void openGlobalTransaction();
+ virtual void closeGlobalTransaction();
+ virtual status_t freezeDisplay(DisplayID dpy, uint32_t flags);
+ virtual status_t unfreezeDisplay(DisplayID dpy, uint32_t flags);
+ virtual int setOrientation(DisplayID dpy, int orientation, uint32_t flags);
+ virtual void signal() const;
+
+ void screenReleased(DisplayID dpy);
+ void screenAcquired(DisplayID dpy);
+
+ overlay_control_device_t* getOverlayEngine() const;
+
+ status_t removeLayer(const sp<LayerBase>& layer);
+ status_t addLayer(const sp<LayerBase>& layer);
+ status_t invalidateLayerVisibility(const sp<LayerBase>& layer);
+
+ sp<Layer> getLayer(const sp<ISurface>& sur) const;
+
+private:
+ friend class Client;
+ friend class LayerBase;
+ friend class LayerBuffer;
+ friend class LayerBaseClient;
+ friend class LayerBaseClient::Surface;
+ friend class Layer;
+ friend class LayerBlur;
+ friend class LayerDim;
+
+ sp<ISurface> createSurface(const sp<Client>& client,
+ int pid, const String8& name,
+ ISurfaceComposerClient::surface_data_t* params,
+ DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
+ uint32_t flags);
+
+ sp<Layer> createNormalSurface(
+ const sp<Client>& client, DisplayID display,
+ uint32_t w, uint32_t h, uint32_t flags,
+ PixelFormat& format);
+
+ sp<LayerBlur> createBlurSurface(
+ const sp<Client>& client, DisplayID display,
+ uint32_t w, uint32_t h, uint32_t flags);
+
+ sp<LayerDim> createDimSurface(
+ const sp<Client>& client, DisplayID display,
+ uint32_t w, uint32_t h, uint32_t flags);
+
+ sp<LayerBuffer> createPushBuffersSurface(
+ const sp<Client>& client, DisplayID display,
+ uint32_t w, uint32_t h, uint32_t flags);
+
+ status_t removeSurface(const sp<Client>& client, SurfaceID sid);
+ status_t destroySurface(const sp<LayerBaseClient>& layer);
+ status_t setClientState(const sp<Client>& client,
+ int32_t count, const layer_state_t* states);
+
+
+ class LayerVector {
+ public:
+ inline LayerVector() { }
+ LayerVector(const LayerVector&);
+ inline size_t size() const { return layers.size(); }
+ inline sp<LayerBase> const* array() const { return layers.array(); }
+ ssize_t add(const sp<LayerBase>&, Vector< sp<LayerBase> >::compar_t);
+ ssize_t remove(const sp<LayerBase>&);
+ ssize_t reorder(const sp<LayerBase>&, Vector< sp<LayerBase> >::compar_t);
+ ssize_t indexOf(const sp<LayerBase>& key, size_t guess=0) const;
+ inline sp<LayerBase> operator [] (size_t i) const { return layers[i]; }
+ private:
+ KeyedVector< sp<LayerBase> , size_t> lookup;
+ Vector< sp<LayerBase> > layers;
+ };
+
+ struct State {
+ State() {
+ orientation = ISurfaceComposer::eOrientationDefault;
+ freezeDisplay = 0;
+ }
+ LayerVector layersSortedByZ;
+ uint8_t orientation;
+ uint8_t orientationType;
+ uint8_t freezeDisplay;
+ };
+
+ virtual bool threadLoop();
+ virtual status_t readyToRun();
+ virtual void onFirstRef();
+
+public: // hack to work around gcc 4.0.3 bug
+ const GraphicPlane& graphicPlane(int dpy) const;
+ GraphicPlane& graphicPlane(int dpy);
+private:
+
+ void waitForEvent();
+public: // hack to work around gcc 4.0.3 bug
+ void signalEvent();
+private:
+ void handleConsoleEvents();
+ void handleTransaction(uint32_t transactionFlags);
+ void handleTransactionLocked(
+ uint32_t transactionFlags,
+ Vector< sp<LayerBase> >& ditchedLayers);
+
+ void computeVisibleRegions(
+ LayerVector& currentLayers,
+ Region& dirtyRegion,
+ Region& wormholeRegion);
+
+ void handlePageFlip();
+ bool lockPageFlip(const LayerVector& currentLayers);
+ void unlockPageFlip(const LayerVector& currentLayers);
+ void handleRepaint();
+ void postFramebuffer();
+ void composeSurfaces(const Region& dirty);
+ void unlockClients();
+
+
+ ssize_t addClientLayer(const sp<Client>& client,
+ const sp<LayerBaseClient>& lbc);
+ status_t addLayer_l(const sp<LayerBase>& layer);
+ status_t removeLayer_l(const sp<LayerBase>& layer);
+ status_t purgatorizeLayer_l(const sp<LayerBase>& layer);
+
+ uint32_t getTransactionFlags(uint32_t flags);
+ uint32_t setTransactionFlags(uint32_t flags);
+ void commitTransaction();
+
+
+ friend class FreezeLock;
+ sp<FreezeLock> getFreezeLock() const;
+ inline void incFreezeCount() {
+ if (mFreezeCount == 0)
+ mFreezeDisplayTime = 0;
+ mFreezeCount++;
+ }
+ inline void decFreezeCount() { if (mFreezeCount > 0) mFreezeCount--; }
+ inline bool hasFreezeRequest() const { return mFreezeDisplay; }
+ inline bool isFrozen() const {
+ return (mFreezeDisplay || mFreezeCount>0) && mBootFinished;
+ }
+
+
+ void debugFlashRegions();
+ void debugShowFPS() const;
+ void drawWormhole() const;
+
+
+ mutable MessageQueue mEventQueue;
+
+ status_t postMessageAsync(const sp<MessageBase>& msg,
+ nsecs_t reltime=0, uint32_t flags = 0);
+
+ status_t postMessageSync(const sp<MessageBase>& msg,
+ nsecs_t reltime=0, uint32_t flags = 0);
+
+ // access must be protected by mStateLock
+ mutable Mutex mStateLock;
+ State mCurrentState;
+ State mDrawingState;
+ volatile int32_t mTransactionFlags;
+ volatile int32_t mTransactionCount;
+ Condition mTransactionCV;
+ bool mResizeTransationPending;
+
+ // protected by mStateLock (but we could use another lock)
+ GraphicPlane mGraphicPlanes[1];
+ bool mLayersRemoved;
+ DefaultKeyedVector< wp<IBinder>, wp<Layer> > mLayerMap;
+
+ // constant members (no synchronization needed for access)
+ sp<IMemoryHeap> mServerHeap;
+ surface_flinger_cblk_t* mServerCblk;
+ GLuint mWormholeTexName;
+ nsecs_t mBootTime;
+ Permission mHardwareTest;
+ Permission mAccessSurfaceFlinger;
+ Permission mDump;
+
+ // Can only accessed from the main thread, these members
+ // don't need synchronization
+ Region mDirtyRegion;
+ Region mDirtyRegionRemovedLayer;
+ Region mInvalidRegion;
+ Region mWormholeRegion;
+ bool mVisibleRegionsDirty;
+ bool mDeferReleaseConsole;
+ bool mFreezeDisplay;
+ int32_t mFreezeCount;
+ nsecs_t mFreezeDisplayTime;
+
+ // don't use a lock for these, we don't care
+ int mDebugRegion;
+ int mDebugBackground;
+ volatile nsecs_t mDebugInSwapBuffers;
+ nsecs_t mLastSwapBufferTime;
+ volatile nsecs_t mDebugInTransaction;
+ nsecs_t mLastTransactionTime;
+ bool mBootFinished;
+
+ // these are thread safe
+ mutable Barrier mReadyToRunBarrier;
+
+ // atomic variables
+ enum {
+ eConsoleReleased = 1,
+ eConsoleAcquired = 2
+ };
+ volatile int32_t mConsoleSignals;
+
+ // only written in the main thread, only read in other threads
+ volatile int32_t mSecureFrameBuffer;
+};
+
+// ---------------------------------------------------------------------------
+
+class FreezeLock : public LightRefBase<FreezeLock> {
+ SurfaceFlinger* mFlinger;
+public:
+ FreezeLock(SurfaceFlinger* flinger)
+ : mFlinger(flinger) {
+ mFlinger->incFreezeCount();
+ }
+ ~FreezeLock() {
+ mFlinger->decFreezeCount();
+ }
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_SURFACE_FLINGER_H
diff --git a/services/surfaceflinger/TextureManager.cpp b/services/surfaceflinger/TextureManager.cpp
new file mode 100644
index 0000000..3b326df
--- /dev/null
+++ b/services/surfaceflinger/TextureManager.cpp
@@ -0,0 +1,342 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include <ui/GraphicBuffer.h>
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <hardware/hardware.h>
+
+#include "clz.h"
+#include "DisplayHardware/DisplayHardware.h"
+#include "GLExtensions.h"
+#include "TextureManager.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+TextureManager::TextureManager()
+ : mGLExtensions(GLExtensions::getInstance())
+{
+}
+
+GLenum TextureManager::getTextureTarget(const Image* image) {
+#if defined(GL_OES_texture_external)
+ switch (image->target) {
+ case Texture::TEXTURE_EXTERNAL:
+ return GL_TEXTURE_EXTERNAL_OES;
+ }
+#endif
+ return GL_TEXTURE_2D;
+}
+
+status_t TextureManager::initTexture(Texture* texture)
+{
+ if (texture->name != -1UL)
+ return INVALID_OPERATION;
+
+ GLuint textureName = -1;
+ glGenTextures(1, &textureName);
+ texture->name = textureName;
+ texture->width = 0;
+ texture->height = 0;
+
+ const GLenum target = GL_TEXTURE_2D;
+ glBindTexture(target, textureName);
+ glTexParameterx(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterx(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameterx(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterx(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+
+ return NO_ERROR;
+}
+
+status_t TextureManager::initTexture(Image* pImage, int32_t format)
+{
+ if (pImage->name != -1UL)
+ return INVALID_OPERATION;
+
+ GLuint textureName = -1;
+ glGenTextures(1, &textureName);
+ pImage->name = textureName;
+ pImage->width = 0;
+ pImage->height = 0;
+
+ GLenum target = GL_TEXTURE_2D;
+#if defined(GL_OES_texture_external)
+ if (GLExtensions::getInstance().haveTextureExternal()) {
+ if (format && isYuvFormat(format)) {
+ target = GL_TEXTURE_EXTERNAL_OES;
+ pImage->target = Texture::TEXTURE_EXTERNAL;
+ }
+ }
+#endif
+
+ glBindTexture(target, textureName);
+ glTexParameterx(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterx(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameterx(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterx(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+
+ return NO_ERROR;
+}
+
+bool TextureManager::isSupportedYuvFormat(int format)
+{
+ switch (format) {
+ case HAL_PIXEL_FORMAT_YV12:
+ return true;
+ }
+ return false;
+}
+
+bool TextureManager::isYuvFormat(int format)
+{
+ switch (format) {
+ // supported YUV formats
+ case HAL_PIXEL_FORMAT_YV12:
+ // Legacy/deprecated YUV formats
+ case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+ case HAL_PIXEL_FORMAT_YCbCr_422_I:
+ case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
+ return true;
+ }
+
+ // Any OEM format needs to be considered
+ if (format>=0x100 && format<=0x1FF)
+ return true;
+
+ return false;
+}
+
+status_t TextureManager::initEglImage(Image* pImage,
+ EGLDisplay dpy, const sp<GraphicBuffer>& buffer)
+{
+ status_t err = NO_ERROR;
+ if (!pImage->dirty) return err;
+
+ // free the previous image
+ if (pImage->image != EGL_NO_IMAGE_KHR) {
+ eglDestroyImageKHR(dpy, pImage->image);
+ pImage->image = EGL_NO_IMAGE_KHR;
+ }
+
+ // construct an EGL_NATIVE_BUFFER_ANDROID
+ android_native_buffer_t* clientBuf = buffer->getNativeBuffer();
+
+ // create the new EGLImageKHR
+ const EGLint attrs[] = {
+ EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
+ EGL_NONE, EGL_NONE
+ };
+ pImage->image = eglCreateImageKHR(
+ dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+ (EGLClientBuffer)clientBuf, attrs);
+
+ if (pImage->image != EGL_NO_IMAGE_KHR) {
+ if (pImage->name == -1UL) {
+ initTexture(pImage, buffer->format);
+ }
+ const GLenum target = getTextureTarget(pImage);
+ glBindTexture(target, pImage->name);
+ glEGLImageTargetTexture2DOES(target, (GLeglImageOES)pImage->image);
+ GLint error = glGetError();
+ if (error != GL_NO_ERROR) {
+ LOGE("glEGLImageTargetTexture2DOES(%p) failed err=0x%04x",
+ pImage->image, error);
+ err = INVALID_OPERATION;
+ } else {
+ // Everything went okay!
+ pImage->dirty = false;
+ pImage->width = clientBuf->width;
+ pImage->height = clientBuf->height;
+ }
+ } else {
+ LOGE("eglCreateImageKHR() failed. err=0x%4x", eglGetError());
+ err = INVALID_OPERATION;
+ }
+ return err;
+}
+
+status_t TextureManager::loadTexture(Texture* texture,
+ const Region& dirty, const GGLSurface& t)
+{
+ if (texture->name == -1UL) {
+ status_t err = initTexture(texture);
+ LOGE_IF(err, "loadTexture failed in initTexture (%s)", strerror(err));
+ return err;
+ }
+
+ if (texture->target != GL_TEXTURE_2D)
+ return INVALID_OPERATION;
+
+ glBindTexture(GL_TEXTURE_2D, texture->name);
+
+ /*
+ * In OpenGL ES we can't specify a stride with glTexImage2D (however,
+ * GL_UNPACK_ALIGNMENT is a limited form of stride).
+ * So if the stride here isn't representable with GL_UNPACK_ALIGNMENT, we
+ * need to do something reasonable (here creating a bigger texture).
+ *
+ * extra pixels = (((stride - width) * pixelsize) / GL_UNPACK_ALIGNMENT);
+ *
+ * This situation doesn't happen often, but some h/w have a limitation
+ * for their framebuffer (eg: must be multiple of 8 pixels), and
+ * we need to take that into account when using these buffers as
+ * textures.
+ *
+ * This should never be a problem with POT textures
+ */
+
+ int unpack = __builtin_ctz(t.stride * bytesPerPixel(t.format));
+ unpack = 1 << ((unpack > 3) ? 3 : unpack);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, unpack);
+
+ /*
+ * round to POT if needed
+ */
+ if (!mGLExtensions.haveNpot()) {
+ texture->NPOTAdjust = true;
+ }
+
+ if (texture->NPOTAdjust) {
+ // find the smallest power-of-two that will accommodate our surface
+ texture->potWidth = 1 << (31 - clz(t.width));
+ texture->potHeight = 1 << (31 - clz(t.height));
+ if (texture->potWidth < t.width) texture->potWidth <<= 1;
+ if (texture->potHeight < t.height) texture->potHeight <<= 1;
+ texture->wScale = float(t.width) / texture->potWidth;
+ texture->hScale = float(t.height) / texture->potHeight;
+ } else {
+ texture->potWidth = t.width;
+ texture->potHeight = t.height;
+ }
+
+ Rect bounds(dirty.bounds());
+ GLvoid* data = 0;
+ if (texture->width != t.width || texture->height != t.height) {
+ texture->width = t.width;
+ texture->height = t.height;
+
+ // texture size changed, we need to create a new one
+ bounds.set(Rect(t.width, t.height));
+ if (t.width == texture->potWidth &&
+ t.height == texture->potHeight) {
+ // we can do it one pass
+ data = t.data;
+ }
+
+ if (t.format == HAL_PIXEL_FORMAT_RGB_565) {
+ glTexImage2D(GL_TEXTURE_2D, 0,
+ GL_RGB, texture->potWidth, texture->potHeight, 0,
+ GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data);
+ } else if (t.format == HAL_PIXEL_FORMAT_RGBA_4444) {
+ glTexImage2D(GL_TEXTURE_2D, 0,
+ GL_RGBA, texture->potWidth, texture->potHeight, 0,
+ GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data);
+ } else if (t.format == HAL_PIXEL_FORMAT_RGBA_8888 ||
+ t.format == HAL_PIXEL_FORMAT_RGBX_8888) {
+ glTexImage2D(GL_TEXTURE_2D, 0,
+ GL_RGBA, texture->potWidth, texture->potHeight, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, data);
+ } else if (isSupportedYuvFormat(t.format)) {
+ // just show the Y plane of YUV buffers
+ glTexImage2D(GL_TEXTURE_2D, 0,
+ GL_LUMINANCE, texture->potWidth, texture->potHeight, 0,
+ GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
+ } else {
+ // oops, we don't handle this format!
+ LOGE("texture=%d, using format %d, which is not "
+ "supported by the GL", texture->name, t.format);
+ }
+ }
+ if (!data) {
+ if (t.format == HAL_PIXEL_FORMAT_RGB_565) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ 0, bounds.top, t.width, bounds.height(),
+ GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
+ t.data + bounds.top*t.stride*2);
+ } else if (t.format == HAL_PIXEL_FORMAT_RGBA_4444) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ 0, bounds.top, t.width, bounds.height(),
+ GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4,
+ t.data + bounds.top*t.stride*2);
+ } else if (t.format == HAL_PIXEL_FORMAT_RGBA_8888 ||
+ t.format == HAL_PIXEL_FORMAT_RGBX_8888) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ 0, bounds.top, t.width, bounds.height(),
+ GL_RGBA, GL_UNSIGNED_BYTE,
+ t.data + bounds.top*t.stride*4);
+ } else if (isSupportedYuvFormat(t.format)) {
+ // just show the Y plane of YUV buffers
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ 0, bounds.top, t.width, bounds.height(),
+ GL_LUMINANCE, GL_UNSIGNED_BYTE,
+ t.data + bounds.top*t.stride);
+ }
+ }
+ return NO_ERROR;
+}
+
+void TextureManager::activateTexture(const Texture& texture, bool filter)
+{
+ const GLenum target = getTextureTarget(&texture);
+ if (target == GL_TEXTURE_2D) {
+ glBindTexture(GL_TEXTURE_2D, texture.name);
+ glEnable(GL_TEXTURE_2D);
+#if defined(GL_OES_texture_external)
+ if (GLExtensions::getInstance().haveTextureExternal()) {
+ glDisable(GL_TEXTURE_EXTERNAL_OES);
+ }
+ } else {
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture.name);
+ glEnable(GL_TEXTURE_EXTERNAL_OES);
+ glDisable(GL_TEXTURE_2D);
+#endif
+ }
+
+ if (filter) {
+ glTexParameterx(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterx(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ } else {
+ glTexParameterx(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterx(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ }
+}
+
+void TextureManager::deactivateTextures()
+{
+ glDisable(GL_TEXTURE_2D);
+#if defined(GL_OES_texture_external)
+ if (GLExtensions::getInstance().haveTextureExternal()) {
+ glDisable(GL_TEXTURE_EXTERNAL_OES);
+ }
+#endif
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/services/surfaceflinger/TextureManager.h b/services/surfaceflinger/TextureManager.h
new file mode 100644
index 0000000..c7c14e7
--- /dev/null
+++ b/services/surfaceflinger/TextureManager.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef ANDROID_TEXTURE_MANAGER_H
+#define ANDROID_TEXTURE_MANAGER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES/gl.h>
+
+#include <ui/Region.h>
+
+#include <pixelflinger/pixelflinger.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class GLExtensions;
+class GraphicBuffer;
+
+// ---------------------------------------------------------------------------
+
+struct Image {
+ enum { TEXTURE_2D=0, TEXTURE_EXTERNAL=1 };
+ Image() : name(-1U), image(EGL_NO_IMAGE_KHR), width(0), height(0),
+ transform(0), dirty(1), target(TEXTURE_2D) { }
+ GLuint name;
+ EGLImageKHR image;
+ GLuint width;
+ GLuint height;
+ uint32_t transform;
+ unsigned dirty : 1;
+ unsigned target : 1;
+};
+
+struct Texture : public Image {
+ Texture() : Image(), NPOTAdjust(0) { }
+ GLuint potWidth;
+ GLuint potHeight;
+ GLfloat wScale;
+ GLfloat hScale;
+ unsigned NPOTAdjust : 1;
+};
+
+// ---------------------------------------------------------------------------
+
+class TextureManager {
+ const GLExtensions& mGLExtensions;
+ static status_t initTexture(Image* texture, int32_t format);
+ static status_t initTexture(Texture* texture);
+ static bool isSupportedYuvFormat(int format);
+ static bool isYuvFormat(int format);
+ static GLenum getTextureTarget(const Image* pImage);
+public:
+
+ TextureManager();
+
+ // load bitmap data into the active buffer
+ status_t loadTexture(Texture* texture,
+ const Region& dirty, const GGLSurface& t);
+
+ // make active buffer an EGLImage if needed
+ status_t initEglImage(Image* texture,
+ EGLDisplay dpy, const sp<GraphicBuffer>& buffer);
+
+ // activate a texture
+ static void activateTexture(const Texture& texture, bool filter);
+
+ // deactivate a texture
+ static void deactivateTextures();
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_TEXTURE_MANAGER_H
diff --git a/services/surfaceflinger/Transform.cpp b/services/surfaceflinger/Transform.cpp
new file mode 100644
index 0000000..5e27cc9
--- /dev/null
+++ b/services/surfaceflinger/Transform.cpp
@@ -0,0 +1,391 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <math.h>
+
+#include <cutils/compiler.h>
+#include <utils/String8.h>
+#include <ui/Region.h>
+
+#include "Transform.h"
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+template <typename T> inline T min(T a, T b) {
+ return a<b ? a : b;
+}
+template <typename T> inline T min(T a, T b, T c) {
+ return min(a, min(b, c));
+}
+template <typename T> inline T min(T a, T b, T c, T d) {
+ return min(a, b, min(c, d));
+}
+
+template <typename T> inline T max(T a, T b) {
+ return a>b ? a : b;
+}
+template <typename T> inline T max(T a, T b, T c) {
+ return max(a, max(b, c));
+}
+template <typename T> inline T max(T a, T b, T c, T d) {
+ return max(a, b, max(c, d));
+}
+
+// ---------------------------------------------------------------------------
+
+Transform::Transform() {
+ reset();
+}
+
+Transform::Transform(const Transform& other)
+ : mMatrix(other.mMatrix), mType(other.mType) {
+}
+
+Transform::Transform(uint32_t orientation) {
+ set(orientation, 0, 0);
+}
+
+Transform::~Transform() {
+}
+
+static const float EPSILON = 0.0f;
+
+bool Transform::isZero(float f) {
+ return fabs(f) <= EPSILON;
+}
+
+bool Transform::absIsOne(float f) {
+ return isZero(fabs(f) - 1.0f);
+}
+
+Transform Transform::operator * (const Transform& rhs) const
+{
+ if (CC_LIKELY(mType == IDENTITY))
+ return rhs;
+
+ Transform r(*this);
+ if (rhs.mType == IDENTITY)
+ return r;
+
+ // TODO: we could use mType to optimize the matrix multiply
+ const mat33& A(mMatrix);
+ const mat33& B(rhs.mMatrix);
+ mat33& D(r.mMatrix);
+ for (int i=0 ; i<3 ; i++) {
+ const float v0 = A[0][i];
+ const float v1 = A[1][i];
+ const float v2 = A[2][i];
+ D[0][i] = v0*B[0][0] + v1*B[0][1] + v2*B[0][2];
+ D[1][i] = v0*B[1][0] + v1*B[1][1] + v2*B[1][2];
+ D[2][i] = v0*B[2][0] + v1*B[2][1] + v2*B[2][2];
+ }
+ r.mType |= rhs.mType;
+
+ // TODO: we could recompute this value from r and rhs
+ r.mType &= 0xFF;
+ r.mType |= UNKNOWN_TYPE;
+ return r;
+}
+
+float const* Transform::operator [] (int i) const {
+ return mMatrix[i].v;
+}
+
+bool Transform::transformed() const {
+ return type() > TRANSLATE;
+}
+
+int Transform::tx() const {
+ return floorf(mMatrix[2][0] + 0.5f);
+}
+
+int Transform::ty() const {
+ return floorf(mMatrix[2][1] + 0.5f);
+}
+
+void Transform::reset() {
+ mType = IDENTITY;
+ for(int i=0 ; i<3 ; i++) {
+ vec3& v(mMatrix[i]);
+ for (int j=0 ; j<3 ; j++)
+ v[j] = ((i==j) ? 1.0f : 0.0f);
+ }
+}
+
+void Transform::set(float tx, float ty)
+{
+ mMatrix[2][0] = tx;
+ mMatrix[2][1] = ty;
+ mMatrix[2][2] = 1.0f;
+
+ if (isZero(tx) && isZero(ty)) {
+ mType &= ~TRANSLATE;
+ } else {
+ mType |= TRANSLATE;
+ }
+}
+
+void Transform::set(float a, float b, float c, float d)
+{
+ mat33& M(mMatrix);
+ M[0][0] = a; M[1][0] = b;
+ M[0][1] = c; M[1][1] = d;
+ M[0][2] = 0; M[1][2] = 0;
+ mType = UNKNOWN_TYPE;
+}
+
+status_t Transform::set(uint32_t flags, float w, float h)
+{
+ if (flags & ROT_INVALID) {
+ // that's not allowed!
+ reset();
+ return BAD_VALUE;
+ }
+
+ mType = flags << 8;
+ float sx = (flags & FLIP_H) ? -1 : 1;
+ float sy = (flags & FLIP_V) ? -1 : 1;
+ float a=0, b=0, c=0, d=0, x=0, y=0;
+ int xmask = 0;
+
+ // computation of x,y
+ // x y
+ // 0 0 0
+ // w 0 ROT90
+ // w h FLIPH|FLIPV
+ // 0 h FLIPH|FLIPV|ROT90
+
+ if (flags & ROT_90) {
+ mType |= ROTATE;
+ b = -sy;
+ c = sx;
+ xmask = 1;
+ } else {
+ a = sx;
+ d = sy;
+ }
+
+ if (flags & FLIP_H) {
+ mType ^= SCALE;
+ xmask ^= 1;
+ }
+
+ if (flags & FLIP_V) {
+ mType ^= SCALE;
+ y = h;
+ }
+
+ if ((flags & ROT_180) == ROT_180) {
+ mType |= ROTATE;
+ }
+
+ if (xmask) {
+ x = w;
+ }
+
+ if (!isZero(x) || !isZero(y)) {
+ mType |= TRANSLATE;
+ }
+
+ mat33& M(mMatrix);
+ M[0][0] = a; M[1][0] = b; M[2][0] = x;
+ M[0][1] = c; M[1][1] = d; M[2][1] = y;
+ M[0][2] = 0; M[1][2] = 0; M[2][2] = 1;
+
+ return NO_ERROR;
+}
+
+Transform::vec2 Transform::transform(const vec2& v) const {
+ vec2 r;
+ const mat33& M(mMatrix);
+ r[0] = M[0][0]*v[0] + M[1][0]*v[1] + M[2][0];
+ r[1] = M[0][1]*v[0] + M[1][1]*v[1] + M[2][1];
+ return r;
+}
+
+Transform::vec3 Transform::transform(const vec3& v) const {
+ vec3 r;
+ const mat33& M(mMatrix);
+ r[0] = M[0][0]*v[0] + M[1][0]*v[1] + M[2][0]*v[2];
+ r[1] = M[0][1]*v[0] + M[1][1]*v[1] + M[2][1]*v[2];
+ r[2] = M[0][2]*v[0] + M[1][2]*v[1] + M[2][2]*v[2];
+ return r;
+}
+
+void Transform::transform(float* point, int x, int y) const
+{
+ const mat33& M(mMatrix);
+ vec2 v(x, y);
+ v = transform(v);
+ point[0] = v[0];
+ point[1] = v[1];
+}
+
+Rect Transform::makeBounds(int w, int h) const
+{
+ return transform( Rect(w, h) );
+}
+
+Rect Transform::transform(const Rect& bounds) const
+{
+ Rect r;
+ vec2 lt( bounds.left, bounds.top );
+ vec2 rt( bounds.right, bounds.top );
+ vec2 lb( bounds.left, bounds.bottom );
+ vec2 rb( bounds.right, bounds.bottom );
+
+ lt = transform(lt);
+ rt = transform(rt);
+ lb = transform(lb);
+ rb = transform(rb);
+
+ r.left = floorf(min(lt[0], rt[0], lb[0], rb[0]) + 0.5f);
+ r.top = floorf(min(lt[1], rt[1], lb[1], rb[1]) + 0.5f);
+ r.right = floorf(max(lt[0], rt[0], lb[0], rb[0]) + 0.5f);
+ r.bottom = floorf(max(lt[1], rt[1], lb[1], rb[1]) + 0.5f);
+
+ return r;
+}
+
+Region Transform::transform(const Region& reg) const
+{
+ Region out;
+ if (CC_UNLIKELY(transformed())) {
+ if (CC_LIKELY(preserveRects())) {
+ Region::const_iterator it = reg.begin();
+ Region::const_iterator const end = reg.end();
+ while (it != end) {
+ out.orSelf(transform(*it++));
+ }
+ } else {
+ out.set(transform(reg.bounds()));
+ }
+ } else {
+ out = reg.translate(tx(), ty());
+ }
+ return out;
+}
+
+uint32_t Transform::type() const
+{
+ if (mType & UNKNOWN_TYPE) {
+ // recompute what this transform is
+
+ const mat33& M(mMatrix);
+ const float a = M[0][0];
+ const float b = M[1][0];
+ const float c = M[0][1];
+ const float d = M[1][1];
+ const float x = M[2][0];
+ const float y = M[2][1];
+
+ bool scale = false;
+ uint32_t flags = ROT_0;
+ if (isZero(b) && isZero(c)) {
+ if (a<0) flags |= FLIP_H;
+ if (d<0) flags |= FLIP_V;
+ if (!absIsOne(a) || !absIsOne(d)) {
+ scale = true;
+ }
+ } else if (isZero(a) && isZero(d)) {
+ flags |= ROT_90;
+ if (b>0) flags |= FLIP_H;
+ if (c<0) flags |= FLIP_V;
+ if (!absIsOne(b) || !absIsOne(c)) {
+ scale = true;
+ }
+ } else {
+ flags = ROT_INVALID;
+ }
+
+ mType = flags << 8;
+ if (flags & ROT_INVALID) {
+ mType |= UNKNOWN;
+ } else {
+ if ((flags & ROT_90) || ((flags & ROT_180) == ROT_180))
+ mType |= ROTATE;
+ if (flags & FLIP_H)
+ mType ^= SCALE;
+ if (flags & FLIP_V)
+ mType ^= SCALE;
+ if (scale)
+ mType |= SCALE;
+ }
+
+ if (!isZero(x) || !isZero(y))
+ mType |= TRANSLATE;
+ }
+ return mType;
+}
+
+uint32_t Transform::getType() const {
+ return type() & 0xFF;
+}
+
+uint32_t Transform::getOrientation() const
+{
+ return (type() >> 8) & 0xFF;
+}
+
+bool Transform::preserveRects() const
+{
+ return (type() & ROT_INVALID) ? false : true;
+}
+
+void Transform::dump(const char* name) const
+{
+ type(); // updates the type
+
+ String8 flags, type;
+ const mat33& m(mMatrix);
+ uint32_t orient = mType >> 8;
+
+ if (orient&ROT_INVALID) {
+ flags.append("ROT_INVALID ");
+ } else {
+ if (orient&ROT_90) {
+ flags.append("ROT_90 ");
+ } else {
+ flags.append("ROT_0 ");
+ }
+ if (orient&FLIP_V)
+ flags.append("FLIP_V ");
+ if (orient&FLIP_H)
+ flags.append("FLIP_H ");
+ }
+
+ if (!(mType&(SCALE|ROTATE|TRANSLATE)))
+ type.append("IDENTITY ");
+ if (mType&SCALE)
+ type.append("SCALE ");
+ if (mType&ROTATE)
+ type.append("ROTATE ");
+ if (mType&TRANSLATE)
+ type.append("TRANSLATE ");
+
+ LOGD("%s 0x%08x (%s, %s)", name, mType, flags.string(), type.string());
+ LOGD("%.4f %.4f %.4f", m[0][0], m[1][0], m[2][0]);
+ LOGD("%.4f %.4f %.4f", m[0][1], m[1][1], m[2][1]);
+ LOGD("%.4f %.4f %.4f", m[0][2], m[1][2], m[2][2]);
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/services/surfaceflinger/Transform.h b/services/surfaceflinger/Transform.h
new file mode 100644
index 0000000..20fa11a
--- /dev/null
+++ b/services/surfaceflinger/Transform.h
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_TRANSFORM_H
+#define ANDROID_TRANSFORM_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <ui/Point.h>
+#include <ui/Rect.h>
+
+namespace android {
+
+class Region;
+
+// ---------------------------------------------------------------------------
+
+class Transform
+{
+public:
+ Transform();
+ Transform(const Transform& other);
+ explicit Transform(uint32_t orientation);
+ ~Transform();
+
+ // FIXME: must match OVERLAY_TRANSFORM_*, pull from hardware.h
+ enum orientation_flags {
+ ROT_0 = 0x00000000,
+ FLIP_H = 0x00000001,
+ FLIP_V = 0x00000002,
+ ROT_90 = 0x00000004,
+ ROT_180 = FLIP_H|FLIP_V,
+ ROT_270 = ROT_180|ROT_90,
+ ROT_INVALID = 0x80
+ };
+
+ enum type_mask {
+ IDENTITY = 0,
+ TRANSLATE = 0x1,
+ ROTATE = 0x2,
+ SCALE = 0x4,
+ UNKNOWN = 0x8
+ };
+
+ // query the transform
+ bool transformed() const;
+ bool preserveRects() const;
+ uint32_t getType() const;
+ uint32_t getOrientation() const;
+
+ float const* operator [] (int i) const; // returns column i
+ int tx() const;
+ int ty() const;
+
+ // modify the transform
+ void reset();
+ void set(float tx, float ty);
+ void set(float a, float b, float c, float d);
+ status_t set(uint32_t flags, float w, float h);
+
+ // transform data
+ Rect makeBounds(int w, int h) const;
+ void transform(float* point, int x, int y) const;
+ Region transform(const Region& reg) const;
+ Transform operator * (const Transform& rhs) const;
+
+ // for debugging
+ void dump(const char* name) const;
+
+private:
+ struct vec3 {
+ float v[3];
+ inline vec3() { }
+ inline vec3(float a, float b, float c) {
+ v[0] = a; v[1] = b; v[2] = c;
+ }
+ inline float operator [] (int i) const { return v[i]; }
+ inline float& operator [] (int i) { return v[i]; }
+ };
+ struct vec2 {
+ float v[2];
+ inline vec2() { }
+ inline vec2(float a, float b) {
+ v[0] = a; v[1] = b;
+ }
+ inline float operator [] (int i) const { return v[i]; }
+ inline float& operator [] (int i) { return v[i]; }
+ };
+ struct mat33 {
+ vec3 v[3];
+ inline const vec3& operator [] (int i) const { return v[i]; }
+ inline vec3& operator [] (int i) { return v[i]; }
+ };
+
+ enum { UNKNOWN_TYPE = 0x80000000 };
+
+ // assumes the last row is < 0 , 0 , 1 >
+ vec2 transform(const vec2& v) const;
+ vec3 transform(const vec3& v) const;
+ Rect transform(const Rect& bounds) const;
+ uint32_t type() const;
+ static bool absIsOne(float f);
+ static bool isZero(float f);
+
+ mat33 mMatrix;
+ mutable uint32_t mType;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif /* ANDROID_TRANSFORM_H */
diff --git a/services/surfaceflinger/clz.cpp b/services/surfaceflinger/clz.cpp
new file mode 100644
index 0000000..2456b86
--- /dev/null
+++ b/services/surfaceflinger/clz.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "clz.h"
+
+namespace android {
+
+int clz_impl(int32_t x)
+{
+#if defined(__arm__) && !defined(__thumb__)
+ return __builtin_clz(x);
+#else
+ if (!x) return 32;
+ int e = 31;
+ if (x&0xFFFF0000) { e -=16; x >>=16; }
+ if (x&0x0000FF00) { e -= 8; x >>= 8; }
+ if (x&0x000000F0) { e -= 4; x >>= 4; }
+ if (x&0x0000000C) { e -= 2; x >>= 2; }
+ if (x&0x00000002) { e -= 1; }
+ return e;
+#endif
+}
+
+}; // namespace android
diff --git a/services/surfaceflinger/clz.h b/services/surfaceflinger/clz.h
new file mode 100644
index 0000000..0ddf986
--- /dev/null
+++ b/services/surfaceflinger/clz.h
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_SURFACE_FLINGER_CLZ_H
+
+#include <stdint.h>
+
+namespace android {
+
+int clz_impl(int32_t x);
+
+int inline clz(int32_t x)
+{
+#if defined(__arm__) && !defined(__thumb__)
+ return __builtin_clz(x);
+#else
+ return clz_impl(x);
+#endif
+}
+
+
+}; // namespace android
+
+#endif /* ANDROID_SURFACE_FLINGER_CLZ_H */
diff --git a/services/surfaceflinger/tests/Android.mk b/services/surfaceflinger/tests/Android.mk
new file mode 100644
index 0000000..5053e7d
--- /dev/null
+++ b/services/surfaceflinger/tests/Android.mk
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/services/surfaceflinger/tests/overlays/Android.mk b/services/surfaceflinger/tests/overlays/Android.mk
new file mode 100644
index 0000000..592b601
--- /dev/null
+++ b/services/surfaceflinger/tests/overlays/Android.mk
@@ -0,0 +1,17 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ overlays.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libutils \
+ libui \
+ libsurfaceflinger_client
+
+LOCAL_MODULE:= test-overlays
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/services/surfaceflinger/tests/overlays/overlays.cpp b/services/surfaceflinger/tests/overlays/overlays.cpp
new file mode 100644
index 0000000..c248a615
--- /dev/null
+++ b/services/surfaceflinger/tests/overlays/overlays.cpp
@@ -0,0 +1,59 @@
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
+#include <utils/Log.h>
+
+#include <ui/Overlay.h>
+
+#include <surfaceflinger/Surface.h>
+#include <surfaceflinger/ISurface.h>
+#include <surfaceflinger/SurfaceComposerClient.h>
+
+using namespace android;
+
+namespace android {
+class Test {
+public:
+ static const sp<ISurface>& getISurface(const sp<Surface>& s) {
+ return s->getISurface();
+ }
+};
+};
+
+int main(int argc, char** argv)
+{
+ // set up the thread-pool
+ sp<ProcessState> proc(ProcessState::self());
+ ProcessState::self()->startThreadPool();
+
+ // create a client to surfaceflinger
+ sp<SurfaceComposerClient> client = new SurfaceComposerClient();
+
+ // create pushbuffer surface
+ sp<Surface> surface = client->createSurface(getpid(), 0, 320, 240,
+ PIXEL_FORMAT_UNKNOWN, ISurfaceComposer::ePushBuffers);
+
+ // get to the isurface
+ sp<ISurface> isurface = Test::getISurface(surface);
+ printf("isurface = %p\n", isurface.get());
+
+ // now request an overlay
+ sp<OverlayRef> ref = isurface->createOverlay(320, 240, PIXEL_FORMAT_RGB_565);
+ sp<Overlay> overlay = new Overlay(ref);
+
+
+ /*
+ * here we can use the overlay API
+ */
+
+ overlay_buffer_t buffer;
+ overlay->dequeueBuffer(&buffer);
+ printf("buffer = %p\n", buffer);
+
+ void* address = overlay->getBufferAddress(buffer);
+ printf("address = %p\n", address);
+
+ overlay->queueBuffer(buffer);
+
+ return 0;
+}
diff --git a/services/surfaceflinger/tests/resize/Android.mk b/services/surfaceflinger/tests/resize/Android.mk
new file mode 100644
index 0000000..24c2d01
--- /dev/null
+++ b/services/surfaceflinger/tests/resize/Android.mk
@@ -0,0 +1,17 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ resize.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libutils \
+ libui \
+ libsurfaceflinger_client
+
+LOCAL_MODULE:= test-resize
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/services/surfaceflinger/tests/resize/resize.cpp b/services/surfaceflinger/tests/resize/resize.cpp
new file mode 100644
index 0000000..127cca3
--- /dev/null
+++ b/services/surfaceflinger/tests/resize/resize.cpp
@@ -0,0 +1,62 @@
+#include <cutils/memory.h>
+
+#include <utils/Log.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
+
+#include <surfaceflinger/Surface.h>
+#include <surfaceflinger/ISurface.h>
+#include <surfaceflinger/SurfaceComposerClient.h>
+
+#include <ui/Overlay.h>
+
+using namespace android;
+
+namespace android {
+class Test {
+public:
+ static const sp<ISurface>& getISurface(const sp<Surface>& s) {
+ return s->getISurface();
+ }
+};
+};
+
+int main(int argc, char** argv)
+{
+ // set up the thread-pool
+ sp<ProcessState> proc(ProcessState::self());
+ ProcessState::self()->startThreadPool();
+
+ // create a client to surfaceflinger
+ sp<SurfaceComposerClient> client = new SurfaceComposerClient();
+
+ // create pushbuffer surface
+ sp<Surface> surface = client->createSurface(getpid(), 0, 160, 240,
+ PIXEL_FORMAT_RGB_565);
+
+
+ client->openTransaction();
+ surface->setLayer(100000);
+ client->closeTransaction();
+
+ Surface::SurfaceInfo info;
+ surface->lock(&info);
+ ssize_t bpr = info.s * bytesPerPixel(info.format);
+ android_memset16((uint16_t*)info.bits, 0xF800, bpr*info.h);
+ surface->unlockAndPost();
+
+ surface->lock(&info);
+ android_memset16((uint16_t*)info.bits, 0x07E0, bpr*info.h);
+ surface->unlockAndPost();
+
+ client->openTransaction();
+ surface->setSize(320, 240);
+ client->closeTransaction();
+
+
+ IPCThreadState::self()->joinThreadPool();
+
+ return 0;
+}